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
			si->si_allattrs = si->si_allopattrs = 1;
336
337
338
339
340
341
		} 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
342
			}
343
344
345
346
		} 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 );
347
348
		}
		attrs[i] = NULL;
349
350
	}
	
351
352
353
354
355
	si->si_attrs = attrs;

	exattrs = anlist2attrs( si->si_exanlist );

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

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

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

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

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

	si->si_exattrs = exattrs;	
399
400
}

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

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

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

	/* 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
430
431
432
433
434
435
436
437
438
439
440
		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;
441
442
443
		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
444

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

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

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

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

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

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

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

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
504
505
506
507
508
509
510
511
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
512
	SlapReply rs = {REP_SEARCH};
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
513
514
515
516
517
518
519
520
521
522
	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
523
524
	e.e_name = si->si_contextdn;
	e.e_nname = si->si_contextdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
	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
545
					changed = 1;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
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
604
					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
605
606
		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
607
608
609
610
611
	}
	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
	return changed;
}

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

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

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

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

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

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
654
655
656
	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
657
658
	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );

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

	/* 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
664

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

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

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

			slap_sync_cookie_free( &si->si_syncCookie, 0 );
684
685
686
687
			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 );
688
689
690
691
692
693
694
		} 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
695
				op->o_req_ndn = si->si_contextdn;
696
697
698
699
700
701
702
703
704
705
706
				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
707
					si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
708
					slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
709
710
711
712
713
714
715
				}
			}
			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
716
					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
717
718
719
720
721
722
723
724
725
					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 );
726
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
727

728
		ch_free( si->si_syncCookie.octet_str.bv_val );
Howard Chu's avatar
Howard Chu committed
729
		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
730
			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
731
			si->si_syncCookie.sid );
732
	} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
733
734
		/* 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
735
		BER_BVZERO( &si->si_syncCookie.octet_str );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
736
737
		/* Look for contextCSN from syncprov overlay. */
		check_syncprov( op, si );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
738
739
740
741
		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
742
743
	}

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

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

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

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

	return rc;
}

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

	*which = 0;

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

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

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

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

	LDAPMessage	*msg = NULL;

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

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

	Modifications	*modlist = NULL;

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

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

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

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

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

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

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

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

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

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

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
928
929
930
				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
931
932
933
934
935
936
937
938
939
940

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

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

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