syncrepl.c 159 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
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 2003-2020 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
 * Portions Copyright 2003 by IBM Corporation.
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
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
36
37
38
#ifdef ENABLE_REWRITE
#include "rewrite.h"
#define SUFFIXM_CTX	"<suffix massage>"
#endif

Howard Chu's avatar
Howard Chu committed
39
40
#define	UUIDLEN	16

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

47
48
typedef struct cookie_state {
	ldap_pvt_thread_mutex_t	cs_mutex;
49
	ldap_pvt_thread_cond_t cs_cond;
50
51
	struct berval *cs_vals;
	int *cs_sids;
52
53
	int	cs_num;
	int cs_age;
54
	int cs_ref;
55
	int cs_updating;
56

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
57
58
59
60
	/* pending changes, not yet committed */
	ldap_pvt_thread_mutex_t	cs_pmutex;
	struct berval *cs_pvals;
	int *cs_psids;
61
	int	cs_pnum;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
62
63
} cookie_state;

64
65
66
67
#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 */

68
69
70
#define	SYNCLOG_LOGGING		0	/* doing a log-based update */
#define	SYNCLOG_FALLBACK	1	/* doing a full refresh */

71
72
73
74
75
#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 */

76
typedef struct syncinfo_s {
77
	struct syncinfo_s	*si_next;
78
79
80
81
	BackendDB		*si_be;
	BackendDB		*si_wbe;
	struct re_s		*si_re;
	int			si_rid;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
82
	char			si_ridtxt[ STRLENOF("rid=999") + 1 ];
Howard Chu's avatar
Howard Chu committed
83
84
	slap_bindconf		si_bindconf;
	struct berval		si_base;
85
86
87
	struct berval		si_logbase;
	struct berval		si_filterstr;
	struct berval		si_logfilterstr;
88
89
	Filter			*si_filter;
	Filter			*si_logfilter;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
90
	struct berval		si_contextdn;
91
92
93
	int			si_scope;
	int			si_attrsonly;
	char			*si_anfile;
Howard Chu's avatar
Howard Chu committed
94
95
	AttributeName		*si_anlist;
	AttributeName		*si_exanlist;
96
97
98
99
100
101
102
103
104
105
106
	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
107
	struct sync_cookie	si_syncCookie;
108
	cookie_state		*si_cookieState;
109
110
111
112
113
114
	int			si_cookieAge;
	int			si_manageDSAit;
	int			si_slimit;
	int			si_tlimit;
	int			si_refreshDelete;
	int			si_refreshPresent;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
115
	int			si_refreshDone;
116
117
	int			si_syncdata;
	int			si_logstate;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
118
	int			si_got;
Howard Chu's avatar
Howard Chu committed
119
	int			si_strict_refresh;	/* stop listening during fallback refresh */
120
	int			si_too_old;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
121
	ber_int_t	si_msgid;
122
123
	Avlnode			*si_presentlist;
	LDAP			*si_ld;
124
	Connection		*si_conn;
125
	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
126
127
128
129
#ifdef ENABLE_REWRITE
	struct rewrite_info *si_rewrite;
	struct berval	si_suffixm;
#endif
Howard Chu's avatar
Howard Chu committed
130
	ldap_pvt_thread_mutex_t	si_mutex;
131
132
} syncinfo_t;

133
static int syncuuid_cmp( const void *, const void * );
Howard Chu's avatar
Howard Chu committed
134
135
136
137
static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
static void presentlist_delete( Avlnode **av, struct berval *syncUUID );
static char *presentlist_find( Avlnode *av, struct berval *syncUUID );
static int presentlist_free( Avlnode *av );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
138
static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
139
140
static int syncrepl_message_to_op(
					syncinfo_t *, Operation *, LDAPMessage * );
141
142
static int syncrepl_message_to_entry(
					syncinfo_t *, Operation *, LDAPMessage *,
143
					Modifications **, Entry **, int, struct berval* );
144
145
static int syncrepl_entry(
					syncinfo_t *, Operation*, Entry*,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
146
147
					Modifications**,int, struct berval*,
					struct berval *cookieCSN );
148
static int syncrepl_updateCookie(
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
149
					syncinfo_t *, Operation *,
150
					struct sync_cookie *, int save );
151
152
static struct berval * slap_uuidstr_from_normalized(
					struct berval *, struct berval *, void * );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
153
154
static int syncrepl_add_glue_ancestors(
	Operation* op, Entry *e );
155

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

159
/* callback functions */
160
161
static int dn_callback( Operation *, SlapReply * );
static int nonpresent_callback( Operation *, SlapReply * );
162

163
static AttributeDescription *sync_descs[4];
164

Howard Chu's avatar
Howard Chu committed
165
166
167
168
169
170
171
172
173
174
/* 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;
175
	struct berval ls_controls;
Howard Chu's avatar
Howard Chu committed
176
177
178
179
180
181
182
183
} logschema;

static logschema changelog_sc = {
	BER_BVC("targetDN"),
	BER_BVC("changeType"),
	BER_BVC("changes"),
	BER_BVC("newRDN"),
	BER_BVC("deleteOldRDN"),
184
185
	BER_BVC("newSuperior"),
	BER_BVC("controls")
Howard Chu's avatar
Howard Chu committed
186
187
188
189
190
191
192
193
};

static logschema accesslog_sc = {
	BER_BVC("reqDN"),
	BER_BVC("reqType"),
	BER_BVC("reqMod"),
	BER_BVC("reqNewRDN"),
	BER_BVC("reqDeleteOldRDN"),
194
195
	BER_BVC("reqNewSuperior"),
	BER_BVC("reqControls")
Howard Chu's avatar
Howard Chu committed
196
197
};

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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
218
219
static slap_overinst syncrepl_ov;

220
static void
221
init_syncrepl(syncinfo_t *si)
222
{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
223
	int i, j, k, l, n;
224
	char **attrs, **exattrs;
225

Howard Chu's avatar
Howard Chu committed
226
227
228
229
230
231
232
233
234
235
236
237
	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
238
239
240
241
242
243
244
		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
245
246
	}

247
248
249
250
251
252
253
	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;
	}

254
255
256
257
	if ( si->si_allattrs && si->si_allopattrs )
		attrs = NULL;
	else
		attrs = anlist2attrs( si->si_anlist );
258

259
260
261
262
	if ( attrs ) {
		if ( si->si_allattrs ) {
			i = 0;
			while ( attrs[i] ) {
263
				if ( !is_at_operational( at_find( attrs[i] ) ) ) {
264
265
266
267
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
268
					}
269
270
				} else {
					i++;
271
272
				}
			}
273
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
274
275
			attrs[i] = ch_strdup("*");
			attrs[i + 1] = NULL;
276

277
278
279
		} else if ( si->si_allopattrs ) {
			i = 0;
			while ( attrs[i] ) {
280
				if ( is_at_operational( at_find( attrs[i] ) ) ) {
281
282
283
284
285
286
287
288
289
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
					}
				} else {
					i++;
				}
			}
290
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
291
292
			attrs[i] = ch_strdup("+");
			attrs[i + 1] = NULL;
293
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
294

295
296
297
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
			j = 0;
			while ( attrs[j] ) {
298
				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
299
300
301
302
					for ( k = j; attrs[k] != NULL; k++ ) {
						if ( k == j )
							ch_free( attrs[k] );
						attrs[k] = attrs[k+1];
303
					}
304
305
				} else {
					j++;
306
307
				}
			}
308
309
310
311
312
		}

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

		if ( si->si_allopattrs ) {
313
			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
314
		} else {
315
			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
316
317
318
319
320
321
		}

		/* Add Attributes */
		if ( si->si_allopattrs ) {
			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
		} else {
322
323
324
			for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
				attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
			}
325
		}
326
		attrs[ n ] = NULL;
327

328
	} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
329

330
		i = 0;
331
332
		if ( si->si_allattrs == si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
333
334
			attrs[i++] = ch_strdup( "*" );
			attrs[i++] = ch_strdup( "+" );
335
336
337
338
339
340
		} 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
341
			}
342
343
344
345
		} 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 );
346
347
		}
		attrs[i] = NULL;
348
349
	}
	
350
351
352
353
354
	si->si_attrs = attrs;

	exattrs = anlist2attrs( si->si_exanlist );

	if ( exattrs ) {
355
356
		for ( n = 0; exattrs[n] != NULL; n++ ) ;

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
357
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
358
359
			j = 0;
			while ( exattrs[j] != NULL ) {
360
				if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
Howard Chu's avatar
Cleanup    
Howard Chu committed
361
					ch_free( exattrs[j] );
362
363
					for ( k = j; exattrs[k] != NULL; k++ ) {
						exattrs[k] = exattrs[k+1];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
364
					}
365
366
				} else {
					j++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
367
368
369
				}
			}
		}
370
371
372

		for ( i = 0; exattrs[i] != NULL; i++ ) {
			for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
373
374
				ObjectClass	*oc;
				if ( ( oc = si->si_anlist[j].an_oc ) ) {
375
376
377
					k = 0;
					while ( oc->soc_required[k] ) {
						if ( !strcmp( exattrs[i],
378
							 oc->soc_required[k]->sat_cname.bv_val ) ) {
Howard Chu's avatar
Cleanup    
Howard Chu committed
379
							ch_free( exattrs[i] );
380
381
382
383
384
							for ( l = i; exattrs[l]; l++ ) {
								exattrs[l] = exattrs[l+1];
							}
						} else {
							k++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
385
386
387
388
389
						}
					}
				}
			}
		}
390
391

		for ( i = 0; exattrs[i] != NULL; i++ ) ;
392
393

		if ( i != n )
394
			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
395
	}
396
397

	si->si_exattrs = exattrs;	
398
399
}

400
static int
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
401
402
ldap_sync_search(
	syncinfo_t *si,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
403
	void *ctx )
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
404
{
405
406
	BerElementBuffer berbuf;
	BerElement *ber = (BerElement *)&berbuf;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
407
	LDAPControl c[3], *ctrls[4];
408
	int rc;
409
410
	int rhint;
	char *base;
411
	char **attrs, *lattrs[9];
412
413
414
	char *filter;
	int attrsonly;
	int scope;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
415

416
417
418
	/* 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
419

420
421
422
	/* If we're using a log but we have no state, then fallback to
	 * normal mode for a full refresh.
	 */
423
	if ( si->si_syncdata && !si->si_syncCookie.numcsns && !si->si_refreshDone ) {
424
		si->si_logstate = SYNCLOG_FALLBACK;
425
	}
426
427
428

	/* 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
429
430
431
432
433
434
435
436
437
438
439
		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;
440
441
442
		lattrs[6] = ls->ls_controls.bv_val;
		lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
		lattrs[8] = NULL;
Howard Chu's avatar
Howard Chu committed
443

444
445
446
		rhint = 0;
		base = si->si_logbase.bv_val;
		filter = si->si_logfilterstr.bv_val;
Howard Chu's avatar
Howard Chu committed
447
		attrs = lattrs;
448
		attrsonly = 0;
449
		scope = LDAP_SCOPE_SUBTREE;
450
451
452
453
454
455
456
457
458
	} 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
459
		si->si_type = LDAP_SYNC_REFRESH_ONLY;
460
	} else {
Howard Chu's avatar
Howard Chu committed
461
		si->si_type = si->si_ctype;
462
463
	}

464
	if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
465
	{
Howard Chu's avatar
Howard Chu committed
466
		ber_printf( ber, "{eOb}",
Howard Chu's avatar
Howard Chu committed
467
			abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
468
	} else {
Howard Chu's avatar
Howard Chu committed
469
		ber_printf( ber, "{eb}",
Howard Chu's avatar
Howard Chu committed
470
			abs(si->si_type), rhint );
471
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
472

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
473
	if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
474
475
476
		ber_free_buf( ber );
		return rc;
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
477

478
	c[0].ldctl_oid = LDAP_CONTROL_SYNC;
479
	c[0].ldctl_iscritical = si->si_type < 0;
480
	ctrls[0] = &c[0];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
481

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
482
483
484
485
486
	c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
	BER_BVZERO( &c[1].ldctl_value );
	c[1].ldctl_iscritical = 1;
	ctrls[1] = &c[1];

487
	if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
488
489
490
491
492
		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;
493
	} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
494
		ctrls[2] = NULL;
495
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
496

497
	rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
498
		ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
499
	ber_free_buf( ber );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
500
501
502
	return rc;
}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
503
504
505
506
507
508
509
510
static int
check_syncprov(
	Operation *op,
	syncinfo_t *si )
{
	AttributeName at[2];
	Attribute a = {0};
	Entry e = {0};
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
511
	SlapReply rs = {REP_SEARCH};
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
512
513
514
515
516
517
518
519
520
521
	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;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
522
523
	e.e_name = si->si_contextdn;
	e.e_nname = si->si_contextdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
	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] )) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
544
					changed = 1;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
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
592
593
594
595
596
597
598
599
600
601
602
603
					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
604
605
		ch_free( si->si_syncCookie.sids );
		slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
606
607
608
609
610
	}
	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
	return changed;
}

611
612
613
614
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
615
616
{
	int	rc;
617
	int cmdline_cookie_found = 0;
618

619
	struct sync_cookie	*sc = NULL;
620
621
622
#ifdef HAVE_TLS
	void	*ssl;
#endif
623

624
	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
625
	if ( rc != LDAP_SUCCESS ) {
626
		goto done;
627
	}
628
	op->o_protocol = LDAP_VERSION3;
629

630
631
632
	/* Set SSF to strongest of TLS, SASL SSFs */
	op->o_sasl_ssf = 0;
	op->o_tls_ssf = 0;
633
	op->o_transport_ssf = 0;
634
#ifdef HAVE_TLS
635
636
637
	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
		== LDAP_SUCCESS && ssl != NULL )
	{
638
639
640
		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
	}
#endif /* HAVE_TLS */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
641
642
643
	{
		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 */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
644
645
646
		if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
			== LDAP_SUCCESS )
			op->o_sasl_ssf = ssf;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
647
	}
648
649
	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
		?  op->o_sasl_ssf : op->o_tls_ssf;
650

651
652
	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
653
654
655
	rc = LDAP_DEREF_NEVER;	/* actually could allow DEREF_FINDING */
	ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
656
657
	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );

Howard Chu's avatar
Howard Chu committed
658
	si->si_syncCookie.rid = si->si_rid;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
659
660
661
662

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

664
665
666
	/* We've just started up, or the remote server hasn't sent us
	 * any meaningful state.
	 */
667
	if ( !si->si_syncCookie.ctxcsn ) {
668
		int i;
669

670
671
672
673
674
675
676
677
678
		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 */
679

680
681
682
			LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );

			slap_sync_cookie_free( &si->si_syncCookie, 0 );
683
684
685
686
			si->si_syncCookie.octet_str = sc->octet_str;
			ch_free( sc );
			/* ctxcsn wasn't parsed yet, do it now */
			slap_parse_sync_cookie( &si->si_syncCookie, NULL );
687
688
689
690
691
692
693
		} else {
			ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
			if ( !si->si_cookieState->cs_num ) {
				/* get contextCSN shadow replica from database */
				BerVarray csn = NULL;
				void *ctx = op->o_tmpmemctx;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
694
				op->o_req_ndn = si->si_contextdn;
695
696
697
698
699
700
701
702
703
704
705
				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;
Howard Chu's avatar
Howard Chu committed
706
					si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
707
					slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
708
709
710
711
712
713
714
				}
			}
			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;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
715
					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
716
717
718
719
720
721
722
723
724
					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 );
725
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
726

727
		ch_free( si->si_syncCookie.octet_str.bv_val );
Howard Chu's avatar
Howard Chu committed
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
	} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
732
733
		/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
		ch_free( si->si_syncCookie.octet_str.bv_val );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
734
		BER_BVZERO( &si->si_syncCookie.octet_str );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
735
736
		/* Look for contextCSN from syncprov overlay. */
		check_syncprov( op, si );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
737
738
739
740
		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
741
742
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
743
744
	si->si_refreshDone = 0;

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

747
	if( rc != LDAP_SUCCESS ) {
748
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
749
			"ldap_search_ext: %s (%d)\n",
750
			si->si_ridtxt, ldap_err2string( rc ), rc );
751
752
753
754
755
	}

done:
	if ( rc ) {
		if ( si->si_ld ) {
756
			ldap_unbind_ext( si->si_ld, NULL, NULL );
757
758
759
760
761
762
763
			si->si_ld = NULL;
		}
	}

	return rc;
}

764
765
766
767
768
769
770
771
static int
compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
{
	int i, j, match = 0;
	const char *text;

	*which = 0;

772
773
774
775
776
	if ( sc1->numcsns < sc2->numcsns ) {
		*which = sc1->numcsns;
		return -1;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
777
778
	for (j=0; j<sc2->numcsns; j++) {
		for (i=0; i<sc1->numcsns; i++) {
779
780
781
782
783
			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
784
				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
785
786
787
788
789
790
			if ( match < 0 ) {
				*which = j;
				return match;
			}
			break;
		}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
791
792
793
794
795
		if ( i == sc1->numcsns ) {
			/* sc2 has a sid sc1 lacks */
			*which = j;
			return -1;
		}
796
797
798
799
	}
	return match;
}

Howard Chu's avatar
Howard Chu committed
800
801
#define	SYNC_PAUSED	-3

802
803
804
805
806
807
808
809
810
811
static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*msg = NULL;

812
813
	struct sync_cookie	syncCookie = { NULL };
	struct sync_cookie	syncCookie_req = { NULL };
814

815
816
	int		rc,
			err = LDAP_SUCCESS;
817
818
819

	Modifications	*modlist = NULL;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
820
	int				m;
821
822
823
824

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

825
	int		refreshDeletes = 0;
Howard Chu's avatar
Howard Chu committed
826
	char empty[6] = "empty";
827

828
	if ( slapd_shutdown ) {
829
		rc = -2;
830
		goto done;
831
832
	}

833
834
835
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

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

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

840
	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
841
842
843
844
845
		tout_p = &tout;
	} else {
		tout_p = NULL;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
846
	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
Howard Chu's avatar
Howard Chu committed
847
		tout_p, &msg ) ) > 0 )
848
	{
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
849
		int				match, punlock, syncstate;
850
		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
851
852
853
854
855
856
		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
857
		struct berval	bdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
858

859
		if ( slapd_shutdown ) {
860
861
			rc = -2;
			goto done;
862
		}
Howard Chu's avatar
Howard Chu committed
863
864
865
		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
866
867
868
869
870
			ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
			if (!bdn.bv_len) {
				bdn.bv_val = empty;
				bdn.bv_len = sizeof(empty)-1;
			}
Howard Chu's avatar
Howard Chu committed
871
872
			/* we can't work without the control */
			if ( rctrls ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
873
				LDAPControl **next = NULL;
Howard Chu's avatar
Howard Chu committed
874
875
876
				/* NOTE: make sure we use the right one;
				 * a better approach would be to run thru
				 * the whole list and take care of all */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
877
878
879
880
				/* 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 */
Howard Chu's avatar
Howard Chu committed
881
882
883
				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
884
					bdn.bv_val[bdn.bv_len] = '\0';
885
					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
Howard Chu's avatar
Howard Chu committed
886
						"got search entry with multiple "
Howard Chu's avatar
Howard Chu committed
887
						"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
888
					ldap_controls_free( rctrls );
Howard Chu's avatar
Howard Chu committed
889
890
891
					rc = -1;
					goto done;
				}
Howard Chu's avatar
Howard Chu committed
892
893
			}
			if ( rctrlp == NULL ) {
Howard Chu's avatar
Howard Chu committed
894
				bdn.bv_val[bdn.bv_len] = '\0';
Howard Chu's avatar
Howard Chu committed
895
896
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
					"got search entry without "
Howard Chu's avatar
Howard Chu committed
897
					"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
Howard Chu's avatar
Howard Chu committed
898
899
900
901
				rc = -1;
				goto done;
			}
			ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
902
			if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
903
					== LBER_ERROR ) {
Howard Chu's avatar
Howard Chu committed
904
905
906
				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 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
907
908
909
910
				ldap_controls_free( rctrls );
				rc = -1;
				goto done;
			}
Howard Chu's avatar
Howard Chu committed
911
912
			/* FIXME: what if syncUUID is NULL or empty?
			 * (happens with back-sql...) */
Howard Chu's avatar
Howard Chu committed
913
			if ( syncUUID[0].bv_len != UUIDLEN ) {
Howard Chu's avatar
Howard Chu committed
914
				bdn.bv_val[bdn.bv_len] = '\0';
Howard Chu's avatar
Howard Chu committed
915
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
Howard Chu's avatar
Howard Chu committed
916
					"got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n",
Howard Chu's avatar
Howard Chu committed
917
					si->si_ridtxt,
Howard Chu's avatar
Howard Chu committed
918
					syncrepl_state2str( syncstate ), bdn.bv_val );
Howard Chu's avatar
Howard Chu committed
919
920
921
922
				ldap_controls_free( rctrls );
				rc = -1;
				goto done;
			}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
923
			punlock = -1;
Howard Chu's avatar
Howard Chu committed
924
			if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
Howard Chu's avatar
Howard Chu committed
925
				if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) != LBER_ERROR ) {
Howard Chu's avatar
Howard Chu committed
926

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
927
928
929
				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
					si->si_ridtxt,
					BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
Howard Chu's avatar
Howard Chu committed
930
931
932
933
934
935
936
937
938
939

				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 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
940
						check_syncprov( op, si );
941
						ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
Howard Chu's avatar
Howard Chu committed
942
						for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
943
944
945
946
#ifdef CHATTY_SYNCLOG
							Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n",
								si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val );
#endif
947
948
949
							/* new SID */
							if ( sid < si->si_cookieState->cs_sids[i] )
								break;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
950
951
							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
952
953
954
									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 );
955
956
									si->si_too_old = 1;
									ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
957
958
959
960
									ldap_controls_free( rctrls );
									rc = 0;
									goto done;
								}
961
								si->si_too_old = 0;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
962
								break;
Howard Chu's avatar
Howard Chu committed
963
964
							}
						}
965
966
						ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
967
						/* check pending CSNs too */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
968
969
970
971
972
973
974
975
						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();
						}
976

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
977
						for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
978
979
							if ( sid < si->si_cookieState->cs_psids[i] )
								break;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
980
981
							if ( si->si_cookieState->cs_psids[i] == sid ) {
								if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
982
									ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
Howard Chu's avatar
Howard Chu committed
983
984
985
									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 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
986
987
988
989
990
991
992
993
994
995
									ldap_controls_free( rctrls );
									rc = 0;
									goto done;
								}
								ber_bvreplace( &si->si_cookieState->cs_pvals[i],
									syncCookie.ctxcsn );
								break;
							}
						}
						/* new SID, add it */
996
997
998
999
1000
						if ( i == si->si_cookieState->cs_pnum ||
							sid != si->si_cookieState->cs_psids[i] ) {
							slap_insert_csn_sids(
								(struct sync_cookie *)&si->si_cookieState->cs_pvals,
								i, sid, syncCookie.ctxcsn );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1001
						}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1002
						assert( punlock < 0 );
1003
						punlock = i;
1004
1005
1006
1007
1008
1009
1010
					} else if (si->si_too_old) {
						bdn.bv_val[bdn.bv_len] = '\0';
						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring (%s)\n",
							si->si_ridtxt, bdn.bv_val, 0 );
						ldap_controls_free( rctrls );
						rc = 0;
						goto done;
Howard Chu's avatar
Howard Chu committed
1011
					}
1012
					op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
Howard Chu's avatar
Howard Chu committed
1013
				}
Howard Chu's avatar
Howard Chu committed
1014
				}
Howard Chu's avatar
Howard Chu committed
1015
1016
1017
1018
1019
1020
1021
			}
			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 )
				{
1022
					rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
1023
1024
1025
1026
1027
				} else switch ( rc ) {
					case LDAP_ALREADY_EXISTS:
					case LDAP_NO_SUCH_OBJECT:
					case LDAP_NO_SUCH_ATTRIBUTE:
					case LDAP_TYPE_OR_VALUE_EXISTS:
1028
					case LDAP_NOT_ALLOWED_ON_NONLEAF:
1029
1030
1031
						rc = LDAP_SYNC_REFRESH_REQUIRED;
						si->si_logstate = SYNCLOG_FALLBACK;
						ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
1032
1033
1034
						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
1035
1036
1037
1038