Home | History | Annotate | Line # | Download | only in slapd
      1 /*	$NetBSD: syncrepl.c,v 1.4 2025/09/05 21:16:26 christos Exp $	*/
      2 
      3 /* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2003-2024 The OpenLDAP Foundation.
      8  * Portions Copyright 2003 by IBM Corporation.
      9  * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted only as authorized by the OpenLDAP
     14  * Public License.
     15  *
     16  * A copy of this license is available in the file LICENSE in the
     17  * top-level directory of the distribution or, alternatively, at
     18  * <http://www.OpenLDAP.org/license.html>.
     19  */
     20 
     21 #include <sys/cdefs.h>
     22 __RCSID("$NetBSD: syncrepl.c,v 1.4 2025/09/05 21:16:26 christos Exp $");
     23 
     24 #include "portable.h"
     25 
     26 #include <stdio.h>
     27 
     28 #include <ac/string.h>
     29 #include <ac/socket.h>
     30 
     31 #include "lutil.h"
     32 #include "slap.h"
     33 #include "lutil_ldap.h"
     34 
     35 #include "slap-config.h"
     36 
     37 #include "ldap_rq.h"
     38 
     39 #include "rewrite.h"
     40 
     41 #include "back-monitor/back-monitor.h"
     42 
     43 #define SUFFIXM_CTX	"<suffix massage>"
     44 
     45 #ifdef LDAP_CONTROL_X_DIRSYNC
     46 #define MSAD_DIRSYNC	0x04
     47 #define MSAD_DIRSYNC_MODIFY	0x10
     48 
     49 static AttributeDescription *sy_ad_objectGUID;
     50 static AttributeDescription *sy_ad_instanceType;
     51 static AttributeDescription *sy_ad_isDeleted;
     52 static AttributeDescription *sy_ad_whenCreated;
     53 static AttributeDescription *sy_ad_dirSyncCookie;
     54 
     55 static struct berval msad_addval = BER_BVC("range=1-1");
     56 static struct berval msad_delval = BER_BVC("range=0-0");
     57 #endif
     58 
     59 static AttributeDescription *sy_ad_nsUniqueId;
     60 static AttributeDescription *sy_ad_dseeLastChange;
     61 
     62 #define DSEE_SYNC_ADD	0x20
     63 
     64 #define	UUIDLEN	16
     65 
     66 struct syncinfo_s;
     67 
     68 struct nonpresent_entry {
     69 	struct berval *npe_name;
     70 	struct berval *npe_nname;
     71 	LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
     72 };
     73 
     74 typedef struct cookie_vals {
     75 	struct berval *cv_vals;
     76 	int *cv_sids;
     77 	int cv_num;
     78 } cookie_vals;
     79 
     80 typedef struct cookie_state {
     81 	ldap_pvt_thread_mutex_t	cs_mutex;
     82 	ldap_pvt_thread_cond_t cs_cond;
     83 	struct berval *cs_vals;
     84 	int *cs_sids;
     85 	int	cs_num;
     86 	int cs_age;
     87 	int cs_ref;
     88 	int cs_updating;
     89 
     90 	/* pending changes, not yet committed */
     91 	ldap_pvt_thread_mutex_t	cs_pmutex;
     92 	struct berval *cs_pvals;
     93 	int *cs_psids;
     94 	int	cs_pnum;
     95 
     96 	/* serialize multi-consumer refreshes */
     97 	ldap_pvt_thread_mutex_t	cs_refresh_mutex;
     98 	struct syncinfo_s *cs_refreshing;
     99 } cookie_state;
    100 
    101 #define SYNC_TIMEOUT	0
    102 #define SYNC_SHUTDOWN	-100
    103 #define SYNC_ERROR		-101
    104 #define SYNC_REPOLL		-102
    105 #define SYNC_PAUSED		-103
    106 #define SYNC_BUSY		-104
    107 
    108 #define	SYNCDATA_DEFAULT	0	/* entries are plain LDAP entries */
    109 #define	SYNCDATA_ACCESSLOG	1	/* entries are accesslog format */
    110 #define	SYNCDATA_CHANGELOG	2	/* entries are changelog format */
    111 
    112 #define	SYNCLOG_LOGGING		0	/* doing a log-based update */
    113 #define	SYNCLOG_FALLBACK	1	/* doing a full refresh */
    114 
    115 #define RETRYNUM_FOREVER	(-1)	/* retry forever */
    116 #define RETRYNUM_TAIL		(-2)	/* end of retrynum array */
    117 #define RETRYNUM_VALID(n)	((n) >= RETRYNUM_FOREVER)	/* valid retrynum */
    118 #define RETRYNUM_FINITE(n)	((n) > RETRYNUM_FOREVER)	/* not forever */
    119 
    120 typedef struct syncinfo_s {
    121 	struct syncinfo_s	*si_next;
    122 	BackendDB		*si_be;
    123 	BackendDB		*si_wbe;
    124 	struct re_s		*si_re;
    125 	int			si_rid;
    126 	char			si_ridtxt[ STRLENOF("rid=999") + 1 ];
    127 	slap_bindconf		si_bindconf;
    128 	struct berval		si_base;
    129 	struct berval		si_logbase;
    130 	struct berval		si_filterstr;
    131 	struct berval		si_logfilterstr;
    132 	Filter			*si_filter;
    133 	Filter			*si_logfilter;
    134 	struct berval		si_contextdn;
    135 	int			si_scope;
    136 	int			si_attrsonly;
    137 	char			*si_anfile;
    138 	AttributeName		*si_anlist;
    139 	AttributeName		*si_exanlist;
    140 	char 			**si_attrs;
    141 	char			**si_exattrs;
    142 	int			si_allattrs;
    143 	int			si_allopattrs;
    144 	int			si_schemachecking;
    145 	int			si_type;	/* the active type */
    146 	int			si_ctype;	/* the configured type */
    147 	time_t			si_interval;
    148 	time_t			*si_retryinterval;
    149 	int			*si_retrynum_init;
    150 	int			*si_retrynum;
    151 	struct sync_cookie	si_syncCookie;
    152 	cookie_state		*si_cookieState;
    153 	int			si_cookieAge;
    154 	int			si_manageDSAit;
    155 	int			si_slimit;
    156 	int			si_tlimit;
    157 	int			si_refreshDelete;
    158 	int			si_refreshPresent;
    159 	int			si_refreshDone;
    160 	int			si_paused;
    161 	int			si_syncdata;
    162 	int			si_logstate;
    163 	int			si_lazyCommit;
    164 	int			si_got;
    165 	int			si_strict_refresh;	/* stop listening during fallback refresh */
    166 	int			si_too_old;
    167 	int			si_is_configdb;
    168 	ber_int_t	si_msgid;
    169 	Avlnode			*si_presentlist;
    170 	LDAP			*si_ld;
    171 	Connection		*si_conn;
    172 	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
    173 	struct rewrite_info *si_rewrite;
    174 	struct berval	si_suffixm;
    175 #ifdef LDAP_CONTROL_X_DIRSYNC
    176 	struct berval		si_dirSyncCookie;
    177 #endif
    178 	unsigned long	si_prevchange;
    179 	unsigned long	si_lastchange;
    180 
    181 	/* monitor info */
    182 	int		si_monitorInited;
    183 	time_t	si_lastconnect;
    184 	time_t	si_lastcontact;
    185 	struct berval	si_connaddr;
    186 	struct berval	si_lastCookieRcvd;
    187 	struct berval	si_lastCookieSent;
    188 	struct berval	si_monitor_ndn;
    189 	char	si_connaddrbuf[LDAP_IPADDRLEN];
    190 
    191 	ldap_pvt_thread_mutex_t	si_monitor_mutex;
    192 	ldap_pvt_thread_mutex_t	si_mutex;
    193 } syncinfo_t;
    194 
    195 static int syncuuid_cmp( const void *, const void * );
    196 static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
    197 static void presentlist_delete( Avlnode **av, struct berval *syncUUID );
    198 static char *presentlist_find( Avlnode *av, struct berval *syncUUID );
    199 static int presentlist_free( Avlnode *av );
    200 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
    201 static int syncrepl_message_to_op(
    202 					syncinfo_t *, Operation *, LDAPMessage *, int );
    203 static int syncrepl_message_to_entry(
    204 					syncinfo_t *, Operation *, LDAPMessage *,
    205 					Modifications **, Entry **, int, struct berval* );
    206 static int syncrepl_entry(
    207 					syncinfo_t *, Operation*, Entry*,
    208 					Modifications**,int, struct berval*,
    209 					struct berval *cookieCSN );
    210 static int syncrepl_updateCookie(
    211 					syncinfo_t *, Operation *,
    212 					struct sync_cookie *, int save );
    213 static struct berval * slap_uuidstr_from_normalized(
    214 					struct berval *, struct berval *, void * );
    215 static int syncrepl_add_glue_ancestors(
    216 	Operation* op, Entry *e );
    217 
    218 #ifdef LDAP_CONTROL_X_DIRSYNC
    219 static int syncrepl_dirsync_message(
    220 					syncinfo_t *, Operation *, LDAPMessage *,
    221 					Modifications **, Entry **, int *, struct berval* );
    222 static int syncrepl_dirsync_cookie(
    223 					syncinfo_t *, Operation *, LDAPControl ** );
    224 #endif
    225 
    226 static int syncrepl_dsee_update( syncinfo_t *si, Operation *op ) ;
    227 
    228 /* delta-mpr overlay handler */
    229 static int syncrepl_op_modify( Operation *op, SlapReply *rs );
    230 
    231 /* callback functions */
    232 static int dn_callback( Operation *, SlapReply * );
    233 static int nonpresent_callback( Operation *, SlapReply * );
    234 
    235 static AttributeDescription *sync_descs[4];
    236 
    237 static AttributeDescription *dsee_descs[7];
    238 
    239 /* delta-mpr */
    240 static AttributeDescription *ad_reqMod, *ad_reqDN;
    241 
    242 typedef struct logschema {
    243 	struct berval ls_dn;
    244 	struct berval ls_req;
    245 	struct berval ls_mod;
    246 	struct berval ls_newRdn;
    247 	struct berval ls_delRdn;
    248 	struct berval ls_newSup;
    249 	struct berval ls_controls;
    250 	struct berval ls_uuid;
    251 	struct berval ls_changenum;
    252 } logschema;
    253 
    254 static logschema changelog_sc = {
    255 	BER_BVC("targetDN"),
    256 	BER_BVC("changeType"),
    257 	BER_BVC("changes"),
    258 	BER_BVC("newRDN"),
    259 	BER_BVC("deleteOldRDN"),
    260 	BER_BVC("newSuperior"),
    261 	BER_BVNULL,
    262 	BER_BVC("targetUniqueId"),
    263 	BER_BVC("changeNumber")
    264 };
    265 
    266 static logschema accesslog_sc = {
    267 	BER_BVC("reqDN"),
    268 	BER_BVC("reqType"),
    269 	BER_BVC("reqMod"),
    270 	BER_BVC("reqNewRDN"),
    271 	BER_BVC("reqDeleteOldRDN"),
    272 	BER_BVC("reqNewSuperior"),
    273 	BER_BVC("reqControls")
    274 };
    275 
    276 static const char *
    277 syncrepl_state2str( int state )
    278 {
    279 	switch ( state ) {
    280 	case LDAP_SYNC_PRESENT:
    281 		return "PRESENT";
    282 
    283 	case LDAP_SYNC_ADD:
    284 		return "ADD";
    285 
    286 	case LDAP_SYNC_MODIFY:
    287 		return "MODIFY";
    288 
    289 	case LDAP_SYNC_DELETE:
    290 		return "DELETE";
    291 #ifdef LDAP_CONTROL_X_DIRSYNC
    292 	case MSAD_DIRSYNC_MODIFY:
    293 		return "DIRSYNC_MOD";
    294 #endif
    295 	case DSEE_SYNC_ADD:
    296 		return "DSEE_ADD";
    297 	}
    298 
    299 	return "UNKNOWN";
    300 }
    301 
    302 static slap_overinst syncrepl_ov;
    303 
    304 static void
    305 init_syncrepl(syncinfo_t *si)
    306 {
    307 	int i, j, k, l, n;
    308 	char **attrs, **exattrs;
    309 
    310 	if ( !syncrepl_ov.on_bi.bi_type ) {
    311 		syncrepl_ov.on_bi.bi_type = "syncrepl";
    312 		syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify;
    313 		overlay_register( &syncrepl_ov );
    314 	}
    315 
    316 	/* delta-MPR needs the overlay, nothing else does.
    317 	 * This must happen before accesslog overlay is configured.
    318 	 */
    319 	if ( si->si_syncdata &&
    320 		!overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
    321 		overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
    322 		if ( !ad_reqMod ) {
    323 			const char *text;
    324 			logschema *ls = &accesslog_sc;
    325 
    326 			slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
    327 			slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
    328 		}
    329 	}
    330 
    331 	if ( !sync_descs[0] ) {
    332 		sync_descs[0] = slap_schema.si_ad_objectClass;
    333 		sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
    334 		sync_descs[2] = slap_schema.si_ad_entryCSN;
    335 		sync_descs[3] = NULL;
    336 	}
    337 
    338 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
    339 		/* DSEE doesn't support allopattrs */
    340 		si->si_allopattrs = 0;
    341 		if ( !dsee_descs[0] ) {
    342 			dsee_descs[0] = slap_schema.si_ad_objectClass;
    343 			dsee_descs[1] = slap_schema.si_ad_creatorsName;
    344 			dsee_descs[2] = slap_schema.si_ad_createTimestamp;
    345 			dsee_descs[3] = slap_schema.si_ad_modifiersName;
    346 			dsee_descs[4] = slap_schema.si_ad_modifyTimestamp;
    347 			dsee_descs[5] = sy_ad_nsUniqueId;
    348 			dsee_descs[6] = NULL;
    349 		}
    350 	}
    351 
    352 	if ( si->si_allattrs && si->si_allopattrs )
    353 		attrs = NULL;
    354 	else
    355 		attrs = anlist2attrs( si->si_anlist );
    356 
    357 	if ( attrs ) {
    358 		if ( si->si_allattrs ) {
    359 			i = 0;
    360 			while ( attrs[i] ) {
    361 				if ( !is_at_operational( at_find( attrs[i] ) ) ) {
    362 					for ( j = i; attrs[j] != NULL; j++ ) {
    363 						if ( j == i )
    364 							ch_free( attrs[i] );
    365 						attrs[j] = attrs[j+1];
    366 					}
    367 				} else {
    368 					i++;
    369 				}
    370 			}
    371 			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
    372 			attrs[i] = ch_strdup("*");
    373 			attrs[i + 1] = NULL;
    374 
    375 		} else if ( si->si_allopattrs ) {
    376 			i = 0;
    377 			while ( attrs[i] ) {
    378 				if ( is_at_operational( at_find( attrs[i] ) ) ) {
    379 					for ( j = i; attrs[j] != NULL; j++ ) {
    380 						if ( j == i )
    381 							ch_free( attrs[i] );
    382 						attrs[j] = attrs[j+1];
    383 					}
    384 				} else {
    385 					i++;
    386 				}
    387 			}
    388 			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
    389 			attrs[i] = ch_strdup("+");
    390 			attrs[i + 1] = NULL;
    391 		}
    392 
    393 		for ( i = 0; sync_descs[i] != NULL; i++ ) {
    394 			j = 0;
    395 			while ( attrs[j] ) {
    396 				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
    397 					for ( k = j; attrs[k] != NULL; k++ ) {
    398 						if ( k == j )
    399 							ch_free( attrs[k] );
    400 						attrs[k] = attrs[k+1];
    401 					}
    402 				} else {
    403 					j++;
    404 				}
    405 			}
    406 		}
    407 
    408 		for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
    409 
    410 		if ( si->si_allopattrs ) {
    411 			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
    412 		} else {
    413 			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
    414 		}
    415 
    416 		/* Add Attributes */
    417 		if ( si->si_allopattrs ) {
    418 			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
    419 		} else {
    420 			if ( si->si_syncdata != SYNCDATA_CHANGELOG ) {
    421 				for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
    422 					attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
    423 				}
    424 			}
    425 		}
    426 		attrs[ n ] = NULL;
    427 
    428 	} else {
    429 
    430 		i = 0;
    431 		if ( si->si_allattrs == si->si_allopattrs ) {
    432 			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
    433 			attrs[i++] = ch_strdup( "*" );
    434 			attrs[i++] = ch_strdup( "+" );
    435 			si->si_allattrs = si->si_allopattrs = 1;
    436 		} else if ( si->si_allattrs && !si->si_allopattrs ) {
    437 			for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
    438 			attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
    439 			attrs[i++] = ch_strdup( "*" );
    440 			for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
    441 				attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
    442 			}
    443 		} else if ( !si->si_allattrs && si->si_allopattrs ) {
    444 			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
    445 			attrs[i++] = ch_strdup( "+" );
    446 			attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
    447 		}
    448 		attrs[i] = NULL;
    449 	}
    450 
    451 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
    452 		for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
    453 		attrs = ( char ** ) ch_realloc( attrs, (n + 6)*sizeof( char * ) );
    454 		for ( i = 0; dsee_descs[ i ] != NULL; i++ ) {
    455 			attrs[ n++ ] = ch_strdup ( dsee_descs[i]->ad_cname.bv_val );
    456 		}
    457 		attrs[n] = NULL;
    458 	}
    459 
    460 	si->si_attrs = attrs;
    461 
    462 	exattrs = anlist2attrs( si->si_exanlist );
    463 
    464 	if ( exattrs ) {
    465 		for ( n = 0; exattrs[n] != NULL; n++ ) ;
    466 
    467 		for ( i = 0; sync_descs[i] != NULL; i++ ) {
    468 			j = 0;
    469 			while ( exattrs[j] != NULL ) {
    470 				if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
    471 					ch_free( exattrs[j] );
    472 					for ( k = j; exattrs[k] != NULL; k++ ) {
    473 						exattrs[k] = exattrs[k+1];
    474 					}
    475 				} else {
    476 					j++;
    477 				}
    478 			}
    479 		}
    480 
    481 		for ( i = 0; exattrs[i] != NULL; i++ ) {
    482 			for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
    483 				ObjectClass	*oc;
    484 				if ( ( oc = si->si_anlist[j].an_oc ) ) {
    485 					k = 0;
    486 					while ( oc->soc_required[k] ) {
    487 						if ( !strcmp( exattrs[i],
    488 							 oc->soc_required[k]->sat_cname.bv_val ) ) {
    489 							ch_free( exattrs[i] );
    490 							for ( l = i; exattrs[l]; l++ ) {
    491 								exattrs[l] = exattrs[l+1];
    492 							}
    493 						} else {
    494 							k++;
    495 						}
    496 					}
    497 				}
    498 			}
    499 		}
    500 
    501 		for ( i = 0; exattrs[i] != NULL; i++ ) ;
    502 
    503 		if ( i != n )
    504 			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
    505 	}
    506 
    507 	si->si_exattrs = exattrs;
    508 }
    509 
    510 static int
    511 start_refresh(syncinfo_t *si)
    512 {
    513 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_refresh_mutex );
    514 	if ( si->si_cookieState->cs_refreshing ) {
    515 		struct re_s* rtask = si->si_re;
    516 
    517 		ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
    518 		ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
    519 		ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
    520 
    521 		si->si_paused = 1;
    522 		Debug( LDAP_DEBUG_SYNC, "start_refresh: %s "
    523 				"a refresh on %s in progress, pausing\n",
    524 				si->si_ridtxt, si->si_cookieState->cs_refreshing->si_ridtxt );
    525 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_refresh_mutex );
    526 		return SYNC_BUSY;
    527 	}
    528 	si->si_cookieState->cs_refreshing = si;
    529 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_refresh_mutex );
    530 
    531 	return LDAP_SUCCESS;
    532 }
    533 
    534 static int
    535 refresh_finished(syncinfo_t *si, int reschedule)
    536 {
    537 	syncinfo_t *sie;
    538 	int removed = 0;
    539 
    540 	if ( si->si_ctype > 0 && si->si_refreshDone && si->si_retrynum ) {
    541 		/* ITS#10234: We've made meaningful progress, reinit retry state */
    542 		int i;
    543 		for ( i = 0; si->si_retrynum_init[i] != RETRYNUM_TAIL; i++ ) {
    544 			si->si_retrynum[i] = si->si_retrynum_init[i];
    545 		}
    546 		si->si_retrynum[i] = RETRYNUM_TAIL;
    547 	}
    548 
    549 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_refresh_mutex );
    550 	if ( si->si_cookieState->cs_refreshing == si ) {
    551 		si->si_cookieState->cs_refreshing = NULL;
    552 		removed = 1;
    553 	}
    554 
    555 	if ( removed && reschedule ) {
    556 		for ( sie = si->si_be->be_syncinfo; sie; sie = sie->si_next ) {
    557 			if ( sie->si_paused ) {
    558 				struct re_s* rtask = sie->si_re;
    559 
    560 				Debug( LDAP_DEBUG_SYNC, "refresh_finished: %s "
    561 						"rescheduling refresh on %s\n",
    562 						si->si_ridtxt, sie->si_ridtxt );
    563 				sie->si_paused = 0;
    564 				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
    565 				rtask->interval.tv_sec = 0;
    566 				ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
    567 				rtask->interval.tv_sec = si->si_interval;
    568 				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
    569 				break;
    570 			}
    571 		}
    572 	}
    573 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_refresh_mutex );
    574 	return removed;
    575 }
    576 
    577 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
    578 
    579 static int
    580 ldap_sync_search(
    581 	syncinfo_t *si,
    582 	void *ctx )
    583 {
    584 	BerElementBuffer berbuf;
    585 	BerElement *ber = (BerElement *)&berbuf;
    586 	LDAPControl c[3], *ctrls[4];
    587 	int rc;
    588 	int rhint;
    589 	char *base;
    590 	char **attrs, *lattrs[9];
    591 	char *filter;
    592 	int attrsonly;
    593 	int scope;
    594 	char filterbuf[sizeof("(changeNumber>=18446744073709551615)")];
    595 
    596 	/* setup LDAP SYNC control */
    597 	ber_init2( ber, NULL, LBER_USE_DER );
    598 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
    599 
    600 	si->si_msgid = 0;
    601 
    602 	/* If we're using a log but we have no state, then fallback to
    603 	 * normal mode for a full refresh.
    604 	 */
    605 	if ( si->si_syncdata ) {
    606 		if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
    607 			LDAPMessage *res, *msg;
    608 			unsigned long first = 0, last = 0;
    609 			int gotfirst = 0, gotlast = 0;
    610 
    611 			if ( (rc = start_refresh( si )) ) {
    612 				return rc;
    613 			}
    614 
    615 			/* See if we're new enough for the remote server */
    616 			lattrs[0] = "firstchangenumber";
    617 			lattrs[1] = "lastchangenumber";
    618 			lattrs[2] = NULL;
    619 			rc = ldap_search_ext_s( si->si_ld, "", LDAP_SCOPE_BASE, generic_filterstr.bv_val, lattrs, 0,
    620 				NULL, NULL, NULL, si->si_slimit, &res );
    621 			if ( rc ) {
    622 				ldap_msgfree( res );
    623 				return rc;
    624 			}
    625 			msg = ldap_first_message( si->si_ld, res );
    626 			if ( msg && ldap_msgtype( msg ) == LDAP_RES_SEARCH_ENTRY ) {
    627 				BerElement *ber = NULL;
    628 				struct berval bv, *bvals, **bvp = &bvals;;
    629 				rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bv );
    630 				for ( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp );
    631 					rc == LDAP_SUCCESS;
    632 					rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp ) ) {
    633 					if ( bv.bv_val == NULL )
    634 						break;
    635 					if ( !strcasecmp( bv.bv_val, "firstchangenumber" )) {
    636 						first = strtoul( bvals[0].bv_val, NULL, 0 );
    637 						gotfirst = 1;
    638 					} else if ( !strcasecmp( bv.bv_val, "lastchangenumber" )) {
    639 						last = strtoul( bvals[0].bv_val, NULL, 0 );
    640 						gotlast = 1;
    641 					}
    642 				}
    643 			}
    644 			ldap_msgfree( res );
    645 			if ( gotfirst && gotlast ) {
    646 				if ( si->si_lastchange < first || (!si->si_lastchange && !si->si_refreshDone ))
    647 					si->si_logstate = SYNCLOG_FALLBACK;
    648 				/* if we're in logging mode, it will update si_lastchange itself */
    649 				if ( si->si_logstate == SYNCLOG_FALLBACK )
    650 					si->si_lastchange = last;
    651 			} else {
    652 				/* should be an error; changelog plugin not enabled on provider */
    653 				si->si_logstate = SYNCLOG_FALLBACK;
    654 			}
    655 		} else
    656 		if ( si->si_logstate == SYNCLOG_LOGGING && !si->si_syncCookie.numcsns &&
    657 				!si->si_refreshDone ) {
    658 			si->si_logstate = SYNCLOG_FALLBACK;
    659 		}
    660 	}
    661 
    662 	/* Use the log parameters if we're in log mode */
    663 	if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
    664 		logschema *ls;
    665 		if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
    666 			ls = &accesslog_sc;
    667 		else
    668 			ls = &changelog_sc;
    669 		lattrs[0] = ls->ls_dn.bv_val;
    670 		lattrs[1] = ls->ls_req.bv_val;
    671 		lattrs[2] = ls->ls_mod.bv_val;
    672 		lattrs[3] = ls->ls_newRdn.bv_val;
    673 		lattrs[4] = ls->ls_delRdn.bv_val;
    674 		lattrs[5] = ls->ls_newSup.bv_val;
    675 		if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
    676 			lattrs[6] = ls->ls_controls.bv_val;
    677 			lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
    678 			lattrs[8] = NULL;
    679 			filter = si->si_logfilterstr.bv_val;
    680 			scope = LDAP_SCOPE_SUBTREE;
    681 		} else {
    682 			lattrs[6] = ls->ls_uuid.bv_val;
    683 			lattrs[7] = ls->ls_changenum.bv_val;
    684 			lattrs[8] = NULL;
    685 			sprintf( filterbuf, "(changeNumber>=%lu)", si->si_lastchange+1 );
    686 			filter = filterbuf;
    687 			scope = LDAP_SCOPE_ONELEVEL;
    688 		}
    689 
    690 		rhint = 0;
    691 		base = si->si_logbase.bv_val;
    692 		attrs = lattrs;
    693 		attrsonly = 0;
    694 	} else {
    695 		if ( (rc = start_refresh( si )) ) {
    696 			return rc;
    697 		}
    698 
    699 		rhint = 1;
    700 		base = si->si_base.bv_val;
    701 		filter = si->si_filterstr.bv_val;
    702 		attrs = si->si_attrs;
    703 		attrsonly = si->si_attrsonly;
    704 		scope = si->si_scope;
    705 	}
    706 	if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
    707 		si->si_type = LDAP_SYNC_REFRESH_ONLY;
    708 	} else {
    709 		si->si_type = si->si_ctype;
    710 	}
    711 
    712 #ifdef LDAP_CONTROL_X_DIRSYNC
    713 	if ( si->si_ctype == MSAD_DIRSYNC ) {
    714 		ber_printf( ber, "{iiO}", LDAP_CONTROL_X_DIRSYNC_INCREMENTAL_VALUES, 0, &si->si_dirSyncCookie );
    715 
    716 		if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
    717 			ber_free_buf( ber );
    718 			return rc;
    719 		}
    720 		c[0].ldctl_oid = LDAP_CONTROL_X_DIRSYNC;
    721 		c[0].ldctl_iscritical = 1;
    722 		ctrls[0] = &c[0];
    723 
    724 		if ( !BER_BVISEMPTY( &si->si_dirSyncCookie )) {
    725 			c[1].ldctl_oid = LDAP_CONTROL_X_SHOW_DELETED;
    726 			BER_BVZERO( &c[1].ldctl_value );
    727 			c[1].ldctl_iscritical = 1;
    728 			ctrls[1] = &c[1];
    729 			ctrls[2] = NULL;
    730 		} else {
    731 			ctrls[1] = NULL;
    732 		}
    733 	} else
    734 #endif
    735 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
    736 		if ( si->si_logstate == SYNCLOG_LOGGING && si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
    737 			c[0].ldctl_oid = LDAP_CONTROL_PERSIST_REQUEST;
    738 			c[0].ldctl_iscritical = 0;
    739 			rc = ldap_create_persistentsearch_control_value( si->si_ld, LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD,
    740 				0, 1, &c[0].ldctl_value );
    741 			ctrls[0] = &c[0];
    742 			ctrls[1] = NULL;
    743 		} else {
    744 			ctrls[0] = NULL;
    745 		}
    746 	} else
    747 	{
    748 		if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
    749 		{
    750 			ber_printf( ber, "{eOb}",
    751 				abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
    752 		} else {
    753 			ber_printf( ber, "{eb}",
    754 				abs(si->si_type), rhint );
    755 		}
    756 
    757 		if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
    758 			ber_free_buf( ber );
    759 			return rc;
    760 		}
    761 
    762 		c[0].ldctl_oid = LDAP_CONTROL_SYNC;
    763 		c[0].ldctl_iscritical = si->si_type < 0;
    764 		ctrls[0] = &c[0];
    765 
    766 		c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
    767 		BER_BVZERO( &c[1].ldctl_value );
    768 		c[1].ldctl_iscritical = 1;
    769 		ctrls[1] = &c[1];
    770 
    771 		if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
    772 			c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
    773 			c[2].ldctl_value = si->si_bindconf.sb_authzId;
    774 			c[2].ldctl_iscritical = 1;
    775 			ctrls[2] = &c[2];
    776 			ctrls[3] = NULL;
    777 		} else {
    778 			ctrls[2] = NULL;
    779 		}
    780 	}
    781 
    782 	si->si_refreshDone = 0;
    783 	si->si_refreshPresent = 0;
    784 	si->si_refreshDelete = 0;
    785 
    786 	rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
    787 		ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
    788 	ber_free_buf( ber );
    789 	return rc;
    790 }
    791 
    792 /* #define DEBUG_MERGE_STATE	1 */
    793 
    794 static int
    795 merge_state( syncinfo_t *si, struct sync_cookie *sc1, struct sync_cookie *sc2 )
    796 {
    797 	int i, j, k, changed = 0;
    798 	int ei, ej;
    799 	int *newsids;
    800 	struct berval *newcsns;
    801 
    802 	ei = sc1->numcsns;
    803 	ej = sc2->numcsns;
    804 #ifdef DEBUG_MERGE_STATE
    805 	for ( i=0; i<ei; i++ ) {
    806 		fprintf(stderr, "merge_state: %s si_syncCookie [%d] %d %s\n",
    807 			si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val );
    808 	}
    809 	for ( i=0; i<ej; i++ ) {
    810 		fprintf(stderr, "merge_state: %s si_cookieState [%d] %d %s\n",
    811 			si->si_ridtxt, i, sc2->sids[i], sc2->ctxcsn[i].bv_val );
    812 	}
    813 #endif
    814 	/* see if they cover the same SIDs */
    815 	if ( ei == ej ) {
    816 		for ( i = 0; i < ei; i++ ) {
    817 			if ( sc1->sids[i] != sc2->sids[i] ) {
    818 				changed = 1;
    819 				break;
    820 			}
    821 		}
    822 		/* SIDs are the same, take fast path */
    823 		if ( !changed ) {
    824 			for ( i = 0; i < ei; i++ ) {
    825 				if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[i] ) < 0 ) {
    826 					ber_bvreplace( &sc1->ctxcsn[i], &sc2->ctxcsn[i] );
    827 					changed = 1;
    828 				}
    829 			}
    830 			return changed;
    831 		}
    832 		changed = 0;
    833 	}
    834 
    835 	i = ei + ej;
    836 	newsids = ch_malloc( sizeof(int) * i );
    837 	newcsns = ch_malloc( sizeof(struct berval) * ( i + 1 ));
    838 
    839 	for ( i=0, j=0, k=0; i < ei || j < ej ; ) {
    840 		if ( i < ei && sc1->sids[i] == -1 ) {
    841 			i++;
    842 			continue;
    843 		}
    844 		if ( j >= ej || (i < ei && sc1->sids[i] < sc2->sids[j] )) {
    845 			newsids[k] = sc1->sids[i];
    846 			ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] );
    847 			i++; k++;
    848 			continue;
    849 		}
    850 		if ( i < ei && sc1->sids[i] == sc2->sids[j] ) {
    851 			newsids[k] = sc1->sids[i];
    852 			if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[j] ) < 0 ) {
    853 				changed = 1;
    854 				ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] );
    855 			} else {
    856 				ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] );
    857 			}
    858 			i++; j++; k++;
    859 			continue;
    860 		}
    861 		if ( j < ej ) {
    862 			if ( sc2->sids[j] == -1 ) {
    863 				j++;
    864 				continue;
    865 			}
    866 			newsids[k] = sc2->sids[j];
    867 			ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] );
    868 			changed = 1;
    869 			j++; k++;
    870 		}
    871 	}
    872 
    873 	ber_bvarray_free( sc1->ctxcsn );
    874 	ch_free( sc1->sids );
    875 	sc1->numcsns = k;
    876 	sc1->sids = ch_realloc( newsids, sizeof(int) * k );
    877 	sc1->ctxcsn = ch_realloc( newcsns, sizeof(struct berval) * (k+1) );
    878 	BER_BVZERO( &sc1->ctxcsn[k] );
    879 #ifdef DEBUG_MERGE_STATE
    880 	for ( i=0; i<sc1->numcsns; i++ ) {
    881 		fprintf(stderr, "merge_state: %s si_syncCookie2 [%d] %d %s\n",
    882 			si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val );
    883 	}
    884 #endif
    885 
    886 	return changed;
    887 }
    888 
    889 #ifdef DEBUG_MERGE_STATE
    890 static void
    891 merge_test( syncinfo_t *si ) {
    892 	struct sync_cookie sc1, sc2;
    893 	int ret;
    894 
    895 	sc1.numcsns = 4;
    896 	sc1.sids = malloc( sizeof( int ) * sc1.numcsns );
    897 	sc1.ctxcsn = malloc( sizeof( struct berval ) * ( sc1.numcsns + 1 ));
    898 	sc1.sids[0] = 1;
    899 	sc1.sids[1] = 3;
    900 	sc1.sids[2] = 4;
    901 	sc1.sids[3] = 5;
    902 	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc1#001#000000");	/* unique */
    903 	ber_dupbv( &sc1.ctxcsn[0], &bv ); }
    904 	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc1#003#000000");	/* lower */
    905 	ber_dupbv( &sc1.ctxcsn[1], &bv ); }
    906 	{ struct berval bv = BER_BVC("20201231000000.100000Z#sc1#004#000000");	/* higher */
    907 	ber_dupbv( &sc1.ctxcsn[2], &bv ); }
    908 	{ struct berval bv = BER_BVC("20200228000000.100000Z#sc1#005#000000");	/* unique */
    909 	ber_dupbv( &sc1.ctxcsn[3], &bv ); }
    910 	BER_BVZERO( &sc1.ctxcsn[sc1.numcsns] );
    911 
    912 	sc2.numcsns = 4;
    913 	sc2.sids = malloc( sizeof( int ) * sc2.numcsns );
    914 	sc2.ctxcsn = malloc( sizeof( struct berval ) * ( sc2.numcsns + 1 ));
    915 	sc2.sids[0] = 2;
    916 	sc2.sids[1] = 3;
    917 	sc2.sids[2] = 4;
    918 	sc2.sids[3] = 6;
    919 	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc2#002#000000");	/* unique */
    920 	ber_dupbv( &sc2.ctxcsn[0], &bv ); }
    921 	{ struct berval bv = BER_BVC("20200331000000.100000Z#sc2#003#000000");	/* higher */
    922 	ber_dupbv( &sc2.ctxcsn[1], &bv ); }
    923 	{ struct berval bv = BER_BVC("20200501000000.100000Z#sc2#004#000000");	/* lower */
    924 	ber_dupbv( &sc2.ctxcsn[2], &bv ); }
    925 	{ struct berval bv = BER_BVC("20200628000000.100000Z#sc2#006#000000");	/* unique */
    926 	ber_dupbv( &sc2.ctxcsn[3], &bv ); }
    927 	BER_BVZERO( &sc2.ctxcsn[sc2.numcsns] );
    928 
    929 	ret = merge_state( si, &sc1, &sc2 );
    930 }
    931 #endif
    932 
    933 static int
    934 check_syncprov(
    935 	Operation *op,
    936 	syncinfo_t *si )
    937 {
    938 	AttributeName at[2];
    939 	Attribute a = {0};
    940 	Entry e = {0};
    941 	SlapReply rs = {REP_SEARCH};
    942 	int i, j, changed = 0;
    943 
    944 	/* Look for contextCSN from syncprov overlay. If
    945 	 * there's no overlay, this will be a no-op. That means
    946 	 * this is a pure consumer, so local changes will not be
    947 	 * allowed, and all changes will already be reflected in
    948 	 * the cookieState.
    949 	 */
    950 	a.a_desc = slap_schema.si_ad_contextCSN;
    951 	e.e_attrs = &a;
    952 	e.e_name = si->si_contextdn;
    953 	e.e_nname = si->si_contextdn;
    954 	at[0].an_name = a.a_desc->ad_cname;
    955 	at[0].an_desc = a.a_desc;
    956 	BER_BVZERO( &at[1].an_name );
    957 	rs.sr_entry = &e;
    958 	rs.sr_flags = REP_ENTRY_MODIFIABLE;
    959 	rs.sr_attrs = at;
    960 	op->o_req_dn = e.e_name;
    961 	op->o_req_ndn = e.e_nname;
    962 
    963 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
    964 	i = backend_operational( op, &rs );
    965 	if ( i == LDAP_SUCCESS && a.a_nvals ) {
    966 		int num = a.a_numvals;
    967 		/* check for differences */
    968 		if ( num != si->si_cookieState->cs_num ) {
    969 			changed = 1;
    970 		} else {
    971 			for ( i=0; i<num; i++ ) {
    972 				if ( ber_bvcmp( &a.a_nvals[i],
    973 					&si->si_cookieState->cs_vals[i] )) {
    974 					changed = 1;
    975 					break;
    976 				}
    977 			}
    978 		}
    979 		if ( changed ) {
    980 			ber_bvarray_free( si->si_cookieState->cs_vals );
    981 			ch_free( si->si_cookieState->cs_sids );
    982 			si->si_cookieState->cs_num = num;
    983 			si->si_cookieState->cs_vals = a.a_nvals;
    984 			si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
    985 				num, NULL );
    986 			si->si_cookieState->cs_age++;
    987 		} else {
    988 			ber_bvarray_free( a.a_nvals );
    989 		}
    990 		ber_bvarray_free( a.a_vals );
    991 	}
    992 	/* See if the cookieState has changed due to anything outside
    993 	 * this particular consumer. That includes other consumers in
    994 	 * the same context, or local changes detected above.
    995 	 */
    996 	if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
    997 		si->si_cookieState->cs_age ) {
    998 		if ( !si->si_syncCookie.numcsns ) {
    999 			ber_bvarray_free( si->si_syncCookie.ctxcsn );
   1000 			ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
   1001 				si->si_cookieState->cs_vals, NULL );
   1002 			changed = 1;
   1003 		} else {
   1004 			changed = merge_state( si, &si->si_syncCookie,
   1005 				(struct sync_cookie *)&si->si_cookieState->cs_vals );
   1006 		}
   1007 	}
   1008 	if ( changed ) {
   1009 		si->si_cookieAge = si->si_cookieState->cs_age;
   1010 		ch_free( si->si_syncCookie.octet_str.bv_val );
   1011 		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
   1012 			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
   1013 			si->si_syncCookie.sid, NULL );
   1014 		ch_free( si->si_syncCookie.sids );
   1015 		slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx );
   1016 	}
   1017 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   1018 	return changed;
   1019 }
   1020 
   1021 static int
   1022 do_syncrep1(
   1023 	Operation *op,
   1024 	syncinfo_t *si )
   1025 {
   1026 	int	rc;
   1027 	int cmdline_cookie_found = 0;
   1028 
   1029 	struct sync_cookie	*sc = NULL;
   1030 #ifdef HAVE_TLS
   1031 	void	*ssl;
   1032 #endif
   1033 
   1034 	si->si_lastconnect = slap_get_time();
   1035 	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
   1036 	if ( rc != LDAP_SUCCESS ) {
   1037 		goto done;
   1038 	}
   1039 	op->o_protocol = LDAP_VERSION3;
   1040 
   1041 	/* Set SSF to strongest of TLS, SASL SSFs */
   1042 	op->o_sasl_ssf = 0;
   1043 	op->o_tls_ssf = 0;
   1044 	op->o_transport_ssf = 0;
   1045 #ifdef HAVE_TLS
   1046 	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
   1047 		== LDAP_SUCCESS && ssl != NULL )
   1048 	{
   1049 		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
   1050 	}
   1051 #endif /* HAVE_TLS */
   1052 	{
   1053 		ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
   1054 						  to use sasl_ssf_t but currently uses ber_len_t */
   1055 		if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
   1056 			== LDAP_SUCCESS )
   1057 			op->o_sasl_ssf = ssf;
   1058 	}
   1059 	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
   1060 		?  op->o_sasl_ssf : op->o_tls_ssf;
   1061 
   1062 	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
   1063 
   1064 	rc = LDAP_DEREF_NEVER;	/* actually could allow DEREF_FINDING */
   1065 	ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
   1066 
   1067 	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
   1068 
   1069 	si->si_syncCookie.rid = si->si_rid;
   1070 
   1071 	/* whenever there are multiple data sources possible, advertise sid */
   1072 	si->si_syncCookie.sid = ( SLAP_MULTIPROVIDER( si->si_be ) || si->si_be != si->si_wbe ) ?
   1073 		slap_serverID : -1;
   1074 
   1075 #ifdef LDAP_CONTROL_X_DIRSYNC
   1076 	if ( si->si_ctype == MSAD_DIRSYNC ) {
   1077 		if ( BER_BVISEMPTY( &si->si_dirSyncCookie )) {
   1078 			BerVarray cookies = NULL;
   1079 			void *ctx = op->o_tmpmemctx;
   1080 
   1081 			op->o_req_ndn = si->si_contextdn;
   1082 			op->o_req_dn = op->o_req_ndn;
   1083 
   1084 			/* try to read stored cookie */
   1085 			op->o_tmpmemctx = NULL;
   1086 			backend_attribute( op, NULL, &op->o_req_ndn,
   1087 				sy_ad_dirSyncCookie, &cookies, ACL_READ );
   1088 			op->o_tmpmemctx = ctx;
   1089 			if ( cookies )
   1090 				si->si_dirSyncCookie = cookies[0];
   1091 		}
   1092 	} else
   1093 #endif
   1094 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
   1095 		if ( !si->si_lastchange ) {
   1096 			BerVarray vals = NULL;
   1097 
   1098 			op->o_req_ndn = si->si_contextdn;
   1099 			op->o_req_dn = op->o_req_ndn;
   1100 			/* try to read last change number */
   1101 			backend_attribute( op, NULL, &op->o_req_ndn,
   1102 				sy_ad_dseeLastChange, &vals, ACL_READ );
   1103 			if ( vals ) {
   1104 				si->si_lastchange = strtoul( vals[0].bv_val, NULL, 0 );
   1105 				si->si_prevchange = si->si_lastchange;
   1106 			}
   1107 		}
   1108 	} else
   1109 	{
   1110 
   1111 		/* We've just started up, or the remote server hasn't sent us
   1112 		 * any meaningful state.
   1113 		 */
   1114 		if ( !si->si_syncCookie.ctxcsn ) {
   1115 			int i;
   1116 
   1117 			LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
   1118 				if ( si->si_rid == sc->rid ) {
   1119 					cmdline_cookie_found = 1;
   1120 					break;
   1121 				}
   1122 			}
   1123 
   1124 			if ( cmdline_cookie_found ) {
   1125 				/* cookie is supplied in the command line */
   1126 
   1127 				LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
   1128 
   1129 				slap_sync_cookie_free( &si->si_syncCookie, 0 );
   1130 				si->si_syncCookie.octet_str = sc->octet_str;
   1131 				ch_free( sc );
   1132 				/* ctxcsn wasn't parsed yet, do it now */
   1133 				slap_parse_sync_cookie( &si->si_syncCookie, NULL );
   1134 			} else {
   1135 				ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   1136 				if ( !si->si_cookieState->cs_num ) {
   1137 					/* get contextCSN shadow replica from database */
   1138 					BerVarray csn = NULL;
   1139 					void *ctx = op->o_tmpmemctx;
   1140 
   1141 					op->o_req_ndn = si->si_contextdn;
   1142 					op->o_req_dn = op->o_req_ndn;
   1143 
   1144 					/* try to read stored contextCSN */
   1145 					op->o_tmpmemctx = NULL;
   1146 					backend_attribute( op, NULL, &op->o_req_ndn,
   1147 						slap_schema.si_ad_contextCSN, &csn, ACL_READ );
   1148 					op->o_tmpmemctx = ctx;
   1149 					if ( csn ) {
   1150 						si->si_cookieState->cs_vals = csn;
   1151 						for (i=0; !BER_BVISNULL( &csn[i] ); i++);
   1152 						si->si_cookieState->cs_num = i;
   1153 						si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
   1154 						slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
   1155 					}
   1156 				}
   1157 				if ( si->si_cookieState->cs_num ) {
   1158 					ber_bvarray_free( si->si_syncCookie.ctxcsn );
   1159 					if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
   1160 						si->si_cookieState->cs_vals, NULL )) {
   1161 						rc = LDAP_NO_MEMORY;
   1162 						ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   1163 						goto done;
   1164 					}
   1165 					si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
   1166 					si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num *
   1167 						sizeof(int) );
   1168 					for ( i=0; i<si->si_syncCookie.numcsns; i++ )
   1169 						si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
   1170 				}
   1171 				ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   1172 			}
   1173 		}
   1174 
   1175 		if ( !cmdline_cookie_found ) {
   1176 			/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
   1177 			ch_free( si->si_syncCookie.octet_str.bv_val );
   1178 			BER_BVZERO( &si->si_syncCookie.octet_str );
   1179 			/* Look for contextCSN from syncprov overlay. */
   1180 			check_syncprov( op, si );
   1181 			if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
   1182 				slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
   1183 					si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
   1184 					si->si_syncCookie.sid, NULL );
   1185 		}
   1186 	}
   1187 
   1188 	Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n",
   1189 		si->si_ridtxt, si->si_syncCookie.octet_str.bv_val ?
   1190 		si->si_syncCookie.octet_str.bv_val : "" );
   1191 
   1192 	if ( si->si_syncCookie.octet_str.bv_val ) {
   1193 		ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
   1194 		ber_bvreplace( &si->si_lastCookieSent, &si->si_syncCookie.octet_str );
   1195 		ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   1196 	}
   1197 
   1198 	rc = ldap_sync_search( si, op->o_tmpmemctx );
   1199 
   1200 	if ( rc == SYNC_BUSY ) {
   1201 		return rc;
   1202 	} else if ( rc != LDAP_SUCCESS ) {
   1203 		refresh_finished( si, 1 );
   1204 		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
   1205 			"ldap_search_ext: %s (%d)\n",
   1206 			si->si_ridtxt, ldap_err2string( rc ), rc );
   1207 	}
   1208 
   1209 done:
   1210 	if ( rc ) {
   1211 		if ( si->si_ld ) {
   1212 			ldap_unbind_ext( si->si_ld, NULL, NULL );
   1213 			si->si_ld = NULL;
   1214 		}
   1215 	}
   1216 
   1217 	return rc;
   1218 }
   1219 
   1220 static int
   1221 compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
   1222 {
   1223 	int i, j, match = 0;
   1224 	const char *text;
   1225 
   1226 	*which = 0;
   1227 
   1228 	if ( sc1->numcsns < sc2->numcsns ) {
   1229 		for ( i=0; i < sc1->numcsns && sc1->sids[i] == sc2->sids[i] ; i++ )
   1230 			/* Find the first one that's missing */;
   1231 		*which = i;
   1232 		return -1;
   1233 	}
   1234 
   1235 	for (j=0; j<sc2->numcsns; j++) {
   1236 		for (i=0; i<sc1->numcsns; i++) {
   1237 			if ( sc1->sids[i] != sc2->sids[j] )
   1238 				continue;
   1239 			value_match( &match, slap_schema.si_ad_entryCSN,
   1240 				slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
   1241 				SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
   1242 				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
   1243 			if ( match < 0 ) {
   1244 				*which = j;
   1245 				return match;
   1246 			}
   1247 			break;
   1248 		}
   1249 		if ( i == sc1->numcsns ) {
   1250 			/* sc2 has a sid sc1 lacks */
   1251 			*which = j;
   1252 			return -1;
   1253 		}
   1254 	}
   1255 	return match;
   1256 }
   1257 
   1258 #define CV_CSN_OK	0
   1259 #define CV_CSN_OLD	1
   1260 #define CV_SID_NEW	2
   1261 
   1262 static int
   1263 check_csn_age(
   1264 	syncinfo_t *si,
   1265 	struct berval *dn,
   1266 	struct berval *csn,
   1267 	int sid,
   1268 	cookie_vals *cv,
   1269 	int *slot )
   1270 {
   1271 	int i, rc = CV_SID_NEW;
   1272 
   1273 	for ( i =0; i<cv->cv_num; i++ ) {
   1274 #ifdef CHATTY_SYNCLOG
   1275 		Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n",
   1276 			si->si_ridtxt, i, cv->cv_vals[i].bv_val );
   1277 #endif
   1278 		/* new SID */
   1279 		if ( sid < cv->cv_sids[i] )
   1280 			break;
   1281 		if ( cv->cv_sids[i] == sid ) {
   1282 			if ( ber_bvcmp( csn, &cv->cv_vals[i] ) <= 0 ) {
   1283 				dn->bv_val[dn->bv_len] = '\0';
   1284 				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
   1285 					si->si_ridtxt, csn->bv_val, dn->bv_val );
   1286 				return CV_CSN_OLD;
   1287 			}
   1288 			rc = CV_CSN_OK;
   1289 			break;
   1290 		}
   1291 	}
   1292 	if ( slot )
   1293 		*slot = i;
   1294 	return rc;
   1295 }
   1296 
   1297 static int
   1298 get_pmutex(
   1299 	syncinfo_t *si
   1300 )
   1301 {
   1302 	if ( !si->si_is_configdb ) {
   1303 		ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_pmutex );
   1304 	} else {
   1305 		/* avoid deadlock when replicating cn=config */
   1306 		while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
   1307 			if ( slapd_shutdown )
   1308 				return SYNC_SHUTDOWN;
   1309 			if ( !ldap_pvt_thread_pool_pausewait( &connection_pool ))
   1310 				ldap_pvt_thread_yield();
   1311 		}
   1312 	}
   1313 	if ( si->si_ctype < 0 ) {
   1314 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
   1315 		return SYNC_SHUTDOWN;
   1316 	}
   1317 
   1318 	return 0;
   1319 }
   1320 
   1321 static int
   1322 do_syncrep2(
   1323 	Operation *op,
   1324 	syncinfo_t *si )
   1325 {
   1326 	BerElementBuffer berbuf;
   1327 	BerElement	*ber = (BerElement *)&berbuf;
   1328 
   1329 	LDAPMessage	*msg = NULL;
   1330 
   1331 	struct sync_cookie	syncCookie = { NULL };
   1332 	struct sync_cookie	syncCookie_req = { NULL };
   1333 
   1334 	int		rc,
   1335 			err = LDAP_SUCCESS;
   1336 
   1337 	Modifications	*modlist = NULL;
   1338 
   1339 	int				m;
   1340 
   1341 	struct timeval tout = { 0, 0 };
   1342 
   1343 	int		refreshDeletes = 0;
   1344 	int		refreshing = !si->si_refreshDone &&
   1345 			!( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING );
   1346 	char empty[6] = "empty";
   1347 
   1348 	if ( slapd_shutdown ) {
   1349 		rc = SYNC_SHUTDOWN;
   1350 		goto done;
   1351 	}
   1352 
   1353 	ber_init2( ber, NULL, LBER_USE_DER );
   1354 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
   1355 
   1356 	Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt );
   1357 
   1358 	slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
   1359 
   1360 	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
   1361 		tout.tv_sec = 0;
   1362 	} else {
   1363 		/* Give some time for refresh response to arrive */
   1364 		tout.tv_sec = si->si_bindconf.sb_timeout_api;
   1365 	}
   1366 
   1367 	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
   1368 		&tout, &msg ) ) > 0 )
   1369 	{
   1370 		int				match, punlock, syncstate;
   1371 		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
   1372 		char			*retoid;
   1373 		LDAPControl		**rctrls = NULL, *rctrlp = NULL;
   1374 		BerVarray		syncUUIDs;
   1375 		ber_len_t		len;
   1376 		ber_tag_t		si_tag;
   1377 		Entry			*entry;
   1378 		struct berval	bdn;
   1379 
   1380 		if ( slapd_shutdown ) {
   1381 			rc = SYNC_SHUTDOWN;
   1382 			goto done;
   1383 		}
   1384 		si->si_lastcontact = slap_get_time();
   1385 		switch( ldap_msgtype( msg ) ) {
   1386 		case LDAP_RES_SEARCH_ENTRY:
   1387 #ifdef LDAP_CONTROL_X_DIRSYNC
   1388 			if ( si->si_ctype == MSAD_DIRSYNC ) {
   1389 				BER_BVZERO( &syncUUID[0] );
   1390 				rc = syncrepl_dirsync_message( si, op, msg, &modlist, &entry, &syncstate, syncUUID );
   1391 				if ( rc == 0 )
   1392 					rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL );
   1393 				op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx );
   1394 				if ( modlist )
   1395 					slap_mods_free( modlist, 1);
   1396 				if ( rc )
   1397 					goto done;
   1398 				break;
   1399 			}
   1400 #endif
   1401 			punlock = -1;
   1402 			ldap_get_entry_controls( si->si_ld, msg, &rctrls );
   1403 			ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
   1404 			if (!bdn.bv_len) {
   1405 				bdn.bv_val = empty;
   1406 				bdn.bv_len = sizeof(empty)-1;
   1407 			}
   1408 			if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
   1409 				if ( si->si_logstate == SYNCLOG_LOGGING ) {
   1410 					rc = syncrepl_message_to_op( si, op, msg, 1 );
   1411 					if ( rc )
   1412 						goto logerr;
   1413 					if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST && rctrls ) {
   1414 						LDAPControl **next = NULL;
   1415 						/* The notification control is only sent during persist phase */
   1416 						rctrlp = ldap_control_find( LDAP_CONTROL_PERSIST_ENTRY_CHANGE_NOTICE, rctrls, &next );
   1417 						if ( rctrlp ) {
   1418 							if ( si->si_refreshDone )
   1419 								syncrepl_dsee_update( si, op );
   1420 						}
   1421 					}
   1422 
   1423 				} else {
   1424 					syncstate = DSEE_SYNC_ADD;
   1425 					rc = syncrepl_message_to_entry( si, op, msg,
   1426 						&modlist, &entry, syncstate, syncUUID );
   1427 					if ( rc == 0 )
   1428 						rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL );
   1429 					op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx );
   1430 					if ( modlist )
   1431 						slap_mods_free( modlist, 1);
   1432 				}
   1433 				if ( rc )
   1434 					goto done;
   1435 				break;
   1436 			}
   1437 			/* we can't work without the control */
   1438 			if ( rctrls ) {
   1439 				LDAPControl **next = NULL;
   1440 				/* NOTE: make sure we use the right one;
   1441 				 * a better approach would be to run thru
   1442 				 * the whole list and take care of all */
   1443 				/* NOTE: since we issue the search request,
   1444 				 * we should know what controls to expect,
   1445 				 * and there should be none apart from the
   1446 				 * sync-related control */
   1447 				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
   1448 				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
   1449 				{
   1450 					bdn.bv_val[bdn.bv_len] = '\0';
   1451 					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
   1452 						"got search entry with multiple "
   1453 						"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val );
   1454 					ldap_controls_free( rctrls );
   1455 					rc = -1;
   1456 					goto done;
   1457 				}
   1458 			}
   1459 			if ( rctrlp == NULL ) {
   1460 				bdn.bv_val[bdn.bv_len] = '\0';
   1461 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
   1462 					"got search entry without "
   1463 					"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val );
   1464 				rc = -1;
   1465 				goto done;
   1466 			}
   1467 			ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
   1468 			if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
   1469 					== LBER_ERROR ) {
   1470 				bdn.bv_val[bdn.bv_len] = '\0';
   1471 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
   1472 					si->si_ridtxt, bdn.bv_val );
   1473 				ldap_controls_free( rctrls );
   1474 				rc = -1;
   1475 				goto done;
   1476 			}
   1477 			/* FIXME: what if syncUUID is NULL or empty?
   1478 			 * (happens with back-sql...) */
   1479 			if ( syncUUID[0].bv_len != UUIDLEN ) {
   1480 				bdn.bv_val[bdn.bv_len] = '\0';
   1481 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
   1482 					"got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n",
   1483 					si->si_ridtxt,
   1484 					syncrepl_state2str( syncstate ), bdn.bv_val );
   1485 				ldap_controls_free( rctrls );
   1486 				rc = -1;
   1487 				goto done;
   1488 			}
   1489 			if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
   1490 				if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) != LBER_ERROR ) {
   1491 
   1492 				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
   1493 					si->si_ridtxt,
   1494 					BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
   1495 
   1496 				if ( !BER_BVISNULL( &cookie ) ) {
   1497 					ch_free( syncCookie.octet_str.bv_val );
   1498 					ber_dupbv( &syncCookie.octet_str, &cookie );
   1499 
   1500 					ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
   1501 					ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
   1502 					ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   1503 				}
   1504 				if ( !BER_BVISNULL( &syncCookie.octet_str ) )
   1505 				{
   1506 					slap_parse_sync_cookie( &syncCookie, NULL );
   1507 					if ( syncCookie.ctxcsn ) {
   1508 						int i, slot, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
   1509 						check_syncprov( op, si );
   1510 						ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   1511 						i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL );
   1512 						ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   1513 						if ( i == CV_CSN_OLD ) {
   1514 							si->si_too_old = 1;
   1515 							ldap_controls_free( rctrls );
   1516 							rc = 0;
   1517 							goto done;
   1518 						}
   1519 						si->si_too_old = 0;
   1520 
   1521 						/* check pending CSNs too */
   1522 						if (( rc = get_pmutex( si )))
   1523 							goto done;
   1524 
   1525 						i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_pvals, &slot );
   1526 						if ( i == CV_CSN_OK ) {
   1527 							ber_bvreplace( &si->si_cookieState->cs_pvals[slot],
   1528 								syncCookie.ctxcsn );
   1529 						} else if ( i == CV_CSN_OLD ) {
   1530 							ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
   1531 							ldap_controls_free( rctrls );
   1532 							rc = 0;
   1533 							goto done;
   1534 						} else {
   1535 						/* new SID, add it */
   1536 							slap_insert_csn_sids(
   1537 								(struct sync_cookie *)&si->si_cookieState->cs_pvals,
   1538 								slot, sid, syncCookie.ctxcsn );
   1539 						}
   1540 						assert( punlock < 0 );
   1541 						punlock = slot;
   1542 					} else if (si->si_too_old) {
   1543 						bdn.bv_val[bdn.bv_len] = '\0';
   1544 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring (%s)\n",
   1545 							si->si_ridtxt, bdn.bv_val );
   1546 						ldap_controls_free( rctrls );
   1547 						rc = 0;
   1548 						goto done;
   1549 					}
   1550 					op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
   1551 				}
   1552 				}
   1553 			}
   1554 			rc = 0;
   1555 			if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
   1556 				modlist = NULL;
   1557 				if ( ( rc = syncrepl_message_to_op( si, op, msg, punlock < 0 ) ) == LDAP_SUCCESS &&
   1558 					syncCookie.ctxcsn )
   1559 				{
   1560 					rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
   1561 				} else
   1562 logerr:
   1563 					switch ( rc ) {
   1564 					case LDAP_ALREADY_EXISTS:
   1565 					case LDAP_NO_SUCH_OBJECT:
   1566 					case LDAP_NO_SUCH_ATTRIBUTE:
   1567 					case LDAP_TYPE_OR_VALUE_EXISTS:
   1568 					case LDAP_NOT_ALLOWED_ON_NONLEAF:
   1569 						rc = LDAP_SYNC_REFRESH_REQUIRED;
   1570 						si->si_logstate = SYNCLOG_FALLBACK;
   1571 						ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
   1572 						bdn.bv_val[bdn.bv_len] = '\0';
   1573 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
   1574 							si->si_ridtxt, bdn.bv_val );
   1575 						if (si->si_strict_refresh) {
   1576 							slap_suspend_listeners();
   1577 							connections_drop();
   1578 						}
   1579 						break;
   1580 					default:
   1581 						break;
   1582 					}
   1583 			} else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
   1584 				&modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS )
   1585 			{
   1586 				if ( punlock < 0 ) {
   1587 					if (( rc = get_pmutex( si )))
   1588 						goto done;
   1589 				}
   1590 				if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
   1591 					syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
   1592 					syncCookie.ctxcsn )
   1593 				{
   1594 					rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
   1595 				}
   1596 				if ( punlock < 0 )
   1597 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
   1598 			}
   1599 			if ( punlock >= 0 ) {
   1600 				/* on failure, revert pending CSN */
   1601 				if ( rc != LDAP_SUCCESS ) {
   1602 					int i;
   1603 					ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   1604 					for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
   1605 						if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
   1606 							ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
   1607 								&si->si_cookieState->cs_vals[i] );
   1608 							break;
   1609 						}
   1610 					}
   1611 					if ( i == si->si_cookieState->cs_num )
   1612 						si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
   1613 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   1614 				}
   1615 				ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
   1616 			}
   1617 			ldap_controls_free( rctrls );
   1618 			if ( modlist ) {
   1619 				slap_mods_free( modlist, 1 );
   1620 			}
   1621 			if ( rc )
   1622 				goto done;
   1623 			break;
   1624 
   1625 		case LDAP_RES_SEARCH_REFERENCE:
   1626 			Debug( LDAP_DEBUG_ANY,
   1627 				"do_syncrep2: %s reference received error\n",
   1628 				si->si_ridtxt );
   1629 			break;
   1630 
   1631 		case LDAP_RES_SEARCH_RESULT:
   1632 			Debug( LDAP_DEBUG_SYNC,
   1633 				"do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
   1634 				si->si_ridtxt );
   1635 			err = LDAP_OTHER; /* FIXME check parse result properly */
   1636 			ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
   1637 				&rctrls, 0 );
   1638 #ifdef LDAP_X_SYNC_REFRESH_REQUIRED
   1639 			if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
   1640 				/* map old result code to registered code */
   1641 				err = LDAP_SYNC_REFRESH_REQUIRED;
   1642 			}
   1643 #endif
   1644 			if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
   1645 				if ( si->si_logstate == SYNCLOG_LOGGING ) {
   1646 					si->si_logstate = SYNCLOG_FALLBACK;
   1647 					Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
   1648 						si->si_ridtxt );
   1649 					if (si->si_strict_refresh) {
   1650 						slap_suspend_listeners();
   1651 						connections_drop();
   1652 					}
   1653 				}
   1654 				rc = err;
   1655 				goto done;
   1656 			}
   1657 			if ( err ) {
   1658 				Debug( LDAP_DEBUG_ANY,
   1659 					"do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
   1660 					si->si_ridtxt, err, ldap_err2string( err ) );
   1661 			}
   1662 			if ( si->si_syncdata == SYNCDATA_CHANGELOG && err == LDAP_SUCCESS ) {
   1663 				rc = syncrepl_dsee_update( si, op );
   1664 				if ( rc == LDAP_SUCCESS ) {
   1665 					if ( si->si_logstate == SYNCLOG_FALLBACK ) {
   1666 						si->si_logstate = SYNCLOG_LOGGING;
   1667 						si->si_refreshDone = 1;
   1668 						rc = LDAP_SYNC_REFRESH_REQUIRED;
   1669 					} else {
   1670 						rc = SYNC_REPOLL;
   1671 					}
   1672 				}
   1673 				goto done;
   1674 			}
   1675 			if ( rctrls ) {
   1676 				LDAPControl **next = NULL;
   1677 #ifdef LDAP_CONTROL_X_DIRSYNC
   1678 				if ( si->si_ctype == MSAD_DIRSYNC ) {
   1679 					rc = syncrepl_dirsync_cookie( si, op, rctrls );
   1680 					if ( rc == LDAP_SUCCESS )
   1681 						rc = SYNC_REPOLL;	/* schedule a re-poll */
   1682 					goto done;
   1683 				}
   1684 #endif
   1685 				/* NOTE: make sure we use the right one;
   1686 				 * a better approach would be to run thru
   1687 				 * the whole list and take care of all */
   1688 				/* NOTE: since we issue the search request,
   1689 				 * we should know what controls to expect,
   1690 				 * and there should be none apart from the
   1691 				 * sync-related control */
   1692 				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next );
   1693 				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) )
   1694 				{
   1695 					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
   1696 						"got search result with multiple "
   1697 						"Sync State control\n", si->si_ridtxt );
   1698 					ldap_controls_free( rctrls );
   1699 					rc = SYNC_ERROR;
   1700 					goto done;
   1701 				}
   1702 			}
   1703 			if ( rctrlp ) {
   1704 				ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
   1705 
   1706 				ber_scanf( ber, "{" /*"}"*/);
   1707 				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
   1708 					ber_scanf( ber, "m", &cookie );
   1709 
   1710 					Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
   1711 						si->si_ridtxt,
   1712 						BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
   1713 
   1714 					if ( !BER_BVISNULL( &cookie ) ) {
   1715 						ch_free( syncCookie.octet_str.bv_val );
   1716 						ber_dupbv( &syncCookie.octet_str, &cookie);
   1717 
   1718 						ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
   1719 						ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
   1720 						ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   1721 					}
   1722 					if ( !BER_BVISNULL( &syncCookie.octet_str ) )
   1723 					{
   1724 						slap_parse_sync_cookie( &syncCookie, NULL );
   1725 						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
   1726 					}
   1727 				}
   1728 				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
   1729 				{
   1730 					ber_scanf( ber, "b", &refreshDeletes );
   1731 				}
   1732 				ber_scanf( ber, /*"{"*/ "}" );
   1733 			}
   1734 			if ( SLAP_MULTIPROVIDER( op->o_bd ) && check_syncprov( op, si )) {
   1735 				slap_sync_cookie_free( &syncCookie_req, 0 );
   1736 				slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
   1737 			}
   1738 			if ( !syncCookie.ctxcsn ) {
   1739 				match = 1;
   1740 			} else if ( !syncCookie_req.ctxcsn ) {
   1741 				match = -1;
   1742 				m = 0;
   1743 			} else {
   1744 				match = compare_csns( &syncCookie_req, &syncCookie, &m );
   1745 			}
   1746 			if ( rctrls ) {
   1747 				ldap_controls_free( rctrls );
   1748 			}
   1749 			if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
   1750 				/* FIXME : different error behaviors according to
   1751 				 *	1) err code : LDAP_BUSY ...
   1752 				 *	2) on err policy : stop service, stop sync, retry
   1753 				 */
   1754 				if ( refreshDeletes == 0 && match < 0 && err == LDAP_SUCCESS )
   1755 				{
   1756 					syncrepl_del_nonpresent( op, si, NULL,
   1757 						&syncCookie, m );
   1758 				} else if ( si->si_presentlist ) {
   1759 					presentlist_free( si->si_presentlist );
   1760 					si->si_presentlist = NULL;
   1761 				}
   1762 			}
   1763 			if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
   1764 			{
   1765 				rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
   1766 			}
   1767 			if ( err == LDAP_SUCCESS
   1768 				&& si->si_logstate == SYNCLOG_FALLBACK ) {
   1769 				si->si_logstate = SYNCLOG_LOGGING;
   1770 				si->si_refreshDone = 1;
   1771 				rc = LDAP_SYNC_REFRESH_REQUIRED;
   1772 				slap_resume_listeners();
   1773 			} else {
   1774 				/* for persist, we shouldn't get a SearchResult so this is an error */
   1775 				if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST )
   1776 					rc = SYNC_ERROR;
   1777 				else
   1778 					rc = SYNC_REPOLL;
   1779 			}
   1780 			goto done;
   1781 
   1782 		case LDAP_RES_INTERMEDIATE:
   1783 			retoid = NULL;
   1784 			retdata = NULL;
   1785 			rc = ldap_parse_intermediate( si->si_ld, msg,
   1786 				&retoid, &retdata, NULL, 0 );
   1787 			if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
   1788 				ber_init2( ber, retdata, LBER_USE_DER );
   1789 
   1790 				switch ( si_tag = ber_peek_tag( ber, &len ) ) {
   1791 				ber_tag_t tag;
   1792 				case LDAP_TAG_SYNC_NEW_COOKIE:
   1793 					Debug( LDAP_DEBUG_SYNC,
   1794 						"do_syncrep2: %s %s - %s\n",
   1795 						si->si_ridtxt,
   1796 						"LDAP_RES_INTERMEDIATE",
   1797 						"NEW_COOKIE" );
   1798 					ber_scanf( ber, "tm", &tag, &cookie );
   1799 					Debug( LDAP_DEBUG_SYNC,
   1800 						"do_syncrep2: %s NEW_COOKIE: %s\n",
   1801 						si->si_ridtxt,
   1802 						cookie.bv_val );
   1803 					if ( !BER_BVISNULL( &cookie ) ) {
   1804 						ch_free( syncCookie.octet_str.bv_val );
   1805 						ber_dupbv( &syncCookie.octet_str, &cookie );
   1806 
   1807 						ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
   1808 						ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
   1809 						ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   1810 					}
   1811 					if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
   1812 						slap_parse_sync_cookie( &syncCookie, NULL );
   1813 						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
   1814 					}
   1815 					break;
   1816 				case LDAP_TAG_SYNC_REFRESH_DELETE:
   1817 				case LDAP_TAG_SYNC_REFRESH_PRESENT:
   1818 					Debug( LDAP_DEBUG_SYNC,
   1819 						"do_syncrep2: %s %s - %s\n",
   1820 						si->si_ridtxt,
   1821 						"LDAP_RES_INTERMEDIATE",
   1822 						si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
   1823 						"REFRESH_PRESENT" : "REFRESH_DELETE" );
   1824 					if ( si->si_refreshDone ) {
   1825 						Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
   1826 								"server sent multiple refreshDone "
   1827 								"messages? Ending session\n",
   1828 								si->si_ridtxt );
   1829 						rc = LDAP_PROTOCOL_ERROR;
   1830 						goto done;
   1831 					}
   1832 					if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
   1833 						si->si_refreshDelete = 1;
   1834 					} else {
   1835 						si->si_refreshPresent = 1;
   1836 					}
   1837 					ber_scanf( ber, "t{" /*"}"*/, &tag );
   1838 					if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
   1839 					{
   1840 						ber_scanf( ber, "m", &cookie );
   1841 
   1842 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
   1843 							si->si_ridtxt,
   1844 							BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
   1845 
   1846 						if ( !BER_BVISNULL( &cookie ) ) {
   1847 							ch_free( syncCookie.octet_str.bv_val );
   1848 							ber_dupbv( &syncCookie.octet_str, &cookie );
   1849 
   1850 							ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
   1851 							ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
   1852 							ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   1853 						}
   1854 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
   1855 						{
   1856 							slap_parse_sync_cookie( &syncCookie, NULL );
   1857 							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
   1858 						}
   1859 					}
   1860 					/* Defaults to TRUE */
   1861 					if ( ber_peek_tag( ber, &len ) ==
   1862 						LDAP_TAG_REFRESHDONE )
   1863 					{
   1864 						ber_scanf( ber, "b", &si->si_refreshDone );
   1865 					} else
   1866 					{
   1867 						si->si_refreshDone = 1;
   1868 					}
   1869 					ber_scanf( ber, /*"{"*/ "}" );
   1870 					if ( refreshing && si->si_refreshDone ) {
   1871 						refresh_finished( si, 1 );
   1872 						refreshing = 0;
   1873 					}
   1874 					break;
   1875 				case LDAP_TAG_SYNC_ID_SET:
   1876 					Debug( LDAP_DEBUG_SYNC,
   1877 						"do_syncrep2: %s %s - %s\n",
   1878 						si->si_ridtxt,
   1879 						"LDAP_RES_INTERMEDIATE",
   1880 						"SYNC_ID_SET" );
   1881 					ber_scanf( ber, "t{" /*"}"*/, &tag );
   1882 					if ( ber_peek_tag( ber, &len ) ==
   1883 						LDAP_TAG_SYNC_COOKIE )
   1884 					{
   1885 						ber_scanf( ber, "m", &cookie );
   1886 
   1887 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
   1888 							si->si_ridtxt,
   1889 							BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
   1890 
   1891 						if ( !BER_BVISNULL( &cookie ) ) {
   1892 							ch_free( syncCookie.octet_str.bv_val );
   1893 							ber_dupbv( &syncCookie.octet_str, &cookie );
   1894 
   1895 							ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
   1896 							ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
   1897 							ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   1898 						}
   1899 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
   1900 						{
   1901 							slap_parse_sync_cookie( &syncCookie, NULL );
   1902 							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
   1903 							compare_csns( &syncCookie_req, &syncCookie, &m );
   1904 						}
   1905 					}
   1906 					if ( ber_peek_tag( ber, &len ) ==
   1907 						LDAP_TAG_REFRESHDELETES )
   1908 					{
   1909 						ber_scanf( ber, "b", &refreshDeletes );
   1910 					}
   1911 					syncUUIDs = NULL;
   1912 					rc = ber_scanf( ber, "[W]", &syncUUIDs );
   1913 					ber_scanf( ber, /*"{"*/ "}" );
   1914 					if ( rc != LBER_ERROR ) {
   1915 						if ( refreshDeletes ) {
   1916 							syncrepl_del_nonpresent( op, si, syncUUIDs,
   1917 								&syncCookie, m );
   1918 							ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
   1919 						} else {
   1920 							int i;
   1921 							for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
   1922 								(void)presentlist_insert( si, &syncUUIDs[i] );
   1923 								slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
   1924 							}
   1925 							slap_sl_free( syncUUIDs, op->o_tmpmemctx );
   1926 						}
   1927 					}
   1928 					rc = 0;
   1929 					slap_sync_cookie_free( &syncCookie, 0 );
   1930 					break;
   1931 				default:
   1932 					Debug( LDAP_DEBUG_ANY,
   1933 						"do_syncrep2: %s unknown syncinfo tag (%ld)\n",
   1934 						si->si_ridtxt, (long) si_tag );
   1935 					ldap_memfree( retoid );
   1936 					ber_bvfree( retdata );
   1937 					continue;
   1938 				}
   1939 
   1940 				if ( SLAP_MULTIPROVIDER( op->o_bd ) && check_syncprov( op, si )) {
   1941 					slap_sync_cookie_free( &syncCookie_req, 0 );
   1942 					slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
   1943 				}
   1944 				if ( !syncCookie.ctxcsn ) {
   1945 					match = 1;
   1946 				} else if ( !syncCookie_req.ctxcsn ) {
   1947 					match = -1;
   1948 					m = 0;
   1949 				} else {
   1950 					match = compare_csns( &syncCookie_req, &syncCookie, &m );
   1951 				}
   1952 
   1953 				if ( match < 0 ) {
   1954 					if ( si->si_refreshPresent == 1 &&
   1955 						si_tag != LDAP_TAG_SYNC_NEW_COOKIE ) {
   1956 						syncrepl_del_nonpresent( op, si, NULL,
   1957 							&syncCookie, m );
   1958 					}
   1959 
   1960 					if ( syncCookie.ctxcsn )
   1961 					{
   1962 						rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
   1963 					}
   1964 					if ( si->si_presentlist ) {
   1965 						presentlist_free( si->si_presentlist );
   1966 						si->si_presentlist = NULL;
   1967 					}
   1968 				}
   1969 
   1970 				ldap_memfree( retoid );
   1971 				ber_bvfree( retdata );
   1972 
   1973 				if ( rc )
   1974 					goto done;
   1975 
   1976 			} else {
   1977 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
   1978 					"unknown intermediate response (%d)\n",
   1979 					si->si_ridtxt, rc );
   1980 				ldap_memfree( retoid );
   1981 				ber_bvfree( retdata );
   1982 			}
   1983 			break;
   1984 
   1985 		default:
   1986 			Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
   1987 				"unknown message (0x%02lx)\n",
   1988 				si->si_ridtxt,
   1989 				(unsigned long)ldap_msgtype( msg ) );
   1990 			break;
   1991 
   1992 		}
   1993 		if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
   1994 			slap_sync_cookie_free( &syncCookie_req, 0 );
   1995 			syncCookie_req = syncCookie;
   1996 			memset( &syncCookie, 0, sizeof( syncCookie ));
   1997 		}
   1998 		ldap_msgfree( msg );
   1999 		msg = NULL;
   2000 		if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
   2001 			slap_sync_cookie_free( &syncCookie, 0 );
   2002 			slap_sync_cookie_free( &syncCookie_req, 0 );
   2003 			return SYNC_PAUSED;
   2004 		}
   2005 	}
   2006 
   2007 	if ( rc == SYNC_ERROR ) {
   2008 		rc = LDAP_OTHER;
   2009 		ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
   2010 		err = rc;
   2011 	}
   2012 
   2013 done:
   2014 	if ( err != LDAP_SUCCESS ) {
   2015 		Debug( LDAP_DEBUG_ANY,
   2016 			"do_syncrep2: %s (%d) %s\n",
   2017 			si->si_ridtxt, err, ldap_err2string( err ) );
   2018 	}
   2019 	if ( refreshing && ( rc || si->si_refreshDone ) ) {
   2020 		refresh_finished( si, 1 );
   2021 	}
   2022 
   2023 	slap_sync_cookie_free( &syncCookie, 0 );
   2024 	slap_sync_cookie_free( &syncCookie_req, 0 );
   2025 
   2026 	if ( msg ) ldap_msgfree( msg );
   2027 
   2028 	if ( rc ) {
   2029 		if ( rc == LDAP_SYNC_REFRESH_REQUIRED && si->si_logstate == SYNCLOG_LOGGING && si->si_ld )
   2030 			return rc;
   2031 		/* never reuse existing connection */
   2032 		if ( si->si_conn ) {
   2033 			connection_client_stop( si->si_conn );
   2034 			si->si_conn = NULL;
   2035 		}
   2036 		ldap_unbind_ext( si->si_ld, NULL, NULL );
   2037 		si->si_ld = NULL;
   2038 	}
   2039 
   2040 	return rc;
   2041 }
   2042 
   2043 static int
   2044 syncrepl_monitor_add( syncinfo_t *si );
   2045 
   2046 static int
   2047 syncrepl_monitor_del( syncinfo_t *si );
   2048 
   2049 static void *
   2050 do_syncrepl(
   2051 	void	*ctx,
   2052 	void	*arg )
   2053 {
   2054 	struct re_s* rtask = arg;
   2055 	syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
   2056 	Connection conn = {0};
   2057 	OperationBuffer opbuf;
   2058 	Operation *op;
   2059 	int rc = LDAP_SUCCESS;
   2060 	int dostop = 0;
   2061 	ber_socket_t s;
   2062 	int i, fail = 0, freeinfo = 0;
   2063 	Backend *be;
   2064 
   2065 	if ( si == NULL )
   2066 		return NULL;
   2067 	if ( slapd_shutdown )
   2068 		return NULL;
   2069 
   2070 	if ( !si->si_monitorInited ) {
   2071 		syncrepl_monitor_add( si );
   2072 		si->si_monitorInited = 1;
   2073 	}
   2074 
   2075 	Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt );
   2076 
   2077 	ldap_pvt_thread_mutex_lock( &si->si_mutex );
   2078 
   2079 	si->si_too_old = 0;
   2080 
   2081 	if ( si->si_ctype < 1 ) {
   2082 		goto deleted;
   2083 	}
   2084 
   2085 	switch( abs( si->si_type ) ) {
   2086 	case LDAP_SYNC_REFRESH_ONLY:
   2087 	case LDAP_SYNC_REFRESH_AND_PERSIST:
   2088 #ifdef LDAP_CONTROL_X_DIRSYNC
   2089 	case MSAD_DIRSYNC:
   2090 #endif
   2091 		break;
   2092 	default:
   2093 		ldap_pvt_thread_mutex_unlock( &si->si_mutex );
   2094 		return NULL;
   2095 	}
   2096 
   2097 	if ( slapd_shutdown ) {
   2098 		if ( si->si_ld ) {
   2099 			if ( si->si_conn ) {
   2100 				connection_client_stop( si->si_conn );
   2101 				si->si_conn = NULL;
   2102 			}
   2103 			ldap_unbind_ext( si->si_ld, NULL, NULL );
   2104 			si->si_ld = NULL;
   2105 		}
   2106 		ldap_pvt_thread_mutex_unlock( &si->si_mutex );
   2107 		return NULL;
   2108 	}
   2109 
   2110 	connection_fake_init( &conn, &opbuf, ctx );
   2111 	op = &opbuf.ob_op;
   2112 	/* o_connids must be unique for slap_graduate_commit_csn */
   2113 	op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
   2114 
   2115 	op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
   2116 	be = si->si_be;
   2117 
   2118 	/* Coordinate contextCSN updates with any syncprov overlays
   2119 	 * in use. This may be complicated by the use of the glue
   2120 	 * overlay.
   2121 	 *
   2122 	 * Typically there is a single syncprov controlling the entire
   2123 	 * glued tree. In that case, our contextCSN updates should
   2124 	 * go to the primary DB. But if there is no syncprov on the
   2125 	 * primary DB, then nothing special is needed here.
   2126 	 *
   2127 	 * Alternatively, there may be individual syncprov overlays
   2128 	 * on each glued branch. In that case, each syncprov only
   2129 	 * knows about changes within its own branch. And so our
   2130 	 * contextCSN updates should only go to the local DB.
   2131 	 */
   2132 	if ( !si->si_wbe ) {
   2133 		if ( SLAP_GLUE_SUBORDINATE( be )) {
   2134 			BackendDB *b0 = be;
   2135 			struct berval ndn = be->be_nsuffix[0];
   2136 			while ( !overlay_is_inst( be, "syncprov" )) {
   2137 				/* If we got all the way to the primary without any
   2138 				 * syncprov, just use original backend */
   2139 				if ( SLAP_GLUE_INSTANCE( be )) {
   2140 					be = b0;
   2141 					break;
   2142 				}
   2143 				dnParent( &ndn, &ndn );
   2144 				be = select_backend( &ndn, 0 );
   2145 			}
   2146 		}
   2147 		si->si_wbe = be;
   2148 		if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) {
   2149 			build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0],
   2150 				(struct berval *)&slap_ldapsync_cn_bv, NULL );
   2151 		} else {
   2152 			si->si_contextdn = si->si_wbe->be_nsuffix[0];
   2153 		}
   2154 	}
   2155 	if ( !si->si_schemachecking )
   2156 		op->o_no_schema_check = 1;
   2157 
   2158 	/* Establish session, do search */
   2159 	if ( !si->si_ld ) {
   2160 		if ( si->si_presentlist ) {
   2161 		    presentlist_free( si->si_presentlist );
   2162 		    si->si_presentlist = NULL;
   2163 		}
   2164 
   2165 		/* use main DB when retrieving contextCSN */
   2166 		op->o_bd = si->si_wbe;
   2167 		op->o_dn = op->o_bd->be_rootdn;
   2168 		op->o_ndn = op->o_bd->be_rootndn;
   2169 		rc = do_syncrep1( op, si );
   2170 	} else if ( !si->si_msgid ) {
   2171 		/* We got a SYNC_BUSY, now told to resume */
   2172 		rc = ldap_sync_search( si, op->o_tmpmemctx );
   2173 	}
   2174 	if ( rc == SYNC_BUSY ) {
   2175 		ldap_pvt_thread_mutex_unlock( &si->si_mutex );
   2176 		return NULL;
   2177 	}
   2178 
   2179 reload:
   2180 	/* Process results */
   2181 	if ( rc == LDAP_SUCCESS ) {
   2182 		ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
   2183 
   2184 		if ( !BER_BVISEMPTY( &si->si_monitor_ndn ))
   2185 		{
   2186 			Sockaddr addr;
   2187 			socklen_t len = sizeof( addr );
   2188 			if ( !getsockname( s, &addr.sa_addr, &len )) {
   2189 				si->si_connaddr.bv_val = si->si_connaddrbuf;
   2190 				si->si_connaddr.bv_len = sizeof( si->si_connaddrbuf );
   2191 				ldap_pvt_sockaddrstr( &addr, &si->si_connaddr );
   2192 			}
   2193 		}
   2194 
   2195 		/* use current DB */
   2196 		op->o_bd = be;
   2197 		op->o_dn = op->o_bd->be_rootdn;
   2198 		op->o_ndn = op->o_bd->be_rootndn;
   2199 		rc = do_syncrep2( op, si );
   2200 		if ( rc == LDAP_SYNC_REFRESH_REQUIRED )	{
   2201 			if ( si->si_logstate == SYNCLOG_LOGGING ) {
   2202 				if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
   2203 					slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
   2204 						si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
   2205 						si->si_syncCookie.sid, NULL );
   2206 				rc = ldap_sync_search( si, op->o_tmpmemctx );
   2207 				goto reload;
   2208 			}
   2209 			/* give up but schedule an immedite retry */
   2210 			rc = SYNC_PAUSED;
   2211 		}
   2212 
   2213 deleted:
   2214 		/* We got deleted while running on cn=config */
   2215 		if ( si->si_ctype < 1 ) {
   2216 			if ( si->si_ctype == -1 ) {
   2217 				si->si_ctype = 0;
   2218 				freeinfo = 1;
   2219 			}
   2220 			if ( si->si_conn )
   2221 				dostop = 1;
   2222 			rc = SYNC_SHUTDOWN;
   2223 		}
   2224 
   2225 		if ( rc != SYNC_PAUSED ) {
   2226 			if ( rc == SYNC_TIMEOUT ) {
   2227 				/* there was nothing to read, try to listen for more */
   2228 				if ( si->si_conn ) {
   2229 					connection_client_enable( si->si_conn );
   2230 				} else {
   2231 					si->si_conn = connection_client_setup( s, do_syncrepl, arg );
   2232 				}
   2233 			} else if ( si->si_conn ) {
   2234 				dostop = 1;
   2235 			}
   2236 		}
   2237 	}
   2238 
   2239 	/* At this point, we have 5 cases:
   2240 	 * 1) for any hard failure, give up and remove this task
   2241 	 * 2) for ServerDown, reschedule this task to run later
   2242 	 * 3) for threadpool pause, reschedule to run immediately
   2243 	 * 4) for SYNC_REPOLL, reschedule to run later
   2244 	 * 5) for SYNC_TIMEOUT, reschedule to defer
   2245 	 */
   2246 	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
   2247 
   2248 	if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask ) ) {
   2249 		ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
   2250 	}
   2251 
   2252 	if ( dostop ) {
   2253 		connection_client_stop( si->si_conn );
   2254 		si->si_conn = NULL;
   2255 	}
   2256 
   2257 	if ( rc == SYNC_PAUSED ) {
   2258 		rtask->interval.tv_sec = 0;
   2259 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
   2260 		rtask->interval.tv_sec = si->si_interval;
   2261 		rc = 0;
   2262 	} else if ( rc == SYNC_TIMEOUT ) {
   2263 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, 1 );
   2264 	} else if ( rc == SYNC_REPOLL ) {
   2265 		rtask->interval.tv_sec = si->si_interval;
   2266 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
   2267 		if ( si->si_retrynum ) {
   2268 			for ( i = 0; si->si_retrynum_init[i] != RETRYNUM_TAIL; i++ ) {
   2269 				si->si_retrynum[i] = si->si_retrynum_init[i];
   2270 			}
   2271 			si->si_retrynum[i] = RETRYNUM_TAIL;
   2272 		}
   2273 		slap_wake_listener();
   2274 		rc = 0;
   2275 	} else {
   2276 		for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
   2277 			if ( si->si_retrynum[i] == RETRYNUM_FOREVER || si->si_retrynum[i] == RETRYNUM_TAIL )
   2278 				break;
   2279 		}
   2280 
   2281 		if ( si->si_ctype < 1 || rc == SYNC_SHUTDOWN
   2282 			|| !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
   2283 			if ( si->si_re ) {
   2284 				ldap_pvt_runqueue_remove( &slapd_rq, rtask );
   2285 				si->si_re = NULL;
   2286 			}
   2287 			fail = RETRYNUM_TAIL;
   2288 		} else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) {
   2289 			if ( si->si_retrynum[i] > 0 )
   2290 				si->si_retrynum[i]--;
   2291 			fail = si->si_retrynum[i];
   2292 			rtask->interval.tv_sec = si->si_retryinterval[i];
   2293 			ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
   2294 			slap_wake_listener();
   2295 		}
   2296 	}
   2297 
   2298 	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
   2299 	ldap_pvt_thread_mutex_unlock( &si->si_mutex );
   2300 
   2301 	if ( rc ) {
   2302 		if ( fail == RETRYNUM_TAIL ) {
   2303 			Debug( LDAP_DEBUG_ANY,
   2304 				"do_syncrepl: %s rc %d quitting\n",
   2305 				si->si_ridtxt, rc );
   2306 		} else if ( fail > 0 ) {
   2307 			Debug( LDAP_DEBUG_ANY,
   2308 				"do_syncrepl: %s rc %d retrying (%d retries left)\n",
   2309 				si->si_ridtxt, rc, fail );
   2310 		} else {
   2311 			Debug( LDAP_DEBUG_ANY,
   2312 				"do_syncrepl: %s rc %d retrying\n",
   2313 				si->si_ridtxt, rc );
   2314 		}
   2315 	}
   2316 
   2317 	/* Do final delete cleanup */
   2318 	if ( freeinfo ) {
   2319 		syncinfo_free( si, 0 );
   2320 	}
   2321 	return NULL;
   2322 }
   2323 
   2324 static int
   2325 syncrepl_rewrite_dn(
   2326 	syncinfo_t *si,
   2327 	struct berval *dn,
   2328 	struct berval *sdn )
   2329 {
   2330 	char nul;
   2331 	int rc;
   2332 
   2333 	nul = dn->bv_val[dn->bv_len];
   2334 	dn->bv_val[dn->bv_len] = 0;
   2335 	rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
   2336 	dn->bv_val[dn->bv_len] = nul;
   2337 
   2338 	if ( sdn->bv_val == dn->bv_val )
   2339 		sdn->bv_val = NULL;
   2340 	else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
   2341 		sdn->bv_len = strlen( sdn->bv_val );
   2342 	return rc;
   2343 }
   2344 #define	REWRITE_VAL(si, ad, bv, bv2)	\
   2345 	BER_BVZERO( &bv2 );	\
   2346 	if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
   2347 		syncrepl_rewrite_dn( si, &bv, &bv2); \
   2348 	if ( BER_BVISNULL( &bv2 ))  \
   2349 		ber_dupbv( &bv2, &bv )
   2350 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
   2351 	BER_BVZERO( &bv2 );	\
   2352 	if (si->si_rewrite) \
   2353 		syncrepl_rewrite_dn(si, &bv, &bv2); \
   2354 	rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
   2355 	ch_free(bv2.bv_val)
   2356 
   2357 static slap_verbmasks modops[] = {
   2358 	{ BER_BVC("add"), LDAP_REQ_ADD },
   2359 	{ BER_BVC("delete"), LDAP_REQ_DELETE },
   2360 	{ BER_BVC("modify"), LDAP_REQ_MODIFY },
   2361 	{ BER_BVC("modrdn"), LDAP_REQ_MODRDN},
   2362 	{ BER_BVNULL, 0 }
   2363 };
   2364 
   2365 static int
   2366 syncrepl_accesslog_mods(
   2367 	syncinfo_t *si,
   2368 	struct berval *vals,
   2369 	struct Modifications **modres
   2370 )
   2371 {
   2372 	char *colon;
   2373 	const char *text;
   2374 	AttributeDescription *ad;
   2375 	struct berval bv, bv2;
   2376 	short op;
   2377 	Modifications *mod = NULL, *modlist = NULL, **modtail;
   2378 	int i, rc = 0;
   2379 
   2380 	modtail = &modlist;
   2381 
   2382 	for (i=0; !BER_BVISNULL( &vals[i] ); i++) {
   2383 		ad = NULL;
   2384 		bv = vals[i];
   2385 
   2386 		colon = ber_bvchr( &bv, ':' );
   2387 		if ( !colon ) {
   2388 			/* Invalid */
   2389 			continue;
   2390 		} else if ( colon == bv.bv_val ) {
   2391 			/* ITS#6545: An empty attribute signals that a new mod
   2392 			 * is about to start */
   2393 			mod = NULL;
   2394 			continue;
   2395 		}
   2396 
   2397 		bv.bv_len = colon - bv.bv_val;
   2398 		if ( slap_bv2ad( &bv, &ad, &text ) ) {
   2399 			/* Invalid */
   2400 			Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
   2401 				"Invalid attribute %s, %s\n",
   2402 				si->si_ridtxt, bv.bv_val, text );
   2403 			slap_mods_free( modlist, 1 );
   2404 			modlist = NULL;
   2405 			rc = -1;
   2406 			break;
   2407 		}
   2408 
   2409 		/* Ignore dynamically generated attrs */
   2410 		if ( ad->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
   2411 			continue;
   2412 		}
   2413 
   2414 		/* Ignore excluded attrs */
   2415 		if ( ldap_charray_inlist( si->si_exattrs,
   2416 			ad->ad_type->sat_cname.bv_val ) )
   2417 		{
   2418 			continue;
   2419 		}
   2420 
   2421 		switch(colon[1]) {
   2422 		case '+':	op = LDAP_MOD_ADD; break;
   2423 		case '-':	op = LDAP_MOD_DELETE; break;
   2424 		case '=':	op = LDAP_MOD_REPLACE; break;
   2425 		case '#':	op = LDAP_MOD_INCREMENT; break;
   2426 		default:	continue;
   2427 		}
   2428 
   2429 		if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) {
   2430 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
   2431 			mod->sml_flags = 0;
   2432 			mod->sml_op = op;
   2433 			mod->sml_next = NULL;
   2434 			mod->sml_desc = ad;
   2435 			mod->sml_type = ad->ad_cname;
   2436 			mod->sml_values = NULL;
   2437 			mod->sml_nvalues = NULL;
   2438 			mod->sml_numvals = 0;
   2439 
   2440 			if ( is_at_single_value( ad->ad_type ) ) {
   2441 				if ( op == LDAP_MOD_ADD ) {
   2442 					/* ITS#9295 an ADD might conflict with an existing value */
   2443 					mod->sml_op = LDAP_MOD_REPLACE;
   2444 				} else if ( op == LDAP_MOD_DELETE ) {
   2445 					/* ITS#9295 the above REPLACE could invalidate subsequent
   2446 					 * DELETEs */
   2447 					mod->sml_op = SLAP_MOD_SOFTDEL;
   2448 				}
   2449 			}
   2450 
   2451 			*modtail = mod;
   2452 			modtail = &mod->sml_next;
   2453 		}
   2454 		if ( colon[2] == ' ' ) {
   2455 			bv.bv_val = colon + 3;
   2456 			bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
   2457 			REWRITE_VAL( si, ad, bv, bv2 );
   2458 			ber_bvarray_add( &mod->sml_values, &bv2 );
   2459 			mod->sml_numvals++;
   2460 		}
   2461 	}
   2462 	*modres = modlist;
   2463 	return rc;
   2464 }
   2465 
   2466 static int
   2467 syncrepl_dsee_uuid(
   2468 	struct berval *dseestr,
   2469 	struct berval *syncUUID,
   2470 	void *ctx
   2471 )
   2472 {
   2473 	slap_mr_normalize_func *normf;
   2474 	/* DSEE UUID is of form 12345678-12345678-12345678-12345678 */
   2475 	if ( dseestr->bv_len != 35 )
   2476 		return -1;
   2477 	dseestr->bv_len++;
   2478 	dseestr->bv_val[35] = '-';
   2479 	normf = slap_schema.si_ad_entryUUID->ad_type->sat_equality->smr_normalize;
   2480 	if ( normf( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, NULL, NULL,
   2481 		dseestr, &syncUUID[0], ctx ))
   2482 		return -1;
   2483 	(void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], ctx );
   2484 	return LDAP_SUCCESS;
   2485 }
   2486 
   2487 static int
   2488 syncrepl_changelog_mods(
   2489 	syncinfo_t *si,
   2490 	ber_tag_t req,
   2491 	struct berval *vals,
   2492 	struct Modifications **modres,
   2493 	struct berval *uuid,
   2494 	void *ctx
   2495 )
   2496 {
   2497 	LDIFRecord lr;
   2498 	struct berval rbuf = vals[0];
   2499 	int i, rc;
   2500 	int lrflags = LDIF_NO_DN;
   2501 	Modifications *mod = NULL, *modlist = NULL, **modtail = &modlist;
   2502 
   2503 	if ( req == LDAP_REQ_ADD )
   2504 		lrflags |= LDIF_ENTRIES_ONLY|LDIF_DEFAULT_ADD;
   2505 	else
   2506 		lrflags |= LDIF_MODS_ONLY;
   2507 
   2508 	rc = ldap_parse_ldif_record_x( &rbuf, 0, &lr, "syncrepl", lrflags, ctx );
   2509 	for (i = 0; lr.lrop_mods[i] != NULL; i++) {
   2510 		AttributeDescription *ad = NULL;
   2511 		const char *text;
   2512 		int j;
   2513 		if ( slap_str2ad( lr.lrop_mods[i]->mod_type, &ad, &text ) ) {
   2514 			/* Invalid */
   2515 			Debug( LDAP_DEBUG_ANY, "syncrepl_changelog_mods: %s "
   2516 				"Invalid attribute %s, %s\n",
   2517 				si->si_ridtxt, lr.lrop_mods[i]->mod_type, text );
   2518 			slap_mods_free( modlist, 1 );
   2519 			modlist = NULL;
   2520 			rc = -1;
   2521 			break;
   2522 		}
   2523 		mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
   2524 		mod->sml_flags = 0;
   2525 		mod->sml_op = lr.lrop_mods[i]->mod_op ^ LDAP_MOD_BVALUES;
   2526 		mod->sml_next = NULL;
   2527 		mod->sml_desc = ad;
   2528 		mod->sml_type = ad->ad_cname;
   2529 		mod->sml_values = NULL;
   2530 		mod->sml_nvalues = NULL;
   2531 		j = 0;
   2532 		if ( lr.lrop_mods[i]->mod_bvalues != NULL ) {
   2533 			for (; lr.lrop_mods[i]->mod_bvalues[j] != NULL; j++ ) {
   2534 				struct berval bv, bv2;
   2535 				bv = *(lr.lrop_mods[i]->mod_bvalues[j]);
   2536 				REWRITE_VAL( si, ad, bv, bv2 );
   2537 				ber_bvarray_add( &mod->sml_values, &bv2 );
   2538 			}
   2539 		}
   2540 		mod->sml_numvals = j;
   2541 
   2542 		*modtail = mod;
   2543 		modtail = &mod->sml_next;
   2544 	}
   2545 	ldap_ldif_record_done( &lr );
   2546 
   2547 	if ( req == LDAP_REQ_ADD && !BER_BVISNULL( uuid )) {
   2548 		struct berval uuids[2];
   2549 		if ( !syncrepl_dsee_uuid( uuid, uuids, ctx )) {
   2550 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
   2551 			mod->sml_flags = 0;
   2552 			mod->sml_op = LDAP_MOD_ADD;
   2553 			mod->sml_next = NULL;
   2554 			mod->sml_desc = slap_schema.si_ad_entryUUID;
   2555 			mod->sml_type = slap_schema.si_ad_entryUUID->ad_cname;
   2556 			mod->sml_values = ch_malloc( 2 * sizeof(struct berval));
   2557 			mod->sml_nvalues = NULL;
   2558 			ber_dupbv( &mod->sml_values[0], &uuids[1] );
   2559 			BER_BVZERO( &mod->sml_values[1] );
   2560 			slap_sl_free( uuids[0].bv_val, ctx );
   2561 			slap_sl_free( uuids[1].bv_val, ctx );
   2562 			mod->sml_numvals = 1;
   2563 			*modtail = mod;
   2564 			modtail = &mod->sml_next;
   2565 		}
   2566 	}
   2567 
   2568 	*modres = modlist;
   2569 	return rc;
   2570 }
   2571 
   2572 typedef struct OpExtraSync {
   2573 	OpExtra oe;
   2574 	syncinfo_t *oe_si;
   2575 } OpExtraSync;
   2576 
   2577 /* Copy the original modlist, split Replace ops into Delete/Add,
   2578  * and drop mod opattrs since this modification is in the past.
   2579  */
   2580 static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
   2581 {
   2582 	Modifications *mod, *modnew = NULL, *modtail = NULL;
   2583 	int size;
   2584 	for ( ; modlist; modlist = modlist->sml_next ) {
   2585 		/* older ops */
   2586 		if ( match < 0 ) {
   2587 			if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
   2588 				modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
   2589 				modlist->sml_desc == slap_schema.si_ad_entryCSN )
   2590 				continue;
   2591 			if ( modlist->sml_values == NULL && modlist->sml_op == LDAP_MOD_REPLACE ) {
   2592 				/* ITS#9359 This adds no values, just change to a delete op */
   2593 				modlist->sml_op = LDAP_MOD_DELETE;
   2594 			} else if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
   2595 				mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
   2596 				mod->sml_desc = modlist->sml_desc;
   2597 				mod->sml_values = NULL;
   2598 				mod->sml_nvalues = NULL;
   2599 				mod->sml_op = LDAP_MOD_DELETE;
   2600 				mod->sml_numvals = 0;
   2601 				mod->sml_flags = 0;
   2602 				if ( !modnew )
   2603 					modnew = mod;
   2604 				if ( modtail )
   2605 					modtail->sml_next = mod;
   2606 				modtail = mod;
   2607 			}
   2608 		}
   2609 		if ( modlist->sml_numvals ) {
   2610 			size = (modlist->sml_numvals+1) * sizeof(struct berval);
   2611 			if ( modlist->sml_nvalues ) size *= 2;
   2612 		} else {
   2613 			size = 0;
   2614 		}
   2615 		size += sizeof(Modifications);
   2616 		mod = op->o_tmpalloc( size, op->o_tmpmemctx );
   2617 		if ( !modnew )
   2618 			modnew = mod;
   2619 		if ( modtail )
   2620 			modtail->sml_next = mod;
   2621 		modtail = mod;
   2622 		mod->sml_desc = modlist->sml_desc;
   2623 		mod->sml_numvals = modlist->sml_numvals;
   2624 		mod->sml_flags = 0;
   2625 		if ( modlist->sml_numvals ) {
   2626 			int i;
   2627 			mod->sml_values = (BerVarray)(mod+1);
   2628 			for (i=0; i<mod->sml_numvals; i++)
   2629 				mod->sml_values[i] = modlist->sml_values[i];
   2630 			BER_BVZERO(&mod->sml_values[i]);
   2631 			if ( modlist->sml_nvalues ) {
   2632 				mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
   2633 				for (i=0; i<mod->sml_numvals; i++)
   2634 					mod->sml_nvalues[i] = modlist->sml_nvalues[i];
   2635 				BER_BVZERO(&mod->sml_nvalues[i]);
   2636 			} else {
   2637 				mod->sml_nvalues = NULL;
   2638 			}
   2639 		} else {
   2640 			mod->sml_values = NULL;
   2641 			mod->sml_nvalues = NULL;
   2642 		}
   2643 		if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
   2644 			mod->sml_op = LDAP_MOD_ADD;
   2645 		else
   2646 			mod->sml_op = modlist->sml_op;
   2647 		mod->sml_next = NULL;
   2648 	}
   2649 	return modnew;
   2650 }
   2651 
   2652 typedef struct resolve_ctxt {
   2653 	syncinfo_t *rx_si;
   2654 	Entry *rx_entry;
   2655 	Modifications *rx_mods;
   2656 } resolve_ctxt;
   2657 
   2658 static void
   2659 compare_vals( Modifications *m1, Modifications *m2 )
   2660 {
   2661 	int i, j;
   2662 	struct berval *bv1, *bv2;
   2663 
   2664 	if ( m2->sml_nvalues ) {
   2665 		bv2 = m2->sml_nvalues;
   2666 		bv1 = m1->sml_nvalues;
   2667 	} else {
   2668 		bv2 = m2->sml_values;
   2669 		bv1 = m1->sml_values;
   2670 	}
   2671 	for ( j=0; j<m2->sml_numvals; j++ ) {
   2672 		for ( i=0; i<m1->sml_numvals; i++ ) {
   2673 			if ( !ber_bvcmp( &bv1[i], &bv2[j] )) {
   2674 				int k;
   2675 				for ( k=i; k<m1->sml_numvals-1; k++ ) {
   2676 					m1->sml_values[k] = m1->sml_values[k+1];
   2677 					if ( m1->sml_nvalues )
   2678 						m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
   2679 				}
   2680 				BER_BVZERO(&m1->sml_values[k]);
   2681 				if ( m1->sml_nvalues ) {
   2682 					BER_BVZERO(&m1->sml_nvalues[k]);
   2683 				}
   2684 				m1->sml_numvals--;
   2685 				i--;
   2686 			}
   2687 		}
   2688 	}
   2689 }
   2690 
   2691 static int
   2692 syncrepl_resolve_cb( Operation *op, SlapReply *rs )
   2693 {
   2694 	if ( rs->sr_type == REP_SEARCH ) {
   2695 		resolve_ctxt *rx = op->o_callback->sc_private;
   2696 		Attribute *a = attr_find( rs->sr_entry->e_attrs, ad_reqMod );
   2697 		if ( a ) {
   2698 			Modifications *oldmods, *newmods, *m1, *m2, **prev;
   2699 			Entry *e = rx->rx_entry;
   2700 			oldmods = rx->rx_mods;
   2701 			syncrepl_accesslog_mods( rx->rx_si, a->a_vals, &newmods );
   2702 			for ( m2 = newmods; m2; m2=m2->sml_next ) {
   2703 				for ( prev = &oldmods, m1 = *prev; m1; m1 = *prev ) {
   2704 					if ( m1->sml_desc != m2->sml_desc ) {
   2705 						prev = &m1->sml_next;
   2706 						continue;
   2707 					}
   2708 					if ( m2->sml_op == LDAP_MOD_DELETE ||
   2709 						m2->sml_op == SLAP_MOD_SOFTDEL ||
   2710 						m2->sml_op == LDAP_MOD_REPLACE ) {
   2711 						int numvals = m2->sml_numvals;
   2712 						if ( m2->sml_op == LDAP_MOD_REPLACE )
   2713 							numvals = 0;
   2714 						/* New delete All cancels everything */
   2715 						if ( numvals == 0 ) {
   2716 drop:
   2717 							*prev = m1->sml_next;
   2718 							op->o_tmpfree( m1, op->o_tmpmemctx );
   2719 							continue;
   2720 						}
   2721 						if ( m1->sml_op == LDAP_MOD_DELETE ||
   2722 							m1->sml_op == SLAP_MOD_SOFTDEL ) {
   2723 							if ( m1->sml_numvals == 0 ) {
   2724 								/* turn this to SOFTDEL later */
   2725 								m1->sml_flags = SLAP_MOD_INTERNAL;
   2726 							} else {
   2727 								compare_vals( m1, m2 );
   2728 								if ( !m1->sml_numvals )
   2729 									goto drop;
   2730 							}
   2731 						} else if ( m1->sml_op == LDAP_MOD_ADD ) {
   2732 							compare_vals( m1, m2 );
   2733 							if ( !m1->sml_numvals )
   2734 								goto drop;
   2735 						}
   2736 					}
   2737 
   2738 					if ( m2->sml_op == LDAP_MOD_ADD ||
   2739 						m2->sml_op == LDAP_MOD_REPLACE ) {
   2740 						if ( m2->sml_desc->ad_type->sat_atype.at_single_value )
   2741 							goto drop;
   2742 						if ( m1->sml_op == LDAP_MOD_DELETE ) {
   2743 							if ( m2->sml_op == LDAP_MOD_REPLACE ) {
   2744 								goto drop;
   2745 							}
   2746 							if ( !m1->sml_numvals ) {
   2747 								Modifications *m;
   2748 								unsigned int size, i;
   2749 								/*
   2750 								 * ITS#9751 An ADD might supersede parts of
   2751 								 * this delete, but we still need to honour the
   2752 								 * rest. Keep resolving as if it was deleting
   2753 								 * specific values
   2754 								 */
   2755 								a = attr_find( e->e_attrs, m1->sml_desc );
   2756 								if ( !a ) {
   2757 									goto drop;
   2758 								}
   2759 
   2760 								size = (a->a_numvals+1) * sizeof(struct berval);
   2761 								if ( a->a_nvals ) size *= 2;
   2762 								size += sizeof(Modifications);
   2763 								m = op->o_tmpalloc( size, op->o_tmpmemctx );
   2764 								*m = *m1;
   2765 
   2766 								m->sml_numvals = a->a_numvals;
   2767 								m->sml_values = (BerVarray)(m+1);
   2768 
   2769 								for ( i=0; i < a->a_numvals; i++ )
   2770 									m->sml_values[i] = a->a_vals[i];
   2771 								BER_BVZERO( &m->sml_values[i] );
   2772 
   2773 								if ( a->a_nvals ) {
   2774 									m->sml_nvalues = m->sml_values + m->sml_numvals + 1;
   2775 									for ( i=0; i < a->a_numvals; i++ )
   2776 										m->sml_nvalues[i] = a->a_nvals[i];
   2777 									BER_BVZERO( &m->sml_nvalues[i] );
   2778 								} else {
   2779 									m->sml_nvalues = NULL;
   2780 								}
   2781 								op->o_tmpfree( m1, op->o_tmpmemctx );
   2782 								*prev = m1 = m;
   2783 							}
   2784 						}
   2785 						compare_vals( m1, m2 );
   2786 						if ( !m1->sml_numvals )
   2787 							goto drop;
   2788 					}
   2789 					prev = &m1->sml_next;
   2790 				}
   2791 			}
   2792 			slap_mods_free( newmods, 1 );
   2793 			rx->rx_mods = oldmods;
   2794 		}
   2795 	}
   2796 	return LDAP_SUCCESS;
   2797 }
   2798 
   2799 typedef struct modify_ctxt {
   2800 	Modifications *mx_orig;
   2801 	Entry *mx_entry;
   2802 } modify_ctxt;
   2803 
   2804 static int
   2805 syncrepl_modify_cb( Operation *op, SlapReply *rs )
   2806 {
   2807 	slap_callback *sc = op->o_callback;
   2808 	modify_ctxt *mx = sc->sc_private;
   2809 	Modifications *ml;
   2810 
   2811 	op->orm_no_opattrs = 0;
   2812 	slap_mods_free( op->orm_modlist, 0 );
   2813 	op->orm_modlist = mx->mx_orig;
   2814 	if ( mx->mx_entry ) {
   2815 		entry_free( mx->mx_entry );
   2816 	}
   2817 	op->o_callback = sc->sc_next;
   2818 	op->o_tmpfree( sc, op->o_tmpmemctx );
   2819 	return SLAP_CB_CONTINUE;
   2820 }
   2821 
   2822 static int
   2823 syncrepl_op_modify( Operation *op, SlapReply *rs )
   2824 {
   2825 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
   2826 	OpExtra *oex;
   2827 	syncinfo_t *si;
   2828 	Entry *e, *e_dup;
   2829 	int rc, match = 0;
   2830 	Modifications *mod, *newlist;
   2831 
   2832 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
   2833 		if ( oex->oe_key == (void *)syncrepl_message_to_op )
   2834 			break;
   2835 	}
   2836 	if ( !oex )
   2837 		return SLAP_CB_CONTINUE;
   2838 
   2839 	si = ((OpExtraSync *)oex)->oe_si;
   2840 
   2841 	/* Check if entryCSN in modlist is newer than entryCSN in entry.
   2842 	 * We do it here because the op has been serialized by accesslog
   2843 	 * by the time we get here. If the CSN is new enough, just do the
   2844 	 * mod. If not, we need to resolve conflicts.
   2845 	 */
   2846 
   2847 	for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
   2848 		if ( mod->sml_desc == slap_schema.si_ad_entryCSN ) break;
   2849 	}
   2850 	/* FIXME: what should we do if entryCSN is missing from the mod? */
   2851 	if ( !mod )
   2852 		return SLAP_CB_CONTINUE;
   2853 
   2854 	{
   2855 		int sid = slap_parse_csn_sid( &mod->sml_nvalues[0] );
   2856 		ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   2857 		rc = check_csn_age( si, &op->o_req_dn, &mod->sml_nvalues[0],
   2858 			sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL );
   2859 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   2860 		if ( rc == CV_CSN_OLD ) {
   2861 			slap_graduate_commit_csn( op );
   2862 			/* tell accesslog this was a failure */
   2863 			rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
   2864 			return LDAP_SUCCESS;
   2865 		}
   2866 	}
   2867 
   2868 	rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
   2869 	if ( rc == 0 ) {
   2870 		Attribute *a;
   2871 		const char *text;
   2872 		a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
   2873 		if ( a ) {
   2874 			value_match( &match, slap_schema.si_ad_entryCSN,
   2875 				slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
   2876 				SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
   2877 				&mod->sml_nvalues[0], &a->a_nvals[0], &text );
   2878 		} else {
   2879 			/* no entryCSN? shouldn't happen. assume mod is newer. */
   2880 			match = 1;
   2881 		}
   2882 		e_dup = entry_dup( e );
   2883 		overlay_entry_release_ov( op, e, 0, on );
   2884 	} else {
   2885 		return SLAP_CB_CONTINUE;
   2886 	}
   2887 
   2888 	/* equal? Should never happen */
   2889 	if ( match == 0 ) {
   2890 		slap_graduate_commit_csn( op );
   2891 		/* tell accesslog this was a failure */
   2892 		rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
   2893 		entry_free( e_dup );
   2894 		return LDAP_SUCCESS;
   2895 	}
   2896 
   2897 	/* mod is older: resolve conflicts...
   2898 	 * 1. Save/copy original modlist. Split Replace to Del/Add.
   2899 	 * 2. Find all mods to this reqDN newer than the mod stamp.
   2900 	 * 3. Resolve any mods in this request that affect attributes
   2901 	 *    touched by newer mods.
   2902 	 *    old         new
   2903 	 *    delete all  delete all  drop
   2904 	 *    delete all  delete X    SOFTDEL
   2905 	 *    delete X    delete all  drop
   2906 	 *    delete X    delete X    drop
   2907 	 *    delete X    delete Y    OK
   2908 	 *    delete all  add X       convert to delete current values,
   2909 	 *                            drop delete X from it
   2910 	 *    delete X    add X       drop
   2911 	 *    delete X    add Y       OK
   2912 	 *    add X       delete all  drop
   2913 	 *    add X       delete X    drop
   2914 	 *    add X       add X       drop
   2915 	 *    add X       add Y       if SV, drop else OK
   2916 	 *
   2917 	 * 4. Swap original modlist back in response callback so
   2918 	 *    that accesslog logs the original mod.
   2919 	 *
   2920 	 * Even if the mod is newer, other out-of-order changes may
   2921 	 * have been committed, forcing us to tweak the modlist:
   2922 	 * 1. Save/copy original modlist.
   2923 	 * 2. Change deletes to soft deletes.
   2924 	 * 3. Change Adds of single-valued attrs to Replace.
   2925 	 */
   2926 
   2927 	newlist = mods_dup( op, op->orm_modlist, match );
   2928 
   2929 	/* mod is older */
   2930 	if ( match < 0 ) {
   2931 		Operation op2 = *op;
   2932 		AttributeName an[2];
   2933 		struct berval bv;
   2934 		int size;
   2935 		SlapReply rs1 = {0};
   2936 		resolve_ctxt rx;
   2937 		slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
   2938         Filter lf[3] = {0};
   2939         AttributeAssertion aa[2] = {0};
   2940 
   2941 		rx.rx_si = si;
   2942 		rx.rx_entry = e_dup;
   2943 		rx.rx_mods = newlist;
   2944 		cb.sc_private = &rx;
   2945 
   2946 		op2.o_tag = LDAP_REQ_SEARCH;
   2947 		op2.ors_scope = LDAP_SCOPE_SUBTREE;
   2948 		op2.ors_deref = LDAP_DEREF_NEVER;
   2949 		op2.o_req_dn = si->si_logbase;
   2950 		op2.o_req_ndn = si->si_logbase;
   2951 		op2.ors_tlimit = SLAP_NO_LIMIT;
   2952 		op2.ors_slimit = SLAP_NO_LIMIT;
   2953 		op2.ors_limit = NULL;
   2954 		memset( an, 0, sizeof(an));
   2955 		an[0].an_desc = ad_reqMod;
   2956 		an[0].an_name = ad_reqMod->ad_cname;
   2957 		op2.ors_attrs = an;
   2958 		op2.ors_attrsonly = 0;
   2959 
   2960 		bv = mod->sml_nvalues[0];
   2961 
   2962 		size = sizeof("(&(entryCSN>=)(reqDN=))");
   2963 		size += bv.bv_len + op->o_req_ndn.bv_len + si->si_logfilterstr.bv_len;
   2964 		op2.ors_filterstr.bv_val = op->o_tmpalloc( size, op->o_tmpmemctx );
   2965 		op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
   2966 			"(&(entryCSN>=%s)(reqDN=%s)%s)",
   2967 			bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
   2968 
   2969         lf[0].f_choice = LDAP_FILTER_AND;
   2970         lf[0].f_and = lf+1;
   2971         lf[1].f_choice = LDAP_FILTER_GE;
   2972         lf[1].f_ava = aa;
   2973         lf[1].f_av_desc = slap_schema.si_ad_entryCSN;
   2974         lf[1].f_av_value = bv;
   2975         lf[1].f_next = lf+2;
   2976         lf[2].f_choice = LDAP_FILTER_EQUALITY;
   2977         lf[2].f_ava = aa+1;
   2978         lf[2].f_av_desc = ad_reqDN;
   2979         lf[2].f_av_value = op->o_req_ndn;
   2980         lf[2].f_next = si->si_logfilter;
   2981 
   2982 		op2.ors_filter = lf;
   2983 
   2984 		op2.o_callback = &cb;
   2985 		op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
   2986 		op2.o_bd->be_search( &op2, &rs1 );
   2987 		newlist = rx.rx_mods;
   2988 	}
   2989 
   2990 	{
   2991 		slap_callback *sc = op->o_tmpalloc( sizeof(slap_callback) +
   2992 			sizeof(modify_ctxt), op->o_tmpmemctx );
   2993 		modify_ctxt *mx = (modify_ctxt *)(sc+1);
   2994 		Modifications *ml;
   2995 
   2996 		sc->sc_response = syncrepl_modify_cb;
   2997 		sc->sc_private = mx;
   2998 		sc->sc_next = op->o_callback;
   2999 		sc->sc_cleanup = NULL;
   3000 		sc->sc_writewait = NULL;
   3001 		overlay_callback_after_backover( op, sc, 1 );
   3002 
   3003 		op->orm_no_opattrs = 1;
   3004 		mx->mx_orig = op->orm_modlist;
   3005 		mx->mx_entry = e_dup;
   3006 		for ( ml = newlist; ml; ml=ml->sml_next ) {
   3007 			if ( ml->sml_flags == SLAP_MOD_INTERNAL ) {
   3008 				ml->sml_flags = 0;
   3009 				ml->sml_op = SLAP_MOD_SOFTDEL;
   3010 			}
   3011 			else if ( ml->sml_op == LDAP_MOD_DELETE )
   3012 				ml->sml_op = SLAP_MOD_SOFTDEL;
   3013 			else if ( ml->sml_op == LDAP_MOD_ADD &&
   3014 				ml->sml_desc->ad_type->sat_atype.at_single_value )
   3015 				ml->sml_op = LDAP_MOD_REPLACE;
   3016 		}
   3017 		op->orm_modlist = newlist;
   3018 		op->o_csn = mod->sml_nvalues[0];
   3019 	}
   3020 
   3021 	return SLAP_CB_CONTINUE;
   3022 }
   3023 
   3024 static int
   3025 syncrepl_null_callback(
   3026 	Operation *op,
   3027 	SlapReply *rs )
   3028 {
   3029 	/* If we're not the last callback in the chain, move to the end */
   3030 	if ( op->o_callback->sc_next ) {
   3031 		slap_callback **sc, *s1;
   3032 		s1 = op->o_callback;
   3033 		op->o_callback = op->o_callback->sc_next;
   3034 		for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) ;
   3035 		*sc = s1;
   3036 		s1->sc_next = NULL;
   3037 		return SLAP_CB_CONTINUE;
   3038 	}
   3039 	if ( rs->sr_err != LDAP_SUCCESS &&
   3040 		rs->sr_err != LDAP_REFERRAL &&
   3041 		rs->sr_err != LDAP_ALREADY_EXISTS &&
   3042 		rs->sr_err != LDAP_NO_SUCH_OBJECT &&
   3043 		rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
   3044 	{
   3045 		Debug( LDAP_DEBUG_ANY,
   3046 			"syncrepl_null_callback : error code 0x%x\n",
   3047 			rs->sr_err );
   3048 	}
   3049 	return LDAP_SUCCESS;
   3050 }
   3051 
   3052 static int
   3053 syncrepl_message_to_op(
   3054 	syncinfo_t	*si,
   3055 	Operation	*op,
   3056 	LDAPMessage	*msg,
   3057 	int do_lock
   3058 )
   3059 {
   3060 	BerElement	*ber = NULL;
   3061 	Modifications	*modlist = NULL;
   3062 	logschema *ls;
   3063 	SlapReply rs = { REP_RESULT };
   3064 	slap_callback cb = { NULL, syncrepl_null_callback, NULL, NULL };
   3065 
   3066 	const char	*text;
   3067 	char txtbuf[SLAP_TEXT_BUFLEN];
   3068 	size_t textlen = sizeof txtbuf;
   3069 
   3070 	struct berval	bdn, dn = BER_BVNULL, ndn;
   3071 	struct berval	bv, bv2, *bvals = NULL;
   3072 	struct berval	rdn = BER_BVNULL, sup = BER_BVNULL,
   3073 		prdn = BER_BVNULL, nrdn = BER_BVNULL,
   3074 		psup = BER_BVNULL, nsup = BER_BVNULL;
   3075 	struct berval	dsee_uuid = BER_BVNULL, dsee_mods = BER_BVNULL;
   3076 	int		rc, deleteOldRdn = 0, freeReqDn = 0;
   3077 	int		do_graduate = 0, do_unlock = 0;
   3078 	unsigned long changenum = 0;
   3079 
   3080 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
   3081 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
   3082 			"Message type should be entry (%d)",
   3083 			si->si_ridtxt, ldap_msgtype( msg ) );
   3084 		return -1;
   3085 	}
   3086 
   3087 	if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
   3088 		ls = &accesslog_sc;
   3089 	else
   3090 		ls = &changelog_sc;
   3091 
   3092 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
   3093 
   3094 	if ( rc != LDAP_SUCCESS ) {
   3095 		Debug( LDAP_DEBUG_ANY,
   3096 			"syncrepl_message_to_op: %s dn get failed (%d)",
   3097 			si->si_ridtxt, rc );
   3098 		return rc;
   3099 	}
   3100 
   3101 	op->o_tag = LBER_DEFAULT;
   3102 	op->o_bd = si->si_wbe;
   3103 
   3104 	if ( BER_BVISEMPTY( &bdn )) {
   3105 		Debug( LDAP_DEBUG_ANY,
   3106 			"syncrepl_message_to_op: %s got empty dn",
   3107 			si->si_ridtxt );
   3108 		return LDAP_OTHER;
   3109 	}
   3110 
   3111 	while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
   3112 		== LDAP_SUCCESS ) {
   3113 		if ( bv.bv_val == NULL )
   3114 			break;
   3115 
   3116 		if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
   3117 			bdn = bvals[0];
   3118 			REWRITE_DN( si, bdn, bv2, dn, ndn );
   3119 			if ( rc != LDAP_SUCCESS ) {
   3120 				Debug( LDAP_DEBUG_ANY,
   3121 					"syncrepl_message_to_op: %s "
   3122 					"dn \"%s\" normalization failed (%d)",
   3123 					si->si_ridtxt, bdn.bv_val, rc );
   3124 				rc = -1;
   3125 				ch_free( bvals );
   3126 				goto done;
   3127 			}
   3128 			op->o_req_dn = dn;
   3129 			op->o_req_ndn = ndn;
   3130 			freeReqDn = 1;
   3131 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_req ) ) {
   3132 			int i = verb_to_mask( bvals[0].bv_val, modops );
   3133 			if ( i < 0 ) {
   3134 				Debug( LDAP_DEBUG_ANY,
   3135 					"syncrepl_message_to_op: %s unknown op %s",
   3136 					si->si_ridtxt, bvals[0].bv_val );
   3137 				ch_free( bvals );
   3138 				rc = -1;
   3139 				goto done;
   3140 			}
   3141 			op->o_tag = modops[i].mask;
   3142 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
   3143 			/* Parse attribute into modlist */
   3144 			if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
   3145 				rc = syncrepl_accesslog_mods( si, bvals, &modlist );
   3146 			} else {
   3147 				dsee_mods = bvals[0];
   3148 			}
   3149 			if ( rc ) goto done;
   3150 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
   3151 			rdn = bvals[0];
   3152 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
   3153 			if ( !ber_bvstrcasecmp( &slap_true_bv, bvals ) ) {
   3154 				deleteOldRdn = 1;
   3155 			}
   3156 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) {
   3157 			sup = bvals[0];
   3158 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_controls ) ) {
   3159 			int i;
   3160 			struct berval rel_ctrl_bv;
   3161 
   3162 			(void)ber_str2bv( "{" LDAP_CONTROL_RELAX, 0, 0, &rel_ctrl_bv );
   3163 			for ( i = 0; bvals[i].bv_val; i++ ) {
   3164 				struct berval cbv, tmp;
   3165 
   3166 				ber_bvchr_post( &cbv, &bvals[i], '}' );
   3167 				ber_bvchr_post( &tmp, &cbv, '{' );
   3168 				ber_bvchr_pre( &cbv, &tmp, ' ' );
   3169 				if ( cbv.bv_len == tmp.bv_len )		/* control w/o value */
   3170 					ber_bvchr_pre( &cbv, &tmp, '}' );
   3171 				if ( !ber_bvcmp( &cbv, &rel_ctrl_bv ) )
   3172 					op->o_relax = SLAP_CONTROL_CRITICAL;
   3173 			}
   3174 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_uuid ) ) {
   3175 			dsee_uuid = bvals[0];
   3176 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_changenum ) ) {
   3177 			changenum = strtoul( bvals->bv_val, NULL, 0 );
   3178 		} else if ( !ber_bvstrcasecmp( &bv,
   3179 			&slap_schema.si_ad_entryCSN->ad_cname ) )
   3180 		{
   3181 			int i, sid = slap_parse_csn_sid( bvals );
   3182 			ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   3183 			i = check_csn_age( si, &bdn, bvals, sid,
   3184 					(cookie_vals *)&si->si_cookieState->cs_vals, NULL );
   3185 			ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   3186 			if ( i == CV_CSN_OLD ) {
   3187 				goto done;
   3188 			}
   3189 			slap_queue_csn( op, bvals );
   3190 			do_graduate = 1;
   3191 		}
   3192 		ch_free( bvals );
   3193 	}
   3194 
   3195 	/* don't parse mods until we've gotten the uuid */
   3196 	if ( si->si_syncdata == SYNCDATA_CHANGELOG && !BER_BVISNULL( &dsee_mods )) {
   3197 		rc = syncrepl_changelog_mods( si, op->o_tag,
   3198 			&dsee_mods, &modlist, &dsee_uuid, op->o_tmpmemctx );
   3199 		if ( rc )
   3200 			goto done;
   3201 	}
   3202 
   3203 	/* If we didn't get a mod type or a target DN, bail out */
   3204 	if ( op->o_tag == LBER_DEFAULT || BER_BVISNULL( &dn ) ) {
   3205 		rc = -1;
   3206 		goto done;
   3207 	}
   3208 
   3209 	if ( do_lock ) {
   3210 		if (( rc = get_pmutex( si )))
   3211 			goto done;
   3212 		do_unlock = 1;
   3213 	}
   3214 
   3215 	op->o_callback = &cb;
   3216 	slap_op_time( &op->o_time, &op->o_tincr );
   3217 
   3218 	Debug( LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s tid %p\n",
   3219 		si->si_ridtxt, (void *)op->o_tid );
   3220 
   3221 	switch( op->o_tag ) {
   3222 	case LDAP_REQ_ADD:
   3223 	case LDAP_REQ_MODIFY:
   3224 		/* If we didn't get required data, bail */
   3225 		if ( !modlist ) goto done;
   3226 
   3227 		rc = slap_mods_check( op, modlist, &text, txtbuf, textlen, NULL );
   3228 
   3229 		if ( rc != LDAP_SUCCESS ) {
   3230 			Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
   3231 				"mods check (%s)\n",
   3232 				si->si_ridtxt, text );
   3233 			goto done;
   3234 		}
   3235 
   3236 		if ( op->o_tag == LDAP_REQ_ADD ) {
   3237 			Entry *e = entry_alloc();
   3238 			op->ora_e = e;
   3239 			ber_dupbv( &op->ora_e->e_name, &op->o_req_dn );
   3240 			ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn );
   3241 			rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen);
   3242 			if( rc != LDAP_SUCCESS ) {
   3243 				Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
   3244 				"mods2entry (%s)\n",
   3245 					si->si_ridtxt, text );
   3246 			} else {
   3247 				rc = op->o_bd->be_add( op, &rs );
   3248 				Debug( LDAP_DEBUG_SYNC,
   3249 					"syncrepl_message_to_op: %s be_add %s (%d)\n",
   3250 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
   3251 				do_graduate = 0;
   3252 				if ( rc == LDAP_ALREADY_EXISTS ) {
   3253 					Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
   3254 					struct berval *vals;
   3255 					if ( a && backend_attribute( op, NULL, &op->o_req_ndn,
   3256 						slap_schema.si_ad_entryCSN, &vals, ACL_READ ) == LDAP_SUCCESS ) {
   3257 						if ( ber_bvcmp( &vals[0], &a->a_vals[0] ) >= 0 )
   3258 							rc = LDAP_SUCCESS;
   3259 						ber_bvarray_free_x( vals, op->o_tmpmemctx );
   3260  					}
   3261 				}
   3262 			}
   3263 			if ( e == op->ora_e )
   3264 				be_entry_release_w( op, op->ora_e );
   3265 		} else {
   3266 			OpExtraSync oes;
   3267 			op->orm_modlist = modlist;
   3268 			op->o_bd = si->si_wbe;
   3269 			/* delta-mpr needs additional checks in syncrepl_op_modify */
   3270 			if ( SLAP_MULTIPROVIDER( op->o_bd )) {
   3271 				oes.oe.oe_key = (void *)syncrepl_message_to_op;
   3272 				oes.oe_si = si;
   3273 				LDAP_SLIST_INSERT_HEAD( &op->o_extra, &oes.oe, oe_next );
   3274 			}
   3275 			rc = op->o_bd->be_modify( op, &rs );
   3276 			if ( SLAP_MULTIPROVIDER( op->o_bd )) {
   3277 				LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
   3278 				BER_BVZERO( &op->o_csn );
   3279 			}
   3280 			modlist = op->orm_modlist;
   3281 			Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
   3282 				"syncrepl_message_to_op: %s be_modify %s (%d)\n",
   3283 				si->si_ridtxt, op->o_req_dn.bv_val, rc );
   3284 			op->o_bd = si->si_be;
   3285 			do_graduate = 0;
   3286 		}
   3287 		break;
   3288 	case LDAP_REQ_MODRDN:
   3289 		if ( BER_BVISNULL( &rdn ) ) goto done;
   3290 
   3291 		if ( rdnPretty( NULL, &rdn, &prdn, NULL ) ) {
   3292 			goto done;
   3293 		}
   3294 		if ( rdnNormalize( 0, NULL, NULL, &rdn, &nrdn, NULL ) ) {
   3295 			goto done;
   3296 		}
   3297 		if ( !BER_BVISNULL( &sup ) ) {
   3298 			REWRITE_DN( si, sup, bv2, psup, nsup );
   3299 			if ( rc )
   3300 				goto done;
   3301 			op->orr_newSup = &psup;
   3302 			op->orr_nnewSup = &nsup;
   3303 		} else {
   3304 			op->orr_newSup = NULL;
   3305 			op->orr_nnewSup = NULL;
   3306 			dnParent( &op->o_req_dn, &psup );
   3307 			dnParent( &op->o_req_ndn, &nsup );
   3308 		}
   3309 		op->orr_newrdn = prdn;
   3310 		op->orr_nnewrdn = nrdn;
   3311 		build_new_dn( &op->orr_newDN, &psup, &op->orr_newrdn, op->o_tmpmemctx );
   3312 		build_new_dn( &op->orr_nnewDN, &nsup, &op->orr_nnewrdn, op->o_tmpmemctx );
   3313 		if ( BER_BVISNULL( &sup ) ) {
   3314 			BER_BVZERO( &psup );
   3315 			BER_BVZERO( &nsup );
   3316 		}
   3317 
   3318 		op->orr_deleteoldrdn = deleteOldRdn;
   3319 		op->orr_modlist = NULL;
   3320 		if ( slap_modrdn2mods( op, &rs ) ) {
   3321 			goto done;
   3322 		}
   3323 
   3324 		/* Append modlist for operational attrs */
   3325 		{
   3326 			Modifications *m;
   3327 
   3328 			for ( m = op->orr_modlist; m->sml_next; m = m->sml_next )
   3329 				;
   3330 			m->sml_next = modlist;
   3331 			modlist = NULL;
   3332 		}
   3333 		rc = op->o_bd->be_modrdn( op, &rs );
   3334 		slap_mods_free( op->orr_modlist, 1 );
   3335 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
   3336 			"syncrepl_message_to_op: %s be_modrdn %s (%d)\n",
   3337 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
   3338 		do_graduate = 0;
   3339 		break;
   3340 	case LDAP_REQ_DELETE:
   3341 		rc = op->o_bd->be_delete( op, &rs );
   3342 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
   3343 			"syncrepl_message_to_op: %s be_delete %s (%d)\n",
   3344 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
   3345 		/* silently ignore this */
   3346 		if ( rc == LDAP_NO_SUCH_OBJECT )
   3347 			rc = LDAP_SUCCESS;
   3348 		do_graduate = 0;
   3349 		break;
   3350 	}
   3351 	if ( si->si_syncdata == SYNCDATA_CHANGELOG && !rc )
   3352 		si->si_lastchange = changenum;
   3353 
   3354 done:
   3355 	if ( do_graduate )
   3356 		slap_graduate_commit_csn( op );
   3357 	if ( do_unlock )
   3358 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
   3359 	op->o_bd = si->si_be;
   3360 	op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
   3361 	BER_BVZERO( &op->o_csn );
   3362 	if ( modlist ) {
   3363 		slap_mods_free( modlist, op->o_tag != LDAP_REQ_ADD );
   3364 	}
   3365 	if ( !BER_BVISNULL( &rdn ) ) {
   3366 		if ( !BER_BVISNULL( &nsup ) ) {
   3367 			ch_free( nsup.bv_val );
   3368 		}
   3369 		if ( !BER_BVISNULL( &psup ) ) {
   3370 			ch_free( psup.bv_val );
   3371 		}
   3372 		if ( !BER_BVISNULL( &nrdn ) ) {
   3373 			ch_free( nrdn.bv_val );
   3374 		}
   3375 		if ( !BER_BVISNULL( &prdn ) ) {
   3376 			ch_free( prdn.bv_val );
   3377 		}
   3378 	}
   3379 	if ( op->o_tag == LDAP_REQ_MODRDN ) {
   3380 		op->o_tmpfree( op->orr_newDN.bv_val, op->o_tmpmemctx );
   3381 		op->o_tmpfree( op->orr_nnewDN.bv_val, op->o_tmpmemctx );
   3382 	}
   3383 	if ( freeReqDn ) {
   3384 		op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
   3385 		op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
   3386 	}
   3387 	ber_free( ber, 0 );
   3388 	return rc;
   3389 }
   3390 
   3391 static int
   3392 syncrepl_message_to_entry(
   3393 	syncinfo_t	*si,
   3394 	Operation	*op,
   3395 	LDAPMessage	*msg,
   3396 	Modifications	**modlist,
   3397 	Entry			**entry,
   3398 	int		syncstate,
   3399 	struct berval	*syncUUID
   3400 )
   3401 {
   3402 	Entry		*e = NULL;
   3403 	BerElement	*ber = NULL;
   3404 	Modifications	tmp;
   3405 	Modifications	*mod;
   3406 	Modifications	**modtail = modlist;
   3407 
   3408 	const char	*text;
   3409 	char txtbuf[SLAP_TEXT_BUFLEN];
   3410 	size_t textlen = sizeof txtbuf;
   3411 
   3412 	struct berval	bdn = BER_BVNULL, dn, ndn, bv2;
   3413 	int		rc, is_ctx;
   3414 
   3415 	*modlist = NULL;
   3416 
   3417 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
   3418 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s "
   3419 			"Message type should be entry (%d)",
   3420 			si->si_ridtxt, ldap_msgtype( msg ) );
   3421 		return -1;
   3422 	}
   3423 
   3424 	op->o_tag = LDAP_REQ_ADD;
   3425 
   3426 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
   3427 	if ( rc != LDAP_SUCCESS ) {
   3428 		Debug( LDAP_DEBUG_ANY,
   3429 			"syncrepl_message_to_entry: %s dn get failed (%d)",
   3430 			si->si_ridtxt, rc );
   3431 		return rc;
   3432 	}
   3433 
   3434 	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
   3435 		Debug( LDAP_DEBUG_ANY,
   3436 			"syncrepl_message_to_entry: %s got empty dn",
   3437 			si->si_ridtxt );
   3438 		return LDAP_OTHER;
   3439 	}
   3440 
   3441 	if ( si->si_syncdata != SYNCDATA_CHANGELOG ) {
   3442 		/* syncUUID[0] is normalized UUID received over the wire
   3443 		 * syncUUID[1] is denormalized UUID, generated here
   3444 		 */
   3445 		(void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
   3446 		Debug( LDAP_DEBUG_SYNC,
   3447 			"syncrepl_message_to_entry: %s DN: %s, UUID: %s\n",
   3448 			si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
   3449 	}
   3450 
   3451 	if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
   3452 		/* NOTE: this could be done even before decoding the DN,
   3453 		 * although encoding errors wouldn't be detected */
   3454 		rc = LDAP_SUCCESS;
   3455 		goto done;
   3456 	}
   3457 
   3458 	if ( entry == NULL ) {
   3459 		return -1;
   3460 	}
   3461 
   3462 	REWRITE_DN( si, bdn, bv2, dn, ndn );
   3463 	if ( rc != LDAP_SUCCESS ) {
   3464 		/* One of the things that could happen is that the schema
   3465 		 * is not lined-up; this could result in unknown attributes.
   3466 		 * A value non conformant to the syntax should be unlikely,
   3467 		 * except when replicating between different versions
   3468 		 * of the software, or when syntax validation bugs are fixed
   3469 		 */
   3470 		Debug( LDAP_DEBUG_ANY,
   3471 			"syncrepl_message_to_entry: "
   3472 			"%s dn \"%s\" normalization failed (%d)",
   3473 			si->si_ridtxt, bdn.bv_val, rc );
   3474 		return rc;
   3475 	}
   3476 
   3477 	ber_dupbv( &op->o_req_dn, &dn );
   3478 	ber_dupbv( &op->o_req_ndn, &ndn );
   3479 	slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
   3480 	slap_sl_free( dn.bv_val, op->o_tmpmemctx );
   3481 
   3482 	is_ctx = dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] );
   3483 
   3484 	e = entry_alloc();
   3485 	e->e_name = op->o_req_dn;
   3486 	e->e_nname = op->o_req_ndn;
   3487 
   3488 	while ( ber_remaining( ber ) ) {
   3489 		if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
   3490 			LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
   3491 		{
   3492 			break;
   3493 		}
   3494 
   3495 		/* Drop all updates to the contextCSN of the context entry
   3496 		 * (ITS#4622, etc.)
   3497 		 */
   3498 		if ( is_ctx && !strcasecmp( tmp.sml_type.bv_val,
   3499 			slap_schema.si_ad_contextCSN->ad_cname.bv_val )) {
   3500 			ber_bvarray_free( tmp.sml_values );
   3501 			continue;
   3502 		}
   3503 
   3504 		/* map nsUniqueId to entryUUID, drop nsUniqueId */
   3505 		if ( si->si_syncdata == SYNCDATA_CHANGELOG &&
   3506 			!strcasecmp( tmp.sml_type.bv_val, sy_ad_nsUniqueId->ad_cname.bv_val )) {
   3507 			rc = syncrepl_dsee_uuid( &tmp.sml_values[0], syncUUID, op->o_tmpmemctx );
   3508 			ber_bvarray_free( tmp.sml_values );
   3509 			if ( rc )
   3510 				goto done;
   3511 			continue;
   3512 		}
   3513 
   3514 		mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
   3515 
   3516 		mod->sml_op = LDAP_MOD_REPLACE;
   3517 		mod->sml_flags = 0;
   3518 		mod->sml_next = NULL;
   3519 		mod->sml_desc = NULL;
   3520 		mod->sml_type = tmp.sml_type;
   3521 		mod->sml_values = tmp.sml_values;
   3522 		mod->sml_nvalues = NULL;
   3523 		mod->sml_numvals = 0;	/* slap_mods_check will set this */
   3524 
   3525 		if (si->si_rewrite) {
   3526 			AttributeDescription *ad = NULL;
   3527 			slap_bv2ad( &tmp.sml_type, &ad, &text );
   3528 			if ( ad ) {
   3529 				mod->sml_desc = ad;
   3530 				mod->sml_type = ad->ad_cname;
   3531 				if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
   3532 					int i;
   3533 					for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
   3534 						syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
   3535 						if ( !BER_BVISNULL( &bv2 )) {
   3536 							ber_memfree( tmp.sml_values[i].bv_val );
   3537 							tmp.sml_values[i] = bv2;
   3538 						}
   3539 					}
   3540 				}
   3541 			}
   3542 		}
   3543 		*modtail = mod;
   3544 		modtail = &mod->sml_next;
   3545 	}
   3546 
   3547 	if ( *modlist == NULL ) {
   3548 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s no attributes\n",
   3549 			si->si_ridtxt );
   3550 		rc = -1;
   3551 		goto done;
   3552 	}
   3553 
   3554 	rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
   3555 
   3556 	if ( rc != LDAP_SUCCESS ) {
   3557 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods check (%s)\n",
   3558 			si->si_ridtxt, text );
   3559 		goto done;
   3560 	}
   3561 
   3562 	/* Strip out dynamically generated attrs */
   3563 	for ( modtail = modlist; *modtail ; ) {
   3564 		mod = *modtail;
   3565 		if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
   3566 			*modtail = mod->sml_next;
   3567 			slap_mod_free( &mod->sml_mod, 0 );
   3568 			ch_free( mod );
   3569 		} else {
   3570 			modtail = &mod->sml_next;
   3571 		}
   3572 	}
   3573 
   3574 	/* Strip out attrs in exattrs list */
   3575 	for ( modtail = modlist; *modtail ; ) {
   3576 		mod = *modtail;
   3577 		if ( ldap_charray_inlist( si->si_exattrs,
   3578 			mod->sml_desc->ad_type->sat_cname.bv_val ) )
   3579 		{
   3580 			*modtail = mod->sml_next;
   3581 			slap_mod_free( &mod->sml_mod, 0 );
   3582 			ch_free( mod );
   3583 		} else {
   3584 			modtail = &mod->sml_next;
   3585 		}
   3586 	}
   3587 
   3588 	rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
   3589 	if( rc != LDAP_SUCCESS ) {
   3590 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods2entry (%s)\n",
   3591 			si->si_ridtxt, text );
   3592 	}
   3593 
   3594 done:
   3595 	ber_free( ber, 0 );
   3596 	if ( rc != LDAP_SUCCESS ) {
   3597 		if ( e ) {
   3598 			entry_free( e );
   3599 			e = NULL;
   3600 		}
   3601 	}
   3602 	if ( entry )
   3603 		*entry = e;
   3604 
   3605 	return rc;
   3606 }
   3607 
   3608 #ifdef LDAP_CONTROL_X_DIRSYNC
   3609 static int
   3610 syncrepl_dirsync_message(
   3611 	syncinfo_t	*si,
   3612 	Operation	*op,
   3613 	LDAPMessage	*msg,
   3614 	Modifications	**modlist,
   3615 	Entry			**entry,
   3616 	int		*syncstate,
   3617 	struct berval	*syncUUID
   3618 )
   3619 {
   3620 	Entry		*e = NULL;
   3621 	BerElement	*ber = NULL;
   3622 	Modifications	tmp;
   3623 	Modifications	*mod, *rangeMod = NULL;
   3624 	Modifications	**modtail = modlist;
   3625 
   3626 	const char	*text;
   3627 	char txtbuf[SLAP_TEXT_BUFLEN];
   3628 	size_t textlen = sizeof txtbuf;
   3629 
   3630 	struct berval	bdn = BER_BVNULL, dn, ndn, bv2;
   3631 	int		rc;
   3632 
   3633 	*modlist = NULL;
   3634 	*syncstate = MSAD_DIRSYNC_MODIFY;
   3635 
   3636 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
   3637 		Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s "
   3638 			"Message type should be entry (%d)\n",
   3639 			si->si_ridtxt, ldap_msgtype( msg ) );
   3640 		return -1;
   3641 	}
   3642 
   3643 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
   3644 	if ( rc != LDAP_SUCCESS ) {
   3645 		Debug( LDAP_DEBUG_ANY,
   3646 			"syncrepl_dirsync_message: %s dn get failed (%d)\n",
   3647 			si->si_ridtxt, rc );
   3648 		return rc;
   3649 	}
   3650 
   3651 	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
   3652 		Debug( LDAP_DEBUG_ANY,
   3653 			"syncrepl_dirsync_message: %s got empty dn\n",
   3654 			si->si_ridtxt );
   3655 		return LDAP_OTHER;
   3656 	}
   3657 
   3658 	while ( ber_remaining( ber ) ) {
   3659 		AttributeDescription *ad = NULL;
   3660 
   3661 		if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
   3662 			LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
   3663 		{
   3664 			break;
   3665 		}
   3666 		if ( tmp.sml_values == NULL )
   3667 			continue;
   3668 
   3669 		mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
   3670 
   3671 		mod->sml_op = LDAP_MOD_REPLACE;
   3672 		mod->sml_flags = 0;
   3673 		mod->sml_next = NULL;
   3674 		mod->sml_desc = NULL;
   3675 		mod->sml_type = tmp.sml_type;
   3676 		mod->sml_values = tmp.sml_values;
   3677 		mod->sml_nvalues = NULL;
   3678 		mod->sml_numvals = 0;	/* slap_mods_check will set this */
   3679 
   3680 		rc = slap_bv2ad( &tmp.sml_type, &ad, &text );
   3681 		if ( !ad ) {
   3682 			Debug( LDAP_DEBUG_ANY,
   3683 				"syncrepl_dirsync_message: %s unknown attributeType %s\n",
   3684 				si->si_ridtxt, tmp.sml_type.bv_val );
   3685 			return rc;
   3686 		}
   3687 		mod->sml_desc = ad;
   3688 		mod->sml_type = ad->ad_cname;
   3689 		if (( ad->ad_flags & SLAP_DESC_TAG_RANGE ) && rangeMod == NULL)
   3690 			rangeMod = mod;
   3691 		if (si->si_rewrite) {
   3692 			if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
   3693 				int i;
   3694 				for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
   3695 					syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
   3696 					if ( !BER_BVISNULL( &bv2 )) {
   3697 						ber_memfree( tmp.sml_values[i].bv_val );
   3698 						tmp.sml_values[i] = bv2;
   3699 					}
   3700 				}
   3701 			}
   3702 		}
   3703 		if ( mod->sml_desc == sy_ad_objectGUID ) {
   3704 			ber_dupbv_x( &syncUUID[0], &tmp.sml_values[0], op->o_tmpmemctx );
   3705 			/* syncUUID[0] is normalized UUID received over the wire
   3706 			 * syncUUID[1] is denormalized UUID, generated here
   3707 			 */
   3708 			(void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
   3709 			Debug( LDAP_DEBUG_SYNC,
   3710 				"syncrepl_dirsync_message: %s DN: %s, UUID: %s\n",
   3711 				si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
   3712 		} else if ( mod->sml_desc == sy_ad_isDeleted ) {
   3713 			*syncstate = LDAP_SYNC_DELETE;
   3714 		} else if ( mod->sml_desc == sy_ad_whenCreated ) {
   3715 			*syncstate = LDAP_SYNC_ADD;
   3716 			*modtail = mod;
   3717 			modtail = &mod->sml_next;
   3718 			mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
   3719 
   3720 			mod->sml_op = LDAP_MOD_REPLACE;
   3721 			mod->sml_flags = 0;
   3722 			mod->sml_next = NULL;
   3723 			mod->sml_desc = slap_schema.si_ad_createTimestamp;
   3724 			mod->sml_type = mod->sml_desc->ad_cname;
   3725 			ber_bvarray_dup_x( &mod->sml_values, tmp.sml_values, NULL );
   3726 			mod->sml_nvalues = NULL;
   3727 			mod->sml_numvals = 0;	/* slap_mods_check will set this */
   3728 		}	/* else is a modify or modrdn */
   3729 
   3730 		*modtail = mod;
   3731 		modtail = &mod->sml_next;
   3732 	}
   3733 
   3734 	if ( *modlist == NULL ) {
   3735 		Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s no attributes\n",
   3736 			si->si_ridtxt );
   3737 		rc = -1;
   3738 		goto done;
   3739 	}
   3740 
   3741 	if ( *syncstate == LDAP_SYNC_DELETE ) {
   3742 		e = NULL;
   3743 		slap_mods_free( *modlist, 1 );
   3744 		*modlist = NULL;
   3745 	} else {
   3746 		/* check for incremental multival mods */
   3747 		if ( *syncstate == MSAD_DIRSYNC_MODIFY && rangeMod != NULL ) {
   3748 			for (; rangeMod; rangeMod = rangeMod->sml_next) {
   3749 				if ( rangeMod->sml_desc->ad_flags & SLAP_DESC_TAG_RANGE ) {
   3750 					if ( bvmatch( &rangeMod->sml_desc->ad_tags, &msad_addval ))
   3751 						rangeMod->sml_op = SLAP_MOD_SOFTADD;
   3752 					else if ( bvmatch( &rangeMod->sml_desc->ad_tags, &msad_delval ))
   3753 						rangeMod->sml_op = SLAP_MOD_SOFTDEL;
   3754 					/* turn the tagged attr into a normal one */
   3755 					if ( rangeMod->sml_op != LDAP_MOD_REPLACE ) {
   3756 						AttributeDescription *ad = NULL;
   3757 						slap_bv2ad( &rangeMod->sml_desc->ad_type->sat_cname, &ad, &text );
   3758 						rangeMod->sml_desc = ad;
   3759 					}
   3760 				}
   3761 			}
   3762 		}
   3763 		rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
   3764 
   3765 		if ( rc != LDAP_SUCCESS ) {
   3766 			Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s mods check (%s)\n",
   3767 				si->si_ridtxt, text );
   3768 			goto done;
   3769 		}
   3770 
   3771 		REWRITE_DN( si, bdn, bv2, dn, ndn );
   3772 		if ( rc != LDAP_SUCCESS ) {
   3773 			/* One of the things that could happen is that the schema
   3774 			 * is not lined-up; this could result in unknown attributes.
   3775 			 * A value non conformant to the syntax should be unlikely,
   3776 			 * except when replicating between different versions
   3777 			 * of the software, or when syntax validation bugs are fixed
   3778 			 */
   3779 			Debug( LDAP_DEBUG_ANY,
   3780 				"syncrepl_dirsync_message: "
   3781 				"%s dn \"%s\" normalization failed (%d)",
   3782 				si->si_ridtxt, bdn.bv_val, rc );
   3783 			return rc;
   3784 		}
   3785 
   3786 		ber_dupbv( &op->o_req_dn, &dn );
   3787 		ber_dupbv( &op->o_req_ndn, &ndn );
   3788 		slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
   3789 		slap_sl_free( dn.bv_val, op->o_tmpmemctx );
   3790 
   3791 		e = entry_alloc();
   3792 		e->e_name = op->o_req_dn;
   3793 		e->e_nname = op->o_req_ndn;
   3794 
   3795 		/* Strip out redundant attrs */
   3796 		if ( *syncstate == MSAD_DIRSYNC_MODIFY ) {
   3797 			for ( modtail = modlist; *modtail ; ) {
   3798 				mod = *modtail;
   3799 				if ( mod->sml_desc == sy_ad_objectGUID ||
   3800 					 mod->sml_desc == sy_ad_instanceType ) {
   3801 					*modtail = mod->sml_next;
   3802 					slap_mod_free( &mod->sml_mod, 0 );
   3803 					ch_free( mod );
   3804 				} else {
   3805 					modtail = &mod->sml_next;
   3806 				}
   3807 			}
   3808 		}
   3809 
   3810 		/* Strip out dynamically generated attrs */
   3811 		for ( modtail = modlist; *modtail ; ) {
   3812 			mod = *modtail;
   3813 			if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
   3814 				*modtail = mod->sml_next;
   3815 				slap_mod_free( &mod->sml_mod, 0 );
   3816 				ch_free( mod );
   3817 			} else {
   3818 				modtail = &mod->sml_next;
   3819 			}
   3820 		}
   3821 
   3822 		/* Strip out attrs in exattrs list */
   3823 		for ( modtail = modlist; *modtail ; ) {
   3824 			mod = *modtail;
   3825 			if ( ldap_charray_inlist( si->si_exattrs,
   3826 				mod->sml_desc->ad_type->sat_cname.bv_val ) )
   3827 			{
   3828 				*modtail = mod->sml_next;
   3829 				slap_mod_free( &mod->sml_mod, 0 );
   3830 				ch_free( mod );
   3831 			} else {
   3832 				modtail = &mod->sml_next;
   3833 			}
   3834 		}
   3835 
   3836 		rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
   3837 		if( rc != LDAP_SUCCESS ) {
   3838 			Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s mods2entry (%s)\n",
   3839 				si->si_ridtxt, text );
   3840 		}
   3841 	}
   3842 
   3843 done:
   3844 	ber_free( ber, 0 );
   3845 	if ( rc != LDAP_SUCCESS ) {
   3846 		if ( e ) {
   3847 			entry_free( e );
   3848 			e = NULL;
   3849 		}
   3850 	}
   3851 	if ( entry )
   3852 		*entry = e;
   3853 
   3854 	return rc;
   3855 }
   3856 
   3857 static int
   3858 syncrepl_dirsync_cookie(
   3859 	syncinfo_t	*si,
   3860 	Operation	*op,
   3861 	LDAPControl	**ctrls
   3862 )
   3863 {
   3864 	LDAPControl *ctrl, **next;
   3865 	Backend *be = op->o_bd;
   3866 	Modifications mod;
   3867 	struct berval vals[2];
   3868 
   3869 	int rc, continueFlag;
   3870 
   3871 	slap_callback cb = { NULL };
   3872 	SlapReply	rs_modify = {REP_RESULT};
   3873 
   3874 	ctrl = ldap_control_find( LDAP_CONTROL_X_DIRSYNC, ctrls, &next );
   3875 	if ( ctrl == NULL ) {
   3876 		ldap_controls_free( ctrls );
   3877 		return -1;
   3878 	}
   3879 	rc = ldap_parse_dirsync_control( si->si_ld, ctrl, &continueFlag, &vals[0] );
   3880 	if ( !bvmatch( &vals[0], &si->si_dirSyncCookie )) {
   3881 
   3882 		BER_BVZERO( &vals[1] );
   3883 		mod.sml_op = LDAP_MOD_REPLACE;
   3884 		mod.sml_desc = sy_ad_dirSyncCookie;
   3885 		mod.sml_type = mod.sml_desc->ad_cname;
   3886 		mod.sml_flags = SLAP_MOD_INTERNAL;
   3887 		mod.sml_nvalues = NULL;
   3888 		mod.sml_next = NULL;
   3889 
   3890 		op->o_bd = si->si_wbe;
   3891 		op->o_tag = LDAP_REQ_MODIFY;
   3892 
   3893 		cb.sc_response = syncrepl_null_callback;
   3894 		cb.sc_private = si;
   3895 
   3896 		op->o_callback = &cb;
   3897 		op->o_req_dn = si->si_contextdn;
   3898 		op->o_req_ndn = si->si_contextdn;
   3899 
   3900 		op->o_dont_replicate = 0;
   3901 
   3902 		slap_op_time( &op->o_time, &op->o_tincr );
   3903 
   3904 		mod.sml_numvals = 1;
   3905 		mod.sml_values = vals;
   3906 
   3907 		op->orm_modlist = &mod;
   3908 		op->orm_no_opattrs = 1;
   3909 		rc = op->o_bd->be_modify( op, &rs_modify );
   3910 		op->orm_no_opattrs = 0;
   3911 
   3912 		op->o_bd = be;
   3913 		if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
   3914 
   3915 		if ( rc == LDAP_SUCCESS ) {
   3916 			ber_bvreplace( &si->si_dirSyncCookie, &vals[0] );
   3917 			/* there are more changes still remaining */
   3918 			if ( continueFlag )
   3919 				rc = LDAP_SYNC_REFRESH_REQUIRED;
   3920 		}
   3921 	}
   3922 
   3923 	ch_free( vals[0].bv_val );
   3924 	ldap_controls_free( ctrls );
   3925 	return rc;
   3926 }
   3927 
   3928 static int syncrepl_dirsync_schema()
   3929 {
   3930 	const char *text;
   3931 	int rc;
   3932 
   3933 	rc = slap_str2ad( "objectGUID", &sy_ad_objectGUID, &text );
   3934 	if ( rc )
   3935 		return rc;
   3936 	rc = slap_str2ad( "instanceType", &sy_ad_instanceType, &text );
   3937 	if ( rc )
   3938 		return rc;
   3939 	rc = slap_str2ad( "isDeleted", &sy_ad_isDeleted, &text );
   3940 	if ( rc )
   3941 		return rc;
   3942 	rc = slap_str2ad( "whenCreated", &sy_ad_whenCreated, &text );
   3943 	if ( rc )
   3944 		return rc;
   3945 	return register_at( "( 1.3.6.1.4.1.4203.666.1.27 "		/* OpenLDAP-specific */
   3946 		"NAME 'dirSyncCookie' "
   3947 		"DESC 'DirSync Cookie for shadow copy' "
   3948 		"EQUALITY octetStringMatch "
   3949 		"ORDERING octetStringOrderingMatch "
   3950 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
   3951 		"SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )", &sy_ad_dirSyncCookie, 0);
   3952 }
   3953 #endif /* LDAP_CONTROL_X_DIRSYNC */
   3954 
   3955 static int syncrepl_dsee_schema()
   3956 {
   3957 	const char *text;
   3958 	int rc;
   3959 
   3960 	rc = slap_str2ad( "nsUniqueId", &sy_ad_nsUniqueId, &text );
   3961 	if ( rc )
   3962 		return rc;
   3963 	return register_at( "( 1.3.6.1.4.1.4203.666.1.28 "		/* OpenLDAP-specific */
   3964 		"NAME 'lastChangeNumber' "
   3965 		"DESC 'RetroChangelog latest change record' "
   3966 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
   3967 		"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", &sy_ad_dseeLastChange, 0);
   3968 }
   3969 
   3970 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
   3971  * entry if a previous refresh was interrupted before sending us a new
   3972  * context state. We try to compare the new entry to the existing entry
   3973  * and ignore the new entry if they are the same.
   3974  *
   3975  * Also, we may get an update where the entryDN has changed, due to
   3976  * a ModDn on the provider. We detect this as well, so we can issue
   3977  * the corresponding operation locally.
   3978  *
   3979  * In the case of a modify, we get a list of all the attributes
   3980  * in the original entry. Rather than deleting the entry and re-adding it,
   3981  * we issue a Modify request that deletes all the attributes and adds all
   3982  * the new ones. This avoids the issue of trying to delete/add a non-leaf
   3983  * entry.
   3984  *
   3985  * We otherwise distinguish ModDN from Modify; in the case of
   3986  * a ModDN we just use the CSN, modifyTimestamp and modifiersName
   3987  * operational attributes from the entry, and do a regular ModDN.
   3988  */
   3989 typedef struct dninfo {
   3990 	syncinfo_t *si;
   3991 	Entry *new_entry;
   3992 	struct berval dn;
   3993 	struct berval ndn;
   3994 	struct berval nnewSup;
   3995 	int syncstate;
   3996 	int renamed;	/* Was an existing entry renamed? */
   3997 	int delOldRDN;	/* Was old RDN deleted? */
   3998 	Modifications **modlist;	/* the modlist we received */
   3999 	Modifications *mods;	/* the modlist we compared */
   4000 	int oldNcount;		/* #values of old naming attr */
   4001 	AttributeDescription *oldDesc;	/* for renames */
   4002 	AttributeDescription *newDesc;	/* for renames */
   4003 } dninfo;
   4004 
   4005 #define HASHUUID	1
   4006 
   4007 /* return 1 if inserted, 0 otherwise */
   4008 static int
   4009 presentlist_insert(
   4010 	syncinfo_t* si,
   4011 	struct berval *syncUUID )
   4012 {
   4013 	char *val;
   4014 
   4015 #ifdef HASHUUID
   4016 	Avlnode **av;
   4017 	unsigned short s;
   4018 
   4019 	if ( !si->si_presentlist )
   4020 		si->si_presentlist = ch_calloc(65536, sizeof( Avlnode * ));
   4021 
   4022 	av = (Avlnode **)si->si_presentlist;
   4023 
   4024 	val = ch_malloc(UUIDLEN-2);
   4025 	memcpy(&s, syncUUID->bv_val, 2);
   4026 	memcpy(val, syncUUID->bv_val+2, UUIDLEN-2);
   4027 
   4028 	if ( ldap_avl_insert( &av[s], val,
   4029 		syncuuid_cmp, ldap_avl_dup_error ) )
   4030 	{
   4031 		ch_free( val );
   4032 		return 0;
   4033 	}
   4034 #else
   4035 	val = ch_malloc(UUIDLEN);
   4036 
   4037 	AC_MEMCPY( val, syncUUID->bv_val, UUIDLEN );
   4038 
   4039 	if ( ldap_avl_insert( &si->si_presentlist, val,
   4040 		syncuuid_cmp, ldap_avl_dup_error ) )
   4041 	{
   4042 		ch_free( val );
   4043 		return 0;
   4044 	}
   4045 #endif
   4046 
   4047 	return 1;
   4048 }
   4049 
   4050 static char *
   4051 presentlist_find(
   4052 	Avlnode *av,
   4053 	struct berval *val )
   4054 {
   4055 #ifdef HASHUUID
   4056 	Avlnode **a2 = (Avlnode **)av;
   4057 	unsigned short s;
   4058 
   4059 	if (!av)
   4060 		return NULL;
   4061 
   4062 	memcpy(&s, val->bv_val, 2);
   4063 	return ldap_avl_find( a2[s], val->bv_val+2, syncuuid_cmp );
   4064 #else
   4065 	return ldap_avl_find( av, val->bv_val, syncuuid_cmp );
   4066 #endif
   4067 }
   4068 
   4069 static int
   4070 presentlist_free( Avlnode *av )
   4071 {
   4072 #ifdef HASHUUID
   4073 	Avlnode **a2 = (Avlnode **)av;
   4074 	int i, count = 0;
   4075 
   4076 	if ( av ) {
   4077 		for (i=0; i<65536; i++) {
   4078 			if (a2[i])
   4079 				count += ldap_avl_free( a2[i], ch_free );
   4080 		}
   4081 		ch_free( av );
   4082 	}
   4083 	return count;
   4084 #else
   4085 	return ldap_avl_free( av, ch_free );
   4086 #endif
   4087 }
   4088 
   4089 static void
   4090 presentlist_delete(
   4091 	Avlnode **av,
   4092 	struct berval *val )
   4093 {
   4094 #ifdef HASHUUID
   4095 	Avlnode **a2 = *(Avlnode ***)av;
   4096 	unsigned short s;
   4097 
   4098 	memcpy(&s, val->bv_val, 2);
   4099 	ldap_avl_delete( &a2[s], val->bv_val+2, syncuuid_cmp );
   4100 #else
   4101 	ldap_avl_delete( av, val->bv_val, syncuuid_cmp );
   4102 #endif
   4103 }
   4104 
   4105 static int
   4106 syncrepl_entry(
   4107 	syncinfo_t* si,
   4108 	Operation *op,
   4109 	Entry* entry,
   4110 	Modifications** modlist,
   4111 	int syncstate,
   4112 	struct berval* syncUUID,
   4113 	struct berval* syncCSN )
   4114 {
   4115 	Backend *be = op->o_bd;
   4116 	slap_callback	cb = { NULL, NULL, NULL, NULL };
   4117 	int syncuuid_inserted = 0;
   4118 
   4119 	SlapReply	rs_search = {REP_RESULT};
   4120 	Filter f = {0};
   4121 	AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
   4122 	int rc = LDAP_SUCCESS;
   4123 
   4124 	struct berval pdn = BER_BVNULL;
   4125 	dninfo dni = {0};
   4126 	int	retry = 1;
   4127 	int	freecsn = 1;
   4128 
   4129 	Debug( LDAP_DEBUG_SYNC,
   4130 		"syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) csn=%s tid %p\n",
   4131 		si->si_ridtxt, syncrepl_state2str( syncstate ), syncCSN ? syncCSN->bv_val : "(none)", (void *)op->o_tid );
   4132 
   4133 	if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
   4134 		if ( !si->si_refreshPresent && !si->si_refreshDone ) {
   4135 			syncuuid_inserted = presentlist_insert( si, syncUUID );
   4136 		}
   4137 	}
   4138 
   4139 	if ( syncstate == LDAP_SYNC_PRESENT ) {
   4140 		return 0;
   4141 	} else if ( syncstate != LDAP_SYNC_DELETE ) {
   4142 		if ( entry == NULL ) {
   4143 			return 0;
   4144 		}
   4145 	}
   4146 
   4147 	if ( syncstate != LDAP_SYNC_DELETE ) {
   4148 		Attribute	*a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
   4149 
   4150 		if ( a == NULL ) {
   4151 			/* add if missing */
   4152 			attr_merge_one( entry, slap_schema.si_ad_entryUUID,
   4153 				&syncUUID[1], syncUUID );
   4154 
   4155 		} else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
   4156 			/* replace only if necessary */
   4157 			if ( a->a_nvals != a->a_vals ) {
   4158 				ber_memfree( a->a_nvals[0].bv_val );
   4159 				ber_dupbv( &a->a_nvals[0], syncUUID );
   4160 			}
   4161 			ber_memfree( a->a_vals[0].bv_val );
   4162 			ber_dupbv( &a->a_vals[0], &syncUUID[1] );
   4163 		}
   4164 	}
   4165 
   4166 	f.f_choice = LDAP_FILTER_EQUALITY;
   4167 	f.f_ava = &ava;
   4168 	ava.aa_desc = slap_schema.si_ad_entryUUID;
   4169 	ava.aa_value = *syncUUID;
   4170 
   4171 	if ( syncuuid_inserted ) {
   4172 		Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
   4173 			si->si_ridtxt, syncUUID[1].bv_val );
   4174 	}
   4175 	op->ors_filter = &f;
   4176 
   4177 	op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID[1].bv_len;
   4178 	op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
   4179 		op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
   4180 	AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
   4181 	AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
   4182 		syncUUID[1].bv_val, syncUUID[1].bv_len );
   4183 	op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
   4184 	op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
   4185 
   4186 	op->o_tag = LDAP_REQ_SEARCH;
   4187 	op->ors_scope = LDAP_SCOPE_SUBTREE;
   4188 	op->ors_deref = LDAP_DEREF_NEVER;
   4189 
   4190 	/* get the entry for this UUID */
   4191 	if ( si->si_rewrite ) {
   4192 		op->o_req_dn = si->si_suffixm;
   4193 		op->o_req_ndn = si->si_suffixm;
   4194 	} else
   4195 	{
   4196 		op->o_req_dn = si->si_base;
   4197 		op->o_req_ndn = si->si_base;
   4198 	}
   4199 
   4200 	op->o_time = slap_get_time();
   4201 	op->ors_tlimit = SLAP_NO_LIMIT;
   4202 	op->ors_slimit = 1;
   4203 	op->ors_limit = NULL;
   4204 
   4205 	op->ors_attrs = slap_anlist_all_attributes;
   4206 	op->ors_attrsonly = 0;
   4207 
   4208 	/* set callback function */
   4209 	op->o_callback = &cb;
   4210 	cb.sc_response = dn_callback;
   4211 	cb.sc_private = &dni;
   4212 	dni.si = si;
   4213 	dni.new_entry = entry;
   4214 	dni.modlist = modlist;
   4215 	dni.syncstate = syncstate;
   4216 
   4217 	rc = be->be_search( op, &rs_search );
   4218 	Debug( LDAP_DEBUG_SYNC,
   4219 			"syncrepl_entry: %s be_search (%d)\n",
   4220 			si->si_ridtxt, rc );
   4221 
   4222 	if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
   4223 		slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
   4224 	}
   4225 
   4226 	cb.sc_response = syncrepl_null_callback;
   4227 	cb.sc_private = si;
   4228 
   4229 	if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
   4230 		Debug( LDAP_DEBUG_SYNC,
   4231 				"syncrepl_entry: %s %s\n",
   4232 				si->si_ridtxt, entry->e_name.bv_val );
   4233 	} else {
   4234 		Debug( LDAP_DEBUG_SYNC,
   4235 				"syncrepl_entry: %s %s\n",
   4236 				si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)" );
   4237 	}
   4238 
   4239 	assert( BER_BVISNULL( &op->o_csn ) );
   4240 	if ( syncCSN ) {
   4241 		slap_queue_csn( op, syncCSN );
   4242 	}
   4243 
   4244 #ifdef SLAP_CONTROL_X_LAZY_COMMIT
   4245 	if ( !si->si_refreshDone && si->si_lazyCommit )
   4246 		op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL;
   4247 #endif
   4248 
   4249 	slap_op_time( &op->o_time, &op->o_tincr );
   4250 	switch ( syncstate ) {
   4251 	case LDAP_SYNC_ADD:
   4252 	case LDAP_SYNC_MODIFY:
   4253 	case DSEE_SYNC_ADD:
   4254 		if ( BER_BVISNULL( &op->o_csn ))
   4255 		{
   4256 
   4257 			Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryCSN );
   4258 			if ( a ) {
   4259 				/* FIXME: op->o_csn is assumed to be
   4260 				 * on the thread's slab; this needs
   4261 				 * to be cleared ASAP.
   4262 				 */
   4263 				op->o_csn = a->a_vals[0];
   4264 				freecsn = 0;
   4265 			}
   4266 		}
   4267 retry_add:;
   4268 		if ( !BER_BVISNULL( &op->o_csn ) ) {
   4269 			/* Check we're not covered by current contextCSN */
   4270 			int i, sid = slap_parse_csn_sid( &op->o_csn );
   4271 			ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   4272 			for ( i=0;
   4273 				i < si->si_cookieState->cs_num &&
   4274 					sid <= si->si_cookieState->cs_sids[i];
   4275 				i++ ) {
   4276 				if ( si->si_cookieState->cs_sids[i] == sid &&
   4277 					ber_bvcmp( &op->o_csn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
   4278 					Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s "
   4279 						"entry '%s' csn=%s not new enough, ignored\n",
   4280 						si->si_ridtxt, entry->e_name.bv_val, op->o_csn.bv_val );
   4281 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   4282 					goto done;
   4283 				}
   4284 			}
   4285 			ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   4286 		}
   4287 		if ( BER_BVISNULL( &dni.dn ) ) {
   4288 			SlapReply	rs_add = {REP_RESULT};
   4289 
   4290 			op->o_req_dn = entry->e_name;
   4291 			op->o_req_ndn = entry->e_nname;
   4292 			op->o_tag = LDAP_REQ_ADD;
   4293 			op->ora_e = entry;
   4294 			op->o_bd = si->si_wbe;
   4295 
   4296 			rc = op->o_bd->be_add( op, &rs_add );
   4297 			Debug( LDAP_DEBUG_SYNC,
   4298 					"syncrepl_entry: %s be_add %s (%d)\n",
   4299 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
   4300 			switch ( rs_add.sr_err ) {
   4301 			case LDAP_SUCCESS:
   4302 				if ( op->ora_e == entry ) {
   4303 					be_entry_release_w( op, entry );
   4304 				}
   4305 				entry = NULL;
   4306 				break;
   4307 
   4308 			case LDAP_REFERRAL:
   4309 			/* we assume that LDAP_NO_SUCH_OBJECT is returned
   4310 			 * only if the suffix entry is not present.
   4311 			 * This should not happen during Persist phase.
   4312 			 */
   4313 			case LDAP_NO_SUCH_OBJECT:
   4314 				if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
   4315 					si->si_refreshDone ) {
   4316 					/* Something's wrong, start over */
   4317 					ber_bvarray_free( si->si_syncCookie.ctxcsn );
   4318 					si->si_syncCookie.ctxcsn = NULL;
   4319 					entry_free( entry );
   4320 					ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   4321 					ber_bvarray_free( si->si_cookieState->cs_vals );
   4322 					ch_free( si->si_cookieState->cs_sids );
   4323 					si->si_cookieState->cs_vals = NULL;
   4324 					si->si_cookieState->cs_sids = 0;
   4325 					si->si_cookieState->cs_num = 0;
   4326 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   4327 					return LDAP_NO_SUCH_OBJECT;
   4328 				}
   4329 				rc = syncrepl_add_glue( op, entry );
   4330 				entry = NULL;
   4331 				break;
   4332 
   4333 			/* if an entry was added via syncrepl_add_glue(),
   4334 			 * it likely has no entryUUID, so the previous
   4335 			 * be_search() doesn't find it.  In this case,
   4336 			 * give syncrepl a chance to modify it. Also
   4337 			 * allow for entries that were recreated with the
   4338 			 * same DN but a different entryUUID.
   4339 			 */
   4340 			case LDAP_ALREADY_EXISTS:
   4341 				if ( retry ) {
   4342 					Operation	op2 = *op;
   4343 					SlapReply	rs2 = { REP_RESULT };
   4344 					slap_callback	cb2 = { 0 };
   4345 
   4346 					op2.o_bd = be;
   4347 					op2.o_tag = LDAP_REQ_SEARCH;
   4348 					op2.o_req_dn = entry->e_name;
   4349 					op2.o_req_ndn = entry->e_nname;
   4350 					op2.ors_scope = LDAP_SCOPE_BASE;
   4351 					op2.ors_deref = LDAP_DEREF_NEVER;
   4352 					op2.ors_attrs = slap_anlist_all_attributes;
   4353 					op2.ors_attrsonly = 0;
   4354 					op2.ors_limit = NULL;
   4355 					op2.ors_slimit = 1;
   4356 					op2.ors_tlimit = SLAP_NO_LIMIT;
   4357 					BER_BVZERO( &op2.o_csn );
   4358 
   4359 					f.f_choice = LDAP_FILTER_PRESENT;
   4360 					f.f_desc = slap_schema.si_ad_objectClass;
   4361 					op2.ors_filter = &f;
   4362 					op2.ors_filterstr = generic_filterstr;
   4363 
   4364 					op2.o_callback = &cb2;
   4365 					cb2.sc_response = dn_callback;
   4366 					cb2.sc_private = &dni;
   4367 
   4368 					rc = be->be_search( &op2, &rs2 );
   4369 					if ( rc ) goto done;
   4370 
   4371 					retry = 0;
   4372 					slap_op_time( &op->o_time, &op->o_tincr );
   4373 					goto retry_add;
   4374 				}
   4375 				/* FALLTHRU */
   4376 
   4377 			default:
   4378 				Debug( LDAP_DEBUG_ANY,
   4379 					"syncrepl_entry: %s be_add %s failed (%d)\n",
   4380 					si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
   4381 				break;
   4382 			}
   4383 			syncCSN = NULL;
   4384 			op->o_bd = be;
   4385 			goto done;
   4386 		}
   4387 		/* FALLTHRU */
   4388 #ifdef LDAP_CONTROL_X_DIRSYNC
   4389 	case MSAD_DIRSYNC_MODIFY:
   4390 #endif
   4391 		op->o_req_dn = dni.dn;
   4392 		op->o_req_ndn = dni.ndn;
   4393 		if ( dni.renamed ) {
   4394 			struct berval noldp, newp;
   4395 			Modifications *mod, **modtail, **ml, *m2 = NULL;
   4396 			int i, got_replace = 0, just_rename = 0;
   4397 			SlapReply rs_modify = {REP_RESULT};
   4398 
   4399 			op->o_tag = LDAP_REQ_MODRDN;
   4400 			dnRdn( &entry->e_name, &op->orr_newrdn );
   4401 			dnRdn( &entry->e_nname, &op->orr_nnewrdn );
   4402 
   4403 			if ( !BER_BVISNULL( &dni.nnewSup )) {
   4404 				dnParent( &entry->e_name, &newp );
   4405 				op->orr_newSup = &newp;
   4406 				op->orr_nnewSup = &dni.nnewSup;
   4407 			} else {
   4408 				op->orr_newSup = NULL;
   4409 				op->orr_nnewSup = NULL;
   4410 			}
   4411 			op->orr_newDN = entry->e_name;
   4412 			op->orr_nnewDN = entry->e_nname;
   4413 			op->orr_deleteoldrdn = dni.delOldRDN;
   4414 			op->orr_modlist = NULL;
   4415 #ifdef LDAP_CONTROL_X_DIRSYNC
   4416 			if ( syncstate != MSAD_DIRSYNC_MODIFY )
   4417 #endif
   4418 			{
   4419 				if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
   4420 					goto done;
   4421 				}
   4422 			}
   4423 
   4424 			/* Drop the RDN-related mods from this op, because their
   4425 			 * equivalents were just setup by slap_modrdn2mods.
   4426 			 *
   4427 			 * If delOldRDN is TRUE then we should see a delete modop
   4428 			 * for oldDesc. We might see a replace instead.
   4429 			 *  delete with no values: therefore newDesc != oldDesc.
   4430 			 *   if oldNcount == 1, then Drop this op.
   4431 			 *  delete with 1 value: can only be the oldRDN value. Drop op.
   4432 			 *  delete with N values: Drop oldRDN value, keep remainder.
   4433 			 *  replace with 1 value: if oldNcount == 1 and
   4434 			 *     newDesc == oldDesc, Drop this op.
   4435 			 * Any other cases must be left intact.
   4436 			 *
   4437 			 * We should also see an add modop for newDesc. (But not if
   4438 			 * we got a replace modop due to delOldRDN.) If it has
   4439 			 * multiple values, we'll have to drop the new RDN value.
   4440 			 */
   4441 			modtail = &op->orr_modlist;
   4442 			if ( dni.delOldRDN ) {
   4443 				for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
   4444 					if ( (*ml)->sml_desc == dni.oldDesc ) {
   4445 						mod = *ml;
   4446 						if ( mod->sml_op == LDAP_MOD_REPLACE &&
   4447 							dni.oldDesc != dni.newDesc ) {
   4448 							/* This Replace is due to other Mods.
   4449 							 * Just let it ride.
   4450 							 */
   4451 							continue;
   4452 						}
   4453 						if ( mod->sml_numvals <= 1 &&
   4454 							dni.oldNcount == 1 &&
   4455 							( mod->sml_op == LDAP_MOD_DELETE ||
   4456 							  mod->sml_op == LDAP_MOD_REPLACE )) {
   4457 							if ( mod->sml_op == LDAP_MOD_REPLACE )
   4458 								got_replace = 1;
   4459 							/* Drop this op */
   4460 							*ml = mod->sml_next;
   4461 							mod->sml_next = NULL;
   4462 							slap_mods_free( mod, 1 );
   4463 							break;
   4464 						}
   4465 						if ( mod->sml_op != LDAP_MOD_DELETE || mod->sml_numvals == 0 )
   4466 							continue;
   4467 						for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
   4468 							if ( m2->sml_desc == dni.oldDesc &&
   4469 								m2->sml_op == LDAP_MOD_DELETE ) break;
   4470 						}
   4471 						for ( i=0; i<mod->sml_numvals; i++ ) {
   4472 							if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
   4473 								mod->sml_numvals--;
   4474 								ch_free( mod->sml_values[i].bv_val );
   4475 								mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
   4476 								BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
   4477 								if ( mod->sml_nvalues ) {
   4478 									ch_free( mod->sml_nvalues[i].bv_val );
   4479 									mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
   4480 									BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
   4481 								}
   4482 								break;
   4483 							}
   4484 						}
   4485 						if ( !mod->sml_numvals ) {
   4486 							/* Drop this op */
   4487 							*ml = mod->sml_next;
   4488 							mod->sml_next = NULL;
   4489 							slap_mods_free( mod, 1 );
   4490 						}
   4491 						break;
   4492 					}
   4493 				}
   4494 			}
   4495 			if ( !got_replace ) {
   4496 				for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
   4497 					if ( (*ml)->sml_desc == dni.newDesc ) {
   4498 						mod = *ml;
   4499 						if ( mod->sml_op != LDAP_MOD_ADD )
   4500 							continue;
   4501 						if ( mod->sml_numvals == 1 ) {
   4502 							/* Drop this op */
   4503 							*ml = mod->sml_next;
   4504 							mod->sml_next = NULL;
   4505 							slap_mods_free( mod, 1 );
   4506 							break;
   4507 						}
   4508 						for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
   4509 							if ( m2->sml_desc == dni.oldDesc &&
   4510 								m2->sml_op == SLAP_MOD_SOFTADD ) break;
   4511 						}
   4512 						for ( i=0; i<mod->sml_numvals; i++ ) {
   4513 							if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
   4514 								mod->sml_numvals--;
   4515 								ch_free( mod->sml_values[i].bv_val );
   4516 								mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
   4517 								BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
   4518 								if ( mod->sml_nvalues ) {
   4519 									ch_free( mod->sml_nvalues[i].bv_val );
   4520 									mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
   4521 									BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
   4522 								}
   4523 								break;
   4524 							}
   4525 						}
   4526 						break;
   4527 					}
   4528 				}
   4529 			}
   4530 
   4531 			/* RDNs must be NUL-terminated for back-ldap */
   4532 			noldp = op->orr_newrdn;
   4533 			ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
   4534 			noldp = op->orr_nnewrdn;
   4535 			ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
   4536 
   4537 			/* Setup opattrs too */
   4538 			{
   4539 				static AttributeDescription *nullattr = NULL;
   4540 				static AttributeDescription **const opattrs[] = {
   4541 					&slap_schema.si_ad_entryCSN,
   4542 					&slap_schema.si_ad_modifiersName,
   4543 					&slap_schema.si_ad_modifyTimestamp,
   4544 					&nullattr
   4545 				};
   4546 				AttributeDescription *opattr;
   4547 				int i;
   4548 
   4549 				modtail = &m2;
   4550 				/* pull mod off incoming modlist */
   4551 				for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
   4552 					for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next )
   4553 					{
   4554 						if ( (*ml)->sml_desc == opattr ) {
   4555 							mod = *ml;
   4556 							*ml = mod->sml_next;
   4557 							mod->sml_next = NULL;
   4558 							*modtail = mod;
   4559 							modtail = &mod->sml_next;
   4560 							break;
   4561 						}
   4562 					}
   4563 				}
   4564 				/* If there are still Modifications left, put the opattrs
   4565 				 * back, and let be_modify run. Otherwise, append the opattrs
   4566 				 * to the orr_modlist.
   4567 				 */
   4568 				if ( dni.mods ) {
   4569 					mod = dni.mods;
   4570 					/* don't set a CSN for the rename op */
   4571 					if ( syncCSN )
   4572 						slap_graduate_commit_csn( op );
   4573 				} else {
   4574 					mod = op->orr_modlist;
   4575 					just_rename = 1;
   4576 				}
   4577 				for ( ; mod->sml_next; mod=mod->sml_next );
   4578 				mod->sml_next = m2;
   4579 			}
   4580 			op->o_bd = si->si_wbe;
   4581 retry_modrdn:;
   4582 			rs_reinit( &rs_modify, REP_RESULT );
   4583 			rc = op->o_bd->be_modrdn( op, &rs_modify );
   4584 
   4585 			/* NOTE: noSuchObject should result because the new superior
   4586 			 * has not been added yet (ITS#6472) */
   4587 			if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
   4588 				Operation op2 = *op;
   4589 				rc = syncrepl_add_glue_ancestors( &op2, entry );
   4590 				if ( rc == LDAP_SUCCESS ) {
   4591 					goto retry_modrdn;
   4592 				}
   4593 			}
   4594 
   4595 			op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
   4596 			op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
   4597 
   4598 			slap_mods_free( op->orr_modlist, 1 );
   4599 			Debug( LDAP_DEBUG_SYNC,
   4600 					"syncrepl_entry: %s be_modrdn %s (%d)\n",
   4601 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
   4602 			op->o_bd = be;
   4603 			/* Renamed entries may still have other mods so just fallthru */
   4604 			op->o_req_dn = entry->e_name;
   4605 			op->o_req_ndn = entry->e_nname;
   4606 			/* Use CSN on the modify */
   4607 			if ( just_rename )
   4608 				syncCSN = NULL;
   4609 			else if ( syncCSN )
   4610 				slap_queue_csn( op, syncCSN );
   4611 		}
   4612 		if ( dni.mods ) {
   4613 			SlapReply rs_modify = {REP_RESULT};
   4614 
   4615 			op->o_tag = LDAP_REQ_MODIFY;
   4616 			op->orm_modlist = dni.mods;
   4617 			op->orm_no_opattrs = 1;
   4618 			op->o_bd = si->si_wbe;
   4619 
   4620 			rc = op->o_bd->be_modify( op, &rs_modify );
   4621 			slap_mods_free( op->orm_modlist, 1 );
   4622 			op->orm_no_opattrs = 0;
   4623 			Debug( LDAP_DEBUG_SYNC,
   4624 					"syncrepl_entry: %s be_modify %s (%d)\n",
   4625 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
   4626 			if ( rs_modify.sr_err != LDAP_SUCCESS ) {
   4627 				Debug( LDAP_DEBUG_ANY,
   4628 					"syncrepl_entry: %s be_modify failed (%d)\n",
   4629 					si->si_ridtxt, rs_modify.sr_err );
   4630 			}
   4631 			syncCSN = NULL;
   4632 			op->o_bd = be;
   4633 		} else if ( !dni.renamed ) {
   4634 			Debug( LDAP_DEBUG_SYNC,
   4635 					"syncrepl_entry: %s entry unchanged, ignored (%s)\n",
   4636 					si->si_ridtxt, op->o_req_dn.bv_val );
   4637 			if ( syncCSN ) {
   4638 				slap_graduate_commit_csn( op );
   4639 				syncCSN = NULL;
   4640 			}
   4641 		}
   4642 		goto done;
   4643 	case LDAP_SYNC_DELETE :
   4644 		if ( !BER_BVISNULL( &dni.dn ) ) {
   4645 			SlapReply	rs_delete = {REP_RESULT};
   4646 			op->o_req_dn = dni.dn;
   4647 			op->o_req_ndn = dni.ndn;
   4648 			op->o_tag = LDAP_REQ_DELETE;
   4649 			op->o_bd = si->si_wbe;
   4650 			if ( !syncCSN && si->si_syncCookie.ctxcsn ) {
   4651 				slap_queue_csn( op, si->si_syncCookie.ctxcsn );
   4652 			}
   4653 			rc = op->o_bd->be_delete( op, &rs_delete );
   4654 			Debug( LDAP_DEBUG_SYNC,
   4655 					"syncrepl_entry: %s be_delete %s (%d)\n",
   4656 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
   4657 			if ( rc == LDAP_NO_SUCH_OBJECT )
   4658 				rc = LDAP_SUCCESS;
   4659 
   4660 			while ( rs_delete.sr_err == LDAP_SUCCESS
   4661 				&& op->o_delete_glue_parent ) {
   4662 				op->o_delete_glue_parent = 0;
   4663 				if ( !be_issuffix( be, &op->o_req_ndn ) ) {
   4664 					slap_callback cb = { NULL };
   4665 					cb.sc_response = syncrepl_null_callback;
   4666 					dnParent( &op->o_req_ndn, &pdn );
   4667 					op->o_req_dn = pdn;
   4668 					op->o_req_ndn = pdn;
   4669 					op->o_callback = &cb;
   4670 					rs_reinit( &rs_delete, REP_RESULT );
   4671 					op->o_bd->be_delete( op, &rs_delete );
   4672 				} else {
   4673 					break;
   4674 				}
   4675 			}
   4676 			syncCSN = NULL;
   4677 			op->o_bd = be;
   4678 		}
   4679 		goto done;
   4680 
   4681 	default :
   4682 		Debug( LDAP_DEBUG_ANY,
   4683 			"syncrepl_entry: %s unknown syncstate\n", si->si_ridtxt );
   4684 		goto done;
   4685 	}
   4686 
   4687 done:
   4688 	slap_sl_free( syncUUID[1].bv_val, op->o_tmpmemctx );
   4689 	BER_BVZERO( &syncUUID[1] );
   4690 	if ( !BER_BVISNULL( &dni.ndn ) ) {
   4691 		op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
   4692 	}
   4693 	if ( !BER_BVISNULL( &dni.dn ) ) {
   4694 		op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
   4695 	}
   4696 	if ( entry ) {
   4697 		entry_free( entry );
   4698 	}
   4699 	if ( syncCSN ) {
   4700 		slap_graduate_commit_csn( op );
   4701 	}
   4702 	if ( !BER_BVISNULL( &op->o_csn ) && freecsn ) {
   4703 		op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
   4704 	}
   4705 	BER_BVZERO( &op->o_csn );
   4706 	return rc;
   4707 }
   4708 
   4709 static struct berval gcbva[] = {
   4710 	BER_BVC("top"),
   4711 	BER_BVC("glue"),
   4712 	BER_BVNULL
   4713 };
   4714 
   4715 #define NP_DELETE_ONE	2
   4716 
   4717 static void
   4718 syncrepl_del_nonpresent(
   4719 	Operation *op,
   4720 	syncinfo_t *si,
   4721 	BerVarray uuids,
   4722 	struct sync_cookie *sc,
   4723 	int m )
   4724 {
   4725 	Backend* be = op->o_bd;
   4726 	slap_callback	cb = { NULL };
   4727 	struct nonpresent_entry *np_list, *np_prev;
   4728 	int rc;
   4729 	AttributeName	an[3]; /* entryUUID, entryCSN, NULL */
   4730 
   4731 	struct berval pdn = BER_BVNULL;
   4732 	struct berval csn;
   4733 
   4734 	if ( si->si_rewrite ) {
   4735 		op->o_req_dn = si->si_suffixm;
   4736 		op->o_req_ndn = si->si_suffixm;
   4737 	} else
   4738 	{
   4739 		op->o_req_dn = si->si_base;
   4740 		op->o_req_ndn = si->si_base;
   4741 	}
   4742 
   4743 	cb.sc_response = nonpresent_callback;
   4744 	cb.sc_private = si;
   4745 
   4746 	op->o_callback = &cb;
   4747 	op->o_tag = LDAP_REQ_SEARCH;
   4748 	op->ors_scope = si->si_scope;
   4749 	op->ors_deref = LDAP_DEREF_NEVER;
   4750 	op->o_time = slap_get_time();
   4751 	op->ors_tlimit = SLAP_NO_LIMIT;
   4752 
   4753 
   4754 	if ( uuids ) {
   4755 		Filter uf;
   4756 		AttributeAssertion eq = ATTRIBUTEASSERTION_INIT;
   4757 		int i;
   4758 
   4759 		op->ors_attrsonly = 1;
   4760 		op->ors_attrs = slap_anlist_no_attrs;
   4761 		op->ors_limit = NULL;
   4762 		op->ors_filter = &uf;
   4763 
   4764 		uf.f_ava = &eq;
   4765 		uf.f_av_desc = slap_schema.si_ad_entryUUID;
   4766 		uf.f_next = NULL;
   4767 		uf.f_choice = LDAP_FILTER_EQUALITY;
   4768 		si->si_refreshDelete |= NP_DELETE_ONE;
   4769 
   4770 		for (i=0; uuids[i].bv_val; i++) {
   4771 			SlapReply rs_search = {REP_RESULT};
   4772 
   4773 			op->ors_slimit = 1;
   4774 			uf.f_av_value = uuids[i];
   4775 			filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
   4776 			Debug( LDAP_DEBUG_SYNC, "syncrepl_del_nonpresent: %s "
   4777 				"checking non-present filter=%s\n",
   4778 				si->si_ridtxt, op->ors_filterstr.bv_val );
   4779 			rc = be->be_search( op, &rs_search );
   4780 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
   4781 		}
   4782 		si->si_refreshDelete ^= NP_DELETE_ONE;
   4783 	} else {
   4784 		Filter *cf, *of;
   4785 		Filter mmf[2];
   4786 		AttributeAssertion mmaa;
   4787 		SlapReply rs_search = {REP_RESULT};
   4788 
   4789 		memset( &an[0], 0, 3 * sizeof( AttributeName ) );
   4790 		an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
   4791 		an[0].an_desc = slap_schema.si_ad_entryUUID;
   4792 		an[1].an_name = slap_schema.si_ad_entryCSN->ad_cname;
   4793 		an[1].an_desc = slap_schema.si_ad_entryCSN;
   4794 		op->ors_attrs = an;
   4795 		op->ors_slimit = SLAP_NO_LIMIT;
   4796 		op->ors_tlimit = SLAP_NO_LIMIT;
   4797 		op->ors_limit = NULL;
   4798 		op->ors_attrsonly = 0;
   4799 		op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
   4800 		/* In multi-provider, updates can continue to arrive while
   4801 		 * we're searching. Limit the search result to entries
   4802 		 * older than our newest cookie CSN.
   4803 		 */
   4804 		if ( SLAP_MULTIPROVIDER( op->o_bd )) {
   4805 			Filter *f;
   4806 			int i;
   4807 
   4808 			f = mmf;
   4809 			f->f_choice = LDAP_FILTER_AND;
   4810 			f->f_next = op->ors_filter;
   4811 			f->f_and = f+1;
   4812 			of = f->f_and;
   4813 			f = of;
   4814 			f->f_choice = LDAP_FILTER_LE;
   4815 			f->f_ava = &mmaa;
   4816 			f->f_av_desc = slap_schema.si_ad_entryCSN;
   4817 			f->f_next = NULL;
   4818 			BER_BVZERO( &f->f_av_value );
   4819 			for ( i=0; i<sc->numcsns; i++ ) {
   4820 				if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 )
   4821 					f->f_av_value = sc->ctxcsn[i];
   4822 			}
   4823 			of = op->ors_filter;
   4824 			op->ors_filter = mmf;
   4825 			filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
   4826 		} else {
   4827 			cf = NULL;
   4828 			op->ors_filterstr = si->si_filterstr;
   4829 		}
   4830 		op->o_nocaching = 1;
   4831 
   4832 
   4833 		rc = be->be_search( op, &rs_search );
   4834 		if ( SLAP_MULTIPROVIDER( op->o_bd )) {
   4835 			op->ors_filter = of;
   4836 		}
   4837 		if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
   4838 		if ( op->ors_filterstr.bv_val != si->si_filterstr.bv_val ) {
   4839 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
   4840 		}
   4841 
   4842 	}
   4843 
   4844 	op->o_nocaching = 0;
   4845 
   4846 	if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
   4847 
   4848 		if ( !BER_BVISNULL( &sc->delcsn ) ) {
   4849 			Debug( LDAP_DEBUG_SYNC, "syncrepl_del_nonpresent: %s "
   4850 					"using delcsn=%s\n",
   4851 					si->si_ridtxt, sc->delcsn.bv_val );
   4852 			csn = sc->delcsn;
   4853 		} else if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
   4854 			csn = sc->ctxcsn[m];
   4855 		} else {
   4856 			csn = si->si_syncCookie.ctxcsn[0];
   4857 		}
   4858 
   4859 		op->o_bd = si->si_wbe;
   4860 		slap_queue_csn( op, &csn );
   4861 
   4862 		np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
   4863 		while ( np_list != NULL ) {
   4864 			SlapReply rs_delete = {REP_RESULT};
   4865 
   4866 			LDAP_LIST_REMOVE( np_list, npe_link );
   4867 			np_prev = np_list;
   4868 			np_list = LDAP_LIST_NEXT( np_list, npe_link );
   4869 			op->o_tag = LDAP_REQ_DELETE;
   4870 			op->o_callback = &cb;
   4871 			cb.sc_response = syncrepl_null_callback;
   4872 			cb.sc_private = si;
   4873 			op->o_req_dn = *np_prev->npe_name;
   4874 			op->o_req_ndn = *np_prev->npe_nname;
   4875 			rc = op->o_bd->be_delete( op, &rs_delete );
   4876 			Debug( LDAP_DEBUG_SYNC,
   4877 				"syncrepl_del_nonpresent: %s be_delete %s (%d)\n",
   4878 				si->si_ridtxt, op->o_req_dn.bv_val, rc );
   4879 
   4880 			if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
   4881 				SlapReply rs_modify = {REP_RESULT};
   4882 				Modifications mod1, mod2, mod3;
   4883 				struct berval vals[2] = { csn, BER_BVNULL };
   4884 
   4885 				mod1.sml_op = LDAP_MOD_REPLACE;
   4886 				mod1.sml_flags = 0;
   4887 				mod1.sml_desc = slap_schema.si_ad_objectClass;
   4888 				mod1.sml_type = mod1.sml_desc->ad_cname;
   4889 				mod1.sml_numvals = 2;
   4890 				mod1.sml_values = &gcbva[0];
   4891 				mod1.sml_nvalues = NULL;
   4892 				mod1.sml_next = &mod2;
   4893 
   4894 				mod2.sml_op = LDAP_MOD_REPLACE;
   4895 				mod2.sml_flags = 0;
   4896 				mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
   4897 				mod2.sml_type = mod2.sml_desc->ad_cname;
   4898 				mod2.sml_numvals = 1;
   4899 				mod2.sml_values = &gcbva[1];
   4900 				mod2.sml_nvalues = NULL;
   4901 				mod2.sml_next = &mod3;
   4902 
   4903 				mod3.sml_op = LDAP_MOD_REPLACE;
   4904 				mod3.sml_flags = 0;
   4905 				mod3.sml_desc = slap_schema.si_ad_entryCSN;
   4906 				mod3.sml_type = mod3.sml_desc->ad_cname;
   4907 				mod3.sml_numvals = 1;
   4908 				mod3.sml_values = vals;
   4909 				mod3.sml_nvalues = NULL;
   4910 				mod3.sml_next = NULL;
   4911 
   4912 				op->o_tag = LDAP_REQ_MODIFY;
   4913 				op->orm_modlist = &mod1;
   4914 
   4915 				rc = op->o_bd->be_modify( op, &rs_modify );
   4916 				if ( mod3.sml_next ) slap_mods_free( mod3.sml_next, 1 );
   4917 			}
   4918 
   4919 			while ( rs_delete.sr_err == LDAP_SUCCESS &&
   4920 					op->o_delete_glue_parent ) {
   4921 				op->o_delete_glue_parent = 0;
   4922 				if ( !be_issuffix( be, &op->o_req_ndn ) ) {
   4923 					slap_callback cb = { NULL };
   4924 					cb.sc_response = syncrepl_null_callback;
   4925 					dnParent( &op->o_req_ndn, &pdn );
   4926 					op->o_req_dn = pdn;
   4927 					op->o_req_ndn = pdn;
   4928 					op->o_callback = &cb;
   4929 					rs_reinit( &rs_delete, REP_RESULT );
   4930 					/* give it a root privil ? */
   4931 					op->o_bd->be_delete( op, &rs_delete );
   4932 				} else {
   4933 					break;
   4934 				}
   4935 			}
   4936 
   4937 			op->o_delete_glue_parent = 0;
   4938 
   4939 			ber_bvfree( np_prev->npe_name );
   4940 			ber_bvfree( np_prev->npe_nname );
   4941 			ch_free( np_prev );
   4942 
   4943 			if ( slapd_shutdown ) {
   4944 				break;
   4945 			}
   4946 		}
   4947 
   4948 		slap_graduate_commit_csn( op );
   4949 		op->o_bd = be;
   4950 
   4951 		op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
   4952 		BER_BVZERO( &op->o_csn );
   4953 	}
   4954 
   4955 	return;
   4956 }
   4957 
   4958 static int
   4959 syncrepl_add_glue_ancestors(
   4960 	Operation* op,
   4961 	Entry *e )
   4962 {
   4963 	Backend *be = op->o_bd;
   4964 	slap_callback cb = { NULL };
   4965 	Attribute	*a;
   4966 	int	rc = LDAP_SUCCESS;
   4967 	int suffrdns;
   4968 	int i;
   4969 	struct berval dn = BER_BVNULL;
   4970 	struct berval ndn = BER_BVNULL;
   4971 	Entry	*glue;
   4972 	struct berval	ptr, nptr;
   4973 	char		*comma;
   4974 
   4975 	op->o_tag = LDAP_REQ_ADD;
   4976 	op->o_callback = &cb;
   4977 	cb.sc_response = syncrepl_null_callback;
   4978 	cb.sc_private = NULL;
   4979 
   4980 	dn = e->e_name;
   4981 	ndn = e->e_nname;
   4982 
   4983 	/* count RDNs in suffix */
   4984 	if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) {
   4985 		for ( i = 0, ptr = be->be_nsuffix[0], comma = ptr.bv_val; comma != NULL; comma = ber_bvchr( &ptr, ',' ) ) {
   4986 			comma++;
   4987 			ptr.bv_len -= comma - ptr.bv_val;
   4988 			ptr.bv_val = comma;
   4989 			i++;
   4990 		}
   4991 		suffrdns = i;
   4992 	} else {
   4993 		/* suffix is "" */
   4994 		suffrdns = 0;
   4995 	}
   4996 
   4997 	/* Start with BE suffix */
   4998 	ptr = dn;
   4999 	for ( i = 0; i < suffrdns; i++ ) {
   5000 		comma = ber_bvrchr( &ptr, ',' );
   5001 		if ( comma != NULL ) {
   5002 			ptr.bv_len = comma - ptr.bv_val;
   5003 		} else {
   5004 			ptr.bv_len = 0;
   5005 			break;
   5006 		}
   5007 	}
   5008 
   5009 	if ( !BER_BVISEMPTY( &ptr ) ) {
   5010 		dn.bv_len -= ptr.bv_len + ( suffrdns != 0 );
   5011 		dn.bv_val += ptr.bv_len + ( suffrdns != 0 );
   5012 	}
   5013 
   5014 	/* the normalizedDNs are always the same length, no counting
   5015 	 * required.
   5016 	 */
   5017 	nptr = ndn;
   5018 	if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
   5019 		ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
   5020 		ndn.bv_len = be->be_nsuffix[0].bv_len;
   5021 
   5022 		nptr.bv_len = ndn.bv_val - nptr.bv_val - 1;
   5023 
   5024 	} else {
   5025 		nptr.bv_len = 0;
   5026 	}
   5027 
   5028 	while ( ndn.bv_val > e->e_nname.bv_val ) {
   5029 		SlapReply	rs_add = {REP_RESULT};
   5030 
   5031 		glue = entry_alloc();
   5032 		ber_dupbv( &glue->e_name, &dn );
   5033 		ber_dupbv( &glue->e_nname, &ndn );
   5034 
   5035 		a = attr_alloc( slap_schema.si_ad_objectClass );
   5036 
   5037 		a->a_numvals = 2;
   5038 		a->a_vals = ch_calloc( 3, sizeof( struct berval ) );
   5039 		ber_dupbv( &a->a_vals[0], &gcbva[0] );
   5040 		ber_dupbv( &a->a_vals[1], &gcbva[1] );
   5041 		ber_dupbv( &a->a_vals[2], &gcbva[2] );
   5042 
   5043 		a->a_nvals = a->a_vals;
   5044 
   5045 		a->a_next = glue->e_attrs;
   5046 		glue->e_attrs = a;
   5047 
   5048 		a = attr_alloc( slap_schema.si_ad_structuralObjectClass );
   5049 
   5050 		a->a_numvals = 1;
   5051 		a->a_vals = ch_calloc( 2, sizeof( struct berval ) );
   5052 		ber_dupbv( &a->a_vals[0], &gcbva[1] );
   5053 		ber_dupbv( &a->a_vals[1], &gcbva[2] );
   5054 
   5055 		a->a_nvals = a->a_vals;
   5056 
   5057 		a->a_next = glue->e_attrs;
   5058 		glue->e_attrs = a;
   5059 
   5060 		op->o_req_dn = glue->e_name;
   5061 		op->o_req_ndn = glue->e_nname;
   5062 		op->ora_e = glue;
   5063 		rc = be->be_add ( op, &rs_add );
   5064 		if ( rs_add.sr_err == LDAP_SUCCESS ) {
   5065 			if ( op->ora_e == glue )
   5066 				be_entry_release_w( op, glue );
   5067 		} else {
   5068 		/* incl. ALREADY EXIST */
   5069 			entry_free( glue );
   5070 			if ( rs_add.sr_err != LDAP_ALREADY_EXISTS ) {
   5071 				entry_free( e );
   5072 				return rc;
   5073 			}
   5074 		}
   5075 
   5076 		/* Move to next child */
   5077 		comma = ber_bvrchr( &ptr, ',' );
   5078 		if ( comma == NULL ) {
   5079 			break;
   5080 		}
   5081 		ptr.bv_len = comma - ptr.bv_val;
   5082 
   5083 		dn.bv_val = ++comma;
   5084 		dn.bv_len = e->e_name.bv_len - (dn.bv_val - e->e_name.bv_val);
   5085 
   5086 		comma = ber_bvrchr( &nptr, ',' );
   5087 		assert( comma != NULL );
   5088 		nptr.bv_len = comma - nptr.bv_val;
   5089 
   5090 		ndn.bv_val = ++comma;
   5091 		ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
   5092 	}
   5093 
   5094 	return rc;
   5095 }
   5096 
   5097 int
   5098 syncrepl_add_glue(
   5099 	Operation* op,
   5100 	Entry *e )
   5101 {
   5102 	slap_callback cb = { NULL };
   5103 	int	rc;
   5104 	Backend *be = op->o_bd;
   5105 	SlapReply	rs_add = {REP_RESULT};
   5106 
   5107 	rc = syncrepl_add_glue_ancestors( op, e );
   5108 	switch ( rc ) {
   5109 	case LDAP_SUCCESS:
   5110 	case LDAP_ALREADY_EXISTS:
   5111 		break;
   5112 
   5113 	default:
   5114 		return rc;
   5115 	}
   5116 
   5117 	op->o_tag = LDAP_REQ_ADD;
   5118 	op->o_callback = &cb;
   5119 	cb.sc_response = syncrepl_null_callback;
   5120 	cb.sc_private = NULL;
   5121 
   5122 	op->o_req_dn = e->e_name;
   5123 	op->o_req_ndn = e->e_nname;
   5124 	op->ora_e = e;
   5125 	rc = be->be_add ( op, &rs_add );
   5126 	if ( rs_add.sr_err == LDAP_SUCCESS ) {
   5127 		if ( op->ora_e == e )
   5128 			be_entry_release_w( op, e );
   5129 	} else {
   5130 		entry_free( e );
   5131 	}
   5132 
   5133 	return rc;
   5134 }
   5135 
   5136 static int
   5137 syncrepl_dsee_update(
   5138 	syncinfo_t *si,
   5139 	Operation *op
   5140 )
   5141 {
   5142 	Backend *be = op->o_bd;
   5143 	Modifications mod;
   5144 	struct berval first = BER_BVNULL;
   5145 	slap_callback cb = { NULL };
   5146 	SlapReply	rs_modify = {REP_RESULT};
   5147 	char valbuf[sizeof("18446744073709551615")];
   5148 	struct berval bvals[2];
   5149 	int rc;
   5150 
   5151 	if ( si->si_lastchange == si->si_prevchange )
   5152 		return 0;
   5153 
   5154 	mod.sml_op = LDAP_MOD_REPLACE;
   5155 	mod.sml_desc = sy_ad_dseeLastChange;
   5156 	mod.sml_type = mod.sml_desc->ad_cname;
   5157 	mod.sml_flags = SLAP_MOD_INTERNAL;
   5158 	mod.sml_nvalues = NULL;
   5159 	mod.sml_values = bvals;
   5160 	mod.sml_numvals = 1;
   5161 	mod.sml_next = NULL;
   5162 	bvals[0].bv_val = valbuf;
   5163 	bvals[0].bv_len = sprintf( valbuf, "%lu", si->si_lastchange );
   5164 	BER_BVZERO( &bvals[1] );
   5165 
   5166 	op->o_bd = si->si_wbe;
   5167 
   5168 	op->o_tag = LDAP_REQ_MODIFY;
   5169 
   5170 	cb.sc_response = syncrepl_null_callback;
   5171 	cb.sc_private = si;
   5172 
   5173 	op->o_callback = &cb;
   5174 	op->o_req_dn = si->si_contextdn;
   5175 	op->o_req_ndn = si->si_contextdn;
   5176 
   5177 	/* update contextCSN */
   5178 	op->o_dont_replicate = 1;
   5179 
   5180 	/* avoid timestamp collisions */
   5181 	slap_op_time( &op->o_time, &op->o_tincr );
   5182 
   5183 	op->orm_modlist = &mod;
   5184 	op->orm_no_opattrs = 1;
   5185 	rc = op->o_bd->be_modify( op, &rs_modify );
   5186 
   5187 	op->o_bd = be;
   5188 	si->si_prevchange = si->si_lastchange;
   5189 
   5190 	return rc;
   5191 }
   5192 
   5193 static int
   5194 syncrepl_updateCookie(
   5195 	syncinfo_t *si,
   5196 	Operation *op,
   5197 	struct sync_cookie *syncCookie,
   5198 	int save )
   5199 {
   5200 	Backend *be = op->o_bd;
   5201 	Modifications mod;
   5202 	struct berval first = BER_BVNULL;
   5203 	struct sync_cookie sc;
   5204 #ifdef CHECK_CSN
   5205 	Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
   5206 #endif
   5207 
   5208 	int rc, i, j, changed = 0;
   5209 	ber_len_t len;
   5210 
   5211 	slap_callback cb = { NULL };
   5212 	SlapReply	rs_modify = {REP_RESULT};
   5213 
   5214 	mod.sml_op = LDAP_MOD_REPLACE;
   5215 	mod.sml_desc = slap_schema.si_ad_contextCSN;
   5216 	mod.sml_type = mod.sml_desc->ad_cname;
   5217 	mod.sml_flags = SLAP_MOD_INTERNAL;
   5218 	mod.sml_nvalues = NULL;
   5219 	mod.sml_next = NULL;
   5220 
   5221 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   5222 	while ( si->si_cookieState->cs_updating )
   5223 		ldap_pvt_thread_cond_wait( &si->si_cookieState->cs_cond, &si->si_cookieState->cs_mutex );
   5224 
   5225 #ifdef CHECK_CSN
   5226 	for ( i=0; i<syncCookie->numcsns; i++ ) {
   5227 		assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i ));
   5228 	}
   5229 	for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
   5230 		assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
   5231 	}
   5232 #endif
   5233 
   5234 	/* clone the cookieState CSNs so we can Replace the whole thing */
   5235 	sc.numcsns = si->si_cookieState->cs_num;
   5236 	if ( sc.numcsns ) {
   5237 		ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
   5238 		sc.sids = ch_malloc( sc.numcsns * sizeof(int));
   5239 		for ( i=0; i<sc.numcsns; i++ )
   5240 			sc.sids[i] = si->si_cookieState->cs_sids[i];
   5241 	} else {
   5242 		sc.ctxcsn = NULL;
   5243 		sc.sids = NULL;
   5244 	}
   5245 
   5246 	/* find any CSNs in the syncCookie that are newer than the cookieState */
   5247 	for ( i=0; i<syncCookie->numcsns; i++ ) {
   5248 		for ( j=0; j<sc.numcsns; j++ ) {
   5249 			if ( syncCookie->sids[i] < sc.sids[j] )
   5250 				break;
   5251 			if ( syncCookie->sids[i] != sc.sids[j] )
   5252 				continue;
   5253 			len = syncCookie->ctxcsn[i].bv_len;
   5254 			if ( len > sc.ctxcsn[j].bv_len )
   5255 				len = sc.ctxcsn[j].bv_len;
   5256 			if ( memcmp( syncCookie->ctxcsn[i].bv_val,
   5257 				sc.ctxcsn[j].bv_val, len ) > 0 ) {
   5258 				ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
   5259 				changed = 1;
   5260 				if ( BER_BVISNULL( &first ) ||
   5261 					memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
   5262 					first = syncCookie->ctxcsn[i];
   5263 				}
   5264 			}
   5265 			break;
   5266 		}
   5267 		/* there was no match for this SID, it's a new CSN */
   5268 		if ( j == sc.numcsns ||
   5269 			syncCookie->sids[i] != sc.sids[j] ) {
   5270 			slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
   5271 				&syncCookie->ctxcsn[i] );
   5272 			if ( BER_BVISNULL( &first ) ||
   5273 				memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
   5274 				first = syncCookie->ctxcsn[i];
   5275 			}
   5276 			changed = 1;
   5277 		}
   5278 	}
   5279 	/* Should never happen, ITS#5065 */
   5280 	if ( BER_BVISNULL( &first ) || !changed ) {
   5281 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   5282 		ber_bvarray_free( sc.ctxcsn );
   5283 		ch_free( sc.sids );
   5284 		return 0;
   5285 	}
   5286 
   5287 	si->si_cookieState->cs_updating = 1;
   5288 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   5289 
   5290 	op->o_bd = si->si_wbe;
   5291 	slap_queue_csn( op, &first );
   5292 
   5293 	op->o_tag = LDAP_REQ_MODIFY;
   5294 
   5295 	cb.sc_response = syncrepl_null_callback;
   5296 	cb.sc_private = si;
   5297 
   5298 	op->o_callback = &cb;
   5299 	op->o_req_dn = si->si_contextdn;
   5300 	op->o_req_ndn = si->si_contextdn;
   5301 
   5302 	/* update contextCSN */
   5303 	op->o_dont_replicate = !save;
   5304 
   5305 	/* avoid timestamp collisions */
   5306 	if ( save )
   5307 		slap_op_time( &op->o_time, &op->o_tincr );
   5308 
   5309 	mod.sml_numvals = sc.numcsns;
   5310 	mod.sml_values = sc.ctxcsn;
   5311 
   5312 	op->orm_modlist = &mod;
   5313 	op->orm_no_opattrs = 1;
   5314 	rc = op->o_bd->be_modify( op, &rs_modify );
   5315 
   5316 	if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
   5317 		SLAP_SYNC_SUBENTRY( op->o_bd )) {
   5318 		const char	*text;
   5319 		char txtbuf[SLAP_TEXT_BUFLEN];
   5320 		size_t textlen = sizeof txtbuf;
   5321 		Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
   5322 		rs_reinit( &rs_modify, REP_RESULT );
   5323 		rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
   5324 		slap_queue_csn( op, &first );
   5325 		op->o_tag = LDAP_REQ_ADD;
   5326 		op->ora_e = e;
   5327 		rc = op->o_bd->be_add( op, &rs_modify );
   5328 		if ( e == op->ora_e )
   5329 			be_entry_release_w( op, op->ora_e );
   5330 	}
   5331 
   5332 	op->orm_no_opattrs = 0;
   5333 	op->o_dont_replicate = 0;
   5334 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
   5335 
   5336 	if ( rs_modify.sr_err == LDAP_SUCCESS ) {
   5337 		slap_sync_cookie_free( &si->si_syncCookie, 0 );
   5338 		ber_bvarray_free( si->si_cookieState->cs_vals );
   5339 		ch_free( si->si_cookieState->cs_sids );
   5340 		si->si_cookieState->cs_vals = sc.ctxcsn;
   5341 		si->si_cookieState->cs_sids = sc.sids;
   5342 		si->si_cookieState->cs_num = sc.numcsns;
   5343 
   5344 		/* Don't just dup the provider's cookie, recreate it */
   5345 		si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
   5346 		ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL );
   5347 		si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * sizeof(int) );
   5348 		for ( i=0; i<si->si_cookieState->cs_num; i++ )
   5349 			si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
   5350 
   5351 		si->si_cookieState->cs_age++;
   5352 		si->si_cookieAge = si->si_cookieState->cs_age;
   5353 	} else {
   5354 		Debug( LDAP_DEBUG_ANY,
   5355 			"syncrepl_updateCookie: %s be_modify failed (%d)\n",
   5356 			si->si_ridtxt, rs_modify.sr_err );
   5357 		ch_free( sc.sids );
   5358 		ber_bvarray_free( sc.ctxcsn );
   5359 	}
   5360 
   5361 #ifdef CHECK_CSN
   5362 	for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
   5363 		assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
   5364 	}
   5365 #endif
   5366 
   5367 	si->si_cookieState->cs_updating = 0;
   5368 	ldap_pvt_thread_cond_broadcast( &si->si_cookieState->cs_cond );
   5369 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
   5370 
   5371 	op->o_bd = be;
   5372 	op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
   5373 	BER_BVZERO( &op->o_csn );
   5374 	if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
   5375 
   5376 	return rc;
   5377 }
   5378 
   5379 /* Compare the attribute from the old entry to the one in the new
   5380  * entry. The Modifications from the new entry will either be left
   5381  * in place, or changed to an Add or Delete as needed.
   5382  */
   5383 static void
   5384 attr_cmp( Operation *op, Attribute *old, Attribute *new,
   5385 	Modifications ***mret, Modifications ***mcur )
   5386 {
   5387 	int i, j;
   5388 	Modifications *mod, **modtail;
   5389 
   5390 	modtail = *mret;
   5391 
   5392 	if ( old ) {
   5393 		int n, o, nn, no;
   5394 		struct berval **adds, **dels;
   5395 		/* count old and new */
   5396 		for ( o=0; old->a_vals[o].bv_val; o++ ) ;
   5397 		for ( n=0; new->a_vals[n].bv_val; n++ ) ;
   5398 
   5399 		/* there MUST be both old and new values */
   5400 		assert( o != 0 );
   5401 		assert( n != 0 );
   5402 		j = 0;
   5403 
   5404 		adds = op->o_tmpalloc( sizeof(struct berval *) * n, op->o_tmpmemctx );
   5405 		dels = op->o_tmpalloc( sizeof(struct berval *) * o, op->o_tmpmemctx );
   5406 
   5407 		for ( i=0; i<o; i++ ) dels[i] = &old->a_vals[i];
   5408 		for ( i=0; i<n; i++ ) adds[i] = &new->a_vals[i];
   5409 
   5410 		nn = n; no = o;
   5411 
   5412 		for ( i=0; i<o; i++ ) {
   5413 			for ( j=0; j<n; j++ ) {
   5414 				if ( !adds[j] )
   5415 					continue;
   5416 				if ( bvmatch( dels[i], adds[j] ) ) {
   5417 					no--;
   5418 					nn--;
   5419 					adds[j] = NULL;
   5420 					dels[i] = NULL;
   5421 					break;
   5422 				}
   5423 			}
   5424 		}
   5425 
   5426 		/* Don't delete/add an objectClass, always use the replace op.
   5427 		 * Modify would fail if provider has replaced entry with a new,
   5428 		 * and the new explicitly includes a superior of a class that was
   5429 		 * only included implicitly in the old entry.  Ref ITS#5517.
   5430 		 *
   5431 		 * Also use replace op if attr has no equality matching rule.
   5432 		 * (ITS#5781)
   5433 		 */
   5434 		if ( ( nn || ( no > 0 && no < o ) ) &&
   5435 			( old->a_desc == slap_schema.si_ad_objectClass ||
   5436 			 !old->a_desc->ad_type->sat_equality ) )
   5437 		{
   5438 			no = o;
   5439 		}
   5440 
   5441 		i = j;
   5442 		/* all old values were deleted, just use the replace op */
   5443 		if ( no == o ) {
   5444 			i = j-1;
   5445 		} else if ( no ) {
   5446 		/* delete some values */
   5447 			mod = ch_malloc( sizeof( Modifications ) );
   5448 			mod->sml_op = LDAP_MOD_DELETE;
   5449 			mod->sml_flags = 0;
   5450 			mod->sml_desc = old->a_desc;
   5451 			mod->sml_type = mod->sml_desc->ad_cname;
   5452 			mod->sml_numvals = no;
   5453 			mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
   5454 			if ( old->a_vals != old->a_nvals ) {
   5455 				mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
   5456 			} else {
   5457 				mod->sml_nvalues = NULL;
   5458 			}
   5459 			j = 0;
   5460 			for ( i = 0; i < o; i++ ) {
   5461 				if ( !dels[i] ) continue;
   5462 				ber_dupbv( &mod->sml_values[j], &old->a_vals[i] );
   5463 				if ( mod->sml_nvalues ) {
   5464 					ber_dupbv( &mod->sml_nvalues[j], &old->a_nvals[i] );
   5465 				}
   5466 				j++;
   5467 			}
   5468 			BER_BVZERO( &mod->sml_values[j] );
   5469 			if ( mod->sml_nvalues ) {
   5470 				BER_BVZERO( &mod->sml_nvalues[j] );
   5471 			}
   5472 			*modtail = mod;
   5473 			modtail = &mod->sml_next;
   5474 			i = j;
   5475 		}
   5476 		op->o_tmpfree( dels, op->o_tmpmemctx );
   5477 		/* some values were added */
   5478 		if ( nn && no < o ) {
   5479 			mod = ch_malloc( sizeof( Modifications ) );
   5480 			if ( is_at_single_value( old->a_desc->ad_type ))
   5481 				mod->sml_op = LDAP_MOD_REPLACE;
   5482 			else
   5483 				mod->sml_op = LDAP_MOD_ADD;
   5484 			mod->sml_flags = 0;
   5485 			mod->sml_desc = old->a_desc;
   5486 			mod->sml_type = mod->sml_desc->ad_cname;
   5487 			mod->sml_numvals = nn;
   5488 			mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
   5489 			if ( old->a_vals != old->a_nvals ) {
   5490 				mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
   5491 			} else {
   5492 				mod->sml_nvalues = NULL;
   5493 			}
   5494 			j = 0;
   5495 			for ( i = 0; i < n; i++ ) {
   5496 				if ( !adds[i] ) continue;
   5497 				ber_dupbv( &mod->sml_values[j], &new->a_vals[i] );
   5498 				if ( mod->sml_nvalues ) {
   5499 					ber_dupbv( &mod->sml_nvalues[j], &new->a_nvals[i] );
   5500 				}
   5501 				j++;
   5502 			}
   5503 			BER_BVZERO( &mod->sml_values[j] );
   5504 			if ( mod->sml_nvalues ) {
   5505 				BER_BVZERO( &mod->sml_nvalues[j] );
   5506 			}
   5507 			*modtail = mod;
   5508 			modtail = &mod->sml_next;
   5509 			i = j;
   5510 		}
   5511 		op->o_tmpfree( adds, op->o_tmpmemctx );
   5512 	} else {
   5513 		/* new attr, just use the new mod */
   5514 		i = 0;
   5515 		j = 1;
   5516 	}
   5517 	/* advance to next element */
   5518 	mod = **mcur;
   5519 	if ( mod ) {
   5520 		if ( i != j ) {
   5521 			**mcur = mod->sml_next;
   5522 			*modtail = mod;
   5523 			modtail = &mod->sml_next;
   5524 		} else {
   5525 			*mcur = &mod->sml_next;
   5526 		}
   5527 	}
   5528 	*mret = modtail;
   5529 }
   5530 
   5531 /* Generate a set of modifications to change the old entry into the
   5532  * new one. On input ml is a list of modifications equivalent to
   5533  * the new entry. It will be massaged and the result will be stored
   5534  * in mods.
   5535  */
   5536 void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
   5537 	Modifications **mods, Modifications **ml, int is_ctx)
   5538 {
   5539 	Modifications **modtail = mods;
   5540 
   5541 	/* We assume that attributes are saved in the same order
   5542 	 * in the remote and local databases. So if we walk through
   5543 	 * the attributeDescriptions one by one they should match in
   5544 	 * lock step. If not, look for an add or delete.
   5545 	 */
   5546 	while ( old && new )
   5547 	{
   5548 		/* If we've seen this before, use its mod now */
   5549 		if ( new->a_flags & SLAP_ATTR_IXADD ) {
   5550 			attr_cmp( op, NULL, new, &modtail, &ml );
   5551 			new = new->a_next;
   5552 			continue;
   5553 		}
   5554 		/* Skip contextCSN */
   5555 		if ( is_ctx && old->a_desc ==
   5556 			slap_schema.si_ad_contextCSN ) {
   5557 			old = old->a_next;
   5558 			continue;
   5559 		}
   5560 
   5561 		if ( old->a_desc != new->a_desc ) {
   5562 			Modifications *mod;
   5563 			Attribute *tmp;
   5564 
   5565 			/* If it's just been re-added later,
   5566 			 * remember that we've seen it.
   5567 			 */
   5568 			tmp = attr_find( new, old->a_desc );
   5569 			if ( tmp ) {
   5570 				tmp->a_flags |= SLAP_ATTR_IXADD;
   5571 			} else {
   5572 				/* If it's a new attribute, pull it in.
   5573 				 */
   5574 				tmp = attr_find( old, new->a_desc );
   5575 				if ( !tmp ) {
   5576 					attr_cmp( op, NULL, new, &modtail, &ml );
   5577 					new = new->a_next;
   5578 					continue;
   5579 				}
   5580 				/* Delete old attr */
   5581 				mod = ch_malloc( sizeof( Modifications ) );
   5582 				mod->sml_op = LDAP_MOD_DELETE;
   5583 				mod->sml_flags = 0;
   5584 				mod->sml_desc = old->a_desc;
   5585 				mod->sml_type = mod->sml_desc->ad_cname;
   5586 				mod->sml_numvals = 0;
   5587 				mod->sml_values = NULL;
   5588 				mod->sml_nvalues = NULL;
   5589 				*modtail = mod;
   5590 				modtail = &mod->sml_next;
   5591 			}
   5592 			old = old->a_next;
   5593 			continue;
   5594 		}
   5595 		/* kludge - always update modifiersName so that it
   5596 		 * stays co-located with the other mod opattrs. But only
   5597 		 * if we know there are other valid mods.
   5598 		 */
   5599 		if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
   5600 			old->a_desc == slap_schema.si_ad_modifyTimestamp ))
   5601 			attr_cmp( op, NULL, new, &modtail, &ml );
   5602 		else
   5603 			attr_cmp( op, old, new, &modtail, &ml );
   5604 		new = new->a_next;
   5605 		old = old->a_next;
   5606 	}
   5607 
   5608 	/* These are all missing from provider */
   5609 	while ( old ) {
   5610 		Modifications *mod = ch_malloc( sizeof( Modifications ) );
   5611 
   5612 		mod->sml_op = LDAP_MOD_DELETE;
   5613 		mod->sml_flags = 0;
   5614 		mod->sml_desc = old->a_desc;
   5615 		mod->sml_type = mod->sml_desc->ad_cname;
   5616 		mod->sml_numvals = 0;
   5617 		mod->sml_values = NULL;
   5618 		mod->sml_nvalues = NULL;
   5619 
   5620 		*modtail = mod;
   5621 		modtail = &mod->sml_next;
   5622 
   5623 		old = old->a_next;
   5624 	}
   5625 
   5626 	/* Newly added attributes */
   5627 	while ( new ) {
   5628 		attr_cmp( op, NULL, new, &modtail, &ml );
   5629 
   5630 		new = new->a_next;
   5631 	}
   5632 
   5633 	*modtail = *ml;
   5634 	*ml = NULL;
   5635 }
   5636 
   5637 /* shallow copy attrs, excluding non-replicated attrs */
   5638 static Attribute *
   5639 attrs_exdup( Operation *op, dninfo *dni, Attribute *attrs )
   5640 {
   5641 	int i;
   5642 	Attribute *tmp, *anew;
   5643 
   5644 	if ( attrs == NULL ) return NULL;
   5645 
   5646 	/* count attrs */
   5647 	for ( tmp = attrs,i=0; tmp; tmp=tmp->a_next ) i++;
   5648 
   5649 	anew = op->o_tmpalloc( i * sizeof(Attribute), op->o_tmpmemctx );
   5650 	for ( tmp = anew; attrs; attrs=attrs->a_next ) {
   5651 		int flag = is_at_operational( attrs->a_desc->ad_type ) ? dni->si->si_allopattrs :
   5652 			dni->si->si_allattrs;
   5653 		if ( !flag && !ad_inlist( attrs->a_desc, dni->si->si_anlist ))
   5654 			continue;
   5655 		if ( dni->si->si_exattrs && ad_inlist( attrs->a_desc, dni->si->si_exanlist ))
   5656 			continue;
   5657 		*tmp = *attrs;
   5658 		tmp->a_next = tmp+1;
   5659 		tmp++;
   5660 	}
   5661 	if ( tmp == anew ) {
   5662 		/* excluded everything */
   5663 		op->o_tmpfree( anew, op->o_tmpmemctx );
   5664 		return NULL;
   5665 	}
   5666 	tmp[-1].a_next = NULL;
   5667 	return anew;
   5668 }
   5669 
   5670 static int
   5671 dn_callback(
   5672 	Operation*	op,
   5673 	SlapReply*	rs )
   5674 {
   5675 	dninfo *dni = op->o_callback->sc_private;
   5676 
   5677 	if ( rs->sr_type == REP_SEARCH ) {
   5678 		if ( !BER_BVISNULL( &dni->dn ) ) {
   5679 			Debug( LDAP_DEBUG_ANY,
   5680 				"dn_callback : consistency error - "
   5681 				"entryUUID is not unique\n" );
   5682 		} else {
   5683 			ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx );
   5684 			ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
   5685 			/* If there is a new entry, see if it differs from the old.
   5686 			 * We compare the non-normalized values so that cosmetic changes
   5687 			 * in the provider are always propagated.
   5688 			 */
   5689 			if ( dni->new_entry ) {
   5690 				Attribute *old, *new;
   5691 				struct berval old_rdn, new_rdn;
   5692 				struct berval old_p, new_p;
   5693 				int is_ctx, new_sup = 0;
   5694 
   5695 #ifdef LDAP_CONTROL_X_DIRSYNC
   5696 				if ( dni->syncstate != MSAD_DIRSYNC_MODIFY )
   5697 #endif
   5698 				{
   5699 					/* If old entry is not a glue entry, make sure new entry
   5700 					 * is actually newer than old entry
   5701 					 */
   5702 					if ( !is_entry_glue( rs->sr_entry )) {
   5703 						old = attr_find( rs->sr_entry->e_attrs,
   5704 							slap_schema.si_ad_entryCSN );
   5705 						new = attr_find( dni->new_entry->e_attrs,
   5706 							slap_schema.si_ad_entryCSN );
   5707 						if ( new && old ) {
   5708 							int rc;
   5709 							ber_len_t len = old->a_vals[0].bv_len;
   5710 							if ( len > new->a_vals[0].bv_len )
   5711 								len = new->a_vals[0].bv_len;
   5712 							rc = memcmp( old->a_vals[0].bv_val,
   5713 								new->a_vals[0].bv_val, len );
   5714 							if ( rc > 0 ) {
   5715 								Debug( LDAP_DEBUG_SYNC,
   5716 									"dn_callback : new entry is older than ours "
   5717 									"%s ours %s, new %s\n",
   5718 									rs->sr_entry->e_name.bv_val,
   5719 									old->a_vals[0].bv_val,
   5720 									new->a_vals[0].bv_val );
   5721 								return LDAP_SUCCESS;
   5722 							} else if ( rc == 0 ) {
   5723 								Debug( LDAP_DEBUG_SYNC,
   5724 									"dn_callback : entries have identical CSN "
   5725 									"%s %s\n",
   5726 									rs->sr_entry->e_name.bv_val,
   5727 									old->a_vals[0].bv_val );
   5728 								return LDAP_SUCCESS;
   5729 							}
   5730 						}
   5731 					}
   5732 
   5733 					is_ctx = dn_match( &rs->sr_entry->e_nname,
   5734 						&op->o_bd->be_nsuffix[0] );
   5735 				}
   5736 
   5737 				/* Did the DN change?
   5738 				 * case changes in the parent are ignored,
   5739 				 * we only want to know if the RDN was
   5740 				 * actually changed.
   5741 				 */
   5742 				dnRdn( &rs->sr_entry->e_name, &old_rdn );
   5743 				dnRdn( &dni->new_entry->e_name, &new_rdn );
   5744 				dnParent( &rs->sr_entry->e_nname, &old_p );
   5745 				dnParent( &dni->new_entry->e_nname, &new_p );
   5746 
   5747 				new_sup = !dn_match( &old_p, &new_p );
   5748 				if ( !dn_match( &old_rdn, &new_rdn ) || new_sup )
   5749 				{
   5750 					struct berval oldRDN, oldVal;
   5751 					AttributeDescription *ad = NULL;
   5752 					int oldpos, newpos;
   5753 					Attribute *a;
   5754 
   5755 					dni->renamed = 1;
   5756 					if ( new_sup )
   5757 						dni->nnewSup = new_p;
   5758 
   5759 					/* See if the oldRDN was deleted */
   5760 					dnRdn( &rs->sr_entry->e_nname, &oldRDN );
   5761 					oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
   5762 					oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
   5763 						oldRDN.bv_val );
   5764 					oldRDN.bv_len -= oldVal.bv_len + 1;
   5765 					slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
   5766 					dni->oldDesc = ad;
   5767 					for ( oldpos=0, a=rs->sr_entry->e_attrs;
   5768 						a && a->a_desc != ad; oldpos++, a=a->a_next );
   5769 					/* a should not be NULL but apparently it happens.
   5770 					 * ITS#7144
   5771 					 */
   5772 					if ( a ) {
   5773 						dni->oldNcount = a->a_numvals;
   5774 						for ( newpos=0, a=dni->new_entry->e_attrs;
   5775 							a && a->a_desc != ad; newpos++, a=a->a_next );
   5776 						if ( !a || oldpos != newpos || attr_valfind( a,
   5777 							SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
   5778 							SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
   5779 							SLAP_MR_VALUE_OF_SYNTAX,
   5780 							&oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS )
   5781 						{
   5782 							dni->delOldRDN = 1;
   5783 						}
   5784 					}
   5785 					/* Get the newRDN's desc */
   5786 					dnRdn( &dni->new_entry->e_nname, &oldRDN );
   5787 					oldVal.bv_val = strchr(oldRDN.bv_val, '=');
   5788 					oldRDN.bv_len = oldVal.bv_val - oldRDN.bv_val;
   5789 					ad = NULL;
   5790 					slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
   5791 					dni->newDesc = ad;
   5792 
   5793 					/* A ModDN has happened, but in Refresh mode other
   5794 					 * changes may have occurred before we picked it up.
   5795 					 * So fallthru to regular Modify processing.
   5796 					 */
   5797 				}
   5798 
   5799 #ifdef LDAP_CONTROL_X_DIRSYNC
   5800 				if ( dni->syncstate == MSAD_DIRSYNC_MODIFY ) {
   5801 					/* DirSync actually sends a diff already, mostly.
   5802 					 * It has no way to indicate deletion of single-valued attrs.
   5803 					 * FIXME: should do an auxiliary search to get the true
   5804 					 * entry contents.
   5805 					 */
   5806 					dni->mods = *dni->modlist;
   5807 					*dni->modlist = NULL;
   5808 				} else
   5809 #endif
   5810 				{
   5811 					Attribute *old = attrs_exdup( op, dni, rs->sr_entry->e_attrs );
   5812 					syncrepl_diff_entry( op, old,
   5813 						dni->new_entry->e_attrs, &dni->mods, dni->modlist,
   5814 						is_ctx );
   5815 					op->o_tmpfree( old, op->o_tmpmemctx );
   5816 				}
   5817 			}
   5818 		}
   5819 	} else if ( rs->sr_type == REP_RESULT ) {
   5820 		if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
   5821 			Debug( LDAP_DEBUG_ANY,
   5822 				"dn_callback : consistency error - "
   5823 				"entryUUID is not unique\n" );
   5824 		}
   5825 	}
   5826 
   5827 	return LDAP_SUCCESS;
   5828 }
   5829 
   5830 static int
   5831 nonpresent_callback(
   5832 	Operation*	op,
   5833 	SlapReply*	rs )
   5834 {
   5835 	syncinfo_t *si = op->o_callback->sc_private;
   5836 	Attribute *a;
   5837 	int count = 0;
   5838 	char *present_uuid = NULL;
   5839 	struct nonpresent_entry *np_entry;
   5840 	struct sync_cookie *syncCookie = op->o_controls[slap_cids.sc_LDAPsync];
   5841 
   5842 	if ( rs->sr_type == REP_RESULT ) {
   5843 		count = presentlist_free( si->si_presentlist );
   5844 		si->si_presentlist = NULL;
   5845 		Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s "
   5846 			"had %d items left in the list\n", si->si_ridtxt, count );
   5847 
   5848 	} else if ( rs->sr_type == REP_SEARCH ) {
   5849 		if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) {
   5850 			a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
   5851 
   5852 			if ( a ) {
   5853 				present_uuid = presentlist_find( si->si_presentlist, &a->a_nvals[0] );
   5854 			}
   5855 
   5856 			Debug(LDAP_DEBUG_SYNC, "nonpresent_callback: "
   5857 				"%s %spresent UUID %s, dn %s\n",
   5858 				si->si_ridtxt,
   5859 				present_uuid ? "" : "non",
   5860 				a ? a->a_vals[0].bv_val : "<missing>",
   5861 				rs->sr_entry->e_name.bv_val );
   5862 
   5863 			if ( a == NULL ) return 0;
   5864 		}
   5865 
   5866 		if ( is_entry_glue( rs->sr_entry ) ) {
   5867 			return LDAP_SUCCESS;
   5868 		}
   5869 
   5870 		if ( present_uuid == NULL ) {
   5871 			int covered = 1; /* covered by our new contextCSN? */
   5872 
   5873 			if ( !syncCookie )
   5874 				syncCookie = &si->si_syncCookie;
   5875 
   5876 			/* TODO: This can go once we can build a filter that takes care of
   5877 			 * the check for us */
   5878 			a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN );
   5879 			if ( a ) {
   5880 				int i, sid = slap_parse_csn_sid( &a->a_nvals[0] );
   5881 				if ( sid != -1 ) {
   5882 					covered = 0;
   5883 					for ( i=0; i < syncCookie->numcsns && syncCookie->sids[i] <= sid; i++ ) {
   5884 						if ( syncCookie->sids[i] == sid &&
   5885 								ber_bvcmp( &a->a_nvals[0], &syncCookie->ctxcsn[i] ) <= 0 ) {
   5886 							covered = 1;
   5887 							break;
   5888 						}
   5889 					}
   5890 				}
   5891 			}
   5892 
   5893 			if ( covered ) {
   5894 				np_entry = (struct nonpresent_entry *)
   5895 					ch_calloc( 1, sizeof( struct nonpresent_entry ) );
   5896 				np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
   5897 				np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
   5898 				LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
   5899 				Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s "
   5900 					"adding entry %s to non-present list\n",
   5901 					si->si_ridtxt, np_entry->npe_name->bv_val );
   5902 			}
   5903 
   5904 		} else {
   5905 			presentlist_delete( &si->si_presentlist, &a->a_nvals[0] );
   5906 			ch_free( present_uuid );
   5907 		}
   5908 	}
   5909 	return LDAP_SUCCESS;
   5910 }
   5911 
   5912 static struct berval *
   5913 slap_uuidstr_from_normalized(
   5914 	struct berval* uuidstr,
   5915 	struct berval* normalized,
   5916 	void *ctx )
   5917 {
   5918 #if 0
   5919 	struct berval *new;
   5920 	unsigned char nibble;
   5921 	int i, d = 0;
   5922 
   5923 	if ( normalized == NULL ) return NULL;
   5924 	if ( normalized->bv_len != 16 ) return NULL;
   5925 
   5926 	if ( uuidstr ) {
   5927 		new = uuidstr;
   5928 	} else {
   5929 		new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
   5930 		if ( new == NULL ) {
   5931 			return NULL;
   5932 		}
   5933 	}
   5934 
   5935 	new->bv_len = 36;
   5936 
   5937 	if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
   5938 		if ( new != uuidstr ) {
   5939 			slap_sl_free( new, ctx );
   5940 		}
   5941 		return NULL;
   5942 	}
   5943 
   5944 	for ( i = 0; i < 16; i++ ) {
   5945 		if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
   5946 			new->bv_val[(i<<1)+d] = '-';
   5947 			d += 1;
   5948 		}
   5949 
   5950 		nibble = (normalized->bv_val[i] >> 4) & 0xF;
   5951 		if ( nibble < 10 ) {
   5952 			new->bv_val[(i<<1)+d] = nibble + '0';
   5953 		} else {
   5954 			new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
   5955 		}
   5956 
   5957 		nibble = (normalized->bv_val[i]) & 0xF;
   5958 		if ( nibble < 10 ) {
   5959 			new->bv_val[(i<<1)+d+1] = nibble + '0';
   5960 		} else {
   5961 			new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
   5962 		}
   5963 	}
   5964 
   5965 	new->bv_val[new->bv_len] = '\0';
   5966 	return new;
   5967 #endif
   5968 
   5969 	struct berval	*new;
   5970 	int		rc = 0;
   5971 
   5972 	if ( normalized == NULL ) return NULL;
   5973 	if ( normalized->bv_len != 16 ) return NULL;
   5974 
   5975 	if ( uuidstr ) {
   5976 		new = uuidstr;
   5977 
   5978 	} else {
   5979 		new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
   5980 		if ( new == NULL ) {
   5981 			return NULL;
   5982 		}
   5983 	}
   5984 
   5985 	new->bv_len = 36;
   5986 
   5987 	if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
   5988 		rc = 1;
   5989 		goto done;
   5990 	}
   5991 
   5992 	rc = lutil_uuidstr_from_normalized( normalized->bv_val,
   5993 		normalized->bv_len, new->bv_val, new->bv_len + 1 );
   5994 
   5995 done:;
   5996 	if ( rc == -1 ) {
   5997 		if ( new != NULL ) {
   5998 			if ( new->bv_val != NULL ) {
   5999 				slap_sl_free( new->bv_val, ctx );
   6000 			}
   6001 
   6002 			if ( new != uuidstr ) {
   6003 				slap_sl_free( new, ctx );
   6004 			}
   6005 		}
   6006 		new = NULL;
   6007 
   6008 	} else {
   6009 		new->bv_len = rc;
   6010 	}
   6011 
   6012 	return new;
   6013 }
   6014 
   6015 static int
   6016 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
   6017 {
   6018 #ifdef HASHUUID
   6019 	return ( memcmp( v_uuid1, v_uuid2, UUIDLEN-2 ));
   6020 #else
   6021 	return ( memcmp( v_uuid1, v_uuid2, UUIDLEN ));
   6022 #endif
   6023 }
   6024 
   6025 void
   6026 syncinfo_free( syncinfo_t *sie, int free_all )
   6027 {
   6028 	syncinfo_t *si_next;
   6029 
   6030 	Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
   6031 		sie->si_ridtxt );
   6032 
   6033 	do {
   6034 		si_next = sie->si_next;
   6035 		sie->si_ctype = 0;
   6036 
   6037 		if ( !BER_BVISEMPTY( &sie->si_monitor_ndn )) {
   6038 			syncrepl_monitor_del( sie );
   6039 		}
   6040 		ch_free( sie->si_lastCookieSent.bv_val );
   6041 		ch_free( sie->si_lastCookieRcvd.bv_val );
   6042 
   6043 		if ( sie->si_ld ) {
   6044 			if ( sie->si_conn ) {
   6045 				connection_client_stop( sie->si_conn );
   6046 				sie->si_conn = NULL;
   6047 			}
   6048 			ldap_unbind_ext( sie->si_ld, NULL, NULL );
   6049 		}
   6050 
   6051 		if ( sie->si_re ) {
   6052 			struct re_s		*re = sie->si_re;
   6053 			sie->si_re = NULL;
   6054 
   6055 			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
   6056 			if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
   6057 				ldap_pvt_runqueue_stoptask( &slapd_rq, re );
   6058 			ldap_pvt_runqueue_remove( &slapd_rq, re );
   6059 			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
   6060 		}
   6061 
   6062 		ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
   6063 		ldap_pvt_thread_mutex_destroy( &sie->si_monitor_mutex );
   6064 
   6065 		bindconf_free( &sie->si_bindconf );
   6066 
   6067 		if ( sie->si_filterstr.bv_val ) {
   6068 			ch_free( sie->si_filterstr.bv_val );
   6069 		}
   6070 		if ( sie->si_filter ) {
   6071 			filter_free( sie->si_filter );
   6072 		}
   6073 		if ( sie->si_logfilterstr.bv_val ) {
   6074 			ch_free( sie->si_logfilterstr.bv_val );
   6075 		}
   6076 		if ( sie->si_logfilter ) {
   6077 			filter_free( sie->si_logfilter );
   6078 		}
   6079 		if ( sie->si_base.bv_val ) {
   6080 			ch_free( sie->si_base.bv_val );
   6081 		}
   6082 		if ( sie->si_logbase.bv_val ) {
   6083 			ch_free( sie->si_logbase.bv_val );
   6084 		}
   6085 		if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
   6086 			ch_free( sie->si_contextdn.bv_val );
   6087 		}
   6088 		if ( sie->si_attrs ) {
   6089 			int i = 0;
   6090 			while ( sie->si_attrs[i] != NULL ) {
   6091 				ch_free( sie->si_attrs[i] );
   6092 				i++;
   6093 			}
   6094 			ch_free( sie->si_attrs );
   6095 		}
   6096 		if ( sie->si_exattrs ) {
   6097 			int i = 0;
   6098 			while ( sie->si_exattrs[i] != NULL ) {
   6099 				ch_free( sie->si_exattrs[i] );
   6100 				i++;
   6101 			}
   6102 			ch_free( sie->si_exattrs );
   6103 		}
   6104 		if ( sie->si_anlist ) {
   6105 			int i = 0;
   6106 			while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
   6107 				ch_free( sie->si_anlist[i].an_name.bv_val );
   6108 				i++;
   6109 			}
   6110 			ch_free( sie->si_anlist );
   6111 		}
   6112 		if ( sie->si_exanlist ) {
   6113 			int i = 0;
   6114 			while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
   6115 				ch_free( sie->si_exanlist[i].an_name.bv_val );
   6116 				i++;
   6117 			}
   6118 			ch_free( sie->si_exanlist );
   6119 		}
   6120 		if ( sie->si_retryinterval ) {
   6121 			ch_free( sie->si_retryinterval );
   6122 		}
   6123 		if ( sie->si_retrynum ) {
   6124 			ch_free( sie->si_retrynum );
   6125 		}
   6126 		if ( sie->si_retrynum_init ) {
   6127 			ch_free( sie->si_retrynum_init );
   6128 		}
   6129 		slap_sync_cookie_free( &sie->si_syncCookie, 0 );
   6130 #ifdef LDAP_CONTROL_X_DIRSYNC
   6131 		if ( sie->si_dirSyncCookie.bv_val ) {
   6132 			ch_free( sie->si_dirSyncCookie.bv_val );
   6133 		}
   6134 #endif
   6135 		if ( sie->si_presentlist ) {
   6136 		    presentlist_free( sie->si_presentlist );
   6137 		}
   6138 		while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
   6139 			struct nonpresent_entry* npe;
   6140 			npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
   6141 			LDAP_LIST_REMOVE( npe, npe_link );
   6142 			if ( npe->npe_name ) {
   6143 				if ( npe->npe_name->bv_val ) {
   6144 					ch_free( npe->npe_name->bv_val );
   6145 				}
   6146 				ch_free( npe->npe_name );
   6147 			}
   6148 			if ( npe->npe_nname ) {
   6149 				if ( npe->npe_nname->bv_val ) {
   6150 					ch_free( npe->npe_nname->bv_val );
   6151 				}
   6152 				ch_free( npe->npe_nname );
   6153 			}
   6154 			ch_free( npe );
   6155 		}
   6156 		if ( sie->si_cookieState ) {
   6157 			/* Could be called from do_syncrepl (server unpaused) */
   6158 			refresh_finished( sie, !free_all );
   6159 
   6160 			sie->si_cookieState->cs_ref--;
   6161 			if ( !sie->si_cookieState->cs_ref ) {
   6162 				ch_free( sie->si_cookieState->cs_sids );
   6163 				ber_bvarray_free( sie->si_cookieState->cs_vals );
   6164 				ldap_pvt_thread_cond_destroy( &sie->si_cookieState->cs_cond );
   6165 				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
   6166 				ch_free( sie->si_cookieState->cs_psids );
   6167 				ber_bvarray_free( sie->si_cookieState->cs_pvals );
   6168 				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
   6169 				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_refresh_mutex );
   6170 				assert( sie->si_cookieState->cs_refreshing == NULL );
   6171 				ch_free( sie->si_cookieState );
   6172 			}
   6173 		}
   6174 		if ( sie->si_rewrite )
   6175 			rewrite_info_delete( &sie->si_rewrite );
   6176 		if ( sie->si_suffixm.bv_val )
   6177 			ch_free( sie->si_suffixm.bv_val );
   6178 		ch_free( sie );
   6179 		sie = si_next;
   6180 	} while ( free_all && si_next );
   6181 }
   6182 
   6183 static int
   6184 config_suffixm( ConfigArgs *c, syncinfo_t *si )
   6185 {
   6186 	char *argvEngine[] = { "rewriteEngine", "on", NULL };
   6187 	char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
   6188 	char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
   6189 	char *vnc, *rnc;
   6190 	int rc;
   6191 
   6192 	if ( si->si_rewrite )
   6193 		rewrite_info_delete( &si->si_rewrite );
   6194 	si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
   6195 
   6196 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
   6197 	if ( rc != LDAP_SUCCESS )
   6198 		return rc;
   6199 
   6200 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
   6201 	if ( rc != LDAP_SUCCESS )
   6202 		return rc;
   6203 
   6204 	vnc = ch_malloc( si->si_base.bv_len + 6 );
   6205 	strcpy( vnc, "(.*)" );
   6206 	lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
   6207 	argvRule[1] = vnc;
   6208 
   6209 	rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
   6210 	strcpy( rnc, "%1" );
   6211 	strcpy( rnc+2, si->si_suffixm.bv_val );
   6212 	argvRule[2] = rnc;
   6213 
   6214 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
   6215 	ch_free( vnc );
   6216 	ch_free( rnc );
   6217 	return rc;
   6218 }
   6219 
   6220 /* NOTE: used & documented in slapd.conf(5) */
   6221 #define IDSTR			"rid"
   6222 #define PROVIDERSTR		"provider"
   6223 #define SCHEMASTR		"schemachecking"
   6224 #define FILTERSTR		"filter"
   6225 #define SEARCHBASESTR		"searchbase"
   6226 #define SCOPESTR		"scope"
   6227 #define ATTRSONLYSTR		"attrsonly"
   6228 #define ATTRSSTR		"attrs"
   6229 #define TYPESTR			"type"
   6230 #define INTERVALSTR		"interval"
   6231 #define RETRYSTR		"retry"
   6232 #define SLIMITSTR		"sizelimit"
   6233 #define TLIMITSTR		"timelimit"
   6234 #define SYNCDATASTR		"syncdata"
   6235 #define LOGBASESTR		"logbase"
   6236 #define LOGFILTERSTR	"logfilter"
   6237 #define SUFFIXMSTR		"suffixmassage"
   6238 #define	STRICT_REFRESH	"strictrefresh"
   6239 #define LAZY_COMMIT		"lazycommit"
   6240 
   6241 /* FIXME: undocumented */
   6242 #define EXATTRSSTR		"exattrs"
   6243 #define MANAGEDSAITSTR		"manageDSAit"
   6244 
   6245 /* mandatory */
   6246 enum {
   6247 	GOT_RID			= 0x00000001U,
   6248 	GOT_PROVIDER		= 0x00000002U,
   6249 	GOT_SCHEMACHECKING	= 0x00000004U,
   6250 	GOT_FILTER		= 0x00000008U,
   6251 	GOT_SEARCHBASE		= 0x00000010U,
   6252 	GOT_SCOPE		= 0x00000020U,
   6253 	GOT_ATTRSONLY		= 0x00000040U,
   6254 	GOT_ATTRS		= 0x00000080U,
   6255 	GOT_TYPE		= 0x00000100U,
   6256 	GOT_INTERVAL		= 0x00000200U,
   6257 	GOT_RETRY		= 0x00000400U,
   6258 	GOT_SLIMIT		= 0x00000800U,
   6259 	GOT_TLIMIT		= 0x00001000U,
   6260 	GOT_SYNCDATA		= 0x00002000U,
   6261 	GOT_LOGBASE		= 0x00004000U,
   6262 	GOT_LOGFILTER		= 0x00008000U,
   6263 	GOT_EXATTRS		= 0x00010000U,
   6264 	GOT_MANAGEDSAIT		= 0x00020000U,
   6265 	GOT_BINDCONF		= 0x00040000U,
   6266 	GOT_SUFFIXM		= 0x00080000U,
   6267 
   6268 /* check */
   6269 	GOT_REQUIRED		= (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
   6270 };
   6271 
   6272 static slap_verbmasks datamodes[] = {
   6273 	{ BER_BVC("default"), SYNCDATA_DEFAULT },
   6274 	{ BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
   6275 	{ BER_BVC("changelog"), SYNCDATA_CHANGELOG },
   6276 	{ BER_BVNULL, 0 }
   6277 };
   6278 
   6279 static int
   6280 parse_syncrepl_retry(
   6281 	ConfigArgs	*c,
   6282 	char		*arg,
   6283 	syncinfo_t	*si )
   6284 {
   6285 	char **retry_list;
   6286 	int j, k, n;
   6287 	int use_default = 0;
   6288 
   6289 	char *val = arg + STRLENOF( RETRYSTR "=" );
   6290 	if ( strcasecmp( val, "undefined" ) == 0 ) {
   6291 		val = "3600 +";
   6292 		use_default = 1;
   6293 	}
   6294 
   6295 	retry_list = (char **) ch_calloc( 1, sizeof( char * ) );
   6296 	retry_list[0] = NULL;
   6297 
   6298 	slap_str2clist( &retry_list, val, " ,\t" );
   6299 
   6300 	for ( k = 0; retry_list && retry_list[k]; k++ ) ;
   6301 	n = k / 2;
   6302 	if ( k % 2 ) {
   6303 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6304 			"Error: incomplete syncrepl retry list" );
   6305 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6306 		for ( k = 0; retry_list && retry_list[k]; k++ ) {
   6307 			ch_free( retry_list[k] );
   6308 		}
   6309 		ch_free( retry_list );
   6310 		return 1;
   6311 	}
   6312 	si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) );
   6313 	si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) );
   6314 	si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) );
   6315 	for ( j = 0; j < n; j++ ) {
   6316 		unsigned long	t;
   6317 		if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
   6318 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6319 				"Error: invalid retry interval \"%s\" (#%d)",
   6320 				retry_list[j*2], j );
   6321 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6322 			/* do some cleanup */
   6323 			return 1;
   6324 		}
   6325 		si->si_retryinterval[j] = (time_t)t;
   6326 		if ( *retry_list[j*2+1] == '+' ) {
   6327 			si->si_retrynum_init[j] = RETRYNUM_FOREVER;
   6328 			si->si_retrynum[j] = RETRYNUM_FOREVER;
   6329 			j++;
   6330 			break;
   6331 		} else {
   6332 			if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
   6333 					|| si->si_retrynum_init[j] <= 0 )
   6334 			{
   6335 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6336 					"Error: invalid initial retry number \"%s\" (#%d)",
   6337 					retry_list[j*2+1], j );
   6338 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6339 				/* do some cleanup */
   6340 				return 1;
   6341 			}
   6342 			if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
   6343 					|| si->si_retrynum[j] <= 0 )
   6344 			{
   6345 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6346 					"Error: invalid retry number \"%s\" (#%d)",
   6347 					retry_list[j*2+1], j );
   6348 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6349 				/* do some cleanup */
   6350 				return 1;
   6351 			}
   6352 		}
   6353 	}
   6354 	if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) {
   6355 		Debug( LDAP_DEBUG_CONFIG,
   6356 			"%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n",
   6357 			c->log );
   6358 	}
   6359 
   6360 	si->si_retrynum_init[j] = RETRYNUM_TAIL;
   6361 	si->si_retrynum[j] = RETRYNUM_TAIL;
   6362 	si->si_retryinterval[j] = 0;
   6363 
   6364 	for ( k = 0; retry_list && retry_list[k]; k++ ) {
   6365 		ch_free( retry_list[k] );
   6366 	}
   6367 	ch_free( retry_list );
   6368 	if ( !use_default ) {
   6369 		si->si_got |= GOT_RETRY;
   6370 	}
   6371 
   6372 	return 0;
   6373 }
   6374 
   6375 static int
   6376 parse_syncrepl_line(
   6377 	ConfigArgs	*c,
   6378 	syncinfo_t	*si )
   6379 {
   6380 	int	i;
   6381 	char	*val;
   6382 
   6383 	for ( i = 1; i < c->argc; i++ ) {
   6384 		if ( !strncasecmp( c->argv[ i ], IDSTR "=",
   6385 					STRLENOF( IDSTR "=" ) ) )
   6386 		{
   6387 			int tmp;
   6388 			/* '\0' string terminator accounts for '=' */
   6389 			val = c->argv[ i ] + STRLENOF( IDSTR "=" );
   6390 			if ( lutil_atoi( &tmp, val ) != 0 ) {
   6391 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6392 					"Error: parse_syncrepl_line: "
   6393 					"unable to parse syncrepl id \"%s\"", val );
   6394 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6395 				return -1;
   6396 			}
   6397 			if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
   6398 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6399 					"Error: parse_syncrepl_line: "
   6400 					"syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
   6401 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6402 				return -1;
   6403 			}
   6404 			si->si_rid = tmp;
   6405 			sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid );
   6406 			si->si_got |= GOT_RID;
   6407 		} else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
   6408 					STRLENOF( PROVIDERSTR "=" ) ) )
   6409 		{
   6410 			val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
   6411 			ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
   6412 #ifdef HAVE_TLS
   6413 			if ( ldap_is_ldaps_url( val ))
   6414 				si->si_bindconf.sb_tls_do_init = 1;
   6415 #endif
   6416 			si->si_got |= GOT_PROVIDER;
   6417 		} else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
   6418 					STRLENOF( SCHEMASTR "=" ) ) )
   6419 		{
   6420 			val = c->argv[ i ] + STRLENOF( SCHEMASTR "=" );
   6421 			if ( !strncasecmp( val, "on", STRLENOF( "on" ) ) ) {
   6422 				si->si_schemachecking = 1;
   6423 			} else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
   6424 				si->si_schemachecking = 0;
   6425 			} else {
   6426 				si->si_schemachecking = 1;
   6427 			}
   6428 			si->si_got |= GOT_SCHEMACHECKING;
   6429 		} else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=",
   6430 					STRLENOF( FILTERSTR "=" ) ) )
   6431 		{
   6432 			val = c->argv[ i ] + STRLENOF( FILTERSTR "=" );
   6433 			if ( si->si_filterstr.bv_val )
   6434 				ch_free( si->si_filterstr.bv_val );
   6435 			ber_str2bv( val, 0, 1, &si->si_filterstr );
   6436 			si->si_got |= GOT_FILTER;
   6437 		} else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=",
   6438 					STRLENOF( LOGFILTERSTR "=" ) ) )
   6439 		{
   6440 			val = c->argv[ i ] + STRLENOF( LOGFILTERSTR "=" );
   6441 			if ( si->si_logfilterstr.bv_val )
   6442 				ch_free( si->si_logfilterstr.bv_val );
   6443 			ber_str2bv( val, 0, 1, &si->si_logfilterstr );
   6444 			si->si_got |= GOT_LOGFILTER;
   6445 		} else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=",
   6446 					STRLENOF( SEARCHBASESTR "=" ) ) )
   6447 		{
   6448 			struct berval	bv;
   6449 			int		rc;
   6450 
   6451 			val = c->argv[ i ] + STRLENOF( SEARCHBASESTR "=" );
   6452 			if ( si->si_base.bv_val ) {
   6453 				ch_free( si->si_base.bv_val );
   6454 			}
   6455 			ber_str2bv( val, 0, 0, &bv );
   6456 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
   6457 			if ( rc != LDAP_SUCCESS ) {
   6458 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6459 					"Invalid base DN \"%s\": %d (%s)",
   6460 					val, rc, ldap_err2string( rc ) );
   6461 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6462 				return -1;
   6463 			}
   6464 			si->si_got |= GOT_SEARCHBASE;
   6465 		} else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
   6466 					STRLENOF( SUFFIXMSTR "=" ) ) )
   6467 		{
   6468 			struct berval	bv;
   6469 			int		rc;
   6470 
   6471 			val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
   6472 			if ( si->si_suffixm.bv_val ) {
   6473 				ch_free( si->si_suffixm.bv_val );
   6474 			}
   6475 			ber_str2bv( val, 0, 0, &bv );
   6476 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
   6477 			if ( rc != LDAP_SUCCESS ) {
   6478 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6479 					"Invalid massage DN \"%s\": %d (%s)",
   6480 					val, rc, ldap_err2string( rc ) );
   6481 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6482 				return -1;
   6483 			}
   6484 			if ( !be_issubordinate( c->be, &si->si_suffixm )) {
   6485 				ch_free( si->si_suffixm.bv_val );
   6486 				BER_BVZERO( &si->si_suffixm );
   6487 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6488 					"Massage DN \"%s\" is not within the database naming context",
   6489 					val );
   6490 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6491 				return -1;
   6492 			}
   6493 			si->si_got |= GOT_SUFFIXM;
   6494 		} else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
   6495 					STRLENOF( LOGBASESTR "=" ) ) )
   6496 		{
   6497 			struct berval	bv;
   6498 			int		rc;
   6499 
   6500 			val = c->argv[ i ] + STRLENOF( LOGBASESTR "=" );
   6501 			if ( si->si_logbase.bv_val ) {
   6502 				ch_free( si->si_logbase.bv_val );
   6503 			}
   6504 			ber_str2bv( val, 0, 0, &bv );
   6505 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_logbase, NULL );
   6506 			if ( rc != LDAP_SUCCESS ) {
   6507 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6508 					"Invalid logbase DN \"%s\": %d (%s)",
   6509 					val, rc, ldap_err2string( rc ) );
   6510 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6511 				return -1;
   6512 			}
   6513 			si->si_got |= GOT_LOGBASE;
   6514 		} else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=",
   6515 					STRLENOF( SCOPESTR "=" ) ) )
   6516 		{
   6517 			int j;
   6518 			val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
   6519 			j = ldap_pvt_str2scope( val );
   6520 			if ( j < 0 ) {
   6521 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6522 					"Error: parse_syncrepl_line: "
   6523 					"unknown scope \"%s\"", val);
   6524 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6525 				return -1;
   6526 			}
   6527 			si->si_scope = j;
   6528 			si->si_got |= GOT_SCOPE;
   6529 		} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
   6530 					STRLENOF( ATTRSONLYSTR ) ) )
   6531 		{
   6532 			si->si_attrsonly = 1;
   6533 			si->si_got |= GOT_ATTRSONLY;
   6534 		} else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=",
   6535 					STRLENOF( ATTRSSTR "=" ) ) )
   6536 		{
   6537 			val = c->argv[ i ] + STRLENOF( ATTRSSTR "=" );
   6538 			if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
   6539 				char *attr_fname;
   6540 				attr_fname = ch_strdup( val + STRLENOF(":include:") );
   6541 				si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
   6542 				if ( si->si_anlist == NULL ) {
   6543 					ch_free( attr_fname );
   6544 					return -1;
   6545 				}
   6546 				si->si_anfile = attr_fname;
   6547 			} else {
   6548 				char *str, *s, *next;
   6549 				const char *delimstr = " ,\t";
   6550 				str = ch_strdup( val );
   6551 				for ( s = ldap_pvt_strtok( str, delimstr, &next );
   6552 						s != NULL;
   6553 						s = ldap_pvt_strtok( NULL, delimstr, &next ) )
   6554 				{
   6555 					if ( strlen(s) == 1 && *s == '*' ) {
   6556 						si->si_allattrs = 1;
   6557 						val[ s - str ] = delimstr[0];
   6558 					}
   6559 					if ( strlen(s) == 1 && *s == '+' ) {
   6560 						si->si_allopattrs = 1;
   6561 						val [ s - str ] = delimstr[0];
   6562 					}
   6563 				}
   6564 				ch_free( str );
   6565 				si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
   6566 				if ( si->si_anlist == NULL ) {
   6567 					return -1;
   6568 				}
   6569 			}
   6570 			si->si_got |= GOT_ATTRS;
   6571 		} else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=",
   6572 					STRLENOF( EXATTRSSTR "=" ) ) )
   6573 		{
   6574 			val = c->argv[ i ] + STRLENOF( EXATTRSSTR "=" );
   6575 			if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
   6576 				char *attr_fname;
   6577 				attr_fname = ch_strdup( val + STRLENOF(":include:") );
   6578 				si->si_exanlist = file2anlist(
   6579 					si->si_exanlist, attr_fname, " ,\t" );
   6580 				if ( si->si_exanlist == NULL ) {
   6581 					ch_free( attr_fname );
   6582 					return -1;
   6583 				}
   6584 				ch_free( attr_fname );
   6585 			} else {
   6586 				si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
   6587 				if ( si->si_exanlist == NULL ) {
   6588 					return -1;
   6589 				}
   6590 			}
   6591 			si->si_got |= GOT_EXATTRS;
   6592 		} else if ( !strncasecmp( c->argv[ i ], TYPESTR "=",
   6593 					STRLENOF( TYPESTR "=" ) ) )
   6594 		{
   6595 			val = c->argv[ i ] + STRLENOF( TYPESTR "=" );
   6596 			if ( !strncasecmp( val, "refreshOnly",
   6597 						STRLENOF("refreshOnly") ) )
   6598 			{
   6599 				si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
   6600 			} else if ( !strncasecmp( val, "refreshAndPersist",
   6601 						STRLENOF("refreshAndPersist") ) )
   6602 			{
   6603 				si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_AND_PERSIST;
   6604 				si->si_interval = 60;
   6605 #ifdef LDAP_CONTROL_X_DIRSYNC
   6606 			} else if ( !strncasecmp( val, "dirSync",
   6607 						STRLENOF("dirSync") ) )
   6608 			{
   6609 				if ( sy_ad_objectGUID == NULL && syncrepl_dirsync_schema()) {
   6610 					sprintf( c->cr_msg, "Error: dirSync schema is missing" );
   6611 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6612 					return -1;
   6613 				}
   6614 				/* MS DirSync is refreshOnly, no persist */
   6615 				si->si_type = si->si_ctype = MSAD_DIRSYNC;
   6616 #endif
   6617 			} else {
   6618 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6619 					"Error: parse_syncrepl_line: "
   6620 					"unknown sync type \"%s\"", val);
   6621 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6622 				return -1;
   6623 			}
   6624 			si->si_got |= GOT_TYPE;
   6625 		} else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=",
   6626 					STRLENOF( INTERVALSTR "=" ) ) )
   6627 		{
   6628 			val = c->argv[ i ] + STRLENOF( INTERVALSTR "=" );
   6629 			if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
   6630 				si->si_interval = 0;
   6631 			} else if ( strchr( val, ':' ) != NULL ) {
   6632 				char *next, *ptr = val;
   6633 				int dd, hh, mm, ss;
   6634 
   6635 				dd = strtol( ptr, &next, 10 );
   6636 				if ( next == ptr || next[0] != ':' || dd < 0 ) {
   6637 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6638 						"Error: parse_syncrepl_line: "
   6639 						"invalid interval \"%s\", unable to parse days", val );
   6640 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6641 					return -1;
   6642 				}
   6643 				ptr = next + 1;
   6644 				hh = strtol( ptr, &next, 10 );
   6645 				if ( next == ptr || next[0] != ':' || hh < 0 || hh > 24 ) {
   6646 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6647 						"Error: parse_syncrepl_line: "
   6648 						"invalid interval \"%s\", unable to parse hours", val );
   6649 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6650 					return -1;
   6651 				}
   6652 				ptr = next + 1;
   6653 				mm = strtol( ptr, &next, 10 );
   6654 				if ( next == ptr || next[0] != ':' || mm < 0 || mm > 60 ) {
   6655 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6656 						"Error: parse_syncrepl_line: "
   6657 						"invalid interval \"%s\", unable to parse minutes", val );
   6658 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6659 					return -1;
   6660 				}
   6661 				ptr = next + 1;
   6662 				ss = strtol( ptr, &next, 10 );
   6663 				if ( next == ptr || next[0] != '\0' || ss < 0 || ss > 60 ) {
   6664 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6665 						"Error: parse_syncrepl_line: "
   6666 						"invalid interval \"%s\", unable to parse seconds", val );
   6667 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6668 					return -1;
   6669 				}
   6670 				si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
   6671 			} else {
   6672 				unsigned long	t;
   6673 
   6674 				if ( lutil_parse_time( val, &t ) != 0 ) {
   6675 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6676 						"Error: parse_syncrepl_line: "
   6677 						"invalid interval \"%s\"", val );
   6678 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6679 					return -1;
   6680 				}
   6681 				si->si_interval = (time_t)t;
   6682 			}
   6683 			if ( si->si_interval < 0 ) {
   6684 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6685 					"Error: parse_syncrepl_line: "
   6686 					"invalid interval \"%ld\"",
   6687 					(long) si->si_interval);
   6688 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6689 				return -1;
   6690 			}
   6691 			si->si_got |= GOT_INTERVAL;
   6692 		} else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=",
   6693 					STRLENOF( RETRYSTR "=" ) ) )
   6694 		{
   6695 			if ( parse_syncrepl_retry( c, c->argv[ i ], si ) ) {
   6696 				return 1;
   6697 			}
   6698 		} else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=",
   6699 					STRLENOF( MANAGEDSAITSTR "=" ) ) )
   6700 		{
   6701 			val = c->argv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
   6702 			if ( lutil_atoi( &si->si_manageDSAit, val ) != 0
   6703 				|| si->si_manageDSAit < 0 || si->si_manageDSAit > 1 )
   6704 			{
   6705 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6706 					"invalid manageDSAit value \"%s\".\n",
   6707 					val );
   6708 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6709 				return 1;
   6710 			}
   6711 			si->si_got |= GOT_MANAGEDSAIT;
   6712 		} else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=",
   6713 					STRLENOF( SLIMITSTR "=") ) )
   6714 		{
   6715 			val = c->argv[ i ] + STRLENOF( SLIMITSTR "=" );
   6716 			if ( strcasecmp( val, "unlimited" ) == 0 ) {
   6717 				si->si_slimit = 0;
   6718 
   6719 			} else if ( lutil_atoi( &si->si_slimit, val ) != 0 || si->si_slimit < 0 ) {
   6720 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6721 					"invalid size limit value \"%s\".\n",
   6722 					val );
   6723 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6724 				return 1;
   6725 			}
   6726 			si->si_got |= GOT_SLIMIT;
   6727 		} else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=",
   6728 					STRLENOF( TLIMITSTR "=" ) ) )
   6729 		{
   6730 			val = c->argv[ i ] + STRLENOF( TLIMITSTR "=" );
   6731 			if ( strcasecmp( val, "unlimited" ) == 0 ) {
   6732 				si->si_tlimit = 0;
   6733 
   6734 			} else if ( lutil_atoi( &si->si_tlimit, val ) != 0 || si->si_tlimit < 0 ) {
   6735 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6736 					"invalid time limit value \"%s\".\n",
   6737 					val );
   6738 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6739 				return 1;
   6740 			}
   6741 			si->si_got |= GOT_TLIMIT;
   6742 		} else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=",
   6743 					STRLENOF( SYNCDATASTR "=" ) ) )
   6744 		{
   6745 			val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
   6746 			si->si_syncdata = verb_to_mask( val, datamodes );
   6747 			si->si_got |= GOT_SYNCDATA;
   6748 			if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
   6749 				if ( sy_ad_nsUniqueId == NULL ) {
   6750 					int rc = syncrepl_dsee_schema();
   6751 					if ( rc ) {
   6752 						snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6753 							"changelog schema problem (%d)\n", rc );
   6754 						Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6755 						return 1;
   6756 					}
   6757 				}
   6758 			}
   6759 		} else if ( !strncasecmp( c->argv[ i ], STRICT_REFRESH,
   6760 					STRLENOF( STRICT_REFRESH ) ) )
   6761 		{
   6762 			si->si_strict_refresh = 1;
   6763 		} else if ( !strncasecmp( c->argv[ i ], LAZY_COMMIT,
   6764 					STRLENOF( LAZY_COMMIT ) ) )
   6765 		{
   6766 			si->si_lazyCommit = 1;
   6767 		} else if ( !bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
   6768 			si->si_got |= GOT_BINDCONF;
   6769 		} else {
   6770 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6771 				"Error: parse_syncrepl_line: "
   6772 				"unable to parse \"%s\"\n", c->argv[ i ] );
   6773 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6774 			return -1;
   6775 		}
   6776 	}
   6777 
   6778 	if ( ( si->si_got & GOT_REQUIRED ) != GOT_REQUIRED ) {
   6779 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6780 			"Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s",
   6781 			si->si_got & GOT_RID ? "" : " "IDSTR,
   6782 			si->si_got & GOT_PROVIDER ? "" : " "PROVIDERSTR,
   6783 			si->si_got & GOT_SEARCHBASE ? "" : " "SEARCHBASESTR );
   6784 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6785 		return -1;
   6786 	}
   6787 
   6788 	if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
   6789 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6790 			"Base DN \"%s\" is not within the database naming context",
   6791 			si->si_base.bv_val );
   6792 		ch_free( si->si_base.bv_val );
   6793 		BER_BVZERO( &si->si_base );
   6794 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6795 		return -1;
   6796 	}
   6797 
   6798 	if ( si->si_got & GOT_SUFFIXM ) {
   6799 		if (config_suffixm( c, si )) {
   6800 			ch_free( si->si_suffixm.bv_val );
   6801 			BER_BVZERO( &si->si_suffixm );
   6802 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   6803 				"Error configuring rewrite engine" );
   6804 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
   6805 			return -1;
   6806 		}
   6807 	}
   6808 
   6809 	if ( !( si->si_got & GOT_RETRY ) ) {
   6810 		Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n",
   6811 			si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)" );
   6812 		if ( si->si_retryinterval == NULL ) {
   6813 			if ( parse_syncrepl_retry( c, "retry=undefined", si ) ) {
   6814 				return 1;
   6815 			}
   6816 		}
   6817 	}
   6818 
   6819 	si->si_filter = str2filter( si->si_filterstr.bv_val );
   6820 	if ( si->si_filter == NULL ) {
   6821 		Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n",
   6822 			si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
   6823 		return 1;
   6824 	}
   6825 
   6826 	if ( si->si_got & GOT_LOGFILTER ) {
   6827 		si->si_logfilter = str2filter( si->si_logfilterstr.bv_val );
   6828 		if ( si->si_logfilter == NULL ) {
   6829 			Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse logfilter=\"%s\"\n",
   6830 				si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_logfilterstr.bv_val );
   6831 			return 1;
   6832 		}
   6833 	}
   6834 
   6835 	return 0;
   6836 }
   6837 
   6838 /* monitor entry contains:
   6839 	provider URLs
   6840 	timestamp of last contact
   6841 	cookievals
   6842 	*/
   6843 
   6844 static ObjectClass	*oc_olmSyncRepl;
   6845 static AttributeDescription	*ad_olmProviderURIList,
   6846 	*ad_olmConnection, *ad_olmSyncPhase,
   6847 	*ad_olmNextConnect, *ad_olmLastConnect, *ad_olmLastContact,
   6848 	*ad_olmLastCookieRcvd, *ad_olmLastCookieSent;
   6849 
   6850 static struct {
   6851 	char *name;
   6852 	char *oid;
   6853 } s_oid[] = {
   6854 	{ "olmSyncReplAttributes",	"olmOverlayAttributes:1" },
   6855 	{ "olmSyncReplObjectClasses", "olmOverlayObjectClasses:1" },
   6856 	{ NULL }
   6857 };
   6858 
   6859 static struct {
   6860 	char *desc;
   6861 	AttributeDescription **ad;
   6862 } s_at[] = {
   6863 	{ "( olmSyncReplAttributes:1 "
   6864 		"NAME ( 'olmSRProviderURIList' ) "
   6865 		"DESC 'List of provider URIs for this consumer instance' "
   6866 		"SUP monitoredInfo "
   6867 		"NO-USER-MODIFICATION "
   6868 		"USAGE dSAOperation )",
   6869 		&ad_olmProviderURIList },
   6870 	{ "( olmSyncReplAttributes:2 "
   6871 		"NAME ( 'olmSRConnection' ) "
   6872 		"DESC 'Local address:port of connection to provider' "
   6873 		"SUP monitoredInfo "
   6874 		"SINGLE-VALUE "
   6875 		"NO-USER-MODIFICATION "
   6876 		"USAGE dSAOperation )",
   6877 		&ad_olmConnection },
   6878 	{ "( olmSyncReplAttributes:3 "
   6879 		"NAME ( 'olmSRSyncPhase' ) "
   6880 		"DESC 'Current syncrepl mode' "
   6881 		"SUP monitoredInfo "
   6882 		"SINGLE-VALUE "
   6883 		"NO-USER-MODIFICATION "
   6884 		"USAGE dSAOperation )",
   6885 		&ad_olmSyncPhase },
   6886 	{ "( olmSyncReplAttributes:4 "
   6887 		"NAME ( 'olmSRNextConnect' ) "
   6888 		"DESC 'Scheduled time of next connection attempt' "
   6889 		"SUP monitorTimestamp "
   6890 		"SINGLE-VALUE "
   6891 		"NO-USER-MODIFICATION "
   6892 		"USAGE dSAOperation )",
   6893 		&ad_olmNextConnect },
   6894 	{ "( olmSyncReplAttributes:5 "
   6895 		"NAME ( 'olmSRLastConnect' ) "
   6896 		"DESC 'Time last connected to provider' "
   6897 		"SUP monitorTimestamp "
   6898 		"SINGLE-VALUE "
   6899 		"NO-USER-MODIFICATION "
   6900 		"USAGE dSAOperation )",
   6901 		&ad_olmLastConnect },
   6902 	{ "( olmSyncReplAttributes:6 "
   6903 		"NAME ( 'olmSRLastContact' ) "
   6904 		"DESC 'Time last message received from provider' "
   6905 		"SUP monitorTimestamp "
   6906 		"SINGLE-VALUE "
   6907 		"NO-USER-MODIFICATION "
   6908 		"USAGE dSAOperation )",
   6909 		&ad_olmLastContact },
   6910 	{ "( olmSyncReplAttributes:7 "
   6911 		"NAME ( 'olmSRLastCookieRcvd' ) "
   6912 		"DESC 'Last sync cookie received from provider' "
   6913 		"SUP monitoredInfo "
   6914 		"NO-USER-MODIFICATION "
   6915 		"USAGE dSAOperation )",
   6916 		&ad_olmLastCookieRcvd },
   6917 	{ "( olmSyncReplAttributes:8 "
   6918 		"NAME ( 'olmSRLastCookieSent' ) "
   6919 		"DESC 'Last sync cookie sent to provider' "
   6920 		"SUP monitoredInfo "
   6921 		"NO-USER-MODIFICATION "
   6922 		"USAGE dSAOperation )",
   6923 		&ad_olmLastCookieSent },
   6924 	{ NULL }
   6925 };
   6926 
   6927 static struct {
   6928 	char *desc;
   6929 	ObjectClass **oc;
   6930 } s_oc[] = {
   6931 	{ "( olmSyncReplObjectClasses:1 "
   6932 		"NAME ( 'olmSyncReplInstance' ) "
   6933 		"SUP monitoredObject STRUCTURAL "
   6934 		"MAY ( "
   6935 			"olmSRProviderURIList "
   6936 			"$ olmSRConnection "
   6937 			"$ olmSRSyncPhase "
   6938 			"$ olmSRNextConnect "
   6939 			"$ olmSRLastConnect "
   6940 			"$ olmSRLastContact "
   6941 			"$ olmSRLastCookieRcvd "
   6942 			"$ olmSRLastCookieSent "
   6943 			") )",
   6944 		&oc_olmSyncRepl },
   6945 	{ NULL }
   6946 };
   6947 
   6948 static int
   6949 syncrepl_monitor_initialized;
   6950 
   6951 int
   6952 syncrepl_monitor_init( void )
   6953 {
   6954 	int i, code;
   6955 
   6956 	if ( syncrepl_monitor_initialized )
   6957 		return 0;
   6958 
   6959 	if ( backend_info( "monitor" ) == NULL )
   6960 		return -1;
   6961 
   6962 	{
   6963 		ConfigArgs c;
   6964 		char *argv[3];
   6965 
   6966 		argv[ 0 ] = "syncrepl monitor";
   6967 		c.argv = argv;
   6968 		c.argc = 2;
   6969 		c.fname = argv[0];
   6970 		for ( i=0; s_oid[i].name; i++ ) {
   6971 			argv[1] = s_oid[i].name;
   6972 			argv[2] = s_oid[i].oid;
   6973 			if ( parse_oidm( &c, 0, NULL )) {
   6974 				Debug( LDAP_DEBUG_ANY,
   6975 					"syncrepl_monitor_init: unable to add "
   6976 					"objectIdentifier \"%s=%s\"\n",
   6977 					s_oid[i].name, s_oid[i].oid );
   6978 					return 2;
   6979 			}
   6980 		}
   6981 	}
   6982 
   6983 	for ( i=0; s_at[i].desc != NULL; i++ ) {
   6984 		code = register_at( s_at[i].desc, s_at[i].ad, 1 );
   6985 		if ( code != LDAP_SUCCESS ) {
   6986 			Debug( LDAP_DEBUG_ANY,
   6987 				"syncrepl_monitor_init: register_at failed for attributeType (%s)\n",
   6988 				s_at[i].desc );
   6989 			return 3;
   6990 		} else {
   6991 			(*s_at[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
   6992 		}
   6993 	}
   6994 
   6995 	for ( i=0; s_oc[i].desc != NULL; i++ ) {
   6996 		code = register_oc( s_oc[i].desc, s_oc[i].oc, 1 );
   6997 		if ( code != LDAP_SUCCESS ) {
   6998 			Debug( LDAP_DEBUG_ANY,
   6999 				"syncrepl_monitor_init: register_oc failed for objectClass (%s)\n",
   7000 				s_oc[i].desc );
   7001 			return 4;
   7002 		} else {
   7003 			(*s_oc[i].oc)->soc_flags |= SLAP_OC_HIDE;
   7004 		}
   7005 	}
   7006 	syncrepl_monitor_initialized = 1;
   7007 
   7008 	return 0;
   7009 }
   7010 
   7011 static const struct berval zerotime = BER_BVC("00000101000000Z");
   7012 
   7013 static int
   7014 syncrepl_monitor_update(
   7015 	Operation *op,
   7016 	SlapReply *rs,
   7017 	Entry *e,
   7018 	void *priv )
   7019 {
   7020 	syncinfo_t *si = (syncinfo_t *)priv;
   7021 	Attribute *a;
   7022 	int isConnected = 0;
   7023 
   7024 	a = attr_find( e->e_attrs, ad_olmConnection );
   7025 	if ( !a )
   7026 		return SLAP_CB_CONTINUE;
   7027 	if ( si->si_ld ) {
   7028 		if (!bvmatch( &a->a_vals[0], &si->si_connaddr )) {
   7029 			AC_MEMCPY( a->a_vals[0].bv_val, si->si_connaddr.bv_val, si->si_connaddr.bv_len );
   7030 			a->a_vals[0].bv_len = si->si_connaddr.bv_len;
   7031 		}
   7032 		isConnected = 1;
   7033 	} else {
   7034 		a->a_vals[0].bv_val[0] = '\0';
   7035 		a->a_vals[0].bv_len = 0;
   7036 	}
   7037 
   7038 	a = a->a_next;
   7039 	if ( a->a_desc != ad_olmSyncPhase )
   7040 		return SLAP_CB_CONTINUE;
   7041 
   7042 	if ( si->si_refreshDone ) {
   7043 		struct berval bv = BER_BVC("Persist");
   7044 		ber_bvreplace( &a->a_vals[0], &bv );
   7045 	} else {
   7046 		if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
   7047 			struct berval bv = BER_BVC("Fallback Refresh");
   7048 			ber_bvreplace( &a->a_vals[0], &bv );
   7049 		} else {
   7050 			struct berval bv = BER_BVC("Refresh");
   7051 			ber_bvreplace( &a->a_vals[0], &bv );
   7052 		}
   7053 	}
   7054 
   7055 	{
   7056 		struct tm tm;
   7057 		char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
   7058 		ber_len_t len;
   7059 
   7060 		a = a->a_next;
   7061 		if ( a->a_desc != ad_olmNextConnect )
   7062 			return SLAP_CB_CONTINUE;
   7063 
   7064 		if ( !isConnected && si->si_re && si->si_re->next_sched.tv_sec ) {
   7065 			time_t next_sched = si->si_re->next_sched.tv_sec;
   7066 			ldap_pvt_gmtime( &next_sched, &tm );
   7067 			lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
   7068 			len = strlen( tmbuf );
   7069 			assert( len == a->a_vals[0].bv_len );
   7070 			AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
   7071 		} else {
   7072 			AC_MEMCPY( a->a_vals[0].bv_val, zerotime.bv_val, zerotime.bv_len );
   7073 		}
   7074 
   7075 		a = a->a_next;
   7076 		if ( a->a_desc != ad_olmLastConnect )
   7077 			return SLAP_CB_CONTINUE;
   7078 
   7079 		if ( si->si_lastconnect ) {
   7080 			ldap_pvt_gmtime( &si->si_lastconnect, &tm );
   7081 			lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
   7082 			len = strlen( tmbuf );
   7083 			assert( len == a->a_vals[0].bv_len );
   7084 			AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
   7085 		}
   7086 
   7087 		a = a->a_next;
   7088 		if ( a->a_desc != ad_olmLastContact )
   7089 			return SLAP_CB_CONTINUE;
   7090 
   7091 		if ( si->si_lastcontact ) {
   7092 			ldap_pvt_gmtime( &si->si_lastcontact, &tm );
   7093 			lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
   7094 			len = strlen( tmbuf );
   7095 			assert( len == a->a_vals[0].bv_len );
   7096 			AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
   7097 		}
   7098 	}
   7099 
   7100 	a = a->a_next;
   7101 	if ( a->a_desc != ad_olmLastCookieRcvd )
   7102 		return SLAP_CB_CONTINUE;
   7103 
   7104 	ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
   7105 	if ( !BER_BVISEMPTY( &si->si_lastCookieRcvd ) &&
   7106 		!bvmatch( &a->a_vals[0], &si->si_lastCookieRcvd ))
   7107 		ber_bvreplace( &a->a_vals[0], &si->si_lastCookieRcvd );
   7108 
   7109 	a = a->a_next;
   7110 	if ( a->a_desc != ad_olmLastCookieSent ) {
   7111 		ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   7112 		return SLAP_CB_CONTINUE;
   7113 	}
   7114 
   7115 	if ( !BER_BVISEMPTY( &si->si_lastCookieSent ) &&
   7116 		!bvmatch( &a->a_vals[0], &si->si_lastCookieSent ))
   7117 		ber_bvreplace( &a->a_vals[0], &si->si_lastCookieSent );
   7118 	ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
   7119 
   7120 	return SLAP_CB_CONTINUE;
   7121 }
   7122 
   7123 static int
   7124 syncrepl_monitor_add(
   7125 	syncinfo_t *si
   7126 )
   7127 {
   7128 	BackendInfo *mi;
   7129 	monitor_extra_t *mbe;
   7130 	struct berval pndn, pdn, rdn, bv;
   7131 	char rdnbuf[sizeof("cn=Consumer 999")];
   7132 	Entry *e, *p;
   7133 	int rc;
   7134 
   7135 	if ( !syncrepl_monitor_initialized )
   7136 		return -1;
   7137 
   7138 	mi = backend_info( "monitor" );
   7139 	if ( !mi || !mi->bi_extra ) {
   7140 		SLAP_DBFLAGS( si->si_be ) ^= SLAP_DBFLAG_MONITORING;
   7141 		return 0;
   7142 	}
   7143 	mbe = mi->bi_extra;
   7144 
   7145 	if ( !mbe->is_configured() ) {
   7146 		return 0;
   7147 	}
   7148 
   7149 	rc = mbe->register_database( si->si_be, &pndn );
   7150 	if ( rc ) {
   7151 		Debug( LDAP_DEBUG_ANY, "syncrepl_monitor_add: "
   7152 			"failed to register the database with back-monitor\n" );
   7153 		return rc;
   7154 	}
   7155 	rdn.bv_len = sprintf(rdnbuf, "cn=Consumer %03d", si->si_rid );
   7156 	rdn.bv_val = rdnbuf;
   7157 	p = mbe->entry_get_unlocked( &pndn );
   7158 	if ( p ) {
   7159 		pdn = p->e_name;
   7160 	} else {
   7161 		pdn = pndn;
   7162 	}
   7163 
   7164 	e = mbe->entry_stub( &pdn, &pndn, &rdn,
   7165 		oc_olmSyncRepl, NULL, NULL );
   7166 	if ( e == NULL ) {
   7167 		Debug( LDAP_DEBUG_ANY,
   7168 			"syncrepl_monitor_add: "
   7169 			"unable to create entry \"%s,%s\"\n",
   7170 			rdn.bv_val, pndn.bv_val );
   7171 		return -1;
   7172 	}
   7173 
   7174 	attr_merge_normalize_one( e, ad_olmProviderURIList,
   7175 		&si->si_bindconf.sb_uri, NULL );
   7176 
   7177 	{
   7178 		si->si_connaddr.bv_val = si->si_connaddrbuf;
   7179 		si->si_connaddr.bv_len = sizeof( si->si_connaddrbuf );
   7180 		si->si_connaddrbuf[0] = '\0';
   7181 		attr_merge_normalize_one( e, ad_olmConnection, &si->si_connaddr, NULL );
   7182 	}
   7183 	{
   7184 		struct berval bv = BER_BVC("Refresh");
   7185 		attr_merge_normalize_one( e, ad_olmSyncPhase, &bv, NULL );
   7186 	}
   7187 	{
   7188 		attr_merge_normalize_one( e, ad_olmNextConnect, (struct berval *)&zerotime, NULL );
   7189 		attr_merge_normalize_one( e, ad_olmLastConnect, (struct berval *)&zerotime, NULL );
   7190 		attr_merge_normalize_one( e, ad_olmLastContact, (struct berval *)&zerotime, NULL );
   7191 	}
   7192 	{
   7193 		struct berval bv = BER_BVC("");
   7194 		attr_merge_normalize_one( e, ad_olmLastCookieRcvd, &bv, NULL );
   7195 		attr_merge_normalize_one( e, ad_olmLastCookieSent, &bv, NULL );
   7196 	}
   7197 	{
   7198 		monitor_callback_t *cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
   7199 		cb->mc_update = syncrepl_monitor_update;
   7200 		cb->mc_private = si;
   7201 		rc = mbe->register_entry( e, cb, NULL, 0 );
   7202 	}
   7203 
   7204 	si->si_monitor_ndn = e->e_nname;
   7205 	BER_BVZERO( &e->e_nname );
   7206 	entry_free( e );
   7207 
   7208 	return rc;
   7209 }
   7210 
   7211 static int
   7212 syncrepl_monitor_del(
   7213 	syncinfo_t *si
   7214 )
   7215 {
   7216 	BackendInfo *mi;
   7217 
   7218 	mi = backend_info( "monitor" );
   7219 	if ( mi && mi->bi_extra ) {
   7220 		monitor_extra_t *mbe = mi->bi_extra;
   7221 		mbe->unregister_entry( &si->si_monitor_ndn );
   7222 	}
   7223 	ch_free( si->si_monitor_ndn.bv_val );
   7224 	return 0;
   7225 }
   7226 
   7227 static int
   7228 add_syncrepl(
   7229 	ConfigArgs *c )
   7230 {
   7231 	syncinfo_t *si;
   7232 	int i, rc = 0;
   7233 
   7234 	if ( !( c->be->be_search && c->be->be_add && c->be->be_modify && c->be->be_delete ) ) {
   7235 		snprintf( c->cr_msg, sizeof(c->cr_msg), "database %s does not support "
   7236 			"operations required for syncrepl", c->be->be_type );
   7237 		Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   7238 		return 1;
   7239 	}
   7240 	if ( BER_BVISEMPTY( &c->be->be_rootdn ) ) {
   7241 		strcpy( c->cr_msg, "rootDN must be defined before syncrepl may be used" );
   7242 		Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   7243 		return 1;
   7244 	}
   7245 	si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
   7246 
   7247 	if ( si == NULL ) {
   7248 		Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n" );
   7249 		return 1;
   7250 	}
   7251 
   7252 	si->si_bindconf.sb_tls = SB_TLS_OFF;
   7253 	si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
   7254 	si->si_schemachecking = 0;
   7255 	ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
   7256 		&si->si_filterstr );
   7257 	si->si_base.bv_val = NULL;
   7258 	si->si_scope = LDAP_SCOPE_SUBTREE;
   7259 	si->si_attrsonly = 0;
   7260 	si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
   7261 	si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
   7262 	si->si_attrs = NULL;
   7263 	si->si_allattrs = 0;
   7264 	si->si_allopattrs = 0;
   7265 	si->si_exattrs = NULL;
   7266 	si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
   7267 	si->si_interval = 86400;
   7268 	si->si_retryinterval = NULL;
   7269 	si->si_retrynum_init = NULL;
   7270 	si->si_retrynum = NULL;
   7271 	si->si_manageDSAit = 0;
   7272 	si->si_tlimit = 0;
   7273 	si->si_slimit = 0;
   7274 
   7275 	si->si_presentlist = NULL;
   7276 	LDAP_LIST_INIT( &si->si_nonpresentlist );
   7277 	ldap_pvt_thread_mutex_init( &si->si_monitor_mutex );
   7278 	ldap_pvt_thread_mutex_init( &si->si_mutex );
   7279 
   7280 	si->si_is_configdb = strcmp( c->be->be_suffix[0].bv_val, "cn=config" ) == 0;
   7281 
   7282 	rc = parse_syncrepl_line( c, si );
   7283 
   7284 	if ( rc == 0 ) {
   7285 		LDAPURLDesc *lud;
   7286 
   7287 		/* Must be LDAPv3 because we need controls */
   7288 		switch ( si->si_bindconf.sb_version ) {
   7289 		case 0:
   7290 			/* not explicitly set */
   7291 			si->si_bindconf.sb_version = LDAP_VERSION3;
   7292 			break;
   7293 		case 3:
   7294 			/* explicitly set */
   7295 			break;
   7296 		default:
   7297 			Debug( LDAP_DEBUG_ANY,
   7298 				"version %d incompatible with syncrepl\n",
   7299 				si->si_bindconf.sb_version );
   7300 			syncinfo_free( si, 0 );
   7301 			return 1;
   7302 		}
   7303 
   7304 		if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
   7305 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
   7306 				"<%s> invalid URL", c->argv[0] );
   7307 			Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
   7308 				c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
   7309 			return 1;
   7310 		}
   7311 
   7312 		si->si_be = c->be;
   7313 		if ( slapMode & SLAP_SERVER_MODE ) {
   7314 			int isMe = 0;
   7315 			/* check if consumer points to current server and database.
   7316 			 * If so, ignore this configuration.
   7317 			 */
   7318 			if ( !SLAP_DBHIDDEN( c->be ) ) {
   7319 				int i;
   7320 				/* if searchbase doesn't match current DB suffix,
   7321 				 * assume it's different
   7322 				 */
   7323 				for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
   7324 					if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
   7325 						isMe = 1;
   7326 						break;
   7327 					}
   7328 				}
   7329 				/* if searchbase matches, see if URLs match */
   7330 				if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
   7331 						lud ) == NULL )
   7332 					isMe = 0;
   7333 			}
   7334 
   7335 			if ( !isMe ) {
   7336 				init_syncrepl( si );
   7337 				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
   7338 				si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
   7339 					si->si_interval, do_syncrepl, si, "do_syncrepl",
   7340 					si->si_ridtxt );
   7341 				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
   7342 				if ( si->si_re )
   7343 					rc = config_sync_shadow( c ) ? -1 : 0;
   7344 				else
   7345 					rc = -1;
   7346 			}
   7347 		} else {
   7348 			/* multiprovider still needs to see this flag in tool mode */
   7349 			rc = config_sync_shadow( c ) ? -1 : 0;
   7350 		}
   7351 		ldap_free_urldesc( lud );
   7352 	}
   7353 
   7354 #ifdef HAVE_TLS
   7355 	/* Use main slapd defaults */
   7356 	bindconf_tls_defaults( &si->si_bindconf );
   7357 #endif
   7358 	if ( rc != 0 ) {
   7359 		Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n" );
   7360 		syncinfo_free( si, 0 );
   7361 		return 1;
   7362 	} else {
   7363 		Debug( LDAP_DEBUG_CONFIG,
   7364 			"Config: ** successfully added syncrepl %s \"%s\"\n",
   7365 			si->si_ridtxt,
   7366 			BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
   7367 			"(null)" : si->si_bindconf.sb_uri.bv_val );
   7368 		if ( c->be->be_syncinfo ) {
   7369 			syncinfo_t **sip;
   7370 
   7371 			si->si_cookieState = c->be->be_syncinfo->si_cookieState;
   7372 
   7373 			for ( i = 0, sip = &c->be->be_syncinfo;
   7374 				(*sip)->si_next && ( c->valx < 0 || i < c->valx );
   7375 				sip = &(*sip)->si_next, i++ )
   7376 				/* advance to the desired position */ ;
   7377 			si->si_next = *sip;
   7378 			*sip = si;
   7379 
   7380 		} else {
   7381 			si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
   7382 			ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
   7383 			ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
   7384 			ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_refresh_mutex );
   7385 			ldap_pvt_thread_cond_init( &si->si_cookieState->cs_cond );
   7386 
   7387 			c->be->be_syncinfo = si;
   7388 			si->si_next = NULL;
   7389 		}
   7390 		si->si_cookieState->cs_ref++;
   7391 
   7392 		syncrepl_monitor_init();
   7393 
   7394 		return 0;
   7395 	}
   7396 }
   7397 
   7398 static void
   7399 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
   7400 {
   7401 	struct berval bc, uri, bs;
   7402 	char buf[BUFSIZ*2], *ptr;
   7403 	ber_len_t len;
   7404 	int i;
   7405 #	define WHATSLEFT	((ber_len_t) (&buf[sizeof( buf )] - ptr))
   7406 
   7407 	BER_BVZERO( bv );
   7408 
   7409 	/* temporarily inhibit bindconf from printing URI */
   7410 	uri = si->si_bindconf.sb_uri;
   7411 	BER_BVZERO( &si->si_bindconf.sb_uri );
   7412 	si->si_bindconf.sb_version = 0;
   7413 	bindconf_unparse( &si->si_bindconf, &bc );
   7414 	si->si_bindconf.sb_uri = uri;
   7415 	si->si_bindconf.sb_version = LDAP_VERSION3;
   7416 
   7417 	ptr = buf;
   7418 	assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
   7419 	len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
   7420 		si->si_rid, si->si_bindconf.sb_uri.bv_val );
   7421 	if ( len >= sizeof( buf ) ) return;
   7422 	ptr += len;
   7423 	if ( !BER_BVISNULL( &bc ) ) {
   7424 		if ( WHATSLEFT <= bc.bv_len ) {
   7425 			free( bc.bv_val );
   7426 			return;
   7427 		}
   7428 		ptr = lutil_strcopy( ptr, bc.bv_val );
   7429 		free( bc.bv_val );
   7430 	}
   7431 	if ( !BER_BVISEMPTY( &si->si_filterstr ) ) {
   7432 		if ( WHATSLEFT <= STRLENOF( " " FILTERSTR "=\"" "\"" ) + si->si_filterstr.bv_len ) return;
   7433 		ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
   7434 		ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
   7435 		*ptr++ = '"';
   7436 	}
   7437 	if ( !BER_BVISNULL( &si->si_base ) ) {
   7438 		if ( WHATSLEFT <= STRLENOF( " " SEARCHBASESTR "=\"" "\"" ) + si->si_base.bv_len ) return;
   7439 		ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
   7440 		ptr = lutil_strcopy( ptr, si->si_base.bv_val );
   7441 		*ptr++ = '"';
   7442 	}
   7443 	if ( !BER_BVISNULL( &si->si_suffixm ) ) {
   7444 		if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
   7445 		ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
   7446 		ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
   7447 		*ptr++ = '"';
   7448 	}
   7449 	if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
   7450 		if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
   7451 		ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
   7452 		ptr = lutil_strcopy( ptr, si->si_logfilterstr.bv_val );
   7453 		*ptr++ = '"';
   7454 	}
   7455 	if ( !BER_BVISNULL( &si->si_logbase ) ) {
   7456 		if ( WHATSLEFT <= STRLENOF( " " LOGBASESTR "=\"" "\"" ) + si->si_logbase.bv_len ) return;
   7457 		ptr = lutil_strcopy( ptr, " " LOGBASESTR "=\"" );
   7458 		ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
   7459 		*ptr++ = '"';
   7460 	}
   7461 	if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
   7462 		if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
   7463 		ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
   7464 		ptr = lutil_strcopy( ptr, bs.bv_val );
   7465 	}
   7466 	if ( si->si_attrsonly ) {
   7467 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
   7468 		ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR );
   7469 	}
   7470 	if ( si->si_anfile ) {
   7471 		if ( WHATSLEFT <= STRLENOF( " " ATTRSSTR "=\":include:" "\"" ) + strlen( si->si_anfile ) ) return;
   7472 		ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:\"" );
   7473 		ptr = lutil_strcopy( ptr, si->si_anfile );
   7474 		*ptr++ = '"';
   7475 	} else if ( si->si_allattrs || si->si_allopattrs ||
   7476 		( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) ) )
   7477 	{
   7478 		char *old;
   7479 
   7480 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
   7481 		ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
   7482 		old = ptr;
   7483 		ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
   7484 		if ( ptr == NULL ) return;
   7485 		if ( si->si_allattrs ) {
   7486 			if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
   7487 			if ( old != ptr ) *ptr++ = ',';
   7488 			*ptr++ = '*';
   7489 		}
   7490 		if ( si->si_allopattrs ) {
   7491 			if ( WHATSLEFT <= STRLENOF( ",+\"" ) ) return;
   7492 			if ( old != ptr ) *ptr++ = ',';
   7493 			*ptr++ = '+';
   7494 		}
   7495 		*ptr++ = '"';
   7496 	}
   7497 	if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
   7498 		if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
   7499 		ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
   7500 		ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
   7501 		if ( ptr == NULL ) return;
   7502 	}
   7503 	if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
   7504 	ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
   7505 	ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
   7506 
   7507 	if ( WHATSLEFT <= STRLENOF( " " TYPESTR "=" ) + STRLENOF( "refreshAndPersist" ) ) return;
   7508 	ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
   7509 #ifdef LDAP_CONTROL_X_DIRSYNC
   7510 	if ( si->si_type == MSAD_DIRSYNC )
   7511 		ptr = lutil_strcopy( ptr, "dirSync" );
   7512 	else
   7513 #endif
   7514 	ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
   7515 		"refreshAndPersist" : "refreshOnly" );
   7516 
   7517 	if ( si->si_type == LDAP_SYNC_REFRESH_ONLY
   7518 #ifdef LDAP_CONTROL_X_DIRSYNC
   7519 		|| si->si_type == MSAD_DIRSYNC
   7520 #endif
   7521 	) {
   7522 		int dd, hh, mm, ss;
   7523 
   7524 		dd = si->si_interval;
   7525 		ss = dd % 60;
   7526 		dd /= 60;
   7527 		mm = dd % 60;
   7528 		dd /= 60;
   7529 		hh = dd % 24;
   7530 		dd /= 24;
   7531 		len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
   7532 			INTERVALSTR, dd, hh, mm, ss );
   7533 		if ( len >= WHATSLEFT ) return;
   7534 		ptr += len;
   7535 	}
   7536 
   7537 	if ( si->si_got & GOT_RETRY ) {
   7538 		const char *space = "";
   7539 		if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
   7540 		ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
   7541 		for (i=0; si->si_retryinterval[i]; i++) {
   7542 			len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
   7543 				(long) si->si_retryinterval[i] );
   7544 			space = " ";
   7545 			if ( WHATSLEFT - 1 <= len ) return;
   7546 			ptr += len;
   7547 			if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
   7548 				*ptr++ = '+';
   7549 			else {
   7550 				len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
   7551 				if ( WHATSLEFT <= len ) return;
   7552 				ptr += len;
   7553 			}
   7554 		}
   7555 		if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
   7556 		*ptr++ = '"';
   7557 	} else {
   7558 		ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" );
   7559 	}
   7560 
   7561 	if ( si->si_slimit ) {
   7562 		len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
   7563 		if ( WHATSLEFT <= len ) return;
   7564 		ptr += len;
   7565 	}
   7566 
   7567 	if ( si->si_tlimit ) {
   7568 		len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
   7569 		if ( WHATSLEFT <= len ) return;
   7570 		ptr += len;
   7571 	}
   7572 
   7573 	if ( si->si_syncdata ) {
   7574 		if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) {
   7575 			if ( WHATSLEFT <= STRLENOF( " " SYNCDATASTR "=" ) + bc.bv_len ) return;
   7576 			ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" );
   7577 			ptr = lutil_strcopy( ptr, bc.bv_val );
   7578 		}
   7579 	}
   7580 
   7581 	if ( si->si_lazyCommit ) {
   7582 		ptr = lutil_strcopy( ptr, " " LAZY_COMMIT );
   7583 	}
   7584 
   7585 	bc.bv_len = ptr - buf;
   7586 	bc.bv_val = buf;
   7587 	ber_dupbv( bv, &bc );
   7588 }
   7589 
   7590 int
   7591 syncrepl_config( ConfigArgs *c )
   7592 {
   7593 	if (c->op == SLAP_CONFIG_EMIT) {
   7594 		if ( c->be->be_syncinfo ) {
   7595 			struct berval bv;
   7596 			syncinfo_t *si;
   7597 
   7598 			for ( si = c->be->be_syncinfo; si; si=si->si_next ) {
   7599 				syncrepl_unparse( si, &bv );
   7600 				ber_bvarray_add( &c->rvalue_vals, &bv );
   7601 			}
   7602 			return 0;
   7603 		}
   7604 		return 1;
   7605 	} else if ( c->op == LDAP_MOD_DELETE ) {
   7606 		int isrunning = 0;
   7607 		if ( c->be->be_syncinfo ) {
   7608 			syncinfo_t *si, **sip;
   7609 			int i;
   7610 
   7611 			for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
   7612 				si = *sip;
   7613 				if ( c->valx == -1 || i == c->valx ) {
   7614 					*sip = si->si_next;
   7615 					si->si_ctype = -1;
   7616 					si->si_next = NULL;
   7617 					/* If the task is currently active, we have to leave
   7618 					 * it running. It will exit on its own. This will only
   7619 					 * happen when running on the cn=config DB.
   7620 					 */
   7621 					if ( si->si_re ) {
   7622 						if ( si->si_be == c->ca_op->o_bd ||
   7623 								ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
   7624 							isrunning = 1;
   7625 						} else {
   7626 							/* There is no active thread, but we must still
   7627 							 * ensure that no thread is (or will be) queued
   7628 							 * while we removes the task.
   7629 							 */
   7630 							struct re_s *re = si->si_re;
   7631 							si->si_re = NULL;
   7632 
   7633 							if ( si->si_conn ) {
   7634 								connection_client_stop( si->si_conn );
   7635 								si->si_conn = NULL;
   7636 							}
   7637 
   7638 							ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
   7639 							if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) {
   7640 								ldap_pvt_runqueue_stoptask( &slapd_rq, re );
   7641 								isrunning = 1;
   7642 							}
   7643 							if ( !re->pool_cookie || ldap_pvt_thread_pool_retract( re->pool_cookie ) > 0 )
   7644 								isrunning = 0;
   7645 
   7646 							ldap_pvt_runqueue_remove( &slapd_rq, re );
   7647 							ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
   7648 
   7649 							ldap_pvt_thread_mutex_unlock( &si->si_mutex );
   7650 						}
   7651 					}
   7652 					if ( !isrunning ) {
   7653 						syncinfo_free( si, 0 );
   7654 					}
   7655 					if ( i == c->valx )
   7656 						break;
   7657 				} else {
   7658 					sip = &si->si_next;
   7659 				}
   7660 			}
   7661 		}
   7662 		if ( !c->be->be_syncinfo ) {
   7663 			SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
   7664 		}
   7665 		return 0;
   7666 	}
   7667 	if ( SLAP_SLURP_SHADOW( c->be ) ) {
   7668 		Debug(LDAP_DEBUG_ANY, "%s: "
   7669 			"syncrepl: database already shadowed.\n",
   7670 			c->log );
   7671 		return(1);
   7672 	} else {
   7673 		return add_syncrepl( c );
   7674 	}
   7675 }
   7676