xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/syncrepl.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: syncrepl.c,v 1.1.1.5 2014/05/28 09:58:48 tron 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-2014 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 "portable.h"
22 
23 #include <stdio.h>
24 
25 #include <ac/string.h>
26 #include <ac/socket.h>
27 
28 #include "lutil.h"
29 #include "slap.h"
30 #include "lutil_ldap.h"
31 
32 #include "config.h"
33 
34 #include "ldap_rq.h"
35 
36 #ifdef ENABLE_REWRITE
37 #include "rewrite.h"
38 #define SUFFIXM_CTX	"<suffix massage>"
39 #endif
40 
41 struct nonpresent_entry {
42 	struct berval *npe_name;
43 	struct berval *npe_nname;
44 	LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
45 };
46 
47 typedef struct cookie_state {
48 	ldap_pvt_thread_mutex_t	cs_mutex;
49 	struct berval *cs_vals;
50 	int *cs_sids;
51 	int	cs_num;
52 	int cs_age;
53 	int cs_ref;
54 
55 	/* pending changes, not yet committed */
56 	ldap_pvt_thread_mutex_t	cs_pmutex;
57 	struct berval *cs_pvals;
58 	int *cs_psids;
59 	int	cs_pnum;
60 } cookie_state;
61 
62 #define	SYNCDATA_DEFAULT	0	/* entries are plain LDAP entries */
63 #define	SYNCDATA_ACCESSLOG	1	/* entries are accesslog format */
64 #define	SYNCDATA_CHANGELOG	2	/* entries are changelog format */
65 
66 #define	SYNCLOG_LOGGING		0	/* doing a log-based update */
67 #define	SYNCLOG_FALLBACK	1	/* doing a full refresh */
68 
69 #define RETRYNUM_FOREVER	(-1)	/* retry forever */
70 #define RETRYNUM_TAIL		(-2)	/* end of retrynum array */
71 #define RETRYNUM_VALID(n)	((n) >= RETRYNUM_FOREVER)	/* valid retrynum */
72 #define RETRYNUM_FINITE(n)	((n) > RETRYNUM_FOREVER)	/* not forever */
73 
74 typedef struct syncinfo_s {
75 	struct syncinfo_s	*si_next;
76 	BackendDB		*si_be;
77 	BackendDB		*si_wbe;
78 	struct re_s		*si_re;
79 	int			si_rid;
80 	char			si_ridtxt[ STRLENOF("rid=999") + 1 ];
81 	slap_bindconf		si_bindconf;
82 	struct berval		si_base;
83 	struct berval		si_logbase;
84 	struct berval		si_filterstr;
85 	Filter			*si_filter;
86 	struct berval		si_logfilterstr;
87 	struct berval		si_contextdn;
88 	int			si_scope;
89 	int			si_attrsonly;
90 	char			*si_anfile;
91 	AttributeName		*si_anlist;
92 	AttributeName		*si_exanlist;
93 	char 			**si_attrs;
94 	char			**si_exattrs;
95 	int			si_allattrs;
96 	int			si_allopattrs;
97 	int			si_schemachecking;
98 	int			si_type;	/* the active type */
99 	int			si_ctype;	/* the configured type */
100 	time_t			si_interval;
101 	time_t			*si_retryinterval;
102 	int			*si_retrynum_init;
103 	int			*si_retrynum;
104 	struct sync_cookie	si_syncCookie;
105 	cookie_state		*si_cookieState;
106 	int			si_cookieAge;
107 	int			si_manageDSAit;
108 	int			si_slimit;
109 	int			si_tlimit;
110 	int			si_refreshDelete;
111 	int			si_refreshPresent;
112 	int			si_refreshDone;
113 	int			si_syncdata;
114 	int			si_logstate;
115 	int			si_got;
116 	int			si_strict_refresh;	/* stop listening during fallback refresh */
117 	int			si_too_old;
118 	ber_int_t	si_msgid;
119 	Avlnode			*si_presentlist;
120 	LDAP			*si_ld;
121 	Connection		*si_conn;
122 	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
123 #ifdef ENABLE_REWRITE
124 	struct rewrite_info *si_rewrite;
125 	struct berval	si_suffixm;
126 #endif
127 	ldap_pvt_thread_mutex_t	si_mutex;
128 } syncinfo_t;
129 
130 static int syncuuid_cmp( const void *, const void * );
131 static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
132 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
133 static int syncrepl_message_to_op(
134 					syncinfo_t *, Operation *, LDAPMessage * );
135 static int syncrepl_message_to_entry(
136 					syncinfo_t *, Operation *, LDAPMessage *,
137 					Modifications **, Entry **, int, struct berval* );
138 static int syncrepl_entry(
139 					syncinfo_t *, Operation*, Entry*,
140 					Modifications**,int, struct berval*,
141 					struct berval *cookieCSN );
142 static int syncrepl_updateCookie(
143 					syncinfo_t *, Operation *,
144 					struct sync_cookie * );
145 static struct berval * slap_uuidstr_from_normalized(
146 					struct berval *, struct berval *, void * );
147 static int syncrepl_add_glue_ancestors(
148 	Operation* op, Entry *e );
149 
150 /* delta-mmr overlay handler */
151 static int syncrepl_op_modify( Operation *op, SlapReply *rs );
152 
153 /* callback functions */
154 static int dn_callback( Operation *, SlapReply * );
155 static int nonpresent_callback( Operation *, SlapReply * );
156 static int null_callback( Operation *, SlapReply * );
157 
158 static AttributeDescription *sync_descs[4];
159 
160 /* delta-mmr */
161 static AttributeDescription *ad_reqMod, *ad_reqDN;
162 
163 typedef struct logschema {
164 	struct berval ls_dn;
165 	struct berval ls_req;
166 	struct berval ls_mod;
167 	struct berval ls_newRdn;
168 	struct berval ls_delRdn;
169 	struct berval ls_newSup;
170 } logschema;
171 
172 static logschema changelog_sc = {
173 	BER_BVC("targetDN"),
174 	BER_BVC("changeType"),
175 	BER_BVC("changes"),
176 	BER_BVC("newRDN"),
177 	BER_BVC("deleteOldRDN"),
178 	BER_BVC("newSuperior")
179 };
180 
181 static logschema accesslog_sc = {
182 	BER_BVC("reqDN"),
183 	BER_BVC("reqType"),
184 	BER_BVC("reqMod"),
185 	BER_BVC("reqNewRDN"),
186 	BER_BVC("reqDeleteOldRDN"),
187 	BER_BVC("reqNewSuperior")
188 };
189 
190 static const char *
191 syncrepl_state2str( int state )
192 {
193 	switch ( state ) {
194 	case LDAP_SYNC_PRESENT:
195 		return "PRESENT";
196 
197 	case LDAP_SYNC_ADD:
198 		return "ADD";
199 
200 	case LDAP_SYNC_MODIFY:
201 		return "MODIFY";
202 
203 	case LDAP_SYNC_DELETE:
204 		return "DELETE";
205 	}
206 
207 	return "UNKNOWN";
208 }
209 
210 static slap_overinst syncrepl_ov;
211 
212 static void
213 init_syncrepl(syncinfo_t *si)
214 {
215 	int i, j, k, l, n;
216 	char **attrs, **exattrs;
217 
218 	if ( !syncrepl_ov.on_bi.bi_type ) {
219 		syncrepl_ov.on_bi.bi_type = "syncrepl";
220 		syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify;
221 		overlay_register( &syncrepl_ov );
222 	}
223 
224 	/* delta-MMR needs the overlay, nothing else does.
225 	 * This must happen before accesslog overlay is configured.
226 	 */
227 	if ( si->si_syncdata &&
228 		!overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
229 		overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
230 		if ( !ad_reqMod ) {
231 			const char *text;
232 			logschema *ls = &accesslog_sc;
233 
234 			slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
235 			slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
236 		}
237 	}
238 
239 	if ( !sync_descs[0] ) {
240 		sync_descs[0] = slap_schema.si_ad_objectClass;
241 		sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
242 		sync_descs[2] = slap_schema.si_ad_entryCSN;
243 		sync_descs[3] = NULL;
244 	}
245 
246 	if ( si->si_allattrs && si->si_allopattrs )
247 		attrs = NULL;
248 	else
249 		attrs = anlist2attrs( si->si_anlist );
250 
251 	if ( attrs ) {
252 		if ( si->si_allattrs ) {
253 			i = 0;
254 			while ( attrs[i] ) {
255 				if ( !is_at_operational( at_find( attrs[i] ) ) ) {
256 					for ( j = i; attrs[j] != NULL; j++ ) {
257 						if ( j == i )
258 							ch_free( attrs[i] );
259 						attrs[j] = attrs[j+1];
260 					}
261 				} else {
262 					i++;
263 				}
264 			}
265 			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
266 			attrs[i] = ch_strdup("*");
267 			attrs[i + 1] = NULL;
268 
269 		} else if ( si->si_allopattrs ) {
270 			i = 0;
271 			while ( attrs[i] ) {
272 				if ( is_at_operational( at_find( attrs[i] ) ) ) {
273 					for ( j = i; attrs[j] != NULL; j++ ) {
274 						if ( j == i )
275 							ch_free( attrs[i] );
276 						attrs[j] = attrs[j+1];
277 					}
278 				} else {
279 					i++;
280 				}
281 			}
282 			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
283 			attrs[i] = ch_strdup("+");
284 			attrs[i + 1] = NULL;
285 		}
286 
287 		for ( i = 0; sync_descs[i] != NULL; i++ ) {
288 			j = 0;
289 			while ( attrs[j] ) {
290 				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
291 					for ( k = j; attrs[k] != NULL; k++ ) {
292 						if ( k == j )
293 							ch_free( attrs[k] );
294 						attrs[k] = attrs[k+1];
295 					}
296 				} else {
297 					j++;
298 				}
299 			}
300 		}
301 
302 		for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
303 
304 		if ( si->si_allopattrs ) {
305 			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
306 		} else {
307 			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
308 		}
309 
310 		/* Add Attributes */
311 		if ( si->si_allopattrs ) {
312 			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
313 		} else {
314 			for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
315 				attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
316 			}
317 		}
318 		attrs[ n ] = NULL;
319 
320 	} else {
321 
322 		i = 0;
323 		if ( si->si_allattrs == si->si_allopattrs ) {
324 			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
325 			attrs[i++] = ch_strdup( "*" );
326 			attrs[i++] = ch_strdup( "+" );
327 		} else if ( si->si_allattrs && !si->si_allopattrs ) {
328 			for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
329 			attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
330 			attrs[i++] = ch_strdup( "*" );
331 			for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
332 				attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
333 			}
334 		} else if ( !si->si_allattrs && si->si_allopattrs ) {
335 			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
336 			attrs[i++] = ch_strdup( "+" );
337 			attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
338 		}
339 		attrs[i] = NULL;
340 	}
341 
342 	si->si_attrs = attrs;
343 
344 	exattrs = anlist2attrs( si->si_exanlist );
345 
346 	if ( exattrs ) {
347 		for ( n = 0; exattrs[n] != NULL; n++ ) ;
348 
349 		for ( i = 0; sync_descs[i] != NULL; i++ ) {
350 			j = 0;
351 			while ( exattrs[j] != NULL ) {
352 				if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
353 					ch_free( exattrs[j] );
354 					for ( k = j; exattrs[k] != NULL; k++ ) {
355 						exattrs[k] = exattrs[k+1];
356 					}
357 				} else {
358 					j++;
359 				}
360 			}
361 		}
362 
363 		for ( i = 0; exattrs[i] != NULL; i++ ) {
364 			for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
365 				ObjectClass	*oc;
366 				if ( ( oc = si->si_anlist[j].an_oc ) ) {
367 					k = 0;
368 					while ( oc->soc_required[k] ) {
369 						if ( !strcmp( exattrs[i],
370 							 oc->soc_required[k]->sat_cname.bv_val ) ) {
371 							ch_free( exattrs[i] );
372 							for ( l = i; exattrs[l]; l++ ) {
373 								exattrs[l] = exattrs[l+1];
374 							}
375 						} else {
376 							k++;
377 						}
378 					}
379 				}
380 			}
381 		}
382 
383 		for ( i = 0; exattrs[i] != NULL; i++ ) ;
384 
385 		if ( i != n )
386 			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
387 	}
388 
389 	si->si_exattrs = exattrs;
390 }
391 
392 static int
393 ldap_sync_search(
394 	syncinfo_t *si,
395 	void *ctx )
396 {
397 	BerElementBuffer berbuf;
398 	BerElement *ber = (BerElement *)&berbuf;
399 	LDAPControl c[3], *ctrls[4];
400 	int rc;
401 	int rhint;
402 	char *base;
403 	char **attrs, *lattrs[8];
404 	char *filter;
405 	int attrsonly;
406 	int scope;
407 
408 	/* setup LDAP SYNC control */
409 	ber_init2( ber, NULL, LBER_USE_DER );
410 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
411 
412 	/* If we're using a log but we have no state, then fallback to
413 	 * normal mode for a full refresh.
414 	 */
415 	if ( si->si_syncdata && !si->si_syncCookie.numcsns ) {
416 		si->si_logstate = SYNCLOG_FALLBACK;
417 	}
418 
419 	/* Use the log parameters if we're in log mode */
420 	if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
421 		logschema *ls;
422 		if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
423 			ls = &accesslog_sc;
424 		else
425 			ls = &changelog_sc;
426 		lattrs[0] = ls->ls_dn.bv_val;
427 		lattrs[1] = ls->ls_req.bv_val;
428 		lattrs[2] = ls->ls_mod.bv_val;
429 		lattrs[3] = ls->ls_newRdn.bv_val;
430 		lattrs[4] = ls->ls_delRdn.bv_val;
431 		lattrs[5] = ls->ls_newSup.bv_val;
432 		lattrs[6] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
433 		lattrs[7] = NULL;
434 
435 		rhint = 0;
436 		base = si->si_logbase.bv_val;
437 		filter = si->si_logfilterstr.bv_val;
438 		attrs = lattrs;
439 		attrsonly = 0;
440 		scope = LDAP_SCOPE_SUBTREE;
441 	} else {
442 		rhint = 1;
443 		base = si->si_base.bv_val;
444 		filter = si->si_filterstr.bv_val;
445 		attrs = si->si_attrs;
446 		attrsonly = si->si_attrsonly;
447 		scope = si->si_scope;
448 	}
449 	if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
450 		si->si_type = LDAP_SYNC_REFRESH_ONLY;
451 	} else {
452 		si->si_type = si->si_ctype;
453 	}
454 
455 	if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
456 	{
457 		ber_printf( ber, "{eOb}",
458 			abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
459 	} else {
460 		ber_printf( ber, "{eb}",
461 			abs(si->si_type), rhint );
462 	}
463 
464 	if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
465 		ber_free_buf( ber );
466 		return rc;
467 	}
468 
469 	c[0].ldctl_oid = LDAP_CONTROL_SYNC;
470 	c[0].ldctl_iscritical = si->si_type < 0;
471 	ctrls[0] = &c[0];
472 
473 	c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
474 	BER_BVZERO( &c[1].ldctl_value );
475 	c[1].ldctl_iscritical = 1;
476 	ctrls[1] = &c[1];
477 
478 	if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
479 		c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
480 		c[2].ldctl_value = si->si_bindconf.sb_authzId;
481 		c[2].ldctl_iscritical = 1;
482 		ctrls[2] = &c[2];
483 		ctrls[3] = NULL;
484 	} else {
485 		ctrls[2] = NULL;
486 	}
487 
488 	rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
489 		ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
490 	ber_free_buf( ber );
491 	return rc;
492 }
493 
494 static int
495 check_syncprov(
496 	Operation *op,
497 	syncinfo_t *si )
498 {
499 	AttributeName at[2];
500 	Attribute a = {0};
501 	Entry e = {0};
502 	SlapReply rs = {REP_SEARCH};
503 	int i, j, changed = 0;
504 
505 	/* Look for contextCSN from syncprov overlay. If
506 	 * there's no overlay, this will be a no-op. That means
507 	 * this is a pure consumer, so local changes will not be
508 	 * allowed, and all changes will already be reflected in
509 	 * the cookieState.
510 	 */
511 	a.a_desc = slap_schema.si_ad_contextCSN;
512 	e.e_attrs = &a;
513 	e.e_name = si->si_contextdn;
514 	e.e_nname = si->si_contextdn;
515 	at[0].an_name = a.a_desc->ad_cname;
516 	at[0].an_desc = a.a_desc;
517 	BER_BVZERO( &at[1].an_name );
518 	rs.sr_entry = &e;
519 	rs.sr_flags = REP_ENTRY_MODIFIABLE;
520 	rs.sr_attrs = at;
521 	op->o_req_dn = e.e_name;
522 	op->o_req_ndn = e.e_nname;
523 
524 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
525 	i = backend_operational( op, &rs );
526 	if ( i == LDAP_SUCCESS && a.a_nvals ) {
527 		int num = a.a_numvals;
528 		/* check for differences */
529 		if ( num != si->si_cookieState->cs_num ) {
530 			changed = 1;
531 		} else {
532 			for ( i=0; i<num; i++ ) {
533 				if ( ber_bvcmp( &a.a_nvals[i],
534 					&si->si_cookieState->cs_vals[i] )) {
535 					changed = 1;
536 					break;
537 				}
538 			}
539 		}
540 		if ( changed ) {
541 			ber_bvarray_free( si->si_cookieState->cs_vals );
542 			ch_free( si->si_cookieState->cs_sids );
543 			si->si_cookieState->cs_num = num;
544 			si->si_cookieState->cs_vals = a.a_nvals;
545 			si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
546 				num, NULL );
547 			si->si_cookieState->cs_age++;
548 		} else {
549 			ber_bvarray_free( a.a_nvals );
550 		}
551 		ber_bvarray_free( a.a_vals );
552 	}
553 	/* See if the cookieState has changed due to anything outside
554 	 * this particular consumer. That includes other consumers in
555 	 * the same context, or local changes detected above.
556 	 */
557 	if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
558 		si->si_cookieState->cs_age ) {
559 		if ( !si->si_syncCookie.numcsns ) {
560 			ber_bvarray_free( si->si_syncCookie.ctxcsn );
561 			ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
562 				si->si_cookieState->cs_vals, NULL );
563 			changed = 1;
564 		} else {
565 			for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
566 				/* bogus, just dup everything */
567 				if ( si->si_syncCookie.sids[i] == -1 ) {
568 					ber_bvarray_free( si->si_syncCookie.ctxcsn );
569 					ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
570 						si->si_cookieState->cs_vals, NULL );
571 					changed = 1;
572 					break;
573 				}
574 				for (j=0; j<si->si_cookieState->cs_num; j++) {
575 					if ( si->si_syncCookie.sids[i] !=
576 						si->si_cookieState->cs_sids[j] )
577 						continue;
578 					if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
579 						&si->si_cookieState->cs_vals[j] ))
580 						break;
581 					ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
582 						&si->si_cookieState->cs_vals[j] );
583 					changed = 1;
584 					break;
585 				}
586 			}
587 		}
588 	}
589 	if ( changed ) {
590 		si->si_cookieAge = si->si_cookieState->cs_age;
591 		ch_free( si->si_syncCookie.octet_str.bv_val );
592 		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
593 			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
594 			si->si_syncCookie.sid );
595 		ch_free( si->si_syncCookie.sids );
596 		slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx );
597 	}
598 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
599 	return changed;
600 }
601 
602 static int
603 do_syncrep1(
604 	Operation *op,
605 	syncinfo_t *si )
606 {
607 	int	rc;
608 	int cmdline_cookie_found = 0;
609 
610 	struct sync_cookie	*sc = NULL;
611 #ifdef HAVE_TLS
612 	void	*ssl;
613 #endif
614 
615 	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
616 	if ( rc != LDAP_SUCCESS ) {
617 		goto done;
618 	}
619 	op->o_protocol = LDAP_VERSION3;
620 
621 	/* Set SSF to strongest of TLS, SASL SSFs */
622 	op->o_sasl_ssf = 0;
623 	op->o_tls_ssf = 0;
624 	op->o_transport_ssf = 0;
625 #ifdef HAVE_TLS
626 	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
627 		== LDAP_SUCCESS && ssl != NULL )
628 	{
629 		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
630 	}
631 #endif /* HAVE_TLS */
632 	{
633 		ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
634 						  to use sasl_ssf_t but currently uses ber_len_t */
635 		if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
636 			== LDAP_SUCCESS )
637 			op->o_sasl_ssf = ssf;
638 	}
639 	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
640 		?  op->o_sasl_ssf : op->o_tls_ssf;
641 
642 	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
643 
644 	rc = LDAP_DEREF_NEVER;	/* actually could allow DEREF_FINDING */
645 	ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
646 
647 	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
648 
649 	si->si_syncCookie.rid = si->si_rid;
650 
651 	/* whenever there are multiple data sources possible, advertise sid */
652 	si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
653 		slap_serverID : -1;
654 
655 	/* We've just started up, or the remote server hasn't sent us
656 	 * any meaningful state.
657 	 */
658 	if ( !si->si_syncCookie.ctxcsn ) {
659 		int i;
660 
661 		LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
662 			if ( si->si_rid == sc->rid ) {
663 				cmdline_cookie_found = 1;
664 				break;
665 			}
666 		}
667 
668 		if ( cmdline_cookie_found ) {
669 			/* cookie is supplied in the command line */
670 
671 			LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
672 
673 			slap_sync_cookie_free( &si->si_syncCookie, 0 );
674 			si->si_syncCookie.octet_str = sc->octet_str;
675 			ch_free( sc );
676 			/* ctxcsn wasn't parsed yet, do it now */
677 			slap_parse_sync_cookie( &si->si_syncCookie, NULL );
678 		} else {
679 			ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
680 			if ( !si->si_cookieState->cs_num ) {
681 				/* get contextCSN shadow replica from database */
682 				BerVarray csn = NULL;
683 				void *ctx = op->o_tmpmemctx;
684 
685 				op->o_req_ndn = si->si_contextdn;
686 				op->o_req_dn = op->o_req_ndn;
687 
688 				/* try to read stored contextCSN */
689 				op->o_tmpmemctx = NULL;
690 				backend_attribute( op, NULL, &op->o_req_ndn,
691 					slap_schema.si_ad_contextCSN, &csn, ACL_READ );
692 				op->o_tmpmemctx = ctx;
693 				if ( csn ) {
694 					si->si_cookieState->cs_vals = csn;
695 					for (i=0; !BER_BVISNULL( &csn[i] ); i++);
696 					si->si_cookieState->cs_num = i;
697 					si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
698 					slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
699 				}
700 			}
701 			if ( si->si_cookieState->cs_num ) {
702 				ber_bvarray_free( si->si_syncCookie.ctxcsn );
703 				if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
704 					si->si_cookieState->cs_vals, NULL )) {
705 					rc = LDAP_NO_MEMORY;
706 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
707 					goto done;
708 				}
709 				si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
710 				si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num *
711 					sizeof(int) );
712 				for ( i=0; i<si->si_syncCookie.numcsns; i++ )
713 					si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
714 			}
715 			ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
716 		}
717 
718 		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
719 			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
720 			si->si_syncCookie.sid );
721 	} else {
722 		/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
723 		ch_free( si->si_syncCookie.octet_str.bv_val );
724 		BER_BVZERO( &si->si_syncCookie.octet_str );
725 		/* Look for contextCSN from syncprov overlay. */
726 		check_syncprov( op, si );
727 		if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
728 			slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
729 				si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
730 				si->si_syncCookie.sid );
731 	}
732 
733 	si->si_refreshDone = 0;
734 
735 	rc = ldap_sync_search( si, op->o_tmpmemctx );
736 
737 	if( rc != LDAP_SUCCESS ) {
738 		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
739 			"ldap_search_ext: %s (%d)\n",
740 			si->si_ridtxt, ldap_err2string( rc ), rc );
741 	}
742 
743 done:
744 	if ( rc ) {
745 		if ( si->si_ld ) {
746 			ldap_unbind_ext( si->si_ld, NULL, NULL );
747 			si->si_ld = NULL;
748 		}
749 	}
750 
751 	return rc;
752 }
753 
754 static int
755 compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
756 {
757 	int i, j, match = 0;
758 	const char *text;
759 
760 	*which = 0;
761 
762 	if ( sc1->numcsns < sc2->numcsns ) {
763 		*which = sc1->numcsns;
764 		return -1;
765 	}
766 
767 	for (j=0; j<sc2->numcsns; j++) {
768 		for (i=0; i<sc1->numcsns; i++) {
769 			if ( sc1->sids[i] != sc2->sids[j] )
770 				continue;
771 			value_match( &match, slap_schema.si_ad_entryCSN,
772 				slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
773 				SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
774 				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
775 			if ( match < 0 ) {
776 				*which = j;
777 				return match;
778 			}
779 			break;
780 		}
781 		if ( i == sc1->numcsns ) {
782 			/* sc2 has a sid sc1 lacks */
783 			*which = j;
784 			return -1;
785 		}
786 	}
787 	return match;
788 }
789 
790 #define	SYNC_PAUSED	-3
791 
792 static int
793 do_syncrep2(
794 	Operation *op,
795 	syncinfo_t *si )
796 {
797 	BerElementBuffer berbuf;
798 	BerElement	*ber = (BerElement *)&berbuf;
799 
800 	LDAPMessage	*msg = NULL;
801 
802 	struct sync_cookie	syncCookie = { NULL };
803 	struct sync_cookie	syncCookie_req = { NULL };
804 
805 	int		rc,
806 			err = LDAP_SUCCESS;
807 
808 	Modifications	*modlist = NULL;
809 
810 	int				m;
811 
812 	struct timeval *tout_p = NULL;
813 	struct timeval tout = { 0, 0 };
814 
815 	int		refreshDeletes = 0;
816 	char empty[6] = "empty";
817 
818 	if ( slapd_shutdown ) {
819 		rc = -2;
820 		goto done;
821 	}
822 
823 	ber_init2( ber, NULL, LBER_USE_DER );
824 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
825 
826 	Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt, 0, 0 );
827 
828 	slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
829 
830 	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
831 		tout_p = &tout;
832 	} else {
833 		tout_p = NULL;
834 	}
835 
836 	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
837 		tout_p, &msg ) ) > 0 )
838 	{
839 		int				match, punlock, syncstate;
840 		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
841 		char			*retoid;
842 		LDAPControl		**rctrls = NULL, *rctrlp = NULL;
843 		BerVarray		syncUUIDs;
844 		ber_len_t		len;
845 		ber_tag_t		si_tag;
846 		Entry			*entry;
847 		struct berval	bdn;
848 
849 		if ( slapd_shutdown ) {
850 			rc = -2;
851 			goto done;
852 		}
853 		switch( ldap_msgtype( msg ) ) {
854 		case LDAP_RES_SEARCH_ENTRY:
855 			ldap_get_entry_controls( si->si_ld, msg, &rctrls );
856 			ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
857 			if (!bdn.bv_len) {
858 				bdn.bv_val = empty;
859 				bdn.bv_len = sizeof(empty)-1;
860 			}
861 			/* we can't work without the control */
862 			if ( rctrls ) {
863 				LDAPControl **next = NULL;
864 				/* NOTE: make sure we use the right one;
865 				 * a better approach would be to run thru
866 				 * the whole list and take care of all */
867 				/* NOTE: since we issue the search request,
868 				 * we should know what controls to expect,
869 				 * and there should be none apart from the
870 				 * sync-related control */
871 				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
872 				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
873 				{
874 					bdn.bv_val[bdn.bv_len] = '\0';
875 					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
876 						"got search entry with multiple "
877 						"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
878 					ldap_controls_free( rctrls );
879 					rc = -1;
880 					goto done;
881 				}
882 			}
883 			if ( rctrlp == NULL ) {
884 				bdn.bv_val[bdn.bv_len] = '\0';
885 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
886 					"got search entry without "
887 					"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
888 				rc = -1;
889 				goto done;
890 			}
891 			ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
892 			if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
893 					== LBER_ERROR ) {
894 				bdn.bv_val[bdn.bv_len] = '\0';
895 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
896 					si->si_ridtxt, bdn.bv_val, 0 );
897 				ldap_controls_free( rctrls );
898 				rc = -1;
899 				goto done;
900 			}
901 			/* FIXME: what if syncUUID is NULL or empty?
902 			 * (happens with back-sql...) */
903 			if ( BER_BVISEMPTY( &syncUUID[0] ) ) {
904 				bdn.bv_val[bdn.bv_len] = '\0';
905 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
906 					"got empty syncUUID with LDAP_SYNC_%s (%s)\n",
907 					si->si_ridtxt,
908 					syncrepl_state2str( syncstate ), bdn.bv_val );
909 				ldap_controls_free( rctrls );
910 				rc = -1;
911 				goto done;
912 			}
913 			punlock = -1;
914 			if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
915 				ber_scanf( ber, /*"{"*/ "m}", &cookie );
916 
917 				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
918 					si->si_ridtxt,
919 					BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
920 
921 				if ( !BER_BVISNULL( &cookie ) ) {
922 					ch_free( syncCookie.octet_str.bv_val );
923 					ber_dupbv( &syncCookie.octet_str, &cookie );
924 				}
925 				if ( !BER_BVISNULL( &syncCookie.octet_str ) )
926 				{
927 					slap_parse_sync_cookie( &syncCookie, NULL );
928 					if ( syncCookie.ctxcsn ) {
929 						int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
930 						check_syncprov( op, si );
931 						for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
932 							/* new SID */
933 							if ( sid < si->si_cookieState->cs_sids[i] )
934 								break;
935 							if ( si->si_cookieState->cs_sids[i] == sid ) {
936 								if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
937 									bdn.bv_val[bdn.bv_len] = '\0';
938 									Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
939 										si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
940 									ldap_controls_free( rctrls );
941 									rc = 0;
942 									si->si_too_old = 1;
943 									goto done;
944 								}
945 								si->si_too_old = 0;
946 								break;
947 							}
948 						}
949 						/* check pending CSNs too */
950 						while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
951 							if ( slapd_shutdown ) {
952 								rc = -2;
953 								goto done;
954 							}
955 							if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
956 								ldap_pvt_thread_yield();
957 						}
958 						for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
959 							if ( sid < si->si_cookieState->cs_psids[i] )
960 								break;
961 							if ( si->si_cookieState->cs_psids[i] == sid ) {
962 								if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
963 									bdn.bv_val[bdn.bv_len] = '\0';
964 									Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s (%s)\n",
965 										si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
966 									ldap_controls_free( rctrls );
967 									rc = 0;
968 									ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
969 									goto done;
970 								}
971 								ber_bvreplace( &si->si_cookieState->cs_pvals[i],
972 									syncCookie.ctxcsn );
973 								break;
974 							}
975 						}
976 						/* new SID, add it */
977 						if ( i == si->si_cookieState->cs_pnum ||
978 							sid != si->si_cookieState->cs_psids[i] ) {
979 							slap_insert_csn_sids(
980 								(struct sync_cookie *)&si->si_cookieState->cs_pvals,
981 								i, sid, syncCookie.ctxcsn );
982 						}
983 						assert( punlock < 0 );
984 						punlock = i;
985 					} else if (si->si_too_old) {
986 						bdn.bv_val[bdn.bv_len] = '\0';
987 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring (%s)\n",
988 							si->si_ridtxt, bdn.bv_val, 0 );
989 						ldap_controls_free( rctrls );
990 						rc = 0;
991 						goto done;
992 					}
993 					op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
994 				}
995 			}
996 			rc = 0;
997 			if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
998 				modlist = NULL;
999 				if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
1000 					syncCookie.ctxcsn )
1001 				{
1002 					rc = syncrepl_updateCookie( si, op, &syncCookie );
1003 				} else switch ( rc ) {
1004 					case LDAP_ALREADY_EXISTS:
1005 					case LDAP_NO_SUCH_OBJECT:
1006 					case LDAP_NO_SUCH_ATTRIBUTE:
1007 					case LDAP_TYPE_OR_VALUE_EXISTS:
1008 					case LDAP_NOT_ALLOWED_ON_NONLEAF:
1009 						rc = LDAP_SYNC_REFRESH_REQUIRED;
1010 						si->si_logstate = SYNCLOG_FALLBACK;
1011 						ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
1012 						bdn.bv_val[bdn.bv_len] = '\0';
1013 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
1014 							si->si_ridtxt, bdn.bv_val, 0 );
1015 						if (si->si_strict_refresh) {
1016 							slap_suspend_listeners();
1017 							connections_drop();
1018 						}
1019 						break;
1020 					default:
1021 						break;
1022 				}
1023 			} else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
1024 				&modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS )
1025 			{
1026 				if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
1027 					syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
1028 					syncCookie.ctxcsn )
1029 				{
1030 					rc = syncrepl_updateCookie( si, op, &syncCookie );
1031 				}
1032 			}
1033 			if ( punlock >= 0 ) {
1034 				/* on failure, revert pending CSN */
1035 				if ( rc != LDAP_SUCCESS ) {
1036 					int i;
1037 					for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
1038 						if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
1039 							ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
1040 								&si->si_cookieState->cs_vals[i] );
1041 							break;
1042 						}
1043 					}
1044 					if ( i == si->si_cookieState->cs_num )
1045 						si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
1046 				}
1047 				ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
1048 			}
1049 			ldap_controls_free( rctrls );
1050 			if ( modlist ) {
1051 				slap_mods_free( modlist, 1 );
1052 			}
1053 			if ( rc )
1054 				goto done;
1055 			break;
1056 
1057 		case LDAP_RES_SEARCH_REFERENCE:
1058 			Debug( LDAP_DEBUG_ANY,
1059 				"do_syncrep2: %s reference received error\n",
1060 				si->si_ridtxt, 0, 0 );
1061 			break;
1062 
1063 		case LDAP_RES_SEARCH_RESULT:
1064 			Debug( LDAP_DEBUG_SYNC,
1065 				"do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
1066 				si->si_ridtxt, 0, 0 );
1067 			err = LDAP_OTHER; /* FIXME check parse result properly */
1068 			ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
1069 				&rctrls, 0 );
1070 #ifdef LDAP_X_SYNC_REFRESH_REQUIRED
1071 			if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
1072 				/* map old result code to registered code */
1073 				err = LDAP_SYNC_REFRESH_REQUIRED;
1074 			}
1075 #endif
1076 			if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
1077 				if ( si->si_logstate == SYNCLOG_LOGGING ) {
1078 					si->si_logstate = SYNCLOG_FALLBACK;
1079 					Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
1080 						si->si_ridtxt, 0, 0 );
1081 					if (si->si_strict_refresh) {
1082 						slap_suspend_listeners();
1083 						connections_drop();
1084 					}
1085 				}
1086 				rc = err;
1087 				goto done;
1088 			}
1089 			if ( err ) {
1090 				Debug( LDAP_DEBUG_ANY,
1091 					"do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
1092 					si->si_ridtxt, err, ldap_err2string( err ) );
1093 			}
1094 			if ( rctrls ) {
1095 				LDAPControl **next = NULL;
1096 				/* NOTE: make sure we use the right one;
1097 				 * a better approach would be to run thru
1098 				 * the whole list and take care of all */
1099 				/* NOTE: since we issue the search request,
1100 				 * we should know what controls to expect,
1101 				 * and there should be none apart from the
1102 				 * sync-related control */
1103 				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next );
1104 				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) )
1105 				{
1106 					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1107 						"got search result with multiple "
1108 						"Sync State control\n", si->si_ridtxt, 0, 0 );
1109 					ldap_controls_free( rctrls );
1110 					rc = -1;
1111 					goto done;
1112 				}
1113 			}
1114 			if ( rctrlp ) {
1115 				ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
1116 
1117 				ber_scanf( ber, "{" /*"}"*/);
1118 				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
1119 					ber_scanf( ber, "m", &cookie );
1120 
1121 					Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1122 						si->si_ridtxt,
1123 						BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
1124 
1125 					if ( !BER_BVISNULL( &cookie ) ) {
1126 						ch_free( syncCookie.octet_str.bv_val );
1127 						ber_dupbv( &syncCookie.octet_str, &cookie);
1128 					}
1129 					if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1130 					{
1131 						slap_parse_sync_cookie( &syncCookie, NULL );
1132 						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1133 					}
1134 				}
1135 				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
1136 				{
1137 					ber_scanf( ber, "b", &refreshDeletes );
1138 				}
1139 				ber_scanf( ber, /*"{"*/ "}" );
1140 			}
1141 			if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
1142 				slap_sync_cookie_free( &syncCookie_req, 0 );
1143 				slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
1144 			}
1145 			if ( !syncCookie.ctxcsn ) {
1146 				match = 1;
1147 			} else if ( !syncCookie_req.ctxcsn ) {
1148 				match = -1;
1149 				m = 0;
1150 			} else {
1151 				match = compare_csns( &syncCookie_req, &syncCookie, &m );
1152 			}
1153 			if ( rctrls ) {
1154 				ldap_controls_free( rctrls );
1155 			}
1156 			if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
1157 				/* FIXME : different error behaviors according to
1158 				 *	1) err code : LDAP_BUSY ...
1159 				 *	2) on err policy : stop service, stop sync, retry
1160 				 */
1161 				if ( refreshDeletes == 0 && match < 0 &&
1162 					err == LDAP_SUCCESS &&
1163 					syncCookie_req.numcsns == syncCookie.numcsns )
1164 				{
1165 					syncrepl_del_nonpresent( op, si, NULL,
1166 						&syncCookie, m );
1167 				} else {
1168 					avl_free( si->si_presentlist, ch_free );
1169 					si->si_presentlist = NULL;
1170 				}
1171 			}
1172 			if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
1173 			{
1174 				rc = syncrepl_updateCookie( si, op, &syncCookie );
1175 			}
1176 			if ( err == LDAP_SUCCESS
1177 				&& si->si_logstate == SYNCLOG_FALLBACK ) {
1178 				si->si_logstate = SYNCLOG_LOGGING;
1179 				rc = LDAP_SYNC_REFRESH_REQUIRED;
1180 				slap_resume_listeners();
1181 			} else {
1182 				rc = -2;
1183 			}
1184 			goto done;
1185 
1186 		case LDAP_RES_INTERMEDIATE:
1187 			retoid = NULL;
1188 			retdata = NULL;
1189 			rc = ldap_parse_intermediate( si->si_ld, msg,
1190 				&retoid, &retdata, NULL, 0 );
1191 			if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
1192 				ber_init2( ber, retdata, LBER_USE_DER );
1193 
1194 				switch ( si_tag = ber_peek_tag( ber, &len ) ) {
1195 				ber_tag_t tag;
1196 				case LDAP_TAG_SYNC_NEW_COOKIE:
1197 					Debug( LDAP_DEBUG_SYNC,
1198 						"do_syncrep2: %s %s - %s\n",
1199 						si->si_ridtxt,
1200 						"LDAP_RES_INTERMEDIATE",
1201 						"NEW_COOKIE" );
1202 					ber_scanf( ber, "tm", &tag, &cookie );
1203 					Debug( LDAP_DEBUG_SYNC,
1204 						"do_syncrep2: %s NEW_COOKIE: %s\n",
1205 						si->si_ridtxt,
1206 						cookie.bv_val, 0);
1207 					if ( !BER_BVISNULL( &cookie ) ) {
1208 						ch_free( syncCookie.octet_str.bv_val );
1209 						ber_dupbv( &syncCookie.octet_str, &cookie );
1210 					}
1211 					if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
1212 						slap_parse_sync_cookie( &syncCookie, NULL );
1213 						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1214 					}
1215 					break;
1216 				case LDAP_TAG_SYNC_REFRESH_DELETE:
1217 				case LDAP_TAG_SYNC_REFRESH_PRESENT:
1218 					Debug( LDAP_DEBUG_SYNC,
1219 						"do_syncrep2: %s %s - %s\n",
1220 						si->si_ridtxt,
1221 						"LDAP_RES_INTERMEDIATE",
1222 						si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
1223 						"REFRESH_PRESENT" : "REFRESH_DELETE" );
1224 					if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
1225 						si->si_refreshDelete = 1;
1226 					} else {
1227 						si->si_refreshPresent = 1;
1228 					}
1229 					ber_scanf( ber, "t{" /*"}"*/, &tag );
1230 					if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
1231 					{
1232 						ber_scanf( ber, "m", &cookie );
1233 
1234 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1235 							si->si_ridtxt,
1236 							BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
1237 
1238 						if ( !BER_BVISNULL( &cookie ) ) {
1239 							ch_free( syncCookie.octet_str.bv_val );
1240 							ber_dupbv( &syncCookie.octet_str, &cookie );
1241 						}
1242 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1243 						{
1244 							slap_parse_sync_cookie( &syncCookie, NULL );
1245 							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1246 						}
1247 					}
1248 					/* Defaults to TRUE */
1249 					if ( ber_peek_tag( ber, &len ) ==
1250 						LDAP_TAG_REFRESHDONE )
1251 					{
1252 						ber_scanf( ber, "b", &si->si_refreshDone );
1253 					} else
1254 					{
1255 						si->si_refreshDone = 1;
1256 					}
1257 					ber_scanf( ber, /*"{"*/ "}" );
1258 					if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
1259 						si->si_refreshDone )
1260 						tout_p = &tout;
1261 					break;
1262 				case LDAP_TAG_SYNC_ID_SET:
1263 					Debug( LDAP_DEBUG_SYNC,
1264 						"do_syncrep2: %s %s - %s\n",
1265 						si->si_ridtxt,
1266 						"LDAP_RES_INTERMEDIATE",
1267 						"SYNC_ID_SET" );
1268 					ber_scanf( ber, "t{" /*"}"*/, &tag );
1269 					if ( ber_peek_tag( ber, &len ) ==
1270 						LDAP_TAG_SYNC_COOKIE )
1271 					{
1272 						ber_scanf( ber, "m", &cookie );
1273 
1274 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1275 							si->si_ridtxt,
1276 							BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
1277 
1278 						if ( !BER_BVISNULL( &cookie ) ) {
1279 							ch_free( syncCookie.octet_str.bv_val );
1280 							ber_dupbv( &syncCookie.octet_str, &cookie );
1281 						}
1282 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1283 						{
1284 							slap_parse_sync_cookie( &syncCookie, NULL );
1285 							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1286 							compare_csns( &syncCookie_req, &syncCookie, &m );
1287 						}
1288 					}
1289 					if ( ber_peek_tag( ber, &len ) ==
1290 						LDAP_TAG_REFRESHDELETES )
1291 					{
1292 						ber_scanf( ber, "b", &refreshDeletes );
1293 					}
1294 					syncUUIDs = NULL;
1295 					ber_scanf( ber, "[W]", &syncUUIDs );
1296 					ber_scanf( ber, /*"{"*/ "}" );
1297 					if ( refreshDeletes ) {
1298 						syncrepl_del_nonpresent( op, si, syncUUIDs,
1299 							&syncCookie, m );
1300 						ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
1301 					} else {
1302 						int i;
1303 						for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
1304 							(void)avl_presentlist_insert( si, &syncUUIDs[i] );
1305 							slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
1306 						}
1307 						slap_sl_free( syncUUIDs, op->o_tmpmemctx );
1308 					}
1309 					slap_sync_cookie_free( &syncCookie, 0 );
1310 					break;
1311 				default:
1312 					Debug( LDAP_DEBUG_ANY,
1313 						"do_syncrep2: %s unknown syncinfo tag (%ld)\n",
1314 						si->si_ridtxt, (long) si_tag, 0 );
1315 					ldap_memfree( retoid );
1316 					ber_bvfree( retdata );
1317 					continue;
1318 				}
1319 
1320 				if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
1321 					slap_sync_cookie_free( &syncCookie_req, 0 );
1322 					slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
1323 				}
1324 				if ( !syncCookie.ctxcsn ) {
1325 					match = 1;
1326 				} else if ( !syncCookie_req.ctxcsn ) {
1327 					match = -1;
1328 					m = 0;
1329 				} else {
1330 					match = compare_csns( &syncCookie_req, &syncCookie, &m );
1331 				}
1332 
1333 				if ( match < 0 ) {
1334 					if ( si->si_refreshPresent == 1 &&
1335 						si_tag != LDAP_TAG_SYNC_NEW_COOKIE &&
1336 						syncCookie_req.numcsns == syncCookie.numcsns ) {
1337 						syncrepl_del_nonpresent( op, si, NULL,
1338 							&syncCookie, m );
1339 					}
1340 
1341 					if ( syncCookie.ctxcsn )
1342 					{
1343 						rc = syncrepl_updateCookie( si, op, &syncCookie);
1344 					}
1345 				}
1346 
1347 				ldap_memfree( retoid );
1348 				ber_bvfree( retdata );
1349 
1350 				if ( rc )
1351 					goto done;
1352 
1353 			} else {
1354 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1355 					"unknown intermediate response (%d)\n",
1356 					si->si_ridtxt, rc, 0 );
1357 				ldap_memfree( retoid );
1358 				ber_bvfree( retdata );
1359 			}
1360 			break;
1361 
1362 		default:
1363 			Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1364 				"unknown message (0x%02lx)\n",
1365 				si->si_ridtxt,
1366 				(unsigned long)ldap_msgtype( msg ), 0 );
1367 			break;
1368 
1369 		}
1370 		if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
1371 			slap_sync_cookie_free( &syncCookie_req, 0 );
1372 			syncCookie_req = syncCookie;
1373 			memset( &syncCookie, 0, sizeof( syncCookie ));
1374 		}
1375 		ldap_msgfree( msg );
1376 		msg = NULL;
1377 		if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
1378 			slap_sync_cookie_free( &syncCookie, 0 );
1379 			slap_sync_cookie_free( &syncCookie_req, 0 );
1380 			return SYNC_PAUSED;
1381 		}
1382 	}
1383 
1384 	if ( rc == -1 ) {
1385 		rc = LDAP_OTHER;
1386 		ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
1387 		err = rc;
1388 	}
1389 
1390 done:
1391 	if ( err != LDAP_SUCCESS ) {
1392 		Debug( LDAP_DEBUG_ANY,
1393 			"do_syncrep2: %s (%d) %s\n",
1394 			si->si_ridtxt, err, ldap_err2string( err ) );
1395 	}
1396 
1397 	slap_sync_cookie_free( &syncCookie, 0 );
1398 	slap_sync_cookie_free( &syncCookie_req, 0 );
1399 
1400 	if ( msg ) ldap_msgfree( msg );
1401 
1402 	if ( rc && rc != LDAP_SYNC_REFRESH_REQUIRED && si->si_ld ) {
1403 		if ( si->si_conn ) {
1404 			connection_client_stop( si->si_conn );
1405 			si->si_conn = NULL;
1406 		}
1407 		ldap_unbind_ext( si->si_ld, NULL, NULL );
1408 		si->si_ld = NULL;
1409 	}
1410 
1411 	return rc;
1412 }
1413 
1414 static void *
1415 do_syncrepl(
1416 	void	*ctx,
1417 	void	*arg )
1418 {
1419 	struct re_s* rtask = arg;
1420 	syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
1421 	Connection conn = {0};
1422 	OperationBuffer opbuf;
1423 	Operation *op;
1424 	int rc = LDAP_SUCCESS;
1425 	int dostop = 0;
1426 	ber_socket_t s;
1427 	int i, defer = 1, fail = 0, freeinfo = 0;
1428 	Backend *be;
1429 
1430 	if ( si == NULL )
1431 		return NULL;
1432 	if ( slapd_shutdown )
1433 		return NULL;
1434 
1435 	Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
1436 
1437 	/* Don't get stuck here while a pause is initiated */
1438 	while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
1439 		if ( slapd_shutdown )
1440 			return NULL;
1441 		if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
1442 			ldap_pvt_thread_yield();
1443 	}
1444 
1445 	si->si_too_old = 0;
1446 
1447 	if ( si->si_ctype < 1 ) {
1448 		goto deleted;
1449 	}
1450 
1451 	switch( abs( si->si_type ) ) {
1452 	case LDAP_SYNC_REFRESH_ONLY:
1453 	case LDAP_SYNC_REFRESH_AND_PERSIST:
1454 		break;
1455 	default:
1456 		ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1457 		return NULL;
1458 	}
1459 
1460 	if ( slapd_shutdown ) {
1461 		if ( si->si_ld ) {
1462 			if ( si->si_conn ) {
1463 				connection_client_stop( si->si_conn );
1464 				si->si_conn = NULL;
1465 			}
1466 			ldap_unbind_ext( si->si_ld, NULL, NULL );
1467 			si->si_ld = NULL;
1468 		}
1469 		ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1470 		return NULL;
1471 	}
1472 
1473 	connection_fake_init( &conn, &opbuf, ctx );
1474 	op = &opbuf.ob_op;
1475 	/* o_connids must be unique for slap_graduate_commit_csn */
1476 	op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
1477 
1478 	op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
1479 	be = si->si_be;
1480 
1481 	/* Coordinate contextCSN updates with any syncprov overlays
1482 	 * in use. This may be complicated by the use of the glue
1483 	 * overlay.
1484 	 *
1485 	 * Typically there is a single syncprov mastering the entire
1486 	 * glued tree. In that case, our contextCSN updates should
1487 	 * go to the master DB. But if there is no syncprov on the
1488 	 * master DB, then nothing special is needed here.
1489 	 *
1490 	 * Alternatively, there may be individual syncprov overlays
1491 	 * on each glued branch. In that case, each syncprov only
1492 	 * knows about changes within its own branch. And so our
1493 	 * contextCSN updates should only go to the local DB.
1494 	 */
1495 	if ( !si->si_wbe ) {
1496 		if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
1497 			BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
1498 			if ( overlay_is_inst( top_be, "syncprov" ))
1499 				si->si_wbe = top_be;
1500 			else
1501 				si->si_wbe = be;
1502 		} else {
1503 			si->si_wbe = be;
1504 		}
1505 		if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) {
1506 			build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0],
1507 				(struct berval *)&slap_ldapsync_cn_bv, NULL );
1508 		} else {
1509 			si->si_contextdn = si->si_wbe->be_nsuffix[0];
1510 		}
1511 	}
1512 	if ( !si->si_schemachecking )
1513 		op->o_no_schema_check = 1;
1514 
1515 	/* Establish session, do search */
1516 	if ( !si->si_ld ) {
1517 		si->si_refreshDelete = 0;
1518 		si->si_refreshPresent = 0;
1519 
1520 		if ( si->si_presentlist ) {
1521 		    avl_free( si->si_presentlist, ch_free );
1522 		    si->si_presentlist = NULL;
1523 		}
1524 
1525 		/* use main DB when retrieving contextCSN */
1526 		op->o_bd = si->si_wbe;
1527 		op->o_dn = op->o_bd->be_rootdn;
1528 		op->o_ndn = op->o_bd->be_rootndn;
1529 		rc = do_syncrep1( op, si );
1530 	}
1531 
1532 reload:
1533 	/* Process results */
1534 	if ( rc == LDAP_SUCCESS ) {
1535 		ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
1536 
1537 		/* use current DB */
1538 		op->o_bd = be;
1539 		op->o_dn = op->o_bd->be_rootdn;
1540 		op->o_ndn = op->o_bd->be_rootndn;
1541 		rc = do_syncrep2( op, si );
1542 		if ( rc == LDAP_SYNC_REFRESH_REQUIRED )	{
1543 			rc = ldap_sync_search( si, op->o_tmpmemctx );
1544 			goto reload;
1545 		}
1546 
1547 deleted:
1548 		/* We got deleted while running on cn=config */
1549 		if ( si->si_ctype < 1 ) {
1550 			if ( si->si_ctype == -1 ) {
1551 				si->si_ctype = 0;
1552 				freeinfo = 1;
1553 			}
1554 			if ( si->si_conn )
1555 				dostop = 1;
1556 			rc = -1;
1557 		}
1558 
1559 		if ( rc != SYNC_PAUSED ) {
1560 			if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
1561 				/* If we succeeded, enable the connection for further listening.
1562 				 * If we failed, tear down the connection and reschedule.
1563 				 */
1564 				if ( rc == LDAP_SUCCESS ) {
1565 					if ( si->si_conn ) {
1566 						connection_client_enable( si->si_conn );
1567 					} else {
1568 						si->si_conn = connection_client_setup( s, do_syncrepl, arg );
1569 					}
1570 				} else if ( si->si_conn ) {
1571 					dostop = 1;
1572 				}
1573 			} else {
1574 				if ( rc == -2 ) rc = 0;
1575 			}
1576 		}
1577 	}
1578 
1579 	/* At this point, we have 5 cases:
1580 	 * 1) for any hard failure, give up and remove this task
1581 	 * 2) for ServerDown, reschedule this task to run later
1582 	 * 3) for threadpool pause, reschedule to run immediately
1583 	 * 4) for Refresh and Success, reschedule to run
1584 	 * 5) for Persist and Success, reschedule to defer
1585 	 */
1586 	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
1587 
1588 	if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask ) ) {
1589 		ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
1590 	}
1591 
1592 	if ( dostop ) {
1593 		connection_client_stop( si->si_conn );
1594 		si->si_conn = NULL;
1595 	}
1596 
1597 	if ( rc == SYNC_PAUSED ) {
1598 		rtask->interval.tv_sec = 0;
1599 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
1600 		rtask->interval.tv_sec = si->si_interval;
1601 		rc = 0;
1602 	} else if ( rc == LDAP_SUCCESS ) {
1603 		if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
1604 			defer = 0;
1605 		}
1606 		rtask->interval.tv_sec = si->si_interval;
1607 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, defer );
1608 		if ( si->si_retrynum ) {
1609 			for ( i = 0; si->si_retrynum_init[i] != RETRYNUM_TAIL; i++ ) {
1610 				si->si_retrynum[i] = si->si_retrynum_init[i];
1611 			}
1612 			si->si_retrynum[i] = RETRYNUM_TAIL;
1613 		}
1614 	} else {
1615 		for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
1616 			if ( si->si_retrynum[i] == RETRYNUM_FOREVER || si->si_retrynum[i] == RETRYNUM_TAIL )
1617 				break;
1618 		}
1619 
1620 		if ( si->si_ctype < 1
1621 			|| !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
1622 			if ( si->si_re ) {
1623 				ldap_pvt_runqueue_remove( &slapd_rq, rtask );
1624 				si->si_re = NULL;
1625 			}
1626 			fail = RETRYNUM_TAIL;
1627 		} else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) {
1628 			if ( si->si_retrynum[i] > 0 )
1629 				si->si_retrynum[i]--;
1630 			fail = si->si_retrynum[i];
1631 			rtask->interval.tv_sec = si->si_retryinterval[i];
1632 			ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
1633 			slap_wake_listener();
1634 		}
1635 	}
1636 
1637 	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
1638 	ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1639 
1640 	if ( rc ) {
1641 		if ( fail == RETRYNUM_TAIL ) {
1642 			Debug( LDAP_DEBUG_ANY,
1643 				"do_syncrepl: %s rc %d quitting\n",
1644 				si->si_ridtxt, rc, 0 );
1645 		} else if ( fail > 0 ) {
1646 			Debug( LDAP_DEBUG_ANY,
1647 				"do_syncrepl: %s rc %d retrying (%d retries left)\n",
1648 				si->si_ridtxt, rc, fail );
1649 		} else {
1650 			Debug( LDAP_DEBUG_ANY,
1651 				"do_syncrepl: %s rc %d retrying\n",
1652 				si->si_ridtxt, rc, 0 );
1653 		}
1654 	}
1655 
1656 	/* Do final delete cleanup */
1657 	if ( freeinfo ) {
1658 		syncinfo_free( si, 0 );
1659 	}
1660 	return NULL;
1661 }
1662 
1663 #ifdef ENABLE_REWRITE
1664 static int
1665 syncrepl_rewrite_dn(
1666 	syncinfo_t *si,
1667 	struct berval *dn,
1668 	struct berval *sdn )
1669 {
1670 	char nul;
1671 	int rc;
1672 
1673 	nul = dn->bv_val[dn->bv_len];
1674 	dn->bv_val[dn->bv_len] = 0;
1675 	rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
1676 	dn->bv_val[dn->bv_len] = nul;
1677 
1678 	if ( sdn->bv_val == dn->bv_val )
1679 		sdn->bv_val = NULL;
1680 	else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
1681 		sdn->bv_len = strlen( sdn->bv_val );
1682 	return rc;
1683 }
1684 #define	REWRITE_VAL(si, ad, bv, bv2)	\
1685 	BER_BVZERO( &bv2 );	\
1686 	if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
1687 		syncrepl_rewrite_dn( si, &bv, &bv2); \
1688 	if ( BER_BVISNULL( &bv2 ))  \
1689 		ber_dupbv( &bv2, &bv )
1690 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
1691 	BER_BVZERO( &bv2 );	\
1692 	if (si->si_rewrite) \
1693 		syncrepl_rewrite_dn(si, &bv, &bv2); \
1694 	rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
1695 	ch_free(bv2.bv_val)
1696 #else
1697 #define REWRITE_VAL(si, ad, bv, bv2)	ber_dupbv(&bv2, &bv)
1698 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
1699 	rc = dnPrettyNormal( NULL, &bv, &dn, &ndn, op->o_tmpmemctx )
1700 #endif
1701 
1702 
1703 static slap_verbmasks modops[] = {
1704 	{ BER_BVC("add"), LDAP_REQ_ADD },
1705 	{ BER_BVC("delete"), LDAP_REQ_DELETE },
1706 	{ BER_BVC("modify"), LDAP_REQ_MODIFY },
1707 	{ BER_BVC("modrdn"), LDAP_REQ_MODRDN},
1708 	{ BER_BVNULL, 0 }
1709 };
1710 
1711 static int
1712 syncrepl_accesslog_mods(
1713 	syncinfo_t *si,
1714 	struct berval *vals,
1715 	struct Modifications **modres
1716 )
1717 {
1718 	char *colon;
1719 	const char *text;
1720 	AttributeDescription *ad;
1721 	struct berval bv, bv2;
1722 	short op;
1723 	Modifications *mod = NULL, *modlist = NULL, **modtail;
1724 	int i, rc = 0;
1725 
1726 	modtail = &modlist;
1727 
1728 	for (i=0; !BER_BVISNULL( &vals[i] ); i++) {
1729 		ad = NULL;
1730 		bv = vals[i];
1731 
1732 		colon = ber_bvchr( &bv, ':' );
1733 		if ( !colon ) {
1734 			/* Invalid */
1735 			continue;
1736 		}
1737 
1738 		bv.bv_len = colon - bv.bv_val;
1739 		if ( slap_bv2ad( &bv, &ad, &text ) ) {
1740 			/* Invalid */
1741 			Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
1742 				"Invalid attribute %s, %s\n",
1743 				si->si_ridtxt, bv.bv_val, text );
1744 			slap_mods_free( modlist, 1 );
1745 			modlist = NULL;
1746 			rc = -1;
1747 			break;
1748 		}
1749 
1750 		/* Ignore dynamically generated attrs */
1751 		if ( ad->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
1752 			continue;
1753 		}
1754 
1755 		/* Ignore excluded attrs */
1756 		if ( ldap_charray_inlist( si->si_exattrs,
1757 			ad->ad_type->sat_cname.bv_val ) )
1758 		{
1759 			continue;
1760 		}
1761 
1762 		switch(colon[1]) {
1763 		case '+':	op = LDAP_MOD_ADD; break;
1764 		case '-':	op = LDAP_MOD_DELETE; break;
1765 		case '=':	op = LDAP_MOD_REPLACE; break;
1766 		case '#':	op = LDAP_MOD_INCREMENT; break;
1767 		default:	continue;
1768 		}
1769 
1770 		if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) {
1771 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1772 			mod->sml_flags = 0;
1773 			mod->sml_op = op;
1774 			mod->sml_next = NULL;
1775 			mod->sml_desc = ad;
1776 			mod->sml_type = ad->ad_cname;
1777 			mod->sml_values = NULL;
1778 			mod->sml_nvalues = NULL;
1779 			mod->sml_numvals = 0;
1780 
1781 			*modtail = mod;
1782 			modtail = &mod->sml_next;
1783 		}
1784 		if ( colon[2] == ' ' ) {
1785 			bv.bv_val = colon + 3;
1786 			bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
1787 			REWRITE_VAL( si, ad, bv, bv2 );
1788 			ber_bvarray_add( &mod->sml_values, &bv2 );
1789 			mod->sml_numvals++;
1790 		}
1791 	}
1792 	*modres = modlist;
1793 	return rc;
1794 }
1795 
1796 static int
1797 syncrepl_changelog_mods(
1798 	syncinfo_t *si,
1799 	struct berval *vals,
1800 	struct Modifications **modres
1801 )
1802 {
1803 	return -1;	/* FIXME */
1804 }
1805 
1806 typedef struct OpExtraSync {
1807 	OpExtra oe;
1808 	syncinfo_t *oe_si;
1809 } OpExtraSync;
1810 
1811 /* Copy the original modlist, split Replace ops into Delete/Add,
1812  * and drop mod opattrs since this modification is in the past.
1813  */
1814 static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
1815 {
1816 	Modifications *mod, *modnew = NULL, *modtail = NULL;
1817 	int size;
1818 	for ( ; modlist; modlist = modlist->sml_next ) {
1819 		/* older ops */
1820 		if ( match < 0 ) {
1821 			if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
1822 				modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
1823 				modlist->sml_desc == slap_schema.si_ad_entryCSN )
1824 				continue;
1825 			if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
1826 				mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
1827 				mod->sml_desc = modlist->sml_desc;
1828 				mod->sml_values = NULL;
1829 				mod->sml_nvalues = NULL;
1830 				mod->sml_op = LDAP_MOD_DELETE;
1831 				mod->sml_numvals = 0;
1832 				mod->sml_flags = 0;
1833 				if ( !modnew )
1834 					modnew = mod;
1835 				if ( modtail )
1836 					modtail->sml_next = mod;
1837 				modtail = mod;
1838 			}
1839 		}
1840 		if ( modlist->sml_numvals ) {
1841 			size = (modlist->sml_numvals+1) * sizeof(struct berval);
1842 			if ( modlist->sml_nvalues ) size *= 2;
1843 		} else {
1844 			size = 0;
1845 		}
1846 		size += sizeof(Modifications);
1847 		mod = op->o_tmpalloc( size, op->o_tmpmemctx );
1848 		if ( !modnew )
1849 			modnew = mod;
1850 		if ( modtail )
1851 			modtail->sml_next = mod;
1852 		modtail = mod;
1853 		mod->sml_desc = modlist->sml_desc;
1854 		mod->sml_numvals = modlist->sml_numvals;
1855 		mod->sml_flags = 0;
1856 		if ( modlist->sml_numvals ) {
1857 			int i;
1858 			mod->sml_values = (BerVarray)(mod+1);
1859 			for (i=0; i<mod->sml_numvals; i++)
1860 				mod->sml_values[i] = modlist->sml_values[i];
1861 			BER_BVZERO(&mod->sml_values[i]);
1862 			if ( modlist->sml_nvalues ) {
1863 				mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
1864 				for (i=0; i<mod->sml_numvals; i++)
1865 					mod->sml_nvalues[i] = modlist->sml_nvalues[i];
1866 				BER_BVZERO(&mod->sml_nvalues[i]);
1867 			} else {
1868 				mod->sml_nvalues = NULL;
1869 			}
1870 		} else {
1871 			mod->sml_values = NULL;
1872 			mod->sml_nvalues = NULL;
1873 		}
1874 		if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
1875 			mod->sml_op = LDAP_MOD_ADD;
1876 		else
1877 			mod->sml_op = modlist->sml_op;
1878 		mod->sml_next = NULL;
1879 	}
1880 	return modnew;
1881 }
1882 
1883 typedef struct resolve_ctxt {
1884 	syncinfo_t *rx_si;
1885 	Modifications *rx_mods;
1886 } resolve_ctxt;
1887 
1888 static void
1889 compare_vals( Modifications *m1, Modifications *m2 )
1890 {
1891 	int i, j;
1892 	struct berval *bv1, *bv2;
1893 
1894 	if ( m2->sml_nvalues ) {
1895 		bv2 = m2->sml_nvalues;
1896 		bv1 = m1->sml_nvalues;
1897 	} else {
1898 		bv2 = m2->sml_values;
1899 		bv1 = m1->sml_values;
1900 	}
1901 	for ( j=0; j<m2->sml_numvals; j++ ) {
1902 		for ( i=0; i<m1->sml_numvals; i++ ) {
1903 			if ( !ber_bvcmp( &bv1[i], &bv2[j] )) {
1904 				int k;
1905 				for ( k=i; k<m1->sml_numvals-1; k++ ) {
1906 					m1->sml_values[k] = m1->sml_values[k+1];
1907 					if ( m1->sml_nvalues )
1908 						m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
1909 				}
1910 				BER_BVZERO(&m1->sml_values[k]);
1911 				if ( m1->sml_nvalues ) {
1912 					BER_BVZERO(&m1->sml_nvalues[k]);
1913 				}
1914 				m1->sml_numvals--;
1915 				i--;
1916 			}
1917 		}
1918 	}
1919 }
1920 
1921 static int
1922 syncrepl_resolve_cb( Operation *op, SlapReply *rs )
1923 {
1924 	if ( rs->sr_type == REP_SEARCH ) {
1925 		resolve_ctxt *rx = op->o_callback->sc_private;
1926 		Attribute *a = attr_find( rs->sr_entry->e_attrs, ad_reqMod );
1927 		if ( a ) {
1928 			Modifications *oldmods, *newmods, *m1, *m2, **prev;
1929 			oldmods = rx->rx_mods;
1930 			syncrepl_accesslog_mods( rx->rx_si, a->a_vals, &newmods );
1931 			for ( m2 = newmods; m2; m2=m2->sml_next ) {
1932 				for ( prev = &oldmods, m1 = *prev; m1; m1 = *prev ) {
1933 					if ( m1->sml_desc != m2->sml_desc ) {
1934 						prev = &m1->sml_next;
1935 						continue;
1936 					}
1937 					if ( m2->sml_op == LDAP_MOD_DELETE ||
1938 						m2->sml_op == LDAP_MOD_REPLACE ) {
1939 						int numvals = m2->sml_numvals;
1940 						if ( m2->sml_op == LDAP_MOD_REPLACE )
1941 							numvals = 0;
1942 						/* New delete All cancels everything */
1943 						if ( numvals == 0 ) {
1944 drop:
1945 							*prev = m1->sml_next;
1946 							op->o_tmpfree( m1, op->o_tmpmemctx );
1947 							continue;
1948 						}
1949 						if ( m1->sml_op == LDAP_MOD_DELETE ) {
1950 							if ( m1->sml_numvals == 0 ) {
1951 								/* turn this to SOFTDEL later */
1952 								m1->sml_flags = SLAP_MOD_INTERNAL;
1953 							} else {
1954 								compare_vals( m1, m2 );
1955 								if ( !m1->sml_numvals )
1956 									goto drop;
1957 							}
1958 						} else if ( m1->sml_op == LDAP_MOD_ADD ) {
1959 							compare_vals( m1, m2 );
1960 							if ( !m1->sml_numvals )
1961 								goto drop;
1962 						}
1963 					}
1964 
1965 					if ( m2->sml_op == LDAP_MOD_ADD ||
1966 						m2->sml_op == LDAP_MOD_REPLACE ) {
1967 						if ( m1->sml_op == LDAP_MOD_DELETE ) {
1968 							if ( !m1->sml_numvals ) goto drop;
1969 							compare_vals( m1, m2 );
1970 							if ( !m1->sml_numvals )
1971 								goto drop;
1972 						}
1973 						if ( m2->sml_desc->ad_type->sat_atype.at_single_value )
1974 							goto drop;
1975 						compare_vals( m1, m2 );
1976 						if ( !m1->sml_numvals )
1977 							goto drop;
1978 					}
1979 					prev = &m1->sml_next;
1980 				}
1981 			}
1982 			slap_mods_free( newmods, 1 );
1983 			rx->rx_mods = oldmods;
1984 		}
1985 	}
1986 	return LDAP_SUCCESS;
1987 }
1988 
1989 typedef struct modify_ctxt {
1990 	Modifications *mx_orig;
1991 	Modifications *mx_free;
1992 } modify_ctxt;
1993 
1994 static int
1995 syncrepl_modify_cb( Operation *op, SlapReply *rs )
1996 {
1997 	slap_callback *sc = op->o_callback;
1998 	modify_ctxt *mx = sc->sc_private;
1999 	Modifications *ml;
2000 
2001 	op->orm_no_opattrs = 0;
2002 	op->orm_modlist = mx->mx_orig;
2003 	for ( ml = mx->mx_free; ml; ml = mx->mx_free ) {
2004 		mx->mx_free = ml->sml_next;
2005 		op->o_tmpfree( ml, op->o_tmpmemctx );
2006 	}
2007 	op->o_callback = sc->sc_next;
2008 	op->o_tmpfree( sc, op->o_tmpmemctx );
2009 	return SLAP_CB_CONTINUE;
2010 }
2011 
2012 static int
2013 syncrepl_op_modify( Operation *op, SlapReply *rs )
2014 {
2015 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
2016 	OpExtra *oex;
2017 	syncinfo_t *si;
2018 	Entry *e;
2019 	int rc, match = 0;
2020 	Modifications *mod, *newlist;
2021 
2022 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
2023 		if ( oex->oe_key == (void *)syncrepl_message_to_op )
2024 			break;
2025 	}
2026 	if ( !oex )
2027 		return SLAP_CB_CONTINUE;
2028 
2029 	si = ((OpExtraSync *)oex)->oe_si;
2030 
2031 	/* Check if entryCSN in modlist is newer than entryCSN in entry.
2032 	 * We do it here because the op has been serialized by accesslog
2033 	 * by the time we get here. If the CSN is new enough, just do the
2034 	 * mod. If not, we need to resolve conflicts.
2035 	 */
2036 
2037 	for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
2038 		if ( mod->sml_desc == slap_schema.si_ad_entryCSN ) break;
2039 	}
2040 	/* FIXME: what should we do if entryCSN is missing from the mod? */
2041 	if ( !mod )
2042 		return SLAP_CB_CONTINUE;
2043 
2044 	rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
2045 	if ( rc == 0 ) {
2046 		Attribute *a;
2047 		const char *text;
2048 		a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
2049 		value_match( &match, slap_schema.si_ad_entryCSN,
2050 			slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
2051 			SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
2052 			&mod->sml_nvalues[0], &a->a_nvals[0], &text );
2053 		overlay_entry_release_ov( op, e, 0, on );
2054 	}
2055 	/* equal? Should never happen */
2056 	if ( match == 0 )
2057 		return LDAP_SUCCESS;
2058 
2059 	/* mod is older: resolve conflicts...
2060 	 * 1. Save/copy original modlist. Split Replace to Del/Add.
2061 	 * 2. Find all mods to this reqDN newer than the mod stamp.
2062 	 * 3. Resolve any mods in this request that affect attributes
2063 	 *    touched by newer mods.
2064 	 *    old         new
2065 	 *    delete all  delete all  drop
2066 	 *    delete all  delete X    SOFTDEL
2067 	 *    delete X    delete all  drop
2068 	 *    delete X    delete X    drop
2069 	 *    delete X    delete Y    OK
2070 	 *    delete all  add X       drop
2071 	 *    delete X    add X       drop
2072 	 *    delete X    add Y       OK
2073 	 *    add X       delete all  drop
2074 	 *    add X       delete X    drop
2075 	 *    add X       add X       drop
2076 	 *    add X       add Y       if SV, drop else OK
2077 	 *
2078 	 * 4. Swap original modlist back in response callback so
2079 	 *    that accesslog logs the original mod.
2080 	 *
2081 	 * Even if the mod is newer, other out-of-order changes may
2082 	 * have been committed, forcing us to tweak the modlist:
2083 	 * 1. Save/copy original modlist.
2084 	 * 2. Change deletes to soft deletes.
2085 	 * 3. Change Adds of single-valued attrs to Replace.
2086 	 */
2087 
2088 	newlist = mods_dup( op, op->orm_modlist, match );
2089 
2090 	/* mod is older */
2091 	if ( match < 0 ) {
2092 		Operation op2 = *op;
2093 		AttributeName an[2];
2094 		const char *text;
2095 		struct berval bv;
2096 		char *ptr;
2097 		Modifications *ml;
2098 		int size, rc;
2099 		SlapReply rs1 = {0};
2100 		resolve_ctxt rx;
2101 		slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
2102 
2103 		rx.rx_si = si;
2104 		rx.rx_mods = newlist;
2105 		cb.sc_private = &rx;
2106 
2107 		op2.o_tag = LDAP_REQ_SEARCH;
2108 		op2.ors_scope = LDAP_SCOPE_SUBTREE;
2109 		op2.ors_deref = LDAP_DEREF_NEVER;
2110 		op2.o_req_dn = si->si_logbase;
2111 		op2.o_req_ndn = si->si_logbase;
2112 		op2.ors_tlimit = SLAP_NO_LIMIT;
2113 		op2.ors_slimit = SLAP_NO_LIMIT;
2114 		op2.ors_limit = NULL;
2115 		memset( an, 0, sizeof(an));
2116 		an[0].an_desc = ad_reqMod;
2117 		an[0].an_name = ad_reqMod->ad_cname;
2118 		op2.ors_attrs = an;
2119 		op2.ors_attrsonly = 0;
2120 
2121 		bv = mod->sml_nvalues[0];
2122 
2123 		size = sizeof("(&(entryCSN>=)(reqDN=))");
2124 		size += bv.bv_len + op->o_req_ndn.bv_len + si->si_logfilterstr.bv_len;
2125 		op2.ors_filterstr.bv_val = op->o_tmpalloc( size, op->o_tmpmemctx );
2126 		op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
2127 			"(&(entryCSN>=%s)(reqDN=%s)%s)",
2128 			bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
2129 		op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val );
2130 
2131 		op2.o_callback = &cb;
2132 		op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
2133 		op2.o_bd->be_search( &op2, &rs1 );
2134 		newlist = rx.rx_mods;
2135 	}
2136 
2137 	{
2138 		slap_callback *sc = op->o_tmpalloc( sizeof(slap_callback) +
2139 			sizeof(modify_ctxt), op->o_tmpmemctx );
2140 		modify_ctxt *mx = (modify_ctxt *)(sc+1);
2141 		Modifications *ml;
2142 
2143 		sc->sc_response = syncrepl_modify_cb;
2144 		sc->sc_private = mx;
2145 		sc->sc_next = op->o_callback;
2146 		sc->sc_cleanup = NULL;
2147 		op->o_callback = sc;
2148 		op->orm_no_opattrs = 1;
2149 		mx->mx_orig = op->orm_modlist;
2150 		mx->mx_free = newlist;
2151 		for ( ml = newlist; ml; ml=ml->sml_next ) {
2152 			if ( ml->sml_flags == SLAP_MOD_INTERNAL ) {
2153 				ml->sml_flags = 0;
2154 				ml->sml_op = SLAP_MOD_SOFTDEL;
2155 			}
2156 			else if ( ml->sml_op == LDAP_MOD_DELETE )
2157 				ml->sml_op = SLAP_MOD_SOFTDEL;
2158 			else if ( ml->sml_op == LDAP_MOD_ADD &&
2159 				ml->sml_desc->ad_type->sat_atype.at_single_value )
2160 				ml->sml_op = LDAP_MOD_REPLACE;
2161 		}
2162 		op->orm_modlist = newlist;
2163 		op->o_csn = mod->sml_nvalues[0];
2164 	}
2165 	return SLAP_CB_CONTINUE;
2166 }
2167 
2168 static int
2169 syncrepl_message_to_op(
2170 	syncinfo_t	*si,
2171 	Operation	*op,
2172 	LDAPMessage	*msg
2173 )
2174 {
2175 	BerElement	*ber = NULL;
2176 	Modifications	*modlist = NULL;
2177 	logschema *ls;
2178 	SlapReply rs = { REP_RESULT };
2179 	slap_callback cb = { NULL, null_callback, NULL, NULL };
2180 
2181 	const char	*text;
2182 	char txtbuf[SLAP_TEXT_BUFLEN];
2183 	size_t textlen = sizeof txtbuf;
2184 
2185 	struct berval	bdn, dn = BER_BVNULL, ndn;
2186 	struct berval	bv, bv2, *bvals = NULL;
2187 	struct berval	rdn = BER_BVNULL, sup = BER_BVNULL,
2188 		prdn = BER_BVNULL, nrdn = BER_BVNULL,
2189 		psup = BER_BVNULL, nsup = BER_BVNULL;
2190 	int		rc, deleteOldRdn = 0, freeReqDn = 0;
2191 	int		do_graduate = 0;
2192 
2193 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
2194 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
2195 			"Message type should be entry (%d)",
2196 			si->si_ridtxt, ldap_msgtype( msg ), 0 );
2197 		return -1;
2198 	}
2199 
2200 	if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
2201 		ls = &accesslog_sc;
2202 	else
2203 		ls = &changelog_sc;
2204 
2205 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
2206 
2207 	if ( rc != LDAP_SUCCESS ) {
2208 		Debug( LDAP_DEBUG_ANY,
2209 			"syncrepl_message_to_op: %s dn get failed (%d)",
2210 			si->si_ridtxt, rc, 0 );
2211 		return rc;
2212 	}
2213 
2214 	op->o_tag = LBER_DEFAULT;
2215 	op->o_bd = si->si_wbe;
2216 
2217 	if ( BER_BVISEMPTY( &bdn )) {
2218 		Debug( LDAP_DEBUG_ANY,
2219 			"syncrepl_message_to_op: %s got empty dn",
2220 			si->si_ridtxt, 0, 0 );
2221 		return LDAP_OTHER;
2222 	}
2223 
2224 	while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
2225 		== LDAP_SUCCESS ) {
2226 		if ( bv.bv_val == NULL )
2227 			break;
2228 
2229 		if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
2230 			bdn = bvals[0];
2231 			REWRITE_DN( si, bdn, bv2, dn, ndn );
2232 			if ( rc != LDAP_SUCCESS ) {
2233 				Debug( LDAP_DEBUG_ANY,
2234 					"syncrepl_message_to_op: %s "
2235 					"dn \"%s\" normalization failed (%d)",
2236 					si->si_ridtxt, bdn.bv_val, rc );
2237 				rc = -1;
2238 				ch_free( bvals );
2239 				goto done;
2240 			}
2241 			ber_dupbv( &op->o_req_dn, &dn );
2242 			ber_dupbv( &op->o_req_ndn, &ndn );
2243 			slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
2244 			slap_sl_free( dn.bv_val, op->o_tmpmemctx );
2245 			freeReqDn = 1;
2246 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_req ) ) {
2247 			int i = verb_to_mask( bvals[0].bv_val, modops );
2248 			if ( i < 0 ) {
2249 				Debug( LDAP_DEBUG_ANY,
2250 					"syncrepl_message_to_op: %s unknown op %s",
2251 					si->si_ridtxt, bvals[0].bv_val, 0 );
2252 				ch_free( bvals );
2253 				rc = -1;
2254 				goto done;
2255 			}
2256 			op->o_tag = modops[i].mask;
2257 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
2258 			/* Parse attribute into modlist */
2259 			if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
2260 				rc = syncrepl_accesslog_mods( si, bvals, &modlist );
2261 			} else {
2262 				rc = syncrepl_changelog_mods( si, bvals, &modlist );
2263 			}
2264 			if ( rc ) goto done;
2265 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
2266 			rdn = bvals[0];
2267 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
2268 			if ( !ber_bvstrcasecmp( &slap_true_bv, bvals ) ) {
2269 				deleteOldRdn = 1;
2270 			}
2271 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) {
2272 			sup = bvals[0];
2273 		} else if ( !ber_bvstrcasecmp( &bv,
2274 			&slap_schema.si_ad_entryCSN->ad_cname ) )
2275 		{
2276 			slap_queue_csn( op, bvals );
2277 			do_graduate = 1;
2278 		}
2279 		ch_free( bvals );
2280 	}
2281 
2282 	/* If we didn't get a mod type or a target DN, bail out */
2283 	if ( op->o_tag == LBER_DEFAULT || BER_BVISNULL( &dn ) ) {
2284 		rc = -1;
2285 		goto done;
2286 	}
2287 
2288 	op->o_callback = &cb;
2289 	slap_op_time( &op->o_time, &op->o_tincr );
2290 
2291 	switch( op->o_tag ) {
2292 	case LDAP_REQ_ADD:
2293 	case LDAP_REQ_MODIFY:
2294 		/* If we didn't get required data, bail */
2295 		if ( !modlist ) goto done;
2296 
2297 		rc = slap_mods_check( op, modlist, &text, txtbuf, textlen, NULL );
2298 
2299 		if ( rc != LDAP_SUCCESS ) {
2300 			Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
2301 				"mods check (%s)\n",
2302 				si->si_ridtxt, text, 0 );
2303 			goto done;
2304 		}
2305 
2306 		if ( op->o_tag == LDAP_REQ_ADD ) {
2307 			Entry *e = entry_alloc();
2308 			op->ora_e = e;
2309 			op->ora_e->e_name = op->o_req_dn;
2310 			op->ora_e->e_nname = op->o_req_ndn;
2311 			freeReqDn = 0;
2312 			rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen);
2313 			if( rc != LDAP_SUCCESS ) {
2314 				Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
2315 				"mods2entry (%s)\n",
2316 					si->si_ridtxt, text, 0 );
2317 			} else {
2318 				rc = op->o_bd->be_add( op, &rs );
2319 				Debug( LDAP_DEBUG_SYNC,
2320 					"syncrepl_message_to_op: %s be_add %s (%d)\n",
2321 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
2322 				do_graduate = 0;
2323 			}
2324 			if ( e == op->ora_e )
2325 				be_entry_release_w( op, op->ora_e );
2326 		} else {
2327 			OpExtraSync oes;
2328 			op->orm_modlist = modlist;
2329 			op->o_bd = si->si_wbe;
2330 			/* delta-mmr needs additional checks in syncrepl_op_modify */
2331 			if ( SLAP_MULTIMASTER( op->o_bd )) {
2332 				oes.oe.oe_key = (void *)syncrepl_message_to_op;
2333 				oes.oe_si = si;
2334 				LDAP_SLIST_INSERT_HEAD( &op->o_extra, &oes.oe, oe_next );
2335 			}
2336 			rc = op->o_bd->be_modify( op, &rs );
2337 			if ( SLAP_MULTIMASTER( op->o_bd )) {
2338 				LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
2339 				BER_BVZERO( &op->o_csn );
2340 			}
2341 			modlist = op->orm_modlist;
2342 			Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
2343 				"syncrepl_message_to_op: %s be_modify %s (%d)\n",
2344 				si->si_ridtxt, op->o_req_dn.bv_val, rc );
2345 			op->o_bd = si->si_be;
2346 			do_graduate = 0;
2347 		}
2348 		break;
2349 	case LDAP_REQ_MODRDN:
2350 		if ( BER_BVISNULL( &rdn ) ) goto done;
2351 
2352 		if ( rdnPretty( NULL, &rdn, &prdn, NULL ) ) {
2353 			goto done;
2354 		}
2355 		if ( rdnNormalize( 0, NULL, NULL, &rdn, &nrdn, NULL ) ) {
2356 			goto done;
2357 		}
2358 		if ( !BER_BVISNULL( &sup ) ) {
2359 			REWRITE_DN( si, sup, bv2, psup, nsup );
2360 			if ( rc )
2361 				goto done;
2362 			op->orr_newSup = &psup;
2363 			op->orr_nnewSup = &nsup;
2364 		} else {
2365 			op->orr_newSup = NULL;
2366 			op->orr_nnewSup = NULL;
2367 		}
2368 		op->orr_newrdn = prdn;
2369 		op->orr_nnewrdn = nrdn;
2370 		op->orr_deleteoldrdn = deleteOldRdn;
2371 		op->orr_modlist = NULL;
2372 		if ( slap_modrdn2mods( op, &rs ) ) {
2373 			goto done;
2374 		}
2375 
2376 		/* Append modlist for operational attrs */
2377 		{
2378 			Modifications *m;
2379 
2380 			for ( m = op->orr_modlist; m->sml_next; m = m->sml_next )
2381 				;
2382 			m->sml_next = modlist;
2383 			modlist = NULL;
2384 		}
2385 		rc = op->o_bd->be_modrdn( op, &rs );
2386 		slap_mods_free( op->orr_modlist, 1 );
2387 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
2388 			"syncrepl_message_to_op: %s be_modrdn %s (%d)\n",
2389 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
2390 		do_graduate = 0;
2391 		break;
2392 	case LDAP_REQ_DELETE:
2393 		rc = op->o_bd->be_delete( op, &rs );
2394 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
2395 			"syncrepl_message_to_op: %s be_delete %s (%d)\n",
2396 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
2397 		do_graduate = 0;
2398 		break;
2399 	}
2400 done:
2401 	if ( do_graduate )
2402 		slap_graduate_commit_csn( op );
2403 	op->o_bd = si->si_be;
2404 	op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
2405 	BER_BVZERO( &op->o_csn );
2406 	if ( modlist ) {
2407 		slap_mods_free( modlist, op->o_tag != LDAP_REQ_ADD );
2408 	}
2409 	if ( !BER_BVISNULL( &rdn ) ) {
2410 		if ( !BER_BVISNULL( &nsup ) ) {
2411 			ch_free( nsup.bv_val );
2412 		}
2413 		if ( !BER_BVISNULL( &psup ) ) {
2414 			ch_free( psup.bv_val );
2415 		}
2416 		if ( !BER_BVISNULL( &nrdn ) ) {
2417 			ch_free( nrdn.bv_val );
2418 		}
2419 		if ( !BER_BVISNULL( &prdn ) ) {
2420 			ch_free( prdn.bv_val );
2421 		}
2422 	}
2423 	if ( freeReqDn ) {
2424 		ch_free( op->o_req_ndn.bv_val );
2425 		ch_free( op->o_req_dn.bv_val );
2426 	}
2427 	ber_free( ber, 0 );
2428 	return rc;
2429 }
2430 
2431 static int
2432 syncrepl_message_to_entry(
2433 	syncinfo_t	*si,
2434 	Operation	*op,
2435 	LDAPMessage	*msg,
2436 	Modifications	**modlist,
2437 	Entry			**entry,
2438 	int		syncstate,
2439 	struct berval	*syncUUID
2440 )
2441 {
2442 	Entry		*e = NULL;
2443 	BerElement	*ber = NULL;
2444 	Modifications	tmp;
2445 	Modifications	*mod;
2446 	Modifications	**modtail = modlist;
2447 
2448 	const char	*text;
2449 	char txtbuf[SLAP_TEXT_BUFLEN];
2450 	size_t textlen = sizeof txtbuf;
2451 
2452 	struct berval	bdn = BER_BVNULL, dn, ndn, bv2;
2453 	int		rc, is_ctx;
2454 
2455 	*modlist = NULL;
2456 
2457 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
2458 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s "
2459 			"Message type should be entry (%d)",
2460 			si->si_ridtxt, ldap_msgtype( msg ), 0 );
2461 		return -1;
2462 	}
2463 
2464 	op->o_tag = LDAP_REQ_ADD;
2465 
2466 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
2467 	if ( rc != LDAP_SUCCESS ) {
2468 		Debug( LDAP_DEBUG_ANY,
2469 			"syncrepl_message_to_entry: %s dn get failed (%d)",
2470 			si->si_ridtxt, rc, 0 );
2471 		return rc;
2472 	}
2473 
2474 	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
2475 		Debug( LDAP_DEBUG_ANY,
2476 			"syncrepl_message_to_entry: %s got empty dn",
2477 			si->si_ridtxt, 0, 0 );
2478 		return LDAP_OTHER;
2479 	}
2480 
2481 	/* syncUUID[0] is normalized UUID received over the wire
2482 	 * syncUUID[1] is denormalized UUID, generated here
2483 	 */
2484 	(void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
2485 	Debug( LDAP_DEBUG_SYNC,
2486 		"syncrepl_message_to_entry: %s DN: %s, UUID: %s\n",
2487 		si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
2488 
2489 	if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
2490 		/* NOTE: this could be done even before decoding the DN,
2491 		 * although encoding errors wouldn't be detected */
2492 		rc = LDAP_SUCCESS;
2493 		goto done;
2494 	}
2495 
2496 	if ( entry == NULL ) {
2497 		return -1;
2498 	}
2499 
2500 	REWRITE_DN( si, bdn, bv2, dn, ndn );
2501 	if ( rc != LDAP_SUCCESS ) {
2502 		/* One of the things that could happen is that the schema
2503 		 * is not lined-up; this could result in unknown attributes.
2504 		 * A value non conformant to the syntax should be unlikely,
2505 		 * except when replicating between different versions
2506 		 * of the software, or when syntax validation bugs are fixed
2507 		 */
2508 		Debug( LDAP_DEBUG_ANY,
2509 			"syncrepl_message_to_entry: "
2510 			"%s dn \"%s\" normalization failed (%d)",
2511 			si->si_ridtxt, bdn.bv_val, rc );
2512 		return rc;
2513 	}
2514 
2515 	ber_dupbv( &op->o_req_dn, &dn );
2516 	ber_dupbv( &op->o_req_ndn, &ndn );
2517 	slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
2518 	slap_sl_free( dn.bv_val, op->o_tmpmemctx );
2519 
2520 	is_ctx = dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] );
2521 
2522 	e = entry_alloc();
2523 	e->e_name = op->o_req_dn;
2524 	e->e_nname = op->o_req_ndn;
2525 
2526 	while ( ber_remaining( ber ) ) {
2527 		if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
2528 			LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
2529 		{
2530 			break;
2531 		}
2532 
2533 		/* Drop all updates to the contextCSN of the context entry
2534 		 * (ITS#4622, etc.)
2535 		 */
2536 		if ( is_ctx && !strcasecmp( tmp.sml_type.bv_val,
2537 			slap_schema.si_ad_contextCSN->ad_cname.bv_val )) {
2538 			ber_bvarray_free( tmp.sml_values );
2539 			continue;
2540 		}
2541 
2542 		mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
2543 
2544 		mod->sml_op = LDAP_MOD_REPLACE;
2545 		mod->sml_flags = 0;
2546 		mod->sml_next = NULL;
2547 		mod->sml_desc = NULL;
2548 		mod->sml_type = tmp.sml_type;
2549 		mod->sml_values = tmp.sml_values;
2550 		mod->sml_nvalues = NULL;
2551 		mod->sml_numvals = 0;	/* slap_mods_check will set this */
2552 
2553 #ifdef ENABLE_REWRITE
2554 		if (si->si_rewrite) {
2555 			AttributeDescription *ad = NULL;
2556 			slap_bv2ad( &tmp.sml_type, &ad, &text );
2557 			if ( ad ) {
2558 				mod->sml_desc = ad;
2559 				mod->sml_type = ad->ad_cname;
2560 				if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
2561 					int i;
2562 					for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
2563 						syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
2564 						if ( !BER_BVISNULL( &bv2 )) {
2565 							ber_memfree( tmp.sml_values[i].bv_val );
2566 							tmp.sml_values[i] = bv2;
2567 						}
2568 					}
2569 				}
2570 			}
2571 		}
2572 #endif
2573 		*modtail = mod;
2574 		modtail = &mod->sml_next;
2575 	}
2576 
2577 	if ( *modlist == NULL ) {
2578 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s no attributes\n",
2579 			si->si_ridtxt, 0, 0 );
2580 		rc = -1;
2581 		goto done;
2582 	}
2583 
2584 	rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
2585 
2586 	if ( rc != LDAP_SUCCESS ) {
2587 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods check (%s)\n",
2588 			si->si_ridtxt, text, 0 );
2589 		goto done;
2590 	}
2591 
2592 	/* Strip out dynamically generated attrs */
2593 	for ( modtail = modlist; *modtail ; ) {
2594 		mod = *modtail;
2595 		if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
2596 			*modtail = mod->sml_next;
2597 			slap_mod_free( &mod->sml_mod, 0 );
2598 			ch_free( mod );
2599 		} else {
2600 			modtail = &mod->sml_next;
2601 		}
2602 	}
2603 
2604 	/* Strip out attrs in exattrs list */
2605 	for ( modtail = modlist; *modtail ; ) {
2606 		mod = *modtail;
2607 		if ( ldap_charray_inlist( si->si_exattrs,
2608 			mod->sml_desc->ad_type->sat_cname.bv_val ) )
2609 		{
2610 			*modtail = mod->sml_next;
2611 			slap_mod_free( &mod->sml_mod, 0 );
2612 			ch_free( mod );
2613 		} else {
2614 			modtail = &mod->sml_next;
2615 		}
2616 	}
2617 
2618 	rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
2619 	if( rc != LDAP_SUCCESS ) {
2620 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods2entry (%s)\n",
2621 			si->si_ridtxt, text, 0 );
2622 	}
2623 
2624 done:
2625 	ber_free( ber, 0 );
2626 	if ( rc != LDAP_SUCCESS ) {
2627 		if ( e ) {
2628 			entry_free( e );
2629 			e = NULL;
2630 		}
2631 	}
2632 	if ( entry )
2633 		*entry = e;
2634 
2635 	return rc;
2636 }
2637 
2638 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
2639 
2640 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
2641  * entry if a previous refresh was interrupted before sending us a new
2642  * context state. We try to compare the new entry to the existing entry
2643  * and ignore the new entry if they are the same.
2644  *
2645  * Also, we may get an update where the entryDN has changed, due to
2646  * a ModDn on the provider. We detect this as well, so we can issue
2647  * the corresponding operation locally.
2648  *
2649  * In the case of a modify, we get a list of all the attributes
2650  * in the original entry. Rather than deleting the entry and re-adding it,
2651  * we issue a Modify request that deletes all the attributes and adds all
2652  * the new ones. This avoids the issue of trying to delete/add a non-leaf
2653  * entry.
2654  *
2655  * We otherwise distinguish ModDN from Modify; in the case of
2656  * a ModDN we just use the CSN, modifyTimestamp and modifiersName
2657  * operational attributes from the entry, and do a regular ModDN.
2658  */
2659 typedef struct dninfo {
2660 	Entry *new_entry;
2661 	struct berval dn;
2662 	struct berval ndn;
2663 	struct berval nnewSup;
2664 	int renamed;	/* Was an existing entry renamed? */
2665 	int delOldRDN;	/* Was old RDN deleted? */
2666 	Modifications **modlist;	/* the modlist we received */
2667 	Modifications *mods;	/* the modlist we compared */
2668 	int oldNcount;		/* #values of old naming attr */
2669 	AttributeDescription *oldDesc;	/* for renames */
2670 	AttributeDescription *newDesc;	/* for renames */
2671 } dninfo;
2672 
2673 /* return 1 if inserted, 0 otherwise */
2674 static int
2675 avl_presentlist_insert(
2676 	syncinfo_t* si,
2677 	struct berval *syncUUID )
2678 {
2679 	struct berval *syncuuid_bv = ch_malloc( sizeof( struct berval ) + syncUUID->bv_len + 1 );
2680 
2681 	syncuuid_bv->bv_len = syncUUID->bv_len;
2682 	syncuuid_bv->bv_val = (char *)&syncuuid_bv[1];
2683 	AC_MEMCPY( syncuuid_bv->bv_val, syncUUID->bv_val, syncUUID->bv_len );
2684 	syncuuid_bv->bv_val[ syncuuid_bv->bv_len ] = '\0';
2685 
2686 	if ( avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
2687 		syncuuid_cmp, avl_dup_error ) )
2688 	{
2689 		ch_free( syncuuid_bv );
2690 		return 0;
2691 	}
2692 
2693 	return 1;
2694 }
2695 
2696 static int
2697 syncrepl_entry(
2698 	syncinfo_t* si,
2699 	Operation *op,
2700 	Entry* entry,
2701 	Modifications** modlist,
2702 	int syncstate,
2703 	struct berval* syncUUID,
2704 	struct berval* syncCSN )
2705 {
2706 	Backend *be = op->o_bd;
2707 	slap_callback	cb = { NULL, NULL, NULL, NULL };
2708 	int syncuuid_inserted = 0;
2709 
2710 	SlapReply	rs_search = {REP_RESULT};
2711 	Filter f = {0};
2712 	AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
2713 	int rc = LDAP_SUCCESS;
2714 
2715 	struct berval pdn = BER_BVNULL;
2716 	dninfo dni = {0};
2717 	int	retry = 1;
2718 	int	freecsn = 1;
2719 
2720 	Debug( LDAP_DEBUG_SYNC,
2721 		"syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s)\n",
2722 		si->si_ridtxt, syncrepl_state2str( syncstate ), 0 );
2723 
2724 	if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
2725 		if ( !si->si_refreshPresent && !si->si_refreshDone ) {
2726 			syncuuid_inserted = avl_presentlist_insert( si, syncUUID );
2727 		}
2728 	}
2729 
2730 	if ( syncstate == LDAP_SYNC_PRESENT ) {
2731 		return 0;
2732 	} else if ( syncstate != LDAP_SYNC_DELETE ) {
2733 		if ( entry == NULL ) {
2734 			return 0;
2735 		}
2736 	}
2737 
2738 	if ( syncstate != LDAP_SYNC_DELETE ) {
2739 		Attribute	*a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
2740 
2741 		if ( a == NULL ) {
2742 			/* add if missing */
2743 			attr_merge_one( entry, slap_schema.si_ad_entryUUID,
2744 				&syncUUID[1], syncUUID );
2745 
2746 		} else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
2747 			/* replace only if necessary */
2748 			if ( a->a_nvals != a->a_vals ) {
2749 				ber_memfree( a->a_nvals[0].bv_val );
2750 				ber_dupbv( &a->a_nvals[0], syncUUID );
2751 			}
2752 			ber_memfree( a->a_vals[0].bv_val );
2753 			ber_dupbv( &a->a_vals[0], &syncUUID[1] );
2754 		}
2755 	}
2756 
2757 	f.f_choice = LDAP_FILTER_EQUALITY;
2758 	f.f_ava = &ava;
2759 	ava.aa_desc = slap_schema.si_ad_entryUUID;
2760 	ava.aa_value = *syncUUID;
2761 
2762 	if ( syncuuid_inserted ) {
2763 		Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
2764 			si->si_ridtxt, syncUUID[1].bv_val, 0 );
2765 	}
2766 	op->ors_filter = &f;
2767 
2768 	op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID[1].bv_len;
2769 	op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
2770 		op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
2771 	AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
2772 	AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
2773 		syncUUID[1].bv_val, syncUUID[1].bv_len );
2774 	op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
2775 	op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
2776 
2777 	op->o_tag = LDAP_REQ_SEARCH;
2778 	op->ors_scope = LDAP_SCOPE_SUBTREE;
2779 	op->ors_deref = LDAP_DEREF_NEVER;
2780 
2781 	/* get the entry for this UUID */
2782 #ifdef ENABLE_REWRITE
2783 	if ( si->si_rewrite ) {
2784 		op->o_req_dn = si->si_suffixm;
2785 		op->o_req_ndn = si->si_suffixm;
2786 	} else
2787 #endif
2788 	{
2789 		op->o_req_dn = si->si_base;
2790 		op->o_req_ndn = si->si_base;
2791 	}
2792 
2793 	op->o_time = slap_get_time();
2794 	op->ors_tlimit = SLAP_NO_LIMIT;
2795 	op->ors_slimit = 1;
2796 	op->ors_limit = NULL;
2797 
2798 	op->ors_attrs = slap_anlist_all_attributes;
2799 	op->ors_attrsonly = 0;
2800 
2801 	/* set callback function */
2802 	op->o_callback = &cb;
2803 	cb.sc_response = dn_callback;
2804 	cb.sc_private = &dni;
2805 	dni.new_entry = entry;
2806 	dni.modlist = modlist;
2807 
2808 	rc = be->be_search( op, &rs_search );
2809 	Debug( LDAP_DEBUG_SYNC,
2810 			"syncrepl_entry: %s be_search (%d)\n",
2811 			si->si_ridtxt, rc, 0 );
2812 
2813 	if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
2814 		slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
2815 	}
2816 
2817 	cb.sc_response = null_callback;
2818 	cb.sc_private = si;
2819 
2820 	if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
2821 		Debug( LDAP_DEBUG_SYNC,
2822 				"syncrepl_entry: %s %s\n",
2823 				si->si_ridtxt, entry->e_name.bv_val, 0 );
2824 	} else {
2825 		Debug( LDAP_DEBUG_SYNC,
2826 				"syncrepl_entry: %s %s\n",
2827 				si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0 );
2828 	}
2829 
2830 	assert( BER_BVISNULL( &op->o_csn ) );
2831 	if ( syncCSN ) {
2832 		slap_queue_csn( op, syncCSN );
2833 	}
2834 
2835 	slap_op_time( &op->o_time, &op->o_tincr );
2836 	switch ( syncstate ) {
2837 	case LDAP_SYNC_ADD:
2838 	case LDAP_SYNC_MODIFY:
2839 		if ( BER_BVISNULL( &op->o_csn ))
2840 		{
2841 
2842 			Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryCSN );
2843 			if ( a ) {
2844 				/* FIXME: op->o_csn is assumed to be
2845 				 * on the thread's slab; this needs
2846 				 * to be cleared ASAP.
2847 				 */
2848 				op->o_csn = a->a_vals[0];
2849 				freecsn = 0;
2850 			}
2851 		}
2852 retry_add:;
2853 		if ( BER_BVISNULL( &dni.dn ) ) {
2854 			SlapReply	rs_add = {REP_RESULT};
2855 
2856 			op->o_req_dn = entry->e_name;
2857 			op->o_req_ndn = entry->e_nname;
2858 			op->o_tag = LDAP_REQ_ADD;
2859 			op->ora_e = entry;
2860 			op->o_bd = si->si_wbe;
2861 
2862 			rc = op->o_bd->be_add( op, &rs_add );
2863 			Debug( LDAP_DEBUG_SYNC,
2864 					"syncrepl_entry: %s be_add %s (%d)\n",
2865 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
2866 			switch ( rs_add.sr_err ) {
2867 			case LDAP_SUCCESS:
2868 				if ( op->ora_e == entry ) {
2869 					be_entry_release_w( op, entry );
2870 				}
2871 				entry = NULL;
2872 				break;
2873 
2874 			case LDAP_REFERRAL:
2875 			/* we assume that LDAP_NO_SUCH_OBJECT is returned
2876 			 * only if the suffix entry is not present.
2877 			 * This should not happen during Persist phase.
2878 			 */
2879 			case LDAP_NO_SUCH_OBJECT:
2880 				if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
2881 					si->si_refreshDone ) {
2882 					/* Something's wrong, start over */
2883 					ber_bvarray_free( si->si_syncCookie.ctxcsn );
2884 					si->si_syncCookie.ctxcsn = NULL;
2885 					ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
2886 					ber_bvarray_free( si->si_cookieState->cs_vals );
2887 					ch_free( si->si_cookieState->cs_sids );
2888 					si->si_cookieState->cs_vals = NULL;
2889 					si->si_cookieState->cs_sids = 0;
2890 					si->si_cookieState->cs_num = 0;
2891 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
2892 					return LDAP_NO_SUCH_OBJECT;
2893 				}
2894 				rc = syncrepl_add_glue( op, entry );
2895 				entry = NULL;
2896 				break;
2897 
2898 			/* if an entry was added via syncrepl_add_glue(),
2899 			 * it likely has no entryUUID, so the previous
2900 			 * be_search() doesn't find it.  In this case,
2901 			 * give syncrepl a chance to modify it. Also
2902 			 * allow for entries that were recreated with the
2903 			 * same DN but a different entryUUID.
2904 			 */
2905 			case LDAP_ALREADY_EXISTS:
2906 				if ( retry ) {
2907 					Operation	op2 = *op;
2908 					SlapReply	rs2 = { REP_RESULT };
2909 					slap_callback	cb2 = { 0 };
2910 
2911 					op2.o_bd = be;
2912 					op2.o_tag = LDAP_REQ_SEARCH;
2913 					op2.o_req_dn = entry->e_name;
2914 					op2.o_req_ndn = entry->e_nname;
2915 					op2.ors_scope = LDAP_SCOPE_BASE;
2916 					op2.ors_deref = LDAP_DEREF_NEVER;
2917 					op2.ors_attrs = slap_anlist_all_attributes;
2918 					op2.ors_attrsonly = 0;
2919 					op2.ors_limit = NULL;
2920 					op2.ors_slimit = 1;
2921 					op2.ors_tlimit = SLAP_NO_LIMIT;
2922 
2923 					f.f_choice = LDAP_FILTER_PRESENT;
2924 					f.f_desc = slap_schema.si_ad_objectClass;
2925 					op2.ors_filter = &f;
2926 					op2.ors_filterstr = generic_filterstr;
2927 
2928 					op2.o_callback = &cb2;
2929 					cb2.sc_response = dn_callback;
2930 					cb2.sc_private = &dni;
2931 
2932 					rc = be->be_search( &op2, &rs2 );
2933 					if ( rc ) goto done;
2934 
2935 					retry = 0;
2936 					slap_op_time( &op->o_time, &op->o_tincr );
2937 					goto retry_add;
2938 				}
2939 				/* FALLTHRU */
2940 
2941 			default:
2942 				Debug( LDAP_DEBUG_ANY,
2943 					"syncrepl_entry: %s be_add %s failed (%d)\n",
2944 					si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
2945 				break;
2946 			}
2947 			syncCSN = NULL;
2948 			op->o_bd = be;
2949 			goto done;
2950 		}
2951 		/* FALLTHRU */
2952 		op->o_req_dn = dni.dn;
2953 		op->o_req_ndn = dni.ndn;
2954 		if ( dni.renamed ) {
2955 			struct berval noldp, newp;
2956 			Modifications *mod, **modtail, **ml, *m2;
2957 			int i, got_replace = 0, just_rename = 0;
2958 			SlapReply rs_modify = {REP_RESULT};
2959 
2960 			op->o_tag = LDAP_REQ_MODRDN;
2961 			dnRdn( &entry->e_name, &op->orr_newrdn );
2962 			dnRdn( &entry->e_nname, &op->orr_nnewrdn );
2963 
2964 			if ( !BER_BVISNULL( &dni.nnewSup )) {
2965 				dnParent( &entry->e_name, &newp );
2966 				op->orr_newSup = &newp;
2967 				op->orr_nnewSup = &dni.nnewSup;
2968 			} else {
2969 				op->orr_newSup = NULL;
2970 				op->orr_nnewSup = NULL;
2971 			}
2972 			op->orr_deleteoldrdn = dni.delOldRDN;
2973 			op->orr_modlist = NULL;
2974 			if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
2975 				goto done;
2976 			}
2977 
2978 			/* Drop the RDN-related mods from this op, because their
2979 			 * equivalents were just setup by slap_modrdn2mods.
2980 			 *
2981 			 * If delOldRDN is TRUE then we should see a delete modop
2982 			 * for oldDesc. We might see a replace instead.
2983 			 *  delete with no values: therefore newDesc != oldDesc.
2984 			 *   if oldNcount == 1, then Drop this op.
2985 			 *  delete with 1 value: can only be the oldRDN value. Drop op.
2986 			 *  delete with N values: Drop oldRDN value, keep remainder.
2987 			 *  replace with 1 value: if oldNcount == 1 and
2988 			 *     newDesc == oldDesc, Drop this op.
2989 			 * Any other cases must be left intact.
2990 			 *
2991 			 * We should also see an add modop for newDesc. (But not if
2992 			 * we got a replace modop due to delOldRDN.) If it has
2993 			 * multiple values, we'll have to drop the new RDN value.
2994 			 */
2995 			modtail = &op->orr_modlist;
2996 			if ( dni.delOldRDN ) {
2997 				for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
2998 					if ( (*ml)->sml_desc == dni.oldDesc ) {
2999 						mod = *ml;
3000 						if ( mod->sml_op == LDAP_MOD_REPLACE &&
3001 							dni.oldDesc != dni.newDesc ) {
3002 							/* This Replace is due to other Mods.
3003 							 * Just let it ride.
3004 							 */
3005 							continue;
3006 						}
3007 						if ( mod->sml_numvals <= 1 &&
3008 							dni.oldNcount == 1 &&
3009 							( mod->sml_op == LDAP_MOD_DELETE ||
3010 							  mod->sml_op == LDAP_MOD_REPLACE )) {
3011 							if ( mod->sml_op == LDAP_MOD_REPLACE )
3012 								got_replace = 1;
3013 							/* Drop this op */
3014 							*ml = mod->sml_next;
3015 							mod->sml_next = NULL;
3016 							slap_mods_free( mod, 1 );
3017 							break;
3018 						}
3019 						if ( mod->sml_op != LDAP_MOD_DELETE || mod->sml_numvals == 0 )
3020 							continue;
3021 						for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
3022 							if ( m2->sml_desc == dni.oldDesc &&
3023 								m2->sml_op == LDAP_MOD_DELETE ) break;
3024 						}
3025 						for ( i=0; i<mod->sml_numvals; i++ ) {
3026 							if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
3027 								mod->sml_numvals--;
3028 								ch_free( mod->sml_values[i].bv_val );
3029 								mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
3030 								BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
3031 								if ( mod->sml_nvalues ) {
3032 									ch_free( mod->sml_nvalues[i].bv_val );
3033 									mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
3034 									BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
3035 								}
3036 								break;
3037 							}
3038 						}
3039 						if ( !mod->sml_numvals ) {
3040 							/* Drop this op */
3041 							*ml = mod->sml_next;
3042 							mod->sml_next = NULL;
3043 							slap_mods_free( mod, 1 );
3044 						}
3045 						break;
3046 					}
3047 				}
3048 			}
3049 			if ( !got_replace ) {
3050 				for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
3051 					if ( (*ml)->sml_desc == dni.newDesc ) {
3052 						mod = *ml;
3053 						if ( mod->sml_op != LDAP_MOD_ADD )
3054 							continue;
3055 						if ( mod->sml_numvals == 1 ) {
3056 							/* Drop this op */
3057 							*ml = mod->sml_next;
3058 							mod->sml_next = NULL;
3059 							slap_mods_free( mod, 1 );
3060 							break;
3061 						}
3062 						for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
3063 							if ( m2->sml_desc == dni.oldDesc &&
3064 								m2->sml_op == SLAP_MOD_SOFTADD ) break;
3065 						}
3066 						for ( i=0; i<mod->sml_numvals; i++ ) {
3067 							if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
3068 								mod->sml_numvals--;
3069 								ch_free( mod->sml_values[i].bv_val );
3070 								mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
3071 								BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
3072 								if ( mod->sml_nvalues ) {
3073 									ch_free( mod->sml_nvalues[i].bv_val );
3074 									mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
3075 									BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
3076 								}
3077 								break;
3078 							}
3079 						}
3080 						break;
3081 					}
3082 				}
3083 			}
3084 
3085 			/* RDNs must be NUL-terminated for back-ldap */
3086 			noldp = op->orr_newrdn;
3087 			ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
3088 			noldp = op->orr_nnewrdn;
3089 			ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
3090 
3091 			/* Setup opattrs too */
3092 			{
3093 				static AttributeDescription *nullattr = NULL;
3094 				static AttributeDescription **const opattrs[] = {
3095 					&slap_schema.si_ad_entryCSN,
3096 					&slap_schema.si_ad_modifiersName,
3097 					&slap_schema.si_ad_modifyTimestamp,
3098 					&nullattr
3099 				};
3100 				AttributeDescription *opattr;
3101 				int i;
3102 
3103 				modtail = &m2;
3104 				/* pull mod off incoming modlist */
3105 				for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
3106 					for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next )
3107 					{
3108 						if ( (*ml)->sml_desc == opattr ) {
3109 							mod = *ml;
3110 							*ml = mod->sml_next;
3111 							mod->sml_next = NULL;
3112 							*modtail = mod;
3113 							modtail = &mod->sml_next;
3114 							break;
3115 						}
3116 					}
3117 				}
3118 				/* If there are still Modifications left, put the opattrs
3119 				 * back, and let be_modify run. Otherwise, append the opattrs
3120 				 * to the orr_modlist.
3121 				 */
3122 				if ( dni.mods ) {
3123 					mod = dni.mods;
3124 					/* don't set a CSN for the rename op */
3125 					if ( syncCSN )
3126 						slap_graduate_commit_csn( op );
3127 				} else {
3128 					mod = op->orr_modlist;
3129 					just_rename = 1;
3130 				}
3131 				for ( ; mod->sml_next; mod=mod->sml_next );
3132 				mod->sml_next = m2;
3133 			}
3134 			op->o_bd = si->si_wbe;
3135 retry_modrdn:;
3136 			rs_reinit( &rs_modify, REP_RESULT );
3137 			rc = op->o_bd->be_modrdn( op, &rs_modify );
3138 
3139 			/* NOTE: noSuchObject should result because the new superior
3140 			 * has not been added yet (ITS#6472) */
3141 			if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
3142 				Operation op2 = *op;
3143 				rc = syncrepl_add_glue_ancestors( &op2, entry );
3144 				if ( rc == LDAP_SUCCESS ) {
3145 					goto retry_modrdn;
3146 				}
3147 			}
3148 
3149 			op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
3150 			op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
3151 
3152 			slap_mods_free( op->orr_modlist, 1 );
3153 			Debug( LDAP_DEBUG_SYNC,
3154 					"syncrepl_entry: %s be_modrdn %s (%d)\n",
3155 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
3156 			op->o_bd = be;
3157 			/* Renamed entries may still have other mods so just fallthru */
3158 			op->o_req_dn = entry->e_name;
3159 			op->o_req_ndn = entry->e_nname;
3160 			/* Use CSN on the modify */
3161 			if ( just_rename )
3162 				syncCSN = NULL;
3163 			else if ( syncCSN )
3164 				slap_queue_csn( op, syncCSN );
3165 		}
3166 		if ( dni.mods ) {
3167 			SlapReply rs_modify = {REP_RESULT};
3168 
3169 			op->o_tag = LDAP_REQ_MODIFY;
3170 			op->orm_modlist = dni.mods;
3171 			op->orm_no_opattrs = 1;
3172 			op->o_bd = si->si_wbe;
3173 
3174 			rc = op->o_bd->be_modify( op, &rs_modify );
3175 			slap_mods_free( op->orm_modlist, 1 );
3176 			op->orm_no_opattrs = 0;
3177 			Debug( LDAP_DEBUG_SYNC,
3178 					"syncrepl_entry: %s be_modify %s (%d)\n",
3179 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
3180 			if ( rs_modify.sr_err != LDAP_SUCCESS ) {
3181 				Debug( LDAP_DEBUG_ANY,
3182 					"syncrepl_entry: %s be_modify failed (%d)\n",
3183 					si->si_ridtxt, rs_modify.sr_err, 0 );
3184 			}
3185 			syncCSN = NULL;
3186 			op->o_bd = be;
3187 		} else if ( !dni.renamed ) {
3188 			Debug( LDAP_DEBUG_SYNC,
3189 					"syncrepl_entry: %s entry unchanged, ignored (%s)\n",
3190 					si->si_ridtxt, op->o_req_dn.bv_val, 0 );
3191 			if ( syncCSN ) {
3192 				slap_graduate_commit_csn( op );
3193 				syncCSN = NULL;
3194 			}
3195 		}
3196 		goto done;
3197 	case LDAP_SYNC_DELETE :
3198 		if ( !BER_BVISNULL( &dni.dn ) ) {
3199 			SlapReply	rs_delete = {REP_RESULT};
3200 			op->o_req_dn = dni.dn;
3201 			op->o_req_ndn = dni.ndn;
3202 			op->o_tag = LDAP_REQ_DELETE;
3203 			op->o_bd = si->si_wbe;
3204 			if ( !syncCSN ) {
3205 				slap_queue_csn( op, si->si_syncCookie.ctxcsn );
3206 			}
3207 			rc = op->o_bd->be_delete( op, &rs_delete );
3208 			Debug( LDAP_DEBUG_SYNC,
3209 					"syncrepl_entry: %s be_delete %s (%d)\n",
3210 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
3211 			if ( rc == LDAP_NO_SUCH_OBJECT )
3212 				rc = LDAP_SUCCESS;
3213 
3214 			while ( rs_delete.sr_err == LDAP_SUCCESS
3215 				&& op->o_delete_glue_parent ) {
3216 				op->o_delete_glue_parent = 0;
3217 				if ( !be_issuffix( be, &op->o_req_ndn ) ) {
3218 					slap_callback cb = { NULL };
3219 					cb.sc_response = slap_null_cb;
3220 					dnParent( &op->o_req_ndn, &pdn );
3221 					op->o_req_dn = pdn;
3222 					op->o_req_ndn = pdn;
3223 					op->o_callback = &cb;
3224 					rs_reinit( &rs_delete, REP_RESULT );
3225 					op->o_bd->be_delete( op, &rs_delete );
3226 				} else {
3227 					break;
3228 				}
3229 			}
3230 			syncCSN = NULL;
3231 			op->o_bd = be;
3232 		}
3233 		goto done;
3234 
3235 	default :
3236 		Debug( LDAP_DEBUG_ANY,
3237 			"syncrepl_entry: %s unknown syncstate\n", si->si_ridtxt, 0, 0 );
3238 		goto done;
3239 	}
3240 
3241 done:
3242 	slap_sl_free( syncUUID[1].bv_val, op->o_tmpmemctx );
3243 	BER_BVZERO( &syncUUID[1] );
3244 	if ( !BER_BVISNULL( &dni.ndn ) ) {
3245 		op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
3246 	}
3247 	if ( !BER_BVISNULL( &dni.dn ) ) {
3248 		op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
3249 	}
3250 	if ( entry ) {
3251 		entry_free( entry );
3252 	}
3253 	if ( syncCSN ) {
3254 		slap_graduate_commit_csn( op );
3255 	}
3256 	if ( !BER_BVISNULL( &op->o_csn ) && freecsn ) {
3257 		op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
3258 	}
3259 	BER_BVZERO( &op->o_csn );
3260 	return rc;
3261 }
3262 
3263 static struct berval gcbva[] = {
3264 	BER_BVC("top"),
3265 	BER_BVC("glue"),
3266 	BER_BVNULL
3267 };
3268 
3269 #define NP_DELETE_ONE	2
3270 
3271 static void
3272 syncrepl_del_nonpresent(
3273 	Operation *op,
3274 	syncinfo_t *si,
3275 	BerVarray uuids,
3276 	struct sync_cookie *sc,
3277 	int m )
3278 {
3279 	Backend* be = op->o_bd;
3280 	slap_callback	cb = { NULL };
3281 	struct nonpresent_entry *np_list, *np_prev;
3282 	int rc;
3283 	AttributeName	an[2];
3284 
3285 	struct berval pdn = BER_BVNULL;
3286 	struct berval csn;
3287 
3288 #ifdef ENABLE_REWRITE
3289 	if ( si->si_rewrite ) {
3290 		op->o_req_dn = si->si_suffixm;
3291 		op->o_req_ndn = si->si_suffixm;
3292 	} else
3293 #endif
3294 	{
3295 		op->o_req_dn = si->si_base;
3296 		op->o_req_ndn = si->si_base;
3297 	}
3298 
3299 	cb.sc_response = nonpresent_callback;
3300 	cb.sc_private = si;
3301 
3302 	op->o_callback = &cb;
3303 	op->o_tag = LDAP_REQ_SEARCH;
3304 	op->ors_scope = si->si_scope;
3305 	op->ors_deref = LDAP_DEREF_NEVER;
3306 	op->o_time = slap_get_time();
3307 	op->ors_tlimit = SLAP_NO_LIMIT;
3308 
3309 
3310 	if ( uuids ) {
3311 		Filter uf;
3312 		AttributeAssertion eq = ATTRIBUTEASSERTION_INIT;
3313 		int i;
3314 
3315 		op->ors_attrsonly = 1;
3316 		op->ors_attrs = slap_anlist_no_attrs;
3317 		op->ors_limit = NULL;
3318 		op->ors_filter = &uf;
3319 
3320 		uf.f_ava = &eq;
3321 		uf.f_av_desc = slap_schema.si_ad_entryUUID;
3322 		uf.f_next = NULL;
3323 		uf.f_choice = LDAP_FILTER_EQUALITY;
3324 		si->si_refreshDelete |= NP_DELETE_ONE;
3325 
3326 		for (i=0; uuids[i].bv_val; i++) {
3327 			SlapReply rs_search = {REP_RESULT};
3328 
3329 			op->ors_slimit = 1;
3330 			uf.f_av_value = uuids[i];
3331 			filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
3332 			rc = be->be_search( op, &rs_search );
3333 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
3334 		}
3335 		si->si_refreshDelete ^= NP_DELETE_ONE;
3336 	} else {
3337 		Filter *cf, *of;
3338 		Filter mmf[2];
3339 		AttributeAssertion mmaa;
3340 		SlapReply rs_search = {REP_RESULT};
3341 
3342 		memset( &an[0], 0, 2 * sizeof( AttributeName ) );
3343 		an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
3344 		an[0].an_desc = slap_schema.si_ad_entryUUID;
3345 		op->ors_attrs = an;
3346 		op->ors_slimit = SLAP_NO_LIMIT;
3347 		op->ors_tlimit = SLAP_NO_LIMIT;
3348 		op->ors_limit = NULL;
3349 		op->ors_attrsonly = 0;
3350 		op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
3351 		/* In multimaster, updates can continue to arrive while
3352 		 * we're searching. Limit the search result to entries
3353 		 * older than our newest cookie CSN.
3354 		 */
3355 		if ( SLAP_MULTIMASTER( op->o_bd )) {
3356 			Filter *f;
3357 			int i;
3358 
3359 			f = mmf;
3360 			f->f_choice = LDAP_FILTER_AND;
3361 			f->f_next = op->ors_filter;
3362 			f->f_and = f+1;
3363 			of = f->f_and;
3364 			f = of;
3365 			f->f_choice = LDAP_FILTER_LE;
3366 			f->f_ava = &mmaa;
3367 			f->f_av_desc = slap_schema.si_ad_entryCSN;
3368 			f->f_next = NULL;
3369 			BER_BVZERO( &f->f_av_value );
3370 			for ( i=0; i<sc->numcsns; i++ ) {
3371 				if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 )
3372 					f->f_av_value = sc->ctxcsn[i];
3373 			}
3374 			of = op->ors_filter;
3375 			op->ors_filter = mmf;
3376 			filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
3377 		} else {
3378 			cf = NULL;
3379 			op->ors_filterstr = si->si_filterstr;
3380 		}
3381 		op->o_nocaching = 1;
3382 
3383 
3384 		rc = be->be_search( op, &rs_search );
3385 		if ( SLAP_MULTIMASTER( op->o_bd )) {
3386 			op->ors_filter = of;
3387 		}
3388 		if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
3389 		if ( op->ors_filterstr.bv_val != si->si_filterstr.bv_val ) {
3390 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
3391 		}
3392 
3393 	}
3394 
3395 	op->o_nocaching = 0;
3396 
3397 	if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
3398 
3399 		if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
3400 			csn = sc->ctxcsn[m];
3401 		} else {
3402 			csn = si->si_syncCookie.ctxcsn[0];
3403 		}
3404 
3405 		op->o_bd = si->si_wbe;
3406 		slap_queue_csn( op, &csn );
3407 
3408 		np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
3409 		while ( np_list != NULL ) {
3410 			SlapReply rs_delete = {REP_RESULT};
3411 
3412 			LDAP_LIST_REMOVE( np_list, npe_link );
3413 			np_prev = np_list;
3414 			np_list = LDAP_LIST_NEXT( np_list, npe_link );
3415 			op->o_tag = LDAP_REQ_DELETE;
3416 			op->o_callback = &cb;
3417 			cb.sc_response = null_callback;
3418 			cb.sc_private = si;
3419 			op->o_req_dn = *np_prev->npe_name;
3420 			op->o_req_ndn = *np_prev->npe_nname;
3421 			rc = op->o_bd->be_delete( op, &rs_delete );
3422 			Debug( LDAP_DEBUG_SYNC,
3423 				"syncrepl_del_nonpresent: %s be_delete %s (%d)\n",
3424 				si->si_ridtxt, op->o_req_dn.bv_val, rc );
3425 
3426 			if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
3427 				SlapReply rs_modify = {REP_RESULT};
3428 				Modifications mod1, mod2;
3429 				mod1.sml_op = LDAP_MOD_REPLACE;
3430 				mod1.sml_flags = 0;
3431 				mod1.sml_desc = slap_schema.si_ad_objectClass;
3432 				mod1.sml_type = mod1.sml_desc->ad_cname;
3433 				mod1.sml_numvals = 2;
3434 				mod1.sml_values = &gcbva[0];
3435 				mod1.sml_nvalues = NULL;
3436 				mod1.sml_next = &mod2;
3437 
3438 				mod2.sml_op = LDAP_MOD_REPLACE;
3439 				mod2.sml_flags = 0;
3440 				mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
3441 				mod2.sml_type = mod2.sml_desc->ad_cname;
3442 				mod2.sml_numvals = 1;
3443 				mod2.sml_values = &gcbva[1];
3444 				mod2.sml_nvalues = NULL;
3445 				mod2.sml_next = NULL;
3446 
3447 				op->o_tag = LDAP_REQ_MODIFY;
3448 				op->orm_modlist = &mod1;
3449 
3450 				rc = op->o_bd->be_modify( op, &rs_modify );
3451 				if ( mod2.sml_next ) slap_mods_free( mod2.sml_next, 1 );
3452 			}
3453 
3454 			while ( rs_delete.sr_err == LDAP_SUCCESS &&
3455 					op->o_delete_glue_parent ) {
3456 				op->o_delete_glue_parent = 0;
3457 				if ( !be_issuffix( be, &op->o_req_ndn ) ) {
3458 					slap_callback cb = { NULL };
3459 					cb.sc_response = slap_null_cb;
3460 					dnParent( &op->o_req_ndn, &pdn );
3461 					op->o_req_dn = pdn;
3462 					op->o_req_ndn = pdn;
3463 					op->o_callback = &cb;
3464 					rs_reinit( &rs_delete, REP_RESULT );
3465 					/* give it a root privil ? */
3466 					op->o_bd->be_delete( op, &rs_delete );
3467 				} else {
3468 					break;
3469 				}
3470 			}
3471 
3472 			op->o_delete_glue_parent = 0;
3473 
3474 			ber_bvfree( np_prev->npe_name );
3475 			ber_bvfree( np_prev->npe_nname );
3476 			ch_free( np_prev );
3477 
3478 			if ( slapd_shutdown ) {
3479 				break;
3480 			}
3481 		}
3482 
3483 		slap_graduate_commit_csn( op );
3484 		op->o_bd = be;
3485 
3486 		op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
3487 		BER_BVZERO( &op->o_csn );
3488 	}
3489 
3490 	return;
3491 }
3492 
3493 static int
3494 syncrepl_add_glue_ancestors(
3495 	Operation* op,
3496 	Entry *e )
3497 {
3498 	Backend *be = op->o_bd;
3499 	slap_callback cb = { NULL };
3500 	Attribute	*a;
3501 	int	rc = LDAP_SUCCESS;
3502 	int suffrdns;
3503 	int i;
3504 	struct berval dn = BER_BVNULL;
3505 	struct berval ndn = BER_BVNULL;
3506 	Entry	*glue;
3507 	struct berval	ptr, nptr;
3508 	char		*comma;
3509 
3510 	op->o_tag = LDAP_REQ_ADD;
3511 	op->o_callback = &cb;
3512 	cb.sc_response = null_callback;
3513 	cb.sc_private = NULL;
3514 
3515 	dn = e->e_name;
3516 	ndn = e->e_nname;
3517 
3518 	/* count RDNs in suffix */
3519 	if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) {
3520 		for ( i = 0, ptr = be->be_nsuffix[0], comma = ptr.bv_val; comma != NULL; comma = ber_bvchr( &ptr, ',' ) ) {
3521 			comma++;
3522 			ptr.bv_len -= comma - ptr.bv_val;
3523 			ptr.bv_val = comma;
3524 			i++;
3525 		}
3526 		suffrdns = i;
3527 	} else {
3528 		/* suffix is "" */
3529 		suffrdns = 0;
3530 	}
3531 
3532 	/* Start with BE suffix */
3533 	ptr = dn;
3534 	for ( i = 0; i < suffrdns; i++ ) {
3535 		comma = ber_bvrchr( &ptr, ',' );
3536 		if ( comma != NULL ) {
3537 			ptr.bv_len = comma - ptr.bv_val;
3538 		} else {
3539 			ptr.bv_len = 0;
3540 			break;
3541 		}
3542 	}
3543 
3544 	if ( !BER_BVISEMPTY( &ptr ) ) {
3545 		dn.bv_len -= ptr.bv_len + ( suffrdns != 0 );
3546 		dn.bv_val += ptr.bv_len + ( suffrdns != 0 );
3547 	}
3548 
3549 	/* the normalizedDNs are always the same length, no counting
3550 	 * required.
3551 	 */
3552 	nptr = ndn;
3553 	if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
3554 		ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
3555 		ndn.bv_len = be->be_nsuffix[0].bv_len;
3556 
3557 		nptr.bv_len = ndn.bv_val - nptr.bv_val - 1;
3558 
3559 	} else {
3560 		nptr.bv_len = 0;
3561 	}
3562 
3563 	while ( ndn.bv_val > e->e_nname.bv_val ) {
3564 		SlapReply	rs_add = {REP_RESULT};
3565 
3566 		glue = entry_alloc();
3567 		ber_dupbv( &glue->e_name, &dn );
3568 		ber_dupbv( &glue->e_nname, &ndn );
3569 
3570 		a = attr_alloc( slap_schema.si_ad_objectClass );
3571 
3572 		a->a_numvals = 2;
3573 		a->a_vals = ch_calloc( 3, sizeof( struct berval ) );
3574 		ber_dupbv( &a->a_vals[0], &gcbva[0] );
3575 		ber_dupbv( &a->a_vals[1], &gcbva[1] );
3576 		ber_dupbv( &a->a_vals[2], &gcbva[2] );
3577 
3578 		a->a_nvals = a->a_vals;
3579 
3580 		a->a_next = glue->e_attrs;
3581 		glue->e_attrs = a;
3582 
3583 		a = attr_alloc( slap_schema.si_ad_structuralObjectClass );
3584 
3585 		a->a_numvals = 1;
3586 		a->a_vals = ch_calloc( 2, sizeof( struct berval ) );
3587 		ber_dupbv( &a->a_vals[0], &gcbva[1] );
3588 		ber_dupbv( &a->a_vals[1], &gcbva[2] );
3589 
3590 		a->a_nvals = a->a_vals;
3591 
3592 		a->a_next = glue->e_attrs;
3593 		glue->e_attrs = a;
3594 
3595 		op->o_req_dn = glue->e_name;
3596 		op->o_req_ndn = glue->e_nname;
3597 		op->ora_e = glue;
3598 		rc = be->be_add ( op, &rs_add );
3599 		if ( rs_add.sr_err == LDAP_SUCCESS ) {
3600 			if ( op->ora_e == glue )
3601 				be_entry_release_w( op, glue );
3602 		} else {
3603 		/* incl. ALREADY EXIST */
3604 			entry_free( glue );
3605 			if ( rs_add.sr_err != LDAP_ALREADY_EXISTS ) {
3606 				entry_free( e );
3607 				return rc;
3608 			}
3609 		}
3610 
3611 		/* Move to next child */
3612 		comma = ber_bvrchr( &ptr, ',' );
3613 		if ( comma == NULL ) {
3614 			break;
3615 		}
3616 		ptr.bv_len = comma - ptr.bv_val;
3617 
3618 		dn.bv_val = ++comma;
3619 		dn.bv_len = e->e_name.bv_len - (dn.bv_val - e->e_name.bv_val);
3620 
3621 		comma = ber_bvrchr( &nptr, ',' );
3622 		assert( comma != NULL );
3623 		nptr.bv_len = comma - nptr.bv_val;
3624 
3625 		ndn.bv_val = ++comma;
3626 		ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
3627 	}
3628 
3629 	return rc;
3630 }
3631 
3632 int
3633 syncrepl_add_glue(
3634 	Operation* op,
3635 	Entry *e )
3636 {
3637 	slap_callback cb = { NULL };
3638 	int	rc;
3639 	Backend *be = op->o_bd;
3640 	SlapReply	rs_add = {REP_RESULT};
3641 
3642 	rc = syncrepl_add_glue_ancestors( op, e );
3643 	switch ( rc ) {
3644 	case LDAP_SUCCESS:
3645 	case LDAP_ALREADY_EXISTS:
3646 		break;
3647 
3648 	default:
3649 		return rc;
3650 	}
3651 
3652 	op->o_tag = LDAP_REQ_ADD;
3653 	op->o_callback = &cb;
3654 	cb.sc_response = null_callback;
3655 	cb.sc_private = NULL;
3656 
3657 	op->o_req_dn = e->e_name;
3658 	op->o_req_ndn = e->e_nname;
3659 	op->ora_e = e;
3660 	rc = be->be_add ( op, &rs_add );
3661 	if ( rs_add.sr_err == LDAP_SUCCESS ) {
3662 		if ( op->ora_e == e )
3663 			be_entry_release_w( op, e );
3664 	} else {
3665 		entry_free( e );
3666 	}
3667 
3668 	return rc;
3669 }
3670 
3671 static int
3672 syncrepl_updateCookie(
3673 	syncinfo_t *si,
3674 	Operation *op,
3675 	struct sync_cookie *syncCookie )
3676 {
3677 	Backend *be = op->o_bd;
3678 	Modifications mod;
3679 	struct berval first = BER_BVNULL;
3680 	struct sync_cookie sc;
3681 #ifdef CHECK_CSN
3682 	Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
3683 #endif
3684 
3685 	int rc, i, j, changed = 0;
3686 	ber_len_t len;
3687 
3688 	slap_callback cb = { NULL };
3689 	SlapReply	rs_modify = {REP_RESULT};
3690 
3691 	mod.sml_op = LDAP_MOD_REPLACE;
3692 	mod.sml_desc = slap_schema.si_ad_contextCSN;
3693 	mod.sml_type = mod.sml_desc->ad_cname;
3694 	mod.sml_flags = SLAP_MOD_INTERNAL;
3695 	mod.sml_nvalues = NULL;
3696 	mod.sml_next = NULL;
3697 
3698 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
3699 
3700 #ifdef CHECK_CSN
3701 	for ( i=0; i<syncCookie->numcsns; i++ ) {
3702 		assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i ));
3703 	}
3704 	for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
3705 		assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
3706 	}
3707 #endif
3708 
3709 	/* clone the cookieState CSNs so we can Replace the whole thing */
3710 	sc.numcsns = si->si_cookieState->cs_num;
3711 	if ( sc.numcsns ) {
3712 		ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
3713 		sc.sids = ch_malloc( sc.numcsns * sizeof(int));
3714 		for ( i=0; i<sc.numcsns; i++ )
3715 			sc.sids[i] = si->si_cookieState->cs_sids[i];
3716 	} else {
3717 		sc.ctxcsn = NULL;
3718 		sc.sids = NULL;
3719 	}
3720 
3721 	/* find any CSNs in the syncCookie that are newer than the cookieState */
3722 	for ( i=0; i<syncCookie->numcsns; i++ ) {
3723 		for ( j=0; j<sc.numcsns; j++ ) {
3724 			if ( syncCookie->sids[i] < sc.sids[j] )
3725 				break;
3726 			if ( syncCookie->sids[i] != sc.sids[j] )
3727 				continue;
3728 			len = syncCookie->ctxcsn[i].bv_len;
3729 			if ( len > sc.ctxcsn[j].bv_len )
3730 				len = sc.ctxcsn[j].bv_len;
3731 			if ( memcmp( syncCookie->ctxcsn[i].bv_val,
3732 				sc.ctxcsn[j].bv_val, len ) > 0 ) {
3733 				ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
3734 				changed = 1;
3735 				if ( BER_BVISNULL( &first ) ||
3736 					memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
3737 					first = syncCookie->ctxcsn[i];
3738 				}
3739 			}
3740 			break;
3741 		}
3742 		/* there was no match for this SID, it's a new CSN */
3743 		if ( j == sc.numcsns ||
3744 			syncCookie->sids[i] != sc.sids[j] ) {
3745 			slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
3746 				&syncCookie->ctxcsn[i] );
3747 			if ( BER_BVISNULL( &first ) ||
3748 				memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
3749 				first = syncCookie->ctxcsn[i];
3750 			}
3751 			changed = 1;
3752 		}
3753 	}
3754 	/* Should never happen, ITS#5065 */
3755 	if ( BER_BVISNULL( &first ) || !changed ) {
3756 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
3757 		ber_bvarray_free( sc.ctxcsn );
3758 		ch_free( sc.sids );
3759 		return 0;
3760 	}
3761 	op->o_bd = si->si_wbe;
3762 	slap_queue_csn( op, &first );
3763 
3764 	op->o_tag = LDAP_REQ_MODIFY;
3765 
3766 	cb.sc_response = null_callback;
3767 	cb.sc_private = si;
3768 
3769 	op->o_callback = &cb;
3770 	op->o_req_dn = si->si_contextdn;
3771 	op->o_req_ndn = si->si_contextdn;
3772 
3773 	/* update contextCSN */
3774 	op->o_dont_replicate = 1;
3775 
3776 	mod.sml_numvals = sc.numcsns;
3777 	mod.sml_values = sc.ctxcsn;
3778 
3779 	op->orm_modlist = &mod;
3780 	op->orm_no_opattrs = 1;
3781 	rc = op->o_bd->be_modify( op, &rs_modify );
3782 
3783 	if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
3784 		SLAP_SYNC_SUBENTRY( op->o_bd )) {
3785 		const char	*text;
3786 		char txtbuf[SLAP_TEXT_BUFLEN];
3787 		size_t textlen = sizeof txtbuf;
3788 		Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
3789 		rs_reinit( &rs_modify, REP_RESULT );
3790 		rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
3791 		op->ora_e = e;
3792 		rc = op->o_bd->be_add( op, &rs_modify );
3793 		if ( e == op->ora_e )
3794 			be_entry_release_w( op, op->ora_e );
3795 	}
3796 
3797 	op->orm_no_opattrs = 0;
3798 	op->o_dont_replicate = 0;
3799 
3800 	if ( rs_modify.sr_err == LDAP_SUCCESS ) {
3801 		slap_sync_cookie_free( &si->si_syncCookie, 0 );
3802 		ber_bvarray_free( si->si_cookieState->cs_vals );
3803 		ch_free( si->si_cookieState->cs_sids );
3804 		si->si_cookieState->cs_vals = sc.ctxcsn;
3805 		si->si_cookieState->cs_sids = sc.sids;
3806 		si->si_cookieState->cs_num = sc.numcsns;
3807 
3808 		/* Don't just dup the provider's cookie, recreate it */
3809 		si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
3810 		ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL );
3811 		si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * sizeof(int) );
3812 		for ( i=0; i<si->si_cookieState->cs_num; i++ )
3813 			si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
3814 
3815 		si->si_cookieState->cs_age++;
3816 		si->si_cookieAge = si->si_cookieState->cs_age;
3817 	} else {
3818 		Debug( LDAP_DEBUG_ANY,
3819 			"syncrepl_updateCookie: %s be_modify failed (%d)\n",
3820 			si->si_ridtxt, rs_modify.sr_err, 0 );
3821 		ch_free( sc.sids );
3822 		ber_bvarray_free( sc.ctxcsn );
3823 	}
3824 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
3825 
3826 	op->o_bd = be;
3827 	op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
3828 	BER_BVZERO( &op->o_csn );
3829 	if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
3830 
3831 #ifdef CHECK_CSN
3832 	for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
3833 		assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
3834 	}
3835 #endif
3836 
3837 	return rc;
3838 }
3839 
3840 /* Compare the attribute from the old entry to the one in the new
3841  * entry. The Modifications from the new entry will either be left
3842  * in place, or changed to an Add or Delete as needed.
3843  */
3844 static void
3845 attr_cmp( Operation *op, Attribute *old, Attribute *new,
3846 	Modifications ***mret, Modifications ***mcur )
3847 {
3848 	int i, j;
3849 	Modifications *mod, **modtail;
3850 
3851 	modtail = *mret;
3852 
3853 	if ( old ) {
3854 		int n, o, nn, no;
3855 		struct berval **adds, **dels;
3856 		/* count old and new */
3857 		for ( o=0; old->a_vals[o].bv_val; o++ ) ;
3858 		for ( n=0; new->a_vals[n].bv_val; n++ ) ;
3859 
3860 		/* there MUST be both old and new values */
3861 		assert( o != 0 );
3862 		assert( n != 0 );
3863 		j = 0;
3864 
3865 		adds = op->o_tmpalloc( sizeof(struct berval *) * n, op->o_tmpmemctx );
3866 		dels = op->o_tmpalloc( sizeof(struct berval *) * o, op->o_tmpmemctx );
3867 
3868 		for ( i=0; i<o; i++ ) dels[i] = &old->a_vals[i];
3869 		for ( i=0; i<n; i++ ) adds[i] = &new->a_vals[i];
3870 
3871 		nn = n; no = o;
3872 
3873 		for ( i=0; i<o; i++ ) {
3874 			for ( j=0; j<n; j++ ) {
3875 				if ( !adds[j] )
3876 					continue;
3877 				if ( bvmatch( dels[i], adds[j] ) ) {
3878 					no--;
3879 					nn--;
3880 					adds[j] = NULL;
3881 					dels[i] = NULL;
3882 					break;
3883 				}
3884 			}
3885 		}
3886 
3887 		/* Don't delete/add an objectClass, always use the replace op.
3888 		 * Modify would fail if provider has replaced entry with a new,
3889 		 * and the new explicitly includes a superior of a class that was
3890 		 * only included implicitly in the old entry.  Ref ITS#5517.
3891 		 *
3892 		 * Also use replace op if attr has no equality matching rule.
3893 		 * (ITS#5781)
3894 		 */
3895 		if ( ( nn || ( no > 0 && no < o ) ) &&
3896 			( old->a_desc == slap_schema.si_ad_objectClass ||
3897 			 !old->a_desc->ad_type->sat_equality ) )
3898 		{
3899 			no = o;
3900 		}
3901 
3902 		i = j;
3903 		/* all old values were deleted, just use the replace op */
3904 		if ( no == o ) {
3905 			i = j-1;
3906 		} else if ( no ) {
3907 		/* delete some values */
3908 			mod = ch_malloc( sizeof( Modifications ) );
3909 			mod->sml_op = LDAP_MOD_DELETE;
3910 			mod->sml_flags = 0;
3911 			mod->sml_desc = old->a_desc;
3912 			mod->sml_type = mod->sml_desc->ad_cname;
3913 			mod->sml_numvals = no;
3914 			mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
3915 			if ( old->a_vals != old->a_nvals ) {
3916 				mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
3917 			} else {
3918 				mod->sml_nvalues = NULL;
3919 			}
3920 			j = 0;
3921 			for ( i = 0; i < o; i++ ) {
3922 				if ( !dels[i] ) continue;
3923 				ber_dupbv( &mod->sml_values[j], &old->a_vals[i] );
3924 				if ( mod->sml_nvalues ) {
3925 					ber_dupbv( &mod->sml_nvalues[j], &old->a_nvals[i] );
3926 				}
3927 				j++;
3928 			}
3929 			BER_BVZERO( &mod->sml_values[j] );
3930 			if ( mod->sml_nvalues ) {
3931 				BER_BVZERO( &mod->sml_nvalues[j] );
3932 			}
3933 			*modtail = mod;
3934 			modtail = &mod->sml_next;
3935 			i = j;
3936 		}
3937 		op->o_tmpfree( dels, op->o_tmpmemctx );
3938 		/* some values were added */
3939 		if ( nn && no < o ) {
3940 			mod = ch_malloc( sizeof( Modifications ) );
3941 			mod->sml_op = LDAP_MOD_ADD;
3942 			mod->sml_flags = 0;
3943 			mod->sml_desc = old->a_desc;
3944 			mod->sml_type = mod->sml_desc->ad_cname;
3945 			mod->sml_numvals = nn;
3946 			mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
3947 			if ( old->a_vals != old->a_nvals ) {
3948 				mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
3949 			} else {
3950 				mod->sml_nvalues = NULL;
3951 			}
3952 			j = 0;
3953 			for ( i = 0; i < n; i++ ) {
3954 				if ( !adds[i] ) continue;
3955 				ber_dupbv( &mod->sml_values[j], &new->a_vals[i] );
3956 				if ( mod->sml_nvalues ) {
3957 					ber_dupbv( &mod->sml_nvalues[j], &new->a_nvals[i] );
3958 				}
3959 				j++;
3960 			}
3961 			BER_BVZERO( &mod->sml_values[j] );
3962 			if ( mod->sml_nvalues ) {
3963 				BER_BVZERO( &mod->sml_nvalues[j] );
3964 			}
3965 			*modtail = mod;
3966 			modtail = &mod->sml_next;
3967 			i = j;
3968 		}
3969 		op->o_tmpfree( adds, op->o_tmpmemctx );
3970 	} else {
3971 		/* new attr, just use the new mod */
3972 		i = 0;
3973 		j = 1;
3974 	}
3975 	/* advance to next element */
3976 	mod = **mcur;
3977 	if ( mod ) {
3978 		if ( i != j ) {
3979 			**mcur = mod->sml_next;
3980 			*modtail = mod;
3981 			modtail = &mod->sml_next;
3982 		} else {
3983 			*mcur = &mod->sml_next;
3984 		}
3985 	}
3986 	*mret = modtail;
3987 }
3988 
3989 /* Generate a set of modifications to change the old entry into the
3990  * new one. On input ml is a list of modifications equivalent to
3991  * the new entry. It will be massaged and the result will be stored
3992  * in mods.
3993  */
3994 void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
3995 	Modifications **mods, Modifications **ml, int is_ctx)
3996 {
3997 	Modifications **modtail = mods;
3998 
3999 	/* We assume that attributes are saved in the same order
4000 	 * in the remote and local databases. So if we walk through
4001 	 * the attributeDescriptions one by one they should match in
4002 	 * lock step. If not, look for an add or delete.
4003 	 */
4004 	while ( old && new )
4005 	{
4006 		/* If we've seen this before, use its mod now */
4007 		if ( new->a_flags & SLAP_ATTR_IXADD ) {
4008 			attr_cmp( op, NULL, new, &modtail, &ml );
4009 			new = new->a_next;
4010 			continue;
4011 		}
4012 		/* Skip contextCSN */
4013 		if ( is_ctx && old->a_desc ==
4014 			slap_schema.si_ad_contextCSN ) {
4015 			old = old->a_next;
4016 			continue;
4017 		}
4018 
4019 		if ( old->a_desc != new->a_desc ) {
4020 			Modifications *mod;
4021 			Attribute *tmp;
4022 
4023 			/* If it's just been re-added later,
4024 			 * remember that we've seen it.
4025 			 */
4026 			tmp = attr_find( new, old->a_desc );
4027 			if ( tmp ) {
4028 				tmp->a_flags |= SLAP_ATTR_IXADD;
4029 			} else {
4030 				/* If it's a new attribute, pull it in.
4031 				 */
4032 				tmp = attr_find( old, new->a_desc );
4033 				if ( !tmp ) {
4034 					attr_cmp( op, NULL, new, &modtail, &ml );
4035 					new = new->a_next;
4036 					continue;
4037 				}
4038 				/* Delete old attr */
4039 				mod = ch_malloc( sizeof( Modifications ) );
4040 				mod->sml_op = LDAP_MOD_DELETE;
4041 				mod->sml_flags = 0;
4042 				mod->sml_desc = old->a_desc;
4043 				mod->sml_type = mod->sml_desc->ad_cname;
4044 				mod->sml_numvals = 0;
4045 				mod->sml_values = NULL;
4046 				mod->sml_nvalues = NULL;
4047 				*modtail = mod;
4048 				modtail = &mod->sml_next;
4049 			}
4050 			old = old->a_next;
4051 			continue;
4052 		}
4053 		/* kludge - always update modifiersName so that it
4054 		 * stays co-located with the other mod opattrs. But only
4055 		 * if we know there are other valid mods.
4056 		 */
4057 		if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
4058 			old->a_desc == slap_schema.si_ad_modifyTimestamp ))
4059 			attr_cmp( op, NULL, new, &modtail, &ml );
4060 		else
4061 			attr_cmp( op, old, new, &modtail, &ml );
4062 		new = new->a_next;
4063 		old = old->a_next;
4064 	}
4065 	*modtail = *ml;
4066 	*ml = NULL;
4067 }
4068 
4069 static int
4070 dn_callback(
4071 	Operation*	op,
4072 	SlapReply*	rs )
4073 {
4074 	dninfo *dni = op->o_callback->sc_private;
4075 
4076 	if ( rs->sr_type == REP_SEARCH ) {
4077 		if ( !BER_BVISNULL( &dni->dn ) ) {
4078 			Debug( LDAP_DEBUG_ANY,
4079 				"dn_callback : consistency error - "
4080 				"entryUUID is not unique\n", 0, 0, 0 );
4081 		} else {
4082 			ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx );
4083 			ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
4084 			/* If there is a new entry, see if it differs from the old.
4085 			 * We compare the non-normalized values so that cosmetic changes
4086 			 * in the provider are always propagated.
4087 			 */
4088 			if ( dni->new_entry ) {
4089 				Attribute *old, *new;
4090 				struct berval old_rdn, new_rdn;
4091 				struct berval old_p, new_p;
4092 				int is_ctx, new_sup = 0;
4093 
4094 				/* If old entry is not a glue entry, make sure new entry
4095 				 * is actually newer than old entry
4096 				 */
4097 				if ( !is_entry_glue( rs->sr_entry )) {
4098 					old = attr_find( rs->sr_entry->e_attrs,
4099 						slap_schema.si_ad_entryCSN );
4100 					new = attr_find( dni->new_entry->e_attrs,
4101 						slap_schema.si_ad_entryCSN );
4102 					if ( new && old ) {
4103 						int rc;
4104 						ber_len_t len = old->a_vals[0].bv_len;
4105 						if ( len > new->a_vals[0].bv_len )
4106 							len = new->a_vals[0].bv_len;
4107 						rc = memcmp( old->a_vals[0].bv_val,
4108 							new->a_vals[0].bv_val, len );
4109 						if ( rc > 0 ) {
4110 							Debug( LDAP_DEBUG_SYNC,
4111 								"dn_callback : new entry is older than ours "
4112 								"%s ours %s, new %s\n",
4113 								rs->sr_entry->e_name.bv_val,
4114 								old->a_vals[0].bv_val,
4115 								new->a_vals[0].bv_val );
4116 							return LDAP_SUCCESS;
4117 						} else if ( rc == 0 ) {
4118 							Debug( LDAP_DEBUG_SYNC,
4119 								"dn_callback : entries have identical CSN "
4120 								"%s %s\n",
4121 								rs->sr_entry->e_name.bv_val,
4122 								old->a_vals[0].bv_val, 0 );
4123 							return LDAP_SUCCESS;
4124 						}
4125 					}
4126 				}
4127 
4128 				is_ctx = dn_match( &rs->sr_entry->e_nname,
4129 					&op->o_bd->be_nsuffix[0] );
4130 
4131 				/* Did the DN change?
4132 				 * case changes in the parent are ignored,
4133 				 * we only want to know if the RDN was
4134 				 * actually changed.
4135 				 */
4136 				dnRdn( &rs->sr_entry->e_name, &old_rdn );
4137 				dnRdn( &dni->new_entry->e_name, &new_rdn );
4138 				dnParent( &rs->sr_entry->e_nname, &old_p );
4139 				dnParent( &dni->new_entry->e_nname, &new_p );
4140 
4141 				new_sup = !dn_match( &old_p, &new_p );
4142 				if ( !dn_match( &old_rdn, &new_rdn ) || new_sup )
4143 				{
4144 					struct berval oldRDN, oldVal;
4145 					AttributeDescription *ad = NULL;
4146 					int oldpos, newpos;
4147 					Attribute *a;
4148 
4149 					dni->renamed = 1;
4150 					if ( new_sup )
4151 						dni->nnewSup = new_p;
4152 
4153 					/* See if the oldRDN was deleted */
4154 					dnRdn( &rs->sr_entry->e_nname, &oldRDN );
4155 					oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
4156 					oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
4157 						oldRDN.bv_val );
4158 					oldRDN.bv_len -= oldVal.bv_len + 1;
4159 					slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
4160 					dni->oldDesc = ad;
4161 					for ( oldpos=0, a=rs->sr_entry->e_attrs;
4162 						a && a->a_desc != ad; oldpos++, a=a->a_next );
4163 					/* a should not be NULL but apparently it happens.
4164 					 * ITS#7144
4165 					 */
4166 					dni->oldNcount = a ? a->a_numvals : 0;
4167 					for ( newpos=0, a=dni->new_entry->e_attrs;
4168 						a && a->a_desc != ad; newpos++, a=a->a_next );
4169 					if ( !a || oldpos != newpos || attr_valfind( a,
4170 						SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
4171 						SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
4172 						SLAP_MR_VALUE_OF_SYNTAX,
4173 						&oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS )
4174 					{
4175 						dni->delOldRDN = 1;
4176 					}
4177 					/* Get the newRDN's desc */
4178 					dnRdn( &dni->new_entry->e_nname, &oldRDN );
4179 					oldVal.bv_val = strchr(oldRDN.bv_val, '=');
4180 					oldRDN.bv_len = oldVal.bv_val - oldRDN.bv_val;
4181 					ad = NULL;
4182 					slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
4183 					dni->newDesc = ad;
4184 
4185 					/* A ModDN has happened, but in Refresh mode other
4186 					 * changes may have occurred before we picked it up.
4187 					 * So fallthru to regular Modify processing.
4188 					 */
4189 				}
4190 
4191 				syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
4192 					dni->new_entry->e_attrs, &dni->mods, dni->modlist,
4193 					is_ctx );
4194 			}
4195 		}
4196 	} else if ( rs->sr_type == REP_RESULT ) {
4197 		if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
4198 			Debug( LDAP_DEBUG_ANY,
4199 				"dn_callback : consistency error - "
4200 				"entryUUID is not unique\n", 0, 0, 0 );
4201 		}
4202 	}
4203 
4204 	return LDAP_SUCCESS;
4205 }
4206 
4207 static int
4208 nonpresent_callback(
4209 	Operation*	op,
4210 	SlapReply*	rs )
4211 {
4212 	syncinfo_t *si = op->o_callback->sc_private;
4213 	Attribute *a;
4214 	int count = 0;
4215 	struct berval* present_uuid = NULL;
4216 	struct nonpresent_entry *np_entry;
4217 
4218 	if ( rs->sr_type == REP_RESULT ) {
4219 		count = avl_free( si->si_presentlist, ch_free );
4220 		si->si_presentlist = NULL;
4221 
4222 	} else if ( rs->sr_type == REP_SEARCH ) {
4223 		if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) {
4224 			a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
4225 
4226 			if ( a ) {
4227 				present_uuid = avl_find( si->si_presentlist, &a->a_nvals[0],
4228 					syncuuid_cmp );
4229 			}
4230 
4231 			if ( LogTest( LDAP_DEBUG_SYNC ) ) {
4232 				char buf[sizeof("rid=999 non")];
4233 
4234 				snprintf( buf, sizeof(buf), "%s %s", si->si_ridtxt,
4235 					present_uuid ? "" : "non" );
4236 
4237 				Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %spresent UUID %s, dn %s\n",
4238 					buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
4239 			}
4240 
4241 			if ( a == NULL ) return 0;
4242 		}
4243 
4244 		if ( present_uuid == NULL ) {
4245 			np_entry = (struct nonpresent_entry *)
4246 				ch_calloc( 1, sizeof( struct nonpresent_entry ) );
4247 			np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
4248 			np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
4249 			LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
4250 
4251 		} else {
4252 			avl_delete( &si->si_presentlist,
4253 				&a->a_nvals[0], syncuuid_cmp );
4254 			ch_free( present_uuid );
4255 		}
4256 	}
4257 	return LDAP_SUCCESS;
4258 }
4259 
4260 static int
4261 null_callback(
4262 	Operation*	op,
4263 	SlapReply*	rs )
4264 {
4265 	if ( rs->sr_err != LDAP_SUCCESS &&
4266 		rs->sr_err != LDAP_REFERRAL &&
4267 		rs->sr_err != LDAP_ALREADY_EXISTS &&
4268 		rs->sr_err != LDAP_NO_SUCH_OBJECT &&
4269 		rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
4270 	{
4271 		Debug( LDAP_DEBUG_ANY,
4272 			"null_callback : error code 0x%x\n",
4273 			rs->sr_err, 0, 0 );
4274 	}
4275 	return LDAP_SUCCESS;
4276 }
4277 
4278 static struct berval *
4279 slap_uuidstr_from_normalized(
4280 	struct berval* uuidstr,
4281 	struct berval* normalized,
4282 	void *ctx )
4283 {
4284 #if 0
4285 	struct berval *new;
4286 	unsigned char nibble;
4287 	int i, d = 0;
4288 
4289 	if ( normalized == NULL ) return NULL;
4290 	if ( normalized->bv_len != 16 ) return NULL;
4291 
4292 	if ( uuidstr ) {
4293 		new = uuidstr;
4294 	} else {
4295 		new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
4296 		if ( new == NULL ) {
4297 			return NULL;
4298 		}
4299 	}
4300 
4301 	new->bv_len = 36;
4302 
4303 	if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
4304 		if ( new != uuidstr ) {
4305 			slap_sl_free( new, ctx );
4306 		}
4307 		return NULL;
4308 	}
4309 
4310 	for ( i = 0; i < 16; i++ ) {
4311 		if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
4312 			new->bv_val[(i<<1)+d] = '-';
4313 			d += 1;
4314 		}
4315 
4316 		nibble = (normalized->bv_val[i] >> 4) & 0xF;
4317 		if ( nibble < 10 ) {
4318 			new->bv_val[(i<<1)+d] = nibble + '0';
4319 		} else {
4320 			new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
4321 		}
4322 
4323 		nibble = (normalized->bv_val[i]) & 0xF;
4324 		if ( nibble < 10 ) {
4325 			new->bv_val[(i<<1)+d+1] = nibble + '0';
4326 		} else {
4327 			new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
4328 		}
4329 	}
4330 
4331 	new->bv_val[new->bv_len] = '\0';
4332 	return new;
4333 #endif
4334 
4335 	struct berval	*new;
4336 	int		rc = 0;
4337 
4338 	if ( normalized == NULL ) return NULL;
4339 	if ( normalized->bv_len != 16 ) return NULL;
4340 
4341 	if ( uuidstr ) {
4342 		new = uuidstr;
4343 
4344 	} else {
4345 		new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
4346 		if ( new == NULL ) {
4347 			return NULL;
4348 		}
4349 	}
4350 
4351 	new->bv_len = 36;
4352 
4353 	if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
4354 		rc = 1;
4355 		goto done;
4356 	}
4357 
4358 	rc = lutil_uuidstr_from_normalized( normalized->bv_val,
4359 		normalized->bv_len, new->bv_val, new->bv_len + 1 );
4360 
4361 done:;
4362 	if ( rc == -1 ) {
4363 		if ( new != NULL ) {
4364 			if ( new->bv_val != NULL ) {
4365 				slap_sl_free( new->bv_val, ctx );
4366 			}
4367 
4368 			if ( new != uuidstr ) {
4369 				slap_sl_free( new, ctx );
4370 			}
4371 		}
4372 		new = NULL;
4373 
4374 	} else {
4375 		new->bv_len = rc;
4376 	}
4377 
4378 	return new;
4379 }
4380 
4381 static int
4382 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
4383 {
4384 	const struct berval *uuid1 = v_uuid1;
4385 	const struct berval *uuid2 = v_uuid2;
4386 	int rc = uuid1->bv_len - uuid2->bv_len;
4387 	if ( rc ) return rc;
4388 	return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
4389 }
4390 
4391 void
4392 syncinfo_free( syncinfo_t *sie, int free_all )
4393 {
4394 	syncinfo_t *si_next;
4395 
4396 	Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
4397 		sie->si_ridtxt, 0, 0 );
4398 
4399 	do {
4400 		si_next = sie->si_next;
4401 
4402 		if ( sie->si_ld ) {
4403 			if ( sie->si_conn ) {
4404 				connection_client_stop( sie->si_conn );
4405 				sie->si_conn = NULL;
4406 			}
4407 			ldap_unbind_ext( sie->si_ld, NULL, NULL );
4408 		}
4409 
4410 		if ( sie->si_re ) {
4411 			struct re_s		*re = sie->si_re;
4412 			sie->si_re = NULL;
4413 
4414 			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
4415 			if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
4416 				ldap_pvt_runqueue_stoptask( &slapd_rq, re );
4417 			ldap_pvt_runqueue_remove( &slapd_rq, re );
4418 			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
4419 		}
4420 
4421 		ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
4422 
4423 		bindconf_free( &sie->si_bindconf );
4424 
4425 		if ( sie->si_filterstr.bv_val ) {
4426 			ch_free( sie->si_filterstr.bv_val );
4427 		}
4428 		if ( sie->si_filter ) {
4429 			filter_free( sie->si_filter );
4430 		}
4431 		if ( sie->si_logfilterstr.bv_val ) {
4432 			ch_free( sie->si_logfilterstr.bv_val );
4433 		}
4434 		if ( sie->si_base.bv_val ) {
4435 			ch_free( sie->si_base.bv_val );
4436 		}
4437 		if ( sie->si_logbase.bv_val ) {
4438 			ch_free( sie->si_logbase.bv_val );
4439 		}
4440 		if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
4441 			ch_free( sie->si_contextdn.bv_val );
4442 		}
4443 		if ( sie->si_attrs ) {
4444 			int i = 0;
4445 			while ( sie->si_attrs[i] != NULL ) {
4446 				ch_free( sie->si_attrs[i] );
4447 				i++;
4448 			}
4449 			ch_free( sie->si_attrs );
4450 		}
4451 		if ( sie->si_exattrs ) {
4452 			int i = 0;
4453 			while ( sie->si_exattrs[i] != NULL ) {
4454 				ch_free( sie->si_exattrs[i] );
4455 				i++;
4456 			}
4457 			ch_free( sie->si_exattrs );
4458 		}
4459 		if ( sie->si_anlist ) {
4460 			int i = 0;
4461 			while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
4462 				ch_free( sie->si_anlist[i].an_name.bv_val );
4463 				i++;
4464 			}
4465 			ch_free( sie->si_anlist );
4466 		}
4467 		if ( sie->si_exanlist ) {
4468 			int i = 0;
4469 			while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
4470 				ch_free( sie->si_exanlist[i].an_name.bv_val );
4471 				i++;
4472 			}
4473 			ch_free( sie->si_exanlist );
4474 		}
4475 		if ( sie->si_retryinterval ) {
4476 			ch_free( sie->si_retryinterval );
4477 		}
4478 		if ( sie->si_retrynum ) {
4479 			ch_free( sie->si_retrynum );
4480 		}
4481 		if ( sie->si_retrynum_init ) {
4482 			ch_free( sie->si_retrynum_init );
4483 		}
4484 		slap_sync_cookie_free( &sie->si_syncCookie, 0 );
4485 		if ( sie->si_presentlist ) {
4486 		    avl_free( sie->si_presentlist, ch_free );
4487 		}
4488 		while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
4489 			struct nonpresent_entry* npe;
4490 			npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
4491 			LDAP_LIST_REMOVE( npe, npe_link );
4492 			if ( npe->npe_name ) {
4493 				if ( npe->npe_name->bv_val ) {
4494 					ch_free( npe->npe_name->bv_val );
4495 				}
4496 				ch_free( npe->npe_name );
4497 			}
4498 			if ( npe->npe_nname ) {
4499 				if ( npe->npe_nname->bv_val ) {
4500 					ch_free( npe->npe_nname->bv_val );
4501 				}
4502 				ch_free( npe->npe_nname );
4503 			}
4504 			ch_free( npe );
4505 		}
4506 		if ( sie->si_cookieState ) {
4507 			sie->si_cookieState->cs_ref--;
4508 			if ( !sie->si_cookieState->cs_ref ) {
4509 				ch_free( sie->si_cookieState->cs_sids );
4510 				ber_bvarray_free( sie->si_cookieState->cs_vals );
4511 				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
4512 				ch_free( sie->si_cookieState->cs_psids );
4513 				ber_bvarray_free( sie->si_cookieState->cs_pvals );
4514 				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
4515 				ch_free( sie->si_cookieState );
4516 			}
4517 		}
4518 #ifdef ENABLE_REWRITE
4519 		if ( sie->si_rewrite )
4520 			rewrite_info_delete( &sie->si_rewrite );
4521 		if ( sie->si_suffixm.bv_val )
4522 			ch_free( sie->si_suffixm.bv_val );
4523 #endif
4524 		ch_free( sie );
4525 		sie = si_next;
4526 	} while ( free_all && si_next );
4527 }
4528 
4529 #ifdef ENABLE_REWRITE
4530 static int
4531 config_suffixm( ConfigArgs *c, syncinfo_t *si )
4532 {
4533 	char *argvEngine[] = { "rewriteEngine", "on", NULL };
4534 	char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
4535 	char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
4536 	char *vnc, *rnc;
4537 	int rc;
4538 
4539 	if ( si->si_rewrite )
4540 		rewrite_info_delete( &si->si_rewrite );
4541 	si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
4542 
4543 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
4544 	if ( rc != LDAP_SUCCESS )
4545 		return rc;
4546 
4547 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
4548 	if ( rc != LDAP_SUCCESS )
4549 		return rc;
4550 
4551 	vnc = ch_malloc( si->si_base.bv_len + 6 );
4552 	strcpy( vnc, "(.*)" );
4553 	lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
4554 	argvRule[1] = vnc;
4555 
4556 	rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
4557 	strcpy( rnc, "%1" );
4558 	strcpy( rnc+2, si->si_suffixm.bv_val );
4559 	argvRule[2] = rnc;
4560 
4561 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
4562 	ch_free( vnc );
4563 	ch_free( rnc );
4564 	return rc;
4565 }
4566 #endif
4567 
4568 /* NOTE: used & documented in slapd.conf(5) */
4569 #define IDSTR			"rid"
4570 #define PROVIDERSTR		"provider"
4571 #define SCHEMASTR		"schemachecking"
4572 #define FILTERSTR		"filter"
4573 #define SEARCHBASESTR		"searchbase"
4574 #define SCOPESTR		"scope"
4575 #define ATTRSONLYSTR		"attrsonly"
4576 #define ATTRSSTR		"attrs"
4577 #define TYPESTR			"type"
4578 #define INTERVALSTR		"interval"
4579 #define RETRYSTR		"retry"
4580 #define SLIMITSTR		"sizelimit"
4581 #define TLIMITSTR		"timelimit"
4582 #define SYNCDATASTR		"syncdata"
4583 #define LOGBASESTR		"logbase"
4584 #define LOGFILTERSTR	"logfilter"
4585 #define SUFFIXMSTR		"suffixmassage"
4586 #define	STRICT_REFRESH	"strictrefresh"
4587 
4588 /* FIXME: undocumented */
4589 #define EXATTRSSTR		"exattrs"
4590 #define MANAGEDSAITSTR		"manageDSAit"
4591 
4592 /* mandatory */
4593 enum {
4594 	GOT_RID			= 0x00000001U,
4595 	GOT_PROVIDER		= 0x00000002U,
4596 	GOT_SCHEMACHECKING	= 0x00000004U,
4597 	GOT_FILTER		= 0x00000008U,
4598 	GOT_SEARCHBASE		= 0x00000010U,
4599 	GOT_SCOPE		= 0x00000020U,
4600 	GOT_ATTRSONLY		= 0x00000040U,
4601 	GOT_ATTRS		= 0x00000080U,
4602 	GOT_TYPE		= 0x00000100U,
4603 	GOT_INTERVAL		= 0x00000200U,
4604 	GOT_RETRY		= 0x00000400U,
4605 	GOT_SLIMIT		= 0x00000800U,
4606 	GOT_TLIMIT		= 0x00001000U,
4607 	GOT_SYNCDATA		= 0x00002000U,
4608 	GOT_LOGBASE		= 0x00004000U,
4609 	GOT_LOGFILTER		= 0x00008000U,
4610 	GOT_EXATTRS		= 0x00010000U,
4611 	GOT_MANAGEDSAIT		= 0x00020000U,
4612 	GOT_BINDCONF		= 0x00040000U,
4613 	GOT_SUFFIXM		= 0x00080000U,
4614 
4615 /* check */
4616 	GOT_REQUIRED		= (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
4617 };
4618 
4619 static slap_verbmasks datamodes[] = {
4620 	{ BER_BVC("default"), SYNCDATA_DEFAULT },
4621 	{ BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
4622 	{ BER_BVC("changelog"), SYNCDATA_CHANGELOG },
4623 	{ BER_BVNULL, 0 }
4624 };
4625 
4626 static int
4627 parse_syncrepl_retry(
4628 	ConfigArgs	*c,
4629 	char		*arg,
4630 	syncinfo_t	*si )
4631 {
4632 	char **retry_list;
4633 	int j, k, n;
4634 	int use_default = 0;
4635 
4636 	char *val = arg + STRLENOF( RETRYSTR "=" );
4637 	if ( strcasecmp( val, "undefined" ) == 0 ) {
4638 		val = "3600 +";
4639 		use_default = 1;
4640 	}
4641 
4642 	retry_list = (char **) ch_calloc( 1, sizeof( char * ) );
4643 	retry_list[0] = NULL;
4644 
4645 	slap_str2clist( &retry_list, val, " ,\t" );
4646 
4647 	for ( k = 0; retry_list && retry_list[k]; k++ ) ;
4648 	n = k / 2;
4649 	if ( k % 2 ) {
4650 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
4651 			"Error: incomplete syncrepl retry list" );
4652 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4653 		for ( k = 0; retry_list && retry_list[k]; k++ ) {
4654 			ch_free( retry_list[k] );
4655 		}
4656 		ch_free( retry_list );
4657 		return 1;
4658 	}
4659 	si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) );
4660 	si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) );
4661 	si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) );
4662 	for ( j = 0; j < n; j++ ) {
4663 		unsigned long	t;
4664 		if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
4665 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
4666 				"Error: invalid retry interval \"%s\" (#%d)",
4667 				retry_list[j*2], j );
4668 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4669 			/* do some cleanup */
4670 			return 1;
4671 		}
4672 		si->si_retryinterval[j] = (time_t)t;
4673 		if ( *retry_list[j*2+1] == '+' ) {
4674 			si->si_retrynum_init[j] = RETRYNUM_FOREVER;
4675 			si->si_retrynum[j] = RETRYNUM_FOREVER;
4676 			j++;
4677 			break;
4678 		} else {
4679 			if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
4680 					|| si->si_retrynum_init[j] <= 0 )
4681 			{
4682 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4683 					"Error: invalid initial retry number \"%s\" (#%d)",
4684 					retry_list[j*2+1], j );
4685 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4686 				/* do some cleanup */
4687 				return 1;
4688 			}
4689 			if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
4690 					|| si->si_retrynum[j] <= 0 )
4691 			{
4692 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4693 					"Error: invalid retry number \"%s\" (#%d)",
4694 					retry_list[j*2+1], j );
4695 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4696 				/* do some cleanup */
4697 				return 1;
4698 			}
4699 		}
4700 	}
4701 	if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) {
4702 		Debug( LDAP_DEBUG_CONFIG,
4703 			"%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n",
4704 			c->log, 0, 0 );
4705 	}
4706 
4707 	si->si_retrynum_init[j] = RETRYNUM_TAIL;
4708 	si->si_retrynum[j] = RETRYNUM_TAIL;
4709 	si->si_retryinterval[j] = 0;
4710 
4711 	for ( k = 0; retry_list && retry_list[k]; k++ ) {
4712 		ch_free( retry_list[k] );
4713 	}
4714 	ch_free( retry_list );
4715 	if ( !use_default ) {
4716 		si->si_got |= GOT_RETRY;
4717 	}
4718 
4719 	return 0;
4720 }
4721 
4722 static int
4723 parse_syncrepl_line(
4724 	ConfigArgs	*c,
4725 	syncinfo_t	*si )
4726 {
4727 	int	i;
4728 	char	*val;
4729 
4730 	for ( i = 1; i < c->argc; i++ ) {
4731 		if ( !strncasecmp( c->argv[ i ], IDSTR "=",
4732 					STRLENOF( IDSTR "=" ) ) )
4733 		{
4734 			int tmp;
4735 			/* '\0' string terminator accounts for '=' */
4736 			val = c->argv[ i ] + STRLENOF( IDSTR "=" );
4737 			if ( lutil_atoi( &tmp, val ) != 0 ) {
4738 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4739 					"Error: parse_syncrepl_line: "
4740 					"unable to parse syncrepl id \"%s\"", val );
4741 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4742 				return -1;
4743 			}
4744 			if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
4745 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4746 					"Error: parse_syncrepl_line: "
4747 					"syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
4748 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4749 				return -1;
4750 			}
4751 			si->si_rid = tmp;
4752 			sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid );
4753 			si->si_got |= GOT_RID;
4754 		} else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
4755 					STRLENOF( PROVIDERSTR "=" ) ) )
4756 		{
4757 			val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
4758 			ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
4759 #ifdef HAVE_TLS
4760 			if ( ldap_is_ldaps_url( val ))
4761 				si->si_bindconf.sb_tls_do_init = 1;
4762 #endif
4763 			si->si_got |= GOT_PROVIDER;
4764 		} else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
4765 					STRLENOF( SCHEMASTR "=" ) ) )
4766 		{
4767 			val = c->argv[ i ] + STRLENOF( SCHEMASTR "=" );
4768 			if ( !strncasecmp( val, "on", STRLENOF( "on" ) ) ) {
4769 				si->si_schemachecking = 1;
4770 			} else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
4771 				si->si_schemachecking = 0;
4772 			} else {
4773 				si->si_schemachecking = 1;
4774 			}
4775 			si->si_got |= GOT_SCHEMACHECKING;
4776 		} else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=",
4777 					STRLENOF( FILTERSTR "=" ) ) )
4778 		{
4779 			val = c->argv[ i ] + STRLENOF( FILTERSTR "=" );
4780 			if ( si->si_filterstr.bv_val )
4781 				ch_free( si->si_filterstr.bv_val );
4782 			ber_str2bv( val, 0, 1, &si->si_filterstr );
4783 			si->si_got |= GOT_FILTER;
4784 		} else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=",
4785 					STRLENOF( LOGFILTERSTR "=" ) ) )
4786 		{
4787 			val = c->argv[ i ] + STRLENOF( LOGFILTERSTR "=" );
4788 			if ( si->si_logfilterstr.bv_val )
4789 				ch_free( si->si_logfilterstr.bv_val );
4790 			ber_str2bv( val, 0, 1, &si->si_logfilterstr );
4791 			si->si_got |= GOT_LOGFILTER;
4792 		} else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=",
4793 					STRLENOF( SEARCHBASESTR "=" ) ) )
4794 		{
4795 			struct berval	bv;
4796 			int		rc;
4797 
4798 			val = c->argv[ i ] + STRLENOF( SEARCHBASESTR "=" );
4799 			if ( si->si_base.bv_val ) {
4800 				ch_free( si->si_base.bv_val );
4801 			}
4802 			ber_str2bv( val, 0, 0, &bv );
4803 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
4804 			if ( rc != LDAP_SUCCESS ) {
4805 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4806 					"Invalid base DN \"%s\": %d (%s)",
4807 					val, rc, ldap_err2string( rc ) );
4808 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4809 				return -1;
4810 			}
4811 			si->si_got |= GOT_SEARCHBASE;
4812 #ifdef ENABLE_REWRITE
4813 		} else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
4814 					STRLENOF( SUFFIXMSTR "=" ) ) )
4815 		{
4816 			struct berval	bv;
4817 			int		rc;
4818 
4819 			val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
4820 			if ( si->si_suffixm.bv_val ) {
4821 				ch_free( si->si_suffixm.bv_val );
4822 			}
4823 			ber_str2bv( val, 0, 0, &bv );
4824 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
4825 			if ( rc != LDAP_SUCCESS ) {
4826 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4827 					"Invalid massage DN \"%s\": %d (%s)",
4828 					val, rc, ldap_err2string( rc ) );
4829 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4830 				return -1;
4831 			}
4832 			if ( !be_issubordinate( c->be, &si->si_suffixm )) {
4833 				ch_free( si->si_suffixm.bv_val );
4834 				BER_BVZERO( &si->si_suffixm );
4835 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4836 					"Massage DN \"%s\" is not within the database naming context",
4837 					val );
4838 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4839 				return -1;
4840 			}
4841 			si->si_got |= GOT_SUFFIXM;
4842 #endif
4843 		} else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
4844 					STRLENOF( LOGBASESTR "=" ) ) )
4845 		{
4846 			struct berval	bv;
4847 			int		rc;
4848 
4849 			val = c->argv[ i ] + STRLENOF( LOGBASESTR "=" );
4850 			if ( si->si_logbase.bv_val ) {
4851 				ch_free( si->si_logbase.bv_val );
4852 			}
4853 			ber_str2bv( val, 0, 0, &bv );
4854 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_logbase, NULL );
4855 			if ( rc != LDAP_SUCCESS ) {
4856 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4857 					"Invalid logbase DN \"%s\": %d (%s)",
4858 					val, rc, ldap_err2string( rc ) );
4859 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4860 				return -1;
4861 			}
4862 			si->si_got |= GOT_LOGBASE;
4863 		} else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=",
4864 					STRLENOF( SCOPESTR "=" ) ) )
4865 		{
4866 			int j;
4867 			val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
4868 			j = ldap_pvt_str2scope( val );
4869 			if ( j < 0 ) {
4870 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4871 					"Error: parse_syncrepl_line: "
4872 					"unknown scope \"%s\"", val);
4873 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4874 				return -1;
4875 			}
4876 			si->si_scope = j;
4877 			si->si_got |= GOT_SCOPE;
4878 		} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
4879 					STRLENOF( ATTRSONLYSTR ) ) )
4880 		{
4881 			si->si_attrsonly = 1;
4882 			si->si_got |= GOT_ATTRSONLY;
4883 		} else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=",
4884 					STRLENOF( ATTRSSTR "=" ) ) )
4885 		{
4886 			val = c->argv[ i ] + STRLENOF( ATTRSSTR "=" );
4887 			if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
4888 				char *attr_fname;
4889 				attr_fname = ch_strdup( val + STRLENOF(":include:") );
4890 				si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
4891 				if ( si->si_anlist == NULL ) {
4892 					ch_free( attr_fname );
4893 					return -1;
4894 				}
4895 				si->si_anfile = attr_fname;
4896 			} else {
4897 				char *str, *s, *next;
4898 				const char *delimstr = " ,\t";
4899 				str = ch_strdup( val );
4900 				for ( s = ldap_pvt_strtok( str, delimstr, &next );
4901 						s != NULL;
4902 						s = ldap_pvt_strtok( NULL, delimstr, &next ) )
4903 				{
4904 					if ( strlen(s) == 1 && *s == '*' ) {
4905 						si->si_allattrs = 1;
4906 						val[ s - str ] = delimstr[0];
4907 					}
4908 					if ( strlen(s) == 1 && *s == '+' ) {
4909 						si->si_allopattrs = 1;
4910 						val [ s - str ] = delimstr[0];
4911 					}
4912 				}
4913 				ch_free( str );
4914 				si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
4915 				if ( si->si_anlist == NULL ) {
4916 					return -1;
4917 				}
4918 			}
4919 			si->si_got |= GOT_ATTRS;
4920 		} else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=",
4921 					STRLENOF( EXATTRSSTR "=" ) ) )
4922 		{
4923 			val = c->argv[ i ] + STRLENOF( EXATTRSSTR "=" );
4924 			if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
4925 				char *attr_fname;
4926 				attr_fname = ch_strdup( val + STRLENOF(":include:") );
4927 				si->si_exanlist = file2anlist(
4928 					si->si_exanlist, attr_fname, " ,\t" );
4929 				if ( si->si_exanlist == NULL ) {
4930 					ch_free( attr_fname );
4931 					return -1;
4932 				}
4933 				ch_free( attr_fname );
4934 			} else {
4935 				si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
4936 				if ( si->si_exanlist == NULL ) {
4937 					return -1;
4938 				}
4939 			}
4940 			si->si_got |= GOT_EXATTRS;
4941 		} else if ( !strncasecmp( c->argv[ i ], TYPESTR "=",
4942 					STRLENOF( TYPESTR "=" ) ) )
4943 		{
4944 			val = c->argv[ i ] + STRLENOF( TYPESTR "=" );
4945 			if ( !strncasecmp( val, "refreshOnly",
4946 						STRLENOF("refreshOnly") ) )
4947 			{
4948 				si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
4949 			} else if ( !strncasecmp( val, "refreshAndPersist",
4950 						STRLENOF("refreshAndPersist") ) )
4951 			{
4952 				si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_AND_PERSIST;
4953 				si->si_interval = 60;
4954 			} else {
4955 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
4956 					"Error: parse_syncrepl_line: "
4957 					"unknown sync type \"%s\"", val);
4958 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4959 				return -1;
4960 			}
4961 			si->si_got |= GOT_TYPE;
4962 		} else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=",
4963 					STRLENOF( INTERVALSTR "=" ) ) )
4964 		{
4965 			val = c->argv[ i ] + STRLENOF( INTERVALSTR "=" );
4966 			if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
4967 				si->si_interval = 0;
4968 			} else if ( strchr( val, ':' ) != NULL ) {
4969 				char *next, *ptr = val;
4970 				int dd, hh, mm, ss;
4971 
4972 				dd = strtol( ptr, &next, 10 );
4973 				if ( next == ptr || next[0] != ':' || dd < 0 ) {
4974 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
4975 						"Error: parse_syncrepl_line: "
4976 						"invalid interval \"%s\", unable to parse days", val );
4977 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4978 					return -1;
4979 				}
4980 				ptr = next + 1;
4981 				hh = strtol( ptr, &next, 10 );
4982 				if ( next == ptr || next[0] != ':' || hh < 0 || hh > 24 ) {
4983 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
4984 						"Error: parse_syncrepl_line: "
4985 						"invalid interval \"%s\", unable to parse hours", val );
4986 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4987 					return -1;
4988 				}
4989 				ptr = next + 1;
4990 				mm = strtol( ptr, &next, 10 );
4991 				if ( next == ptr || next[0] != ':' || mm < 0 || mm > 60 ) {
4992 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
4993 						"Error: parse_syncrepl_line: "
4994 						"invalid interval \"%s\", unable to parse minutes", val );
4995 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4996 					return -1;
4997 				}
4998 				ptr = next + 1;
4999 				ss = strtol( ptr, &next, 10 );
5000 				if ( next == ptr || next[0] != '\0' || ss < 0 || ss > 60 ) {
5001 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
5002 						"Error: parse_syncrepl_line: "
5003 						"invalid interval \"%s\", unable to parse seconds", val );
5004 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5005 					return -1;
5006 				}
5007 				si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
5008 			} else {
5009 				unsigned long	t;
5010 
5011 				if ( lutil_parse_time( val, &t ) != 0 ) {
5012 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
5013 						"Error: parse_syncrepl_line: "
5014 						"invalid interval \"%s\"", val );
5015 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5016 					return -1;
5017 				}
5018 				si->si_interval = (time_t)t;
5019 			}
5020 			if ( si->si_interval < 0 ) {
5021 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
5022 					"Error: parse_syncrepl_line: "
5023 					"invalid interval \"%ld\"",
5024 					(long) si->si_interval);
5025 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5026 				return -1;
5027 			}
5028 			si->si_got |= GOT_INTERVAL;
5029 		} else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=",
5030 					STRLENOF( RETRYSTR "=" ) ) )
5031 		{
5032 			if ( parse_syncrepl_retry( c, c->argv[ i ], si ) ) {
5033 				return 1;
5034 			}
5035 		} else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=",
5036 					STRLENOF( MANAGEDSAITSTR "=" ) ) )
5037 		{
5038 			val = c->argv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
5039 			if ( lutil_atoi( &si->si_manageDSAit, val ) != 0
5040 				|| si->si_manageDSAit < 0 || si->si_manageDSAit > 1 )
5041 			{
5042 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
5043 					"invalid manageDSAit value \"%s\".\n",
5044 					val );
5045 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5046 				return 1;
5047 			}
5048 			si->si_got |= GOT_MANAGEDSAIT;
5049 		} else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=",
5050 					STRLENOF( SLIMITSTR "=") ) )
5051 		{
5052 			val = c->argv[ i ] + STRLENOF( SLIMITSTR "=" );
5053 			if ( strcasecmp( val, "unlimited" ) == 0 ) {
5054 				si->si_slimit = 0;
5055 
5056 			} else if ( lutil_atoi( &si->si_slimit, val ) != 0 || si->si_slimit < 0 ) {
5057 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
5058 					"invalid size limit value \"%s\".\n",
5059 					val );
5060 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5061 				return 1;
5062 			}
5063 			si->si_got |= GOT_SLIMIT;
5064 		} else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=",
5065 					STRLENOF( TLIMITSTR "=" ) ) )
5066 		{
5067 			val = c->argv[ i ] + STRLENOF( TLIMITSTR "=" );
5068 			if ( strcasecmp( val, "unlimited" ) == 0 ) {
5069 				si->si_tlimit = 0;
5070 
5071 			} else if ( lutil_atoi( &si->si_tlimit, val ) != 0 || si->si_tlimit < 0 ) {
5072 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
5073 					"invalid time limit value \"%s\".\n",
5074 					val );
5075 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5076 				return 1;
5077 			}
5078 			si->si_got |= GOT_TLIMIT;
5079 		} else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=",
5080 					STRLENOF( SYNCDATASTR "=" ) ) )
5081 		{
5082 			val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
5083 			si->si_syncdata = verb_to_mask( val, datamodes );
5084 			si->si_got |= GOT_SYNCDATA;
5085 		} else if ( !strncasecmp( c->argv[ i ], STRICT_REFRESH,
5086 					STRLENOF( STRICT_REFRESH ) ) )
5087 		{
5088 			si->si_strict_refresh = 1;
5089 		} else if ( !bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
5090 			si->si_got |= GOT_BINDCONF;
5091 		} else {
5092 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
5093 				"Error: parse_syncrepl_line: "
5094 				"unable to parse \"%s\"\n", c->argv[ i ] );
5095 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5096 			return -1;
5097 		}
5098 	}
5099 
5100 	if ( ( si->si_got & GOT_REQUIRED ) != GOT_REQUIRED ) {
5101 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
5102 			"Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s",
5103 			si->si_got & GOT_RID ? "" : " "IDSTR,
5104 			si->si_got & GOT_PROVIDER ? "" : " "PROVIDERSTR,
5105 			si->si_got & GOT_SEARCHBASE ? "" : " "SEARCHBASESTR );
5106 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5107 		return -1;
5108 	}
5109 
5110 	if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
5111 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
5112 			"Base DN \"%s\" is not within the database naming context",
5113 			si->si_base.bv_val );
5114 		ch_free( si->si_base.bv_val );
5115 		BER_BVZERO( &si->si_base );
5116 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5117 		return -1;
5118 	}
5119 
5120 #ifdef ENABLE_REWRITE
5121 	if ( si->si_got & GOT_SUFFIXM ) {
5122 		if (config_suffixm( c, si )) {
5123 			ch_free( si->si_suffixm.bv_val );
5124 			BER_BVZERO( &si->si_suffixm );
5125 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
5126 				"Error configuring rewrite engine" );
5127 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5128 			return -1;
5129 		}
5130 	}
5131 #endif
5132 
5133 	if ( !( si->si_got & GOT_RETRY ) ) {
5134 		Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n",
5135 			si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", 0 );
5136 		if ( si->si_retryinterval == NULL ) {
5137 			if ( parse_syncrepl_retry( c, "retry=undefined", si ) ) {
5138 				return 1;
5139 			}
5140 		}
5141 	}
5142 
5143 	si->si_filter = str2filter( si->si_filterstr.bv_val );
5144 	if ( si->si_filter == NULL ) {
5145 		Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n",
5146 			si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
5147 		return 1;
5148 	}
5149 
5150 	return 0;
5151 }
5152 
5153 static int
5154 add_syncrepl(
5155 	ConfigArgs *c )
5156 {
5157 	syncinfo_t *si;
5158 	int	rc = 0;
5159 
5160 	if ( !( c->be->be_search && c->be->be_add && c->be->be_modify && c->be->be_delete ) ) {
5161 		snprintf( c->cr_msg, sizeof(c->cr_msg), "database %s does not support "
5162 			"operations required for syncrepl", c->be->be_type );
5163 		Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
5164 		return 1;
5165 	}
5166 	if ( BER_BVISEMPTY( &c->be->be_rootdn ) ) {
5167 		strcpy( c->cr_msg, "rootDN must be defined before syncrepl may be used" );
5168 		Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
5169 		return 1;
5170 	}
5171 	si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
5172 
5173 	if ( si == NULL ) {
5174 		Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
5175 		return 1;
5176 	}
5177 
5178 	si->si_bindconf.sb_tls = SB_TLS_OFF;
5179 	si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
5180 	si->si_schemachecking = 0;
5181 	ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
5182 		&si->si_filterstr );
5183 	si->si_base.bv_val = NULL;
5184 	si->si_scope = LDAP_SCOPE_SUBTREE;
5185 	si->si_attrsonly = 0;
5186 	si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
5187 	si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
5188 	si->si_attrs = NULL;
5189 	si->si_allattrs = 0;
5190 	si->si_allopattrs = 0;
5191 	si->si_exattrs = NULL;
5192 	si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
5193 	si->si_interval = 86400;
5194 	si->si_retryinterval = NULL;
5195 	si->si_retrynum_init = NULL;
5196 	si->si_retrynum = NULL;
5197 	si->si_manageDSAit = 0;
5198 	si->si_tlimit = 0;
5199 	si->si_slimit = 0;
5200 
5201 	si->si_presentlist = NULL;
5202 	LDAP_LIST_INIT( &si->si_nonpresentlist );
5203 	ldap_pvt_thread_mutex_init( &si->si_mutex );
5204 
5205 	rc = parse_syncrepl_line( c, si );
5206 
5207 	if ( rc == 0 ) {
5208 		LDAPURLDesc *lud;
5209 
5210 		/* Must be LDAPv3 because we need controls */
5211 		switch ( si->si_bindconf.sb_version ) {
5212 		case 0:
5213 			/* not explicitly set */
5214 			si->si_bindconf.sb_version = LDAP_VERSION3;
5215 			break;
5216 		case 3:
5217 			/* explicitly set */
5218 			break;
5219 		default:
5220 			Debug( LDAP_DEBUG_ANY,
5221 				"version %d incompatible with syncrepl\n",
5222 				si->si_bindconf.sb_version, 0, 0 );
5223 			syncinfo_free( si, 0 );
5224 			return 1;
5225 		}
5226 
5227 		if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
5228 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
5229 				"<%s> invalid URL", c->argv[0] );
5230 			Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
5231 				c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
5232 			return 1;
5233 		}
5234 
5235 		si->si_be = c->be;
5236 		if ( slapMode & SLAP_SERVER_MODE ) {
5237 			int isMe = 0;
5238 			/* check if consumer points to current server and database.
5239 			 * If so, ignore this configuration.
5240 			 */
5241 			if ( !SLAP_DBHIDDEN( c->be ) ) {
5242 				int i;
5243 				/* if searchbase doesn't match current DB suffix,
5244 				 * assume it's different
5245 				 */
5246 				for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
5247 					if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
5248 						isMe = 1;
5249 						break;
5250 					}
5251 				}
5252 				/* if searchbase matches, see if URLs match */
5253 				if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
5254 						lud ) == NULL )
5255 					isMe = 0;
5256 			}
5257 
5258 			if ( !isMe ) {
5259 				init_syncrepl( si );
5260 				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
5261 				si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
5262 					si->si_interval, do_syncrepl, si, "do_syncrepl",
5263 					si->si_ridtxt );
5264 				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
5265 				if ( si->si_re )
5266 					rc = config_sync_shadow( c ) ? -1 : 0;
5267 				else
5268 					rc = -1;
5269 			}
5270 		} else {
5271 			/* mirrormode still needs to see this flag in tool mode */
5272 			rc = config_sync_shadow( c ) ? -1 : 0;
5273 		}
5274 		ldap_free_urldesc( lud );
5275 	}
5276 
5277 #ifdef HAVE_TLS
5278 	/* Use main slapd defaults */
5279 	bindconf_tls_defaults( &si->si_bindconf );
5280 #endif
5281 	if ( rc < 0 ) {
5282 		Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
5283 		syncinfo_free( si, 0 );
5284 		return 1;
5285 	} else {
5286 		Debug( LDAP_DEBUG_CONFIG,
5287 			"Config: ** successfully added syncrepl %s \"%s\"\n",
5288 			si->si_ridtxt,
5289 			BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
5290 			"(null)" : si->si_bindconf.sb_uri.bv_val, 0 );
5291 		if ( c->be->be_syncinfo ) {
5292 			syncinfo_t *sip;
5293 
5294 			si->si_cookieState = c->be->be_syncinfo->si_cookieState;
5295 
5296 			/* add new syncrepl to end of list (same order as when deleting) */
5297 			for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next );
5298 			sip->si_next = si;
5299 		} else {
5300 			si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
5301 			ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
5302 			ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
5303 
5304 			c->be->be_syncinfo = si;
5305 		}
5306 		si->si_cookieState->cs_ref++;
5307 
5308 		si->si_next = NULL;
5309 
5310 		return 0;
5311 	}
5312 }
5313 
5314 static void
5315 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
5316 {
5317 	struct berval bc, uri, bs;
5318 	char buf[BUFSIZ*2], *ptr;
5319 	ber_len_t len;
5320 	int i;
5321 #	define WHATSLEFT	((ber_len_t) (&buf[sizeof( buf )] - ptr))
5322 
5323 	BER_BVZERO( bv );
5324 
5325 	/* temporarily inhibit bindconf from printing URI */
5326 	uri = si->si_bindconf.sb_uri;
5327 	BER_BVZERO( &si->si_bindconf.sb_uri );
5328 	si->si_bindconf.sb_version = 0;
5329 	bindconf_unparse( &si->si_bindconf, &bc );
5330 	si->si_bindconf.sb_uri = uri;
5331 	si->si_bindconf.sb_version = LDAP_VERSION3;
5332 
5333 	ptr = buf;
5334 	assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
5335 	len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
5336 		si->si_rid, si->si_bindconf.sb_uri.bv_val );
5337 	if ( len >= sizeof( buf ) ) return;
5338 	ptr += len;
5339 	if ( !BER_BVISNULL( &bc ) ) {
5340 		if ( WHATSLEFT <= bc.bv_len ) {
5341 			free( bc.bv_val );
5342 			return;
5343 		}
5344 		ptr = lutil_strcopy( ptr, bc.bv_val );
5345 		free( bc.bv_val );
5346 	}
5347 	if ( !BER_BVISEMPTY( &si->si_filterstr ) ) {
5348 		if ( WHATSLEFT <= STRLENOF( " " FILTERSTR "=\"" "\"" ) + si->si_filterstr.bv_len ) return;
5349 		ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
5350 		ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
5351 		*ptr++ = '"';
5352 	}
5353 	if ( !BER_BVISNULL( &si->si_base ) ) {
5354 		if ( WHATSLEFT <= STRLENOF( " " SEARCHBASESTR "=\"" "\"" ) + si->si_base.bv_len ) return;
5355 		ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
5356 		ptr = lutil_strcopy( ptr, si->si_base.bv_val );
5357 		*ptr++ = '"';
5358 	}
5359 #ifdef ENABLE_REWRITE
5360 	if ( !BER_BVISNULL( &si->si_suffixm ) ) {
5361 		if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
5362 		ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
5363 		ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
5364 		*ptr++ = '"';
5365 	}
5366 #endif
5367 	if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
5368 		if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
5369 		ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
5370 		ptr = lutil_strcopy( ptr, si->si_logfilterstr.bv_val );
5371 		*ptr++ = '"';
5372 	}
5373 	if ( !BER_BVISNULL( &si->si_logbase ) ) {
5374 		if ( WHATSLEFT <= STRLENOF( " " LOGBASESTR "=\"" "\"" ) + si->si_logbase.bv_len ) return;
5375 		ptr = lutil_strcopy( ptr, " " LOGBASESTR "=\"" );
5376 		ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
5377 		*ptr++ = '"';
5378 	}
5379 	if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
5380 		if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
5381 		ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
5382 		ptr = lutil_strcopy( ptr, bs.bv_val );
5383 	}
5384 	if ( si->si_attrsonly ) {
5385 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
5386 		ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR );
5387 	}
5388 	if ( si->si_anfile ) {
5389 		if ( WHATSLEFT <= STRLENOF( " " ATTRSSTR "=\":include:" "\"" ) + strlen( si->si_anfile ) ) return;
5390 		ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:\"" );
5391 		ptr = lutil_strcopy( ptr, si->si_anfile );
5392 		*ptr++ = '"';
5393 	} else if ( si->si_allattrs || si->si_allopattrs ||
5394 		( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) ) )
5395 	{
5396 		char *old;
5397 
5398 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
5399 		ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
5400 		old = ptr;
5401 		ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
5402 		if ( ptr == NULL ) return;
5403 		if ( si->si_allattrs ) {
5404 			if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
5405 			if ( old != ptr ) *ptr++ = ',';
5406 			*ptr++ = '*';
5407 		}
5408 		if ( si->si_allopattrs ) {
5409 			if ( WHATSLEFT <= STRLENOF( ",+\"" ) ) return;
5410 			if ( old != ptr ) *ptr++ = ',';
5411 			*ptr++ = '+';
5412 		}
5413 		*ptr++ = '"';
5414 	}
5415 	if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
5416 		if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
5417 		ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
5418 		ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
5419 		if ( ptr == NULL ) return;
5420 	}
5421 	if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
5422 	ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
5423 	ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
5424 
5425 	if ( WHATSLEFT <= STRLENOF( " " TYPESTR "=" ) + STRLENOF( "refreshAndPersist" ) ) return;
5426 	ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
5427 	ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
5428 		"refreshAndPersist" : "refreshOnly" );
5429 
5430 	if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
5431 		int dd, hh, mm, ss;
5432 
5433 		dd = si->si_interval;
5434 		ss = dd % 60;
5435 		dd /= 60;
5436 		mm = dd % 60;
5437 		dd /= 60;
5438 		hh = dd % 24;
5439 		dd /= 24;
5440 		len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
5441 			INTERVALSTR, dd, hh, mm, ss );
5442 		if ( len >= WHATSLEFT ) return;
5443 		ptr += len;
5444 	}
5445 
5446 	if ( si->si_got & GOT_RETRY ) {
5447 		const char *space = "";
5448 		if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
5449 		ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
5450 		for (i=0; si->si_retryinterval[i]; i++) {
5451 			len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
5452 				(long) si->si_retryinterval[i] );
5453 			space = " ";
5454 			if ( WHATSLEFT - 1 <= len ) return;
5455 			ptr += len;
5456 			if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
5457 				*ptr++ = '+';
5458 			else {
5459 				len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
5460 				if ( WHATSLEFT <= len ) return;
5461 				ptr += len;
5462 			}
5463 		}
5464 		if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
5465 		*ptr++ = '"';
5466 	} else {
5467 		ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" );
5468 	}
5469 
5470 	if ( si->si_slimit ) {
5471 		len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
5472 		if ( WHATSLEFT <= len ) return;
5473 		ptr += len;
5474 	}
5475 
5476 	if ( si->si_tlimit ) {
5477 		len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
5478 		if ( WHATSLEFT <= len ) return;
5479 		ptr += len;
5480 	}
5481 
5482 	if ( si->si_syncdata ) {
5483 		if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) {
5484 			if ( WHATSLEFT <= STRLENOF( " " SYNCDATASTR "=" ) + bc.bv_len ) return;
5485 			ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" );
5486 			ptr = lutil_strcopy( ptr, bc.bv_val );
5487 		}
5488 	}
5489 	bc.bv_len = ptr - buf;
5490 	bc.bv_val = buf;
5491 	ber_dupbv( bv, &bc );
5492 }
5493 
5494 int
5495 syncrepl_config( ConfigArgs *c )
5496 {
5497 	if (c->op == SLAP_CONFIG_EMIT) {
5498 		if ( c->be->be_syncinfo ) {
5499 			struct berval bv;
5500 			syncinfo_t *si;
5501 
5502 			for ( si = c->be->be_syncinfo; si; si=si->si_next ) {
5503 				syncrepl_unparse( si, &bv );
5504 				ber_bvarray_add( &c->rvalue_vals, &bv );
5505 			}
5506 			return 0;
5507 		}
5508 		return 1;
5509 	} else if ( c->op == LDAP_MOD_DELETE ) {
5510 		int isrunning = 0;
5511 		if ( c->be->be_syncinfo ) {
5512 			syncinfo_t *si, **sip;
5513 			int i;
5514 
5515 			for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
5516 				si = *sip;
5517 				if ( c->valx == -1 || i == c->valx ) {
5518 					*sip = si->si_next;
5519 					si->si_ctype = -1;
5520 					si->si_next = NULL;
5521 					/* If the task is currently active, we have to leave
5522 					 * it running. It will exit on its own. This will only
5523 					 * happen when running on the cn=config DB.
5524 					 */
5525 					if ( si->si_re ) {
5526 						if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
5527 							isrunning = 1;
5528 						} else {
5529 							/* There is no active thread, but we must still
5530 							 * ensure that no thread is (or will be) queued
5531 							 * while we removes the task.
5532 							 */
5533 							struct re_s *re = si->si_re;
5534 							si->si_re = NULL;
5535 
5536 							if ( si->si_conn ) {
5537 								connection_client_stop( si->si_conn );
5538 								si->si_conn = NULL;
5539 							}
5540 
5541 							ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
5542 							if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) {
5543 								ldap_pvt_runqueue_stoptask( &slapd_rq, re );
5544 								isrunning = 1;
5545 							}
5546 							if ( ldap_pvt_thread_pool_retract( &connection_pool,
5547 									re->routine, re ) > 0 )
5548 								isrunning = 0;
5549 
5550 							ldap_pvt_runqueue_remove( &slapd_rq, re );
5551 							ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
5552 
5553 							ldap_pvt_thread_mutex_unlock( &si->si_mutex );
5554 						}
5555 					}
5556 					if ( !isrunning ) {
5557 						syncinfo_free( si, 0 );
5558 					}
5559 					if ( i == c->valx )
5560 						break;
5561 				} else {
5562 					sip = &si->si_next;
5563 				}
5564 			}
5565 		}
5566 		if ( !c->be->be_syncinfo ) {
5567 			SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
5568 		}
5569 		return 0;
5570 	}
5571 	if ( SLAP_SLURP_SHADOW( c->be ) ) {
5572 		Debug(LDAP_DEBUG_ANY, "%s: "
5573 			"syncrepl: database already shadowed.\n",
5574 			c->log, 0, 0);
5575 		return(1);
5576 	} else {
5577 		return add_syncrepl( c );
5578 	}
5579 }
5580