syncrepl.c 150 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 2003-2011 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
 * Portions Copyright 2003 by IBM Corporation.
7
 * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
 * All rights reserved.
9
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
10
11
12
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
13
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
14
15
16
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
17
 */
18
19
20
21
22
23
24
25
26
27
28
29

#include "portable.h"

#include <stdio.h>

#include <ac/string.h>
#include <ac/socket.h>

#include "lutil.h"
#include "slap.h"
#include "lutil_ldap.h"

30
31
#include "config.h"

32
33
#include "ldap_rq.h"

34
35
#ifdef ENABLE_REWRITE
#include "rewrite.h"
Howard Chu's avatar
Howard Chu committed
36
#define SUFFIXM_CTX	"<suffix massage>"
37
38
#endif

39
40
41
42
43
44
struct nonpresent_entry {
	struct berval *npe_name;
	struct berval *npe_nname;
	LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
};

45
46
47
48
typedef struct cookie_state {
	ldap_pvt_thread_mutex_t	cs_mutex;
	int	cs_num;
	int cs_age;
49
	int cs_ref;
50
51
52
	struct berval *cs_vals;
	int *cs_sids;
	
53
54
55
56
57
58
59
	/* pending changes, not yet committed */
	ldap_pvt_thread_mutex_t	cs_pmutex;
	int	cs_pnum;
	struct berval *cs_pvals;
	int *cs_psids;
} cookie_state;

60
61
62
63
#define	SYNCDATA_DEFAULT	0	/* entries are plain LDAP entries */
#define	SYNCDATA_ACCESSLOG	1	/* entries are accesslog format */
#define	SYNCDATA_CHANGELOG	2	/* entries are changelog format */

64
65
66
#define	SYNCLOG_LOGGING		0	/* doing a log-based update */
#define	SYNCLOG_FALLBACK	1	/* doing a full refresh */

67
68
69
70
71
#define RETRYNUM_FOREVER	(-1)	/* retry forever */
#define RETRYNUM_TAIL		(-2)	/* end of retrynum array */
#define RETRYNUM_VALID(n)	((n) >= RETRYNUM_FOREVER)	/* valid retrynum */
#define RETRYNUM_FINITE(n)	((n) > RETRYNUM_FOREVER)	/* not forever */

72
typedef struct syncinfo_s {
73
	struct syncinfo_s	*si_next;
74
75
76
77
	BackendDB		*si_be;
	BackendDB		*si_wbe;
	struct re_s		*si_re;
	int			si_rid;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
78
	char			si_ridtxt[ STRLENOF("rid=999") + 1 ];
Howard Chu's avatar
Howard Chu committed
79
80
	slap_bindconf		si_bindconf;
	struct berval		si_base;
81
82
	struct berval		si_logbase;
	struct berval		si_filterstr;
83
	Filter			*si_filter;
84
	struct berval		si_logfilterstr;
85
	struct berval		si_contextdn;
86
87
88
	int			si_scope;
	int			si_attrsonly;
	char			*si_anfile;
Howard Chu's avatar
Howard Chu committed
89
90
	AttributeName		*si_anlist;
	AttributeName		*si_exanlist;
91
92
93
94
95
96
97
98
99
100
101
	char 			**si_attrs;
	char			**si_exattrs;
	int			si_allattrs;
	int			si_allopattrs;
	int			si_schemachecking;
	int			si_type;	/* the active type */
	int			si_ctype;	/* the configured type */
	time_t			si_interval;
	time_t			*si_retryinterval;
	int			*si_retrynum_init;
	int			*si_retrynum;
Howard Chu's avatar
Howard Chu committed
102
	struct sync_cookie	si_syncCookie;
103
	cookie_state		*si_cookieState;
104
105
106
107
108
109
	int			si_cookieAge;
	int			si_manageDSAit;
	int			si_slimit;
	int			si_tlimit;
	int			si_refreshDelete;
	int			si_refreshPresent;
110
	int			si_refreshDone;
111
112
	int			si_syncdata;
	int			si_logstate;
113
	int			si_got;
Howard Chu's avatar
Howard Chu committed
114
	int			si_strict_refresh;	/* stop listening during fallback refresh */
115
	ber_int_t	si_msgid;
116
117
	Avlnode			*si_presentlist;
	LDAP			*si_ld;
118
	Connection		*si_conn;
119
	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
120
121
122
123
#ifdef ENABLE_REWRITE
	struct rewrite_info *si_rewrite;
	struct berval	si_suffixm;
#endif
Howard Chu's avatar
Howard Chu committed
124
	ldap_pvt_thread_mutex_t	si_mutex;
125
126
} syncinfo_t;

127
static int syncuuid_cmp( const void *, const void * );
128
static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
129
static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
130
131
static int syncrepl_message_to_op(
					syncinfo_t *, Operation *, LDAPMessage * );
132
133
134
135
136
static int syncrepl_message_to_entry(
					syncinfo_t *, Operation *, LDAPMessage *,
					Modifications **, Entry **, int );
static int syncrepl_entry(
					syncinfo_t *, Operation*, Entry*,
137
138
					Modifications**,int, struct berval*,
					struct berval *cookieCSN );
139
static int syncrepl_updateCookie(
140
					syncinfo_t *, Operation *,
141
142
143
					struct sync_cookie * );
static struct berval * slap_uuidstr_from_normalized(
					struct berval *, struct berval *, void * );
144
145
static int syncrepl_add_glue_ancestors(
	Operation* op, Entry *e );
146

Howard Chu's avatar
Howard Chu committed
147
148
149
/* delta-mmr overlay handler */
static int syncrepl_op_modify( Operation *op, SlapReply *rs );

150
/* callback functions */
151
152
153
static int dn_callback( Operation *, SlapReply * );
static int nonpresent_callback( Operation *, SlapReply * );
static int null_callback( Operation *, SlapReply * );
154

155
static AttributeDescription *sync_descs[4];
156

Howard Chu's avatar
Howard Chu committed
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/* delta-mmr */
static AttributeDescription *ad_reqMod, *ad_reqDN;

typedef struct logschema {
	struct berval ls_dn;
	struct berval ls_req;
	struct berval ls_mod;
	struct berval ls_newRdn;
	struct berval ls_delRdn;
	struct berval ls_newSup;
} logschema;

static logschema changelog_sc = {
	BER_BVC("targetDN"),
	BER_BVC("changeType"),
	BER_BVC("changes"),
	BER_BVC("newRDN"),
	BER_BVC("deleteOldRDN"),
	BER_BVC("newSuperior")
};

static logschema accesslog_sc = {
	BER_BVC("reqDN"),
	BER_BVC("reqType"),
	BER_BVC("reqMod"),
	BER_BVC("reqNewRDN"),
	BER_BVC("reqDeleteOldRDN"),
	BER_BVC("reqNewSuperior")
};

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
static const char *
syncrepl_state2str( int state )
{
	switch ( state ) {
	case LDAP_SYNC_PRESENT:
		return "PRESENT";

	case LDAP_SYNC_ADD:
		return "ADD";

	case LDAP_SYNC_MODIFY:
		return "MODIFY";

	case LDAP_SYNC_DELETE:
		return "DELETE";
	}

	return "UNKNOWN";
}

Howard Chu's avatar
Howard Chu committed
207
208
static slap_overinst syncrepl_ov;

209
static void
210
init_syncrepl(syncinfo_t *si)
211
{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
212
	int i, j, k, l, n;
213
	char **attrs, **exattrs;
214

Howard Chu's avatar
Howard Chu committed
215
216
217
218
219
220
221
222
223
224
225
226
	if ( !syncrepl_ov.on_bi.bi_type ) {
		syncrepl_ov.on_bi.bi_type = "syncrepl";
		syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify;
		overlay_register( &syncrepl_ov );
	}

	/* delta-MMR needs the overlay, nothing else does.
	 * This must happen before accesslog overlay is configured.
	 */
	if ( si->si_syncdata &&
		!overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
		overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
Howard Chu's avatar
Howard Chu committed
227
228
229
230
231
232
233
		if ( !ad_reqMod ) {
			const char *text;
			logschema *ls = &accesslog_sc;

			slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
			slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
		}
Howard Chu's avatar
Howard Chu committed
234
235
	}

236
237
238
239
240
241
242
	if ( !sync_descs[0] ) {
		sync_descs[0] = slap_schema.si_ad_objectClass;
		sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
		sync_descs[2] = slap_schema.si_ad_entryCSN;
		sync_descs[3] = NULL;
	}

243
244
245
246
	if ( si->si_allattrs && si->si_allopattrs )
		attrs = NULL;
	else
		attrs = anlist2attrs( si->si_anlist );
247

248
249
250
251
	if ( attrs ) {
		if ( si->si_allattrs ) {
			i = 0;
			while ( attrs[i] ) {
252
				if ( !is_at_operational( at_find( attrs[i] ) ) ) {
253
254
255
256
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
257
					}
258
259
				} else {
					i++;
260
261
				}
			}
262
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
263
264
			attrs[i] = ch_strdup("*");
			attrs[i + 1] = NULL;
265

266
267
268
		} else if ( si->si_allopattrs ) {
			i = 0;
			while ( attrs[i] ) {
269
				if ( is_at_operational( at_find( attrs[i] ) ) ) {
270
271
272
273
274
275
276
277
278
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
					}
				} else {
					i++;
				}
			}
279
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
280
281
			attrs[i] = ch_strdup("+");
			attrs[i + 1] = NULL;
282
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
283

284
285
286
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
			j = 0;
			while ( attrs[j] ) {
287
				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
288
289
290
291
					for ( k = j; attrs[k] != NULL; k++ ) {
						if ( k == j )
							ch_free( attrs[k] );
						attrs[k] = attrs[k+1];
292
					}
293
294
				} else {
					j++;
295
296
				}
			}
297
298
299
300
301
		}

		for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;

		if ( si->si_allopattrs ) {
302
			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
303
		} else {
304
			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
305
306
307
308
309
310
		}

		/* Add Attributes */
		if ( si->si_allopattrs ) {
			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
		} else {
311
312
313
			for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
				attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
			}
314
		}
315
		attrs[ n ] = NULL;
316

317
	} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
318

319
		i = 0;
320
321
		if ( si->si_allattrs == si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
322
323
			attrs[i++] = ch_strdup( "*" );
			attrs[i++] = ch_strdup( "+" );
324
325
326
327
328
329
		} else if ( si->si_allattrs && !si->si_allopattrs ) {
			for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
			attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
			attrs[i++] = ch_strdup( "*" );
			for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
				attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
330
			}
331
332
333
334
		} else if ( !si->si_allattrs && si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
			attrs[i++] = ch_strdup( "+" );
			attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
335
336
		}
		attrs[i] = NULL;
337
338
	}
	
339
340
341
342
343
	si->si_attrs = attrs;

	exattrs = anlist2attrs( si->si_exanlist );

	if ( exattrs ) {
344
345
		for ( n = 0; exattrs[n] != NULL; n++ ) ;

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
346
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
347
348
			j = 0;
			while ( exattrs[j] != NULL ) {
349
				if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
Howard Chu's avatar
Cleanup    
Howard Chu committed
350
					ch_free( exattrs[j] );
351
352
					for ( k = j; exattrs[k] != NULL; k++ ) {
						exattrs[k] = exattrs[k+1];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
353
					}
354
355
				} else {
					j++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
356
357
358
				}
			}
		}
359
360
361

		for ( i = 0; exattrs[i] != NULL; i++ ) {
			for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
362
363
				ObjectClass	*oc;
				if ( ( oc = si->si_anlist[j].an_oc ) ) {
364
365
366
					k = 0;
					while ( oc->soc_required[k] ) {
						if ( !strcmp( exattrs[i],
367
							 oc->soc_required[k]->sat_cname.bv_val ) ) {
Howard Chu's avatar
Cleanup    
Howard Chu committed
368
							ch_free( exattrs[i] );
369
370
371
372
373
							for ( l = i; exattrs[l]; l++ ) {
								exattrs[l] = exattrs[l+1];
							}
						} else {
							k++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
374
375
376
377
378
						}
					}
				}
			}
		}
379
380

		for ( i = 0; exattrs[i] != NULL; i++ ) ;
381
382

		if ( i != n )
383
			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
384
	}
385
386

	si->si_exattrs = exattrs;	
387
388
}

389
static int
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
390
391
ldap_sync_search(
	syncinfo_t *si,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
392
	void *ctx )
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
393
{
394
395
	BerElementBuffer berbuf;
	BerElement *ber = (BerElement *)&berbuf;
396
	LDAPControl c[3], *ctrls[4];
397
	int rc;
398
399
	int rhint;
	char *base;
Howard Chu's avatar
Howard Chu committed
400
	char **attrs, *lattrs[8];
401
402
403
	char *filter;
	int attrsonly;
	int scope;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
404

405
406
407
	/* setup LDAP SYNC control */
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
408

409
410
411
	/* If we're using a log but we have no state, then fallback to
	 * normal mode for a full refresh.
	 */
412
	if ( si->si_syncdata && !si->si_syncCookie.numcsns ) {
413
		si->si_logstate = SYNCLOG_FALLBACK;
414
	}
415
416
417

	/* Use the log parameters if we're in log mode */
	if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
Howard Chu's avatar
Howard Chu committed
418
419
420
421
422
423
424
425
426
427
428
429
430
431
		logschema *ls;
		if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
			ls = &accesslog_sc;
		else
			ls = &changelog_sc;
		lattrs[0] = ls->ls_dn.bv_val;
		lattrs[1] = ls->ls_req.bv_val;
		lattrs[2] = ls->ls_mod.bv_val;
		lattrs[3] = ls->ls_newRdn.bv_val;
		lattrs[4] = ls->ls_delRdn.bv_val;
		lattrs[5] = ls->ls_newSup.bv_val;
		lattrs[6] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
		lattrs[7] = NULL;

432
433
434
		rhint = 0;
		base = si->si_logbase.bv_val;
		filter = si->si_logfilterstr.bv_val;
Howard Chu's avatar
Howard Chu committed
435
		attrs = lattrs;
436
		attrsonly = 0;
437
		scope = LDAP_SCOPE_SUBTREE;
438
439
440
441
442
443
444
445
446
	} else {
		rhint = 1;
		base = si->si_base.bv_val;
		filter = si->si_filterstr.bv_val;
		attrs = si->si_attrs;
		attrsonly = si->si_attrsonly;
		scope = si->si_scope;
	}
	if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
Howard Chu's avatar
Howard Chu committed
447
		si->si_type = LDAP_SYNC_REFRESH_ONLY;
448
	} else {
Howard Chu's avatar
Howard Chu committed
449
		si->si_type = si->si_ctype;
450
451
	}

452
	if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
453
	{
Howard Chu's avatar
Howard Chu committed
454
		ber_printf( ber, "{eOb}",
Howard Chu's avatar
Howard Chu committed
455
			abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
456
	} else {
Howard Chu's avatar
Howard Chu committed
457
		ber_printf( ber, "{eb}",
Howard Chu's avatar
Howard Chu committed
458
			abs(si->si_type), rhint );
459
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
460

461
	if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
462
463
464
		ber_free_buf( ber );
		return rc;
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
465

466
	c[0].ldctl_oid = LDAP_CONTROL_SYNC;
467
	c[0].ldctl_iscritical = si->si_type < 0;
468
	ctrls[0] = &c[0];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
469

470
471
472
473
474
	c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
	BER_BVZERO( &c[1].ldctl_value );
	c[1].ldctl_iscritical = 1;
	ctrls[1] = &c[1];

475
	if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
476
477
478
479
480
		c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
		c[2].ldctl_value = si->si_bindconf.sb_authzId;
		c[2].ldctl_iscritical = 1;
		ctrls[2] = &c[2];
		ctrls[3] = NULL;
481
	} else {
482
		ctrls[2] = NULL;
483
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
484

485
	rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
486
		ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
487
	ber_free_buf( ber );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
488
489
490
	return rc;
}

491
492
493
494
495
496
497
498
static int
check_syncprov(
	Operation *op,
	syncinfo_t *si )
{
	AttributeName at[2];
	Attribute a = {0};
	Entry e = {0};
499
	SlapReply rs = {REP_SEARCH};
500
501
502
503
504
505
506
507
508
509
	int i, j, changed = 0;

	/* Look for contextCSN from syncprov overlay. If
	 * there's no overlay, this will be a no-op. That means
	 * this is a pure consumer, so local changes will not be
	 * allowed, and all changes will already be reflected in
	 * the cookieState.
	 */
	a.a_desc = slap_schema.si_ad_contextCSN;
	e.e_attrs = &a;
510
511
	e.e_name = si->si_contextdn;
	e.e_nname = si->si_contextdn;
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
	at[0].an_name = a.a_desc->ad_cname;
	at[0].an_desc = a.a_desc;
	BER_BVZERO( &at[1].an_name );
	rs.sr_entry = &e;
	rs.sr_flags = REP_ENTRY_MODIFIABLE;
	rs.sr_attrs = at;
	op->o_req_dn = e.e_name;
	op->o_req_ndn = e.e_nname;

	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
	i = backend_operational( op, &rs );
	if ( i == LDAP_SUCCESS && a.a_nvals ) {
		int num = a.a_numvals;
		/* check for differences */
		if ( num != si->si_cookieState->cs_num ) {
			changed = 1;
		} else {
			for ( i=0; i<num; i++ ) {
				if ( ber_bvcmp( &a.a_nvals[i],
					&si->si_cookieState->cs_vals[i] )) {
532
					changed = 1;
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
					break;
				}
			}
		}
		if ( changed ) {
			ber_bvarray_free( si->si_cookieState->cs_vals );
			ch_free( si->si_cookieState->cs_sids );
			si->si_cookieState->cs_num = num;
			si->si_cookieState->cs_vals = a.a_nvals;
			si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
				num, NULL );
			si->si_cookieState->cs_age++;
		} else {
			ber_bvarray_free( a.a_nvals );
		}
		ber_bvarray_free( a.a_vals );
	}
	/* See if the cookieState has changed due to anything outside
	 * this particular consumer. That includes other consumers in
	 * the same context, or local changes detected above.
	 */
	if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
		si->si_cookieState->cs_age ) {
		if ( !si->si_syncCookie.numcsns ) {
			ber_bvarray_free( si->si_syncCookie.ctxcsn );
			ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
				si->si_cookieState->cs_vals, NULL );
			changed = 1;
		} else {
			for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
				/* bogus, just dup everything */
				if ( si->si_syncCookie.sids[i] == -1 ) {
					ber_bvarray_free( si->si_syncCookie.ctxcsn );
					ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
						si->si_cookieState->cs_vals, NULL );
					changed = 1;
					break;
				}
				for (j=0; j<si->si_cookieState->cs_num; j++) {
					if ( si->si_syncCookie.sids[i] !=
						si->si_cookieState->cs_sids[j] )
						continue;
					if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
						&si->si_cookieState->cs_vals[j] ))
						break;
					ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
						&si->si_cookieState->cs_vals[j] );
					changed = 1;
					break;
				}
			}
		}
	}
	if ( changed ) {
		si->si_cookieAge = si->si_cookieState->cs_age;
		ch_free( si->si_syncCookie.octet_str.bv_val );
		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
			si->si_syncCookie.sid );
Howard Chu's avatar
Howard Chu committed
592
		slap_parse_sync_cookie( &si->si_syncCookie, NULL );
593
594
595
596
597
	}
	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
	return changed;
}

598
599
600
601
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
602
603
{
	int	rc;
604
	int cmdline_cookie_found = 0;
605

606
	struct sync_cookie	*sc = NULL;
607
608
609
#ifdef HAVE_TLS
	void	*ssl;
#endif
610

611
	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
612
	if ( rc != LDAP_SUCCESS ) {
613
		goto done;
614
	}
615
	op->o_protocol = LDAP_VERSION3;
616

617
618
619
	/* Set SSF to strongest of TLS, SASL SSFs */
	op->o_sasl_ssf = 0;
	op->o_tls_ssf = 0;
620
	op->o_transport_ssf = 0;
621
#ifdef HAVE_TLS
622
623
624
	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
		== LDAP_SUCCESS && ssl != NULL )
	{
625
626
627
		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
	}
#endif /* HAVE_TLS */
628
629
630
	{
		ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
						  to use sasl_ssf_t but currently uses ber_len_t */
Howard Chu's avatar
Howard Chu committed
631
632
633
		if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
			== LDAP_SUCCESS )
			op->o_sasl_ssf = ssf;
634
	}
635
636
	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
		?  op->o_sasl_ssf : op->o_tls_ssf;
637

638
639
	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );

640
641
642
	rc = LDAP_DEREF_NEVER;	/* actually could allow DEREF_FINDING */
	ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );

643
644
	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );

645
	si->si_syncCookie.rid = si->si_rid;
646
647

	/* whenever there are multiple data sources possible, advertise sid */
Howard Chu's avatar
Howard Chu committed
648
649
	si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
		slap_serverID : -1;
650

651
652
653
	/* We've just started up, or the remote server hasn't sent us
	 * any meaningful state.
	 */
654
	if ( !si->si_syncCookie.ctxcsn ) {
655
		int i;
656

657
658
659
660
661
662
663
664
665
		LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
			if ( si->si_rid == sc->rid ) {
				cmdline_cookie_found = 1;
				break;
			}
		}

		if ( cmdline_cookie_found ) {
			/* cookie is supplied in the command line */
666

667
668
			LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );

669
670
			/* ctxcsn wasn't parsed yet, do it now */
			slap_parse_sync_cookie( sc, op->o_tmpmemctx );
671
			slap_sync_cookie_free( &si->si_syncCookie, 0 );
672
673
			slap_dup_sync_cookie( &si->si_syncCookie, sc );
			slap_sync_cookie_free( sc, 1 );
674
675
676
677
		} else {
			ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
			if ( !si->si_cookieState->cs_num ) {
				/* get contextCSN shadow replica from database */
Howard Chu's avatar
Howard Chu committed
678
				BerVarray csn = NULL;
679
680
				void *ctx = op->o_tmpmemctx;

681
				op->o_req_ndn = si->si_contextdn;
Howard Chu's avatar
Howard Chu committed
682
683
684
685
686
687
688
689
690
691
692
693
				op->o_req_dn = op->o_req_ndn;

				/* try to read stored contextCSN */
				op->o_tmpmemctx = NULL;
				backend_attribute( op, NULL, &op->o_req_ndn,
					slap_schema.si_ad_contextCSN, &csn, ACL_READ );
				op->o_tmpmemctx = ctx;
				if ( csn ) {
					si->si_cookieState->cs_vals = csn;
					for (i=0; !BER_BVISNULL( &csn[i] ); i++);
					si->si_cookieState->cs_num = i;
					si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
694
695
696
697
698
699
700
				}
			}
			if ( si->si_cookieState->cs_num ) {
				ber_bvarray_free( si->si_syncCookie.ctxcsn );
				if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
					si->si_cookieState->cs_vals, NULL )) {
					rc = LDAP_NO_MEMORY;
Howard Chu's avatar
Howard Chu committed
701
					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
702
703
704
705
706
707
708
709
710
					goto done;
				}
				si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
				si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num *
					sizeof(int) );
				for ( i=0; i<si->si_syncCookie.numcsns; i++ )
					si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
			}
			ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
711
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
712

Howard Chu's avatar
Howard Chu committed
713
		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
714
			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
715
			si->si_syncCookie.sid );
716
	} else {
717
718
		/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
		ch_free( si->si_syncCookie.octet_str.bv_val );
719
		BER_BVZERO( &si->si_syncCookie.octet_str );
720
721
		/* Look for contextCSN from syncprov overlay. */
		check_syncprov( op, si );
722
723
724
725
		if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
			slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
				si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
				si->si_syncCookie.sid );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
726
727
	}

728
729
	si->si_refreshDone = 0;

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
730
	rc = ldap_sync_search( si, op->o_tmpmemctx );
731

732
	if( rc != LDAP_SUCCESS ) {
733
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
734
			"ldap_search_ext: %s (%d)\n",
735
			si->si_ridtxt, ldap_err2string( rc ), rc );
736
737
738
739
740
	}

done:
	if ( rc ) {
		if ( si->si_ld ) {
741
			ldap_unbind_ext( si->si_ld, NULL, NULL );
742
743
744
745
746
747
748
			si->si_ld = NULL;
		}
	}

	return rc;
}

749
750
751
752
753
754
755
756
static int
compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
{
	int i, j, match = 0;
	const char *text;

	*which = 0;

757
758
759
760
761
	if ( sc1->numcsns < sc2->numcsns ) {
		*which = sc1->numcsns;
		return -1;
	}

762
763
	for (j=0; j<sc2->numcsns; j++) {
		for (i=0; i<sc1->numcsns; i++) {
764
765
766
767
768
			if ( sc1->sids[i] != sc2->sids[j] )
				continue;
			value_match( &match, slap_schema.si_ad_entryCSN,
				slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
				SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
Howard Chu's avatar
Howard Chu committed
769
				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
770
771
772
773
774
775
			if ( match < 0 ) {
				*which = j;
				return match;
			}
			break;
		}
776
777
778
779
780
		if ( i == sc1->numcsns ) {
			/* sc2 has a sid sc1 lacks */
			*which = j;
			return -1;
		}
781
782
783
784
	}
	return match;
}

785
786
#define	SYNC_PAUSED	-3

787
788
789
790
791
792
793
794
795
796
static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*msg = NULL;

797
798
	struct sync_cookie	syncCookie = { NULL };
	struct sync_cookie	syncCookie_req = { NULL };
799

800
801
	int		rc,
			err = LDAP_SUCCESS;
802
803
804

	Modifications	*modlist = NULL;

805
	int				m;
806
807
808
809

	struct timeval *tout_p = NULL;
	struct timeval tout = { 0, 0 };

810
	int		refreshDeletes = 0;
Howard Chu's avatar
Howard Chu committed
811
	char empty[6] = "empty";
812

813
	if ( slapd_shutdown ) {
814
		rc = -2;
815
		goto done;
816
817
	}

818
819
820
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

821
	Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt, 0, 0 );
822

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
823
	slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
824

Kurt Zeilenga's avatar
Kurt Zeilenga committed
825
	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
826
827
828
829
830
		tout_p = &tout;
	} else {
		tout_p = NULL;
	}

831
	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
832
		tout_p, &msg ) ) > 0 )
833
	{
834
835
836
837
838
839
840
841
		int				match, punlock, syncstate;
		struct berval	*retdata, syncUUID, cookie = BER_BVNULL;
		char			*retoid;
		LDAPControl		**rctrls = NULL, *rctrlp = NULL;
		BerVarray		syncUUIDs;
		ber_len_t		len;
		ber_tag_t		si_tag;
		Entry			*entry;
Howard Chu's avatar
Howard Chu committed
842
		struct berval	bdn;
843

844
		if ( slapd_shutdown ) {
845
846
			rc = -2;
			goto done;
847
		}
848
849
850
		switch( ldap_msgtype( msg ) ) {
		case LDAP_RES_SEARCH_ENTRY:
			ldap_get_entry_controls( si->si_ld, msg, &rctrls );
Howard Chu's avatar
Howard Chu committed
851
852
853
854
855
			ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
			if (!bdn.bv_len) {
				bdn.bv_val = empty;
				bdn.bv_len = sizeof(empty)-1;
			}
856
857
			/* we can't work without the control */
			if ( rctrls ) {
Howard Chu's avatar
Howard Chu committed
858
				LDAPControl **next = NULL;
859
860
861
				/* NOTE: make sure we use the right one;
				 * a better approach would be to run thru
				 * the whole list and take care of all */
862
863
864
865
				/* NOTE: since we issue the search request,
				 * we should know what controls to expect,
				 * and there should be none apart from the
				 * sync-related control */
866
867
868
				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
				{
Howard Chu's avatar
Howard Chu committed
869
					bdn.bv_val[bdn.bv_len] = '\0';
870
					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
871
						"got search entry with multiple "
Howard Chu's avatar
Howard Chu committed
872
						"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
873
					ldap_controls_free( rctrls );
Howard Chu's avatar
Howard Chu committed
874
875
876
					rc = -1;
					goto done;
				}
877
878
			}
			if ( rctrlp == NULL ) {
Howard Chu's avatar
Howard Chu committed
879
				bdn.bv_val[bdn.bv_len] = '\0';
880
881
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
					"got search entry without "
Howard Chu's avatar
Howard Chu committed
882
					"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
883
884
885
886
				rc = -1;
				goto done;
			}
			ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
887
888
			if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID )
					== LBER_ERROR ) {
Howard Chu's avatar
Howard Chu committed
889
890
891
				bdn.bv_val[bdn.bv_len] = '\0';
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
					si->si_ridtxt, bdn.bv_val, 0 );
892
893
894
895
				ldap_controls_free( rctrls );
				rc = -1;
				goto done;
			}
896
897
898
			/* FIXME: what if syncUUID is NULL or empty?
			 * (happens with back-sql...) */
			if ( BER_BVISEMPTY( &syncUUID ) ) {
Howard Chu's avatar
Howard Chu committed
899
				bdn.bv_val[bdn.bv_len] = '\0';
900
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
Howard Chu's avatar
Howard Chu committed
901
					"got empty syncUUID with LDAP_SYNC_%s (%s)\n",
902
					si->si_ridtxt,
Howard Chu's avatar
Howard Chu committed
903
					syncrepl_state2str( syncstate ), bdn.bv_val );
904
905
906
907
				ldap_controls_free( rctrls );
				rc = -1;
				goto done;
			}
908
			punlock = -1;
909
910
911
			if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
				ber_scanf( ber, /*"{"*/ "m}", &cookie );

912
913
914
				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
					si->si_ridtxt,
					BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
915
916
917
918
919
920
921
922
923
924

				if ( !BER_BVISNULL( &cookie ) ) {
					ch_free( syncCookie.octet_str.bv_val );
					ber_dupbv( &syncCookie.octet_str, &cookie );
				}
				if ( !BER_BVISNULL( &syncCookie.octet_str ) )
				{
					slap_parse_sync_cookie( &syncCookie, NULL );
					if ( syncCookie.ctxcsn ) {
						int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
925
						check_syncprov( op, si );
926
						for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
927
928
							if ( si->si_cookieState->cs_sids[i] == sid ) {
								if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
Howard Chu's avatar
Howard Chu committed
929
930
931
									bdn.bv_val[bdn.bv_len] = '\0';
									Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
										si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
932
933
934
935
936
									ldap_controls_free( rctrls );
									rc = 0;
									goto done;
								}
								break;
937
938
							}
						}
939
						/* check pending CSNs too */
940
941
942
943
944
945
946
947
						while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
							if ( slapd_shutdown ) {
								rc = -2;
								goto done;
							}
							if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
								ldap_pvt_thread_yield();
						}
948
949
950
						for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
							if ( si->si_cookieState->cs_psids[i] == sid ) {
								if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
Howard Chu's avatar
Howard Chu committed
951
952
953
									bdn.bv_val[bdn.bv_len] = '\0';
									Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s (%s)\n",
										si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
954
955
956
957
958
959
960
961
962
963
964
965
966
967
									ldap_controls_free( rctrls );
									rc = 0;
									ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
									goto done;
								}
								ber_bvreplace( &si->si_cookieState->cs_pvals[i],
									syncCookie.ctxcsn );
								break;
							}
						}
						/* new SID, add it */
						if ( i == si->si_cookieState->cs_pnum ) {
							value_add( &si->si_cookieState->cs_pvals, syncCookie.ctxcsn );
							si->si_cookieState->cs_pnum++;
Howard Chu's avatar
Howard Chu committed
968
							si->si_cookieState->cs_psids = ch_realloc( si->si_cookieState->cs_psids, si->si_cookieState->cs_pnum * sizeof(int));
969
970
							si->si_cookieState->cs_psids[i] = sid;
						}
971
						assert( punlock < 0 );
972
						punlock = i;
973
					}
974
					op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
975
976
977
978
979
980
981
982
				}
			}
			rc = 0;
			if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
				modlist = NULL;
				if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
					syncCookie.ctxcsn )
				{
983
					rc = syncrepl_updateCookie( si, op, &syncCookie );
984
985
986
987
988
989
990
991
				} else switch ( rc ) {
					case LDAP_ALREADY_EXISTS:
					case LDAP_NO_SUCH_OBJECT:
					case LDAP_NO_SUCH_ATTRIBUTE:
					case LDAP_TYPE_OR_VALUE_EXISTS:
						rc = LDAP_SYNC_REFRESH_REQUIRED;
						si->si_logstate = SYNCLOG_FALLBACK;
						ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
992
993
994
						bdn.bv_val[bdn.bv_len] = '\0';
						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
							si->si_ridtxt, bdn.bv_val, 0 );
Howard Chu's avatar
Howard Chu committed
995
996
997
998
						if (si->si_strict_refresh) {
							slap_suspend_listeners();
							connections_drop();
						}
999
1000
1001
						break;
					default:
						break;
1002
1003
1004
1005
1006
1007
1008
1009
				}
			} else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
				&modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
			{
				if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
					syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
					syncCookie.ctxcsn )
				{
1010
					rc = syncrepl_updateCookie( si, op, &syncCookie );
1011
1012
				}
			}
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
			if ( punlock >= 0 ) {
				/* on failure, revert pending CSN */
				if ( rc != LDAP_SUCCESS ) {
					int i;
					for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
						if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
							ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
								&si->si_cookieState->cs_vals[i] );
							break;
						}
					}
					if ( i == si->si_cookieState->cs_num )
						si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
				}
1027
				ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
1028
			}
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
			ldap_controls_free( rctrls );
			if ( modlist ) {
				slap_mods_free( modlist, 1 );
			}
			if ( rc )
				goto done;
			break;

		case LDAP_RES_SEARCH_REFERENCE:
			Debug( LDAP_DEBUG_ANY,
				"do_syncrep2: %s reference received error\n",
				si->si_ridtxt, 0, 0 );
			break;

		case LDAP_RES_SEARCH_RESULT:
			Debug( LDAP_DEBUG_SYNC,
				"do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
				si->si_ridtxt, 0, 0 );
1047
			err = LDAP_OTHER; /* FIXME check parse result properly */
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
			ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
				&rctrls, 0 );
#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
			if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
				/* map old result code to registered code */
				err = LDAP_SYNC_REFRESH_REQUIRED;
			}
#endif
			if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
				if ( si->si_logstate == SYNCLOG_LOGGING ) {
					si->si_logstate = SYNCLOG_FALLBACK;
1059
1060
					Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
						si->si_ridtxt, 0, 0 );
Howard Chu's avatar
Howard Chu committed
1061
1062
1063
1064
					if (si->si_strict_refresh) {
						slap_suspend_listeners();
						connections_drop();
					}
1065
				}
1066
1067
1068
				rc = err;
				goto done;
			}
1069
1070
1071
1072
1073
			if ( err ) {
				Debug( LDAP_DEBUG_ANY,
					"do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
					si->si_ridtxt, err, ldap_err2string( err ) );
			}
1074
			if ( rctrls ) {
Howard Chu's avatar
Howard Chu committed
1075
				LDAPControl **next = NULL;
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
				/* NOTE: make sure we use the right one;
				 * a better approach would be to run thru
				 * the whole list and take care of all */
				/* NOTE: since we issue the search request,
				 * we should know what controls to expect,
				 * and there should be none apart from the
				 * sync-related control */
				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next );
				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) )
				{
					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
						"got search result with multiple "
						"Sync State control\n", si->si_ridtxt, 0, 0 );
					ldap_controls_free( rctrls );
					rc = -1;
					goto done;
				}
			}