syncrepl.c 187 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.
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
#include "rewrite.h"
Howard Chu's avatar
Howard Chu committed
35
#define SUFFIXM_CTX	"<suffix massage>"
36

Howard Chu's avatar
Howard Chu committed
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifdef LDAP_CONTROL_X_DIRSYNC
#define MSAD_DIRSYNC	0x04
#define MSAD_DIRSYNC_MODIFY	0x10

static AttributeDescription *sy_ad_objectGUID;
static AttributeDescription *sy_ad_instanceType;
static AttributeDescription *sy_ad_isDeleted;
static AttributeDescription *sy_ad_whenCreated;
static AttributeDescription *sy_ad_dirSyncCookie;

static struct berval msad_addval = BER_BVC("range=1-1");
static struct berval msad_delval = BER_BVC("range=0-0");
#endif

51
52
53
54
55
static AttributeDescription *sy_ad_nsUniqueId;
static AttributeDescription *sy_ad_dseeLastChange;

#define DSEE_SYNC_ADD	0x20

Howard Chu's avatar
Howard Chu committed
56
57
#define	UUIDLEN	16

58
59
60
61
62
63
struct nonpresent_entry {
	struct berval *npe_name;
	struct berval *npe_nname;
	LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
};

64
65
typedef struct cookie_state {
	ldap_pvt_thread_mutex_t	cs_mutex;
66
	ldap_pvt_thread_cond_t cs_cond;
67
68
	struct berval *cs_vals;
	int *cs_sids;
69
70
	int	cs_num;
	int cs_age;
71
	int cs_ref;
72
	int cs_updating;
73

74
75
76
77
	/* pending changes, not yet committed */
	ldap_pvt_thread_mutex_t	cs_pmutex;
	struct berval *cs_pvals;
	int *cs_psids;
78
	int	cs_pnum;
79
80
} cookie_state;

81
82
83
84
#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 */

85
86
87
#define	SYNCLOG_LOGGING		0	/* doing a log-based update */
#define	SYNCLOG_FALLBACK	1	/* doing a full refresh */

88
89
90
91
92
#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 */

93
typedef struct syncinfo_s {
94
	struct syncinfo_s	*si_next;
95
96
97
98
	BackendDB		*si_be;
	BackendDB		*si_wbe;
	struct re_s		*si_re;
	int			si_rid;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
99
	char			si_ridtxt[ STRLENOF("rid=999") + 1 ];
Howard Chu's avatar
Howard Chu committed
100
101
	slap_bindconf		si_bindconf;
	struct berval		si_base;
102
103
104
	struct berval		si_logbase;
	struct berval		si_filterstr;
	struct berval		si_logfilterstr;
105
106
	Filter			*si_filter;
	Filter			*si_logfilter;
107
	struct berval		si_contextdn;
108
109
110
	int			si_scope;
	int			si_attrsonly;
	char			*si_anfile;
Howard Chu's avatar
Howard Chu committed
111
112
	AttributeName		*si_anlist;
	AttributeName		*si_exanlist;
113
114
115
116
117
118
119
120
121
122
123
	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
124
	struct sync_cookie	si_syncCookie;
125
	cookie_state		*si_cookieState;
126
127
128
129
130
131
	int			si_cookieAge;
	int			si_manageDSAit;
	int			si_slimit;
	int			si_tlimit;
	int			si_refreshDelete;
	int			si_refreshPresent;
132
	int			si_refreshDone;
133
134
	int			si_syncdata;
	int			si_logstate;
Howard Chu's avatar
Howard Chu committed
135
	int			si_lazyCommit;
136
	int			si_got;
Howard Chu's avatar
Howard Chu committed
137
	int			si_strict_refresh;	/* stop listening during fallback refresh */
138
	int			si_too_old;
139
	ber_int_t	si_msgid;
140
141
	Avlnode			*si_presentlist;
	LDAP			*si_ld;
142
	Connection		*si_conn;
143
	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
144
145
	struct rewrite_info *si_rewrite;
	struct berval	si_suffixm;
Howard Chu's avatar
Howard Chu committed
146
147
#ifdef LDAP_CONTROL_X_DIRSYNC
	struct berval		si_dirSyncCookie;
148
149
150
#endif
	unsigned long	si_prevchange;;
	unsigned long	si_lastchange;
Howard Chu's avatar
Howard Chu committed
151
	ldap_pvt_thread_mutex_t	si_mutex;
152
153
} syncinfo_t;

154
static int syncuuid_cmp( const void *, const void * );
Howard Chu's avatar
Howard Chu committed
155
156
157
158
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 );
159
static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
160
161
static int syncrepl_message_to_op(
					syncinfo_t *, Operation *, LDAPMessage * );
162
163
static int syncrepl_message_to_entry(
					syncinfo_t *, Operation *, LDAPMessage *,
164
					Modifications **, Entry **, int, struct berval* );
165
166
static int syncrepl_entry(
					syncinfo_t *, Operation*, Entry*,
167
168
					Modifications**,int, struct berval*,
					struct berval *cookieCSN );
169
static int syncrepl_updateCookie(
170
					syncinfo_t *, Operation *,
171
					struct sync_cookie *, int save );
172
173
static struct berval * slap_uuidstr_from_normalized(
					struct berval *, struct berval *, void * );
174
175
static int syncrepl_add_glue_ancestors(
	Operation* op, Entry *e );
176

Howard Chu's avatar
Howard Chu committed
177
178
179
180
181
182
183
184
#ifdef LDAP_CONTROL_X_DIRSYNC
static int syncrepl_dirsync_message(
					syncinfo_t *, Operation *, LDAPMessage *,
					Modifications **, Entry **, int *, struct berval* );
static int syncrepl_dirsync_cookie(
					syncinfo_t *, Operation *, LDAPControl ** );
#endif

185
186
static int syncrepl_dsee_update( syncinfo_t *si, Operation *op ) ;

187
/* delta-mpr overlay handler */
Howard Chu's avatar
Howard Chu committed
188
189
static int syncrepl_op_modify( Operation *op, SlapReply *rs );

190
/* callback functions */
191
192
static int dn_callback( Operation *, SlapReply * );
static int nonpresent_callback( Operation *, SlapReply * );
193

194
static AttributeDescription *sync_descs[4];
195

196
197
static AttributeDescription *dsee_descs[7];

198
/* delta-mpr */
Howard Chu's avatar
Howard Chu committed
199
200
201
202
203
204
205
206
207
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;
208
	struct berval ls_controls;
209
210
	struct berval ls_uuid;
	struct berval ls_changenum;
Howard Chu's avatar
Howard Chu committed
211
212
213
214
215
216
217
218
} logschema;

static logschema changelog_sc = {
	BER_BVC("targetDN"),
	BER_BVC("changeType"),
	BER_BVC("changes"),
	BER_BVC("newRDN"),
	BER_BVC("deleteOldRDN"),
219
	BER_BVC("newSuperior"),
220
221
222
	BER_BVNULL,
	BER_BVC("targetUniqueId"),
	BER_BVC("changeNumber")
Howard Chu's avatar
Howard Chu committed
223
224
225
226
227
228
229
230
};

static logschema accesslog_sc = {
	BER_BVC("reqDN"),
	BER_BVC("reqType"),
	BER_BVC("reqMod"),
	BER_BVC("reqNewRDN"),
	BER_BVC("reqDeleteOldRDN"),
231
232
	BER_BVC("reqNewSuperior"),
	BER_BVC("reqControls")
Howard Chu's avatar
Howard Chu committed
233
234
};

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
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";
Howard Chu's avatar
Howard Chu committed
250
251
252
#ifdef LDAP_CONTROL_X_DIRSYNC
	case MSAD_DIRSYNC_MODIFY:
		return "DIRSYNC_MOD";
253
254
255
#endif
	case DSEE_SYNC_ADD:
		return "DSEE_ADD";
256
257
258
259
260
	}

	return "UNKNOWN";
}

Howard Chu's avatar
Howard Chu committed
261
262
static slap_overinst syncrepl_ov;

263
static void
264
init_syncrepl(syncinfo_t *si)
265
{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
266
	int i, j, k, l, n;
267
	char **attrs, **exattrs;
268

Howard Chu's avatar
Howard Chu committed
269
270
271
272
273
274
	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 );
	}

275
	/* delta-MPR needs the overlay, nothing else does.
276
277
278
279
	 * This must happen before accesslog overlay is configured.
	 */
	if ( si->si_syncdata &&
		!overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
Howard Chu's avatar
Howard Chu committed
280
		overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
281
		if ( !ad_reqMod ) {
Howard Chu's avatar
Howard Chu committed
282
283
284
285
286
287
			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
288
289
	}

290
291
292
293
294
295
296
	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;
	}

297
298
299
300
301
302
303
304
305
306
307
308
309
310
	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
		/* DSEE doesn't support allopattrs */
		si->si_allopattrs = 0;
		if ( !dsee_descs[0] ) {
			dsee_descs[0] = slap_schema.si_ad_objectClass;
			dsee_descs[1] = slap_schema.si_ad_creatorsName;
			dsee_descs[2] = slap_schema.si_ad_createTimestamp;
			dsee_descs[3] = slap_schema.si_ad_modifiersName;
			dsee_descs[4] = slap_schema.si_ad_modifyTimestamp;
			dsee_descs[5] = sy_ad_nsUniqueId;
			dsee_descs[6] = NULL;
		}
	}

311
312
313
314
	if ( si->si_allattrs && si->si_allopattrs )
		attrs = NULL;
	else
		attrs = anlist2attrs( si->si_anlist );
315

316
317
318
319
	if ( attrs ) {
		if ( si->si_allattrs ) {
			i = 0;
			while ( attrs[i] ) {
320
				if ( !is_at_operational( at_find( attrs[i] ) ) ) {
321
322
323
324
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
325
					}
326
327
				} else {
					i++;
328
329
				}
			}
330
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
331
332
			attrs[i] = ch_strdup("*");
			attrs[i + 1] = NULL;
333

334
335
336
		} else if ( si->si_allopattrs ) {
			i = 0;
			while ( attrs[i] ) {
337
				if ( is_at_operational( at_find( attrs[i] ) ) ) {
338
339
340
341
342
343
344
345
346
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
					}
				} else {
					i++;
				}
			}
347
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
348
349
			attrs[i] = ch_strdup("+");
			attrs[i + 1] = NULL;
350
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
351

352
353
354
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
			j = 0;
			while ( attrs[j] ) {
355
				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
356
357
358
359
					for ( k = j; attrs[k] != NULL; k++ ) {
						if ( k == j )
							ch_free( attrs[k] );
						attrs[k] = attrs[k+1];
360
					}
361
362
				} else {
					j++;
363
364
				}
			}
365
366
367
368
369
		}

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

		if ( si->si_allopattrs ) {
370
			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
371
		} else {
372
			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
373
374
375
376
377
378
		}

		/* Add Attributes */
		if ( si->si_allopattrs ) {
			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
		} else {
379
380
381
382
			if ( si->si_syncdata != SYNCDATA_CHANGELOG ) {
				for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
					attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
				}
383
			}
384
		}
385
		attrs[ n ] = NULL;
386

387
	} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
388

389
		i = 0;
390
391
		if ( si->si_allattrs == si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
392
393
			attrs[i++] = ch_strdup( "*" );
			attrs[i++] = ch_strdup( "+" );
394
			si->si_allattrs = si->si_allopattrs = 1;
395
396
397
398
399
400
		} 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
401
			}
402
403
404
405
		} 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 );
406
407
		}
		attrs[i] = NULL;
408
	}
409
410
411
412
413
414
415

	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
		for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
		attrs = ( char ** ) ch_realloc( attrs, (n + 6)*sizeof( char * ) );
		for ( i = 0; dsee_descs[ i ] != NULL; i++ ) {
			attrs[ n++ ] = ch_strdup ( dsee_descs[i]->ad_cname.bv_val );
		}
Howard Chu's avatar
Howard Chu committed
416
		attrs[n] = NULL;
417
	}
418
	
419
420
421
422
423
	si->si_attrs = attrs;

	exattrs = anlist2attrs( si->si_exanlist );

	if ( exattrs ) {
424
425
		for ( n = 0; exattrs[n] != NULL; n++ ) ;

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
426
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
427
428
			j = 0;
			while ( exattrs[j] != NULL ) {
429
				if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
Howard Chu's avatar
Cleanup    
Howard Chu committed
430
					ch_free( exattrs[j] );
431
432
					for ( k = j; exattrs[k] != NULL; k++ ) {
						exattrs[k] = exattrs[k+1];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
433
					}
434
435
				} else {
					j++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
436
437
438
				}
			}
		}
439
440
441

		for ( i = 0; exattrs[i] != NULL; i++ ) {
			for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
442
443
				ObjectClass	*oc;
				if ( ( oc = si->si_anlist[j].an_oc ) ) {
444
445
446
					k = 0;
					while ( oc->soc_required[k] ) {
						if ( !strcmp( exattrs[i],
447
							 oc->soc_required[k]->sat_cname.bv_val ) ) {
Howard Chu's avatar
Cleanup    
Howard Chu committed
448
							ch_free( exattrs[i] );
449
450
451
452
453
							for ( l = i; exattrs[l]; l++ ) {
								exattrs[l] = exattrs[l+1];
							}
						} else {
							k++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
454
455
456
457
458
						}
					}
				}
			}
		}
459
460

		for ( i = 0; exattrs[i] != NULL; i++ ) ;
461
462

		if ( i != n )
463
			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
464
	}
465
466

	si->si_exattrs = exattrs;	
467
468
}

469
470
static struct berval generic_filterstr = BER_BVC("(objectclass=*)");

471
static int
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
472
473
ldap_sync_search(
	syncinfo_t *si,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
474
	void *ctx )
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
475
{
476
477
	BerElementBuffer berbuf;
	BerElement *ber = (BerElement *)&berbuf;
478
	LDAPControl c[3], *ctrls[4];
479
	int rc;
480
481
	int rhint;
	char *base;
482
	char **attrs, *lattrs[9];
483
484
485
	char *filter;
	int attrsonly;
	int scope;
486
	char filterbuf[sizeof("(changeNumber>=18446744073709551615)")];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
487

488
489
490
	/* 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
491

492
493
494
	/* If we're using a log but we have no state, then fallback to
	 * normal mode for a full refresh.
	 */
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
	if ( si->si_syncdata ) {
		if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
			LDAPMessage *res, *msg;
			unsigned long first = 0, last = 0;
			int gotfirst = 0, gotlast = 0;
			/* See if we're new enough for the remote server */
			lattrs[0] = "firstchangenumber";
			lattrs[1] = "lastchangenumber";
			lattrs[2] = NULL;
			rc = ldap_search_ext_s( si->si_ld, "", LDAP_SCOPE_BASE, generic_filterstr.bv_val, lattrs, 0,
				NULL, NULL, NULL, si->si_slimit, &res );
			if ( rc )
				return rc;
			msg = ldap_first_message( si->si_ld, res );
			if ( msg && ldap_msgtype( msg ) == LDAP_RES_SEARCH_ENTRY ) {
				BerElement *ber = NULL;
				struct berval bv, *bvals, **bvp = &bvals;;
				rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bv );
				for ( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp );
					rc == LDAP_SUCCESS;
					rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp ) ) {
					if ( bv.bv_val == NULL )
						break;
					if ( !strcasecmp( bv.bv_val, "firstchangenumber" )) {
						first = strtoul( bvals[0].bv_val, NULL, 0 );
						gotfirst = 1;
					} else if ( !strcasecmp( bv.bv_val, "lastchangenumber" )) {
						last = strtoul( bvals[0].bv_val, NULL, 0 );
						gotlast = 1;
					}
				}
			}
			ldap_msgfree( res );
			if ( gotfirst && gotlast ) {
Howard Chu's avatar
Howard Chu committed
529
				if ( si->si_lastchange < first || (!si->si_lastchange && !si->si_refreshDone ))
530
531
532
533
534
535
536
537
538
					si->si_logstate = SYNCLOG_FALLBACK;
				/* if we're in logging mode, it will update si_lastchange itself */
				if ( si->si_logstate == SYNCLOG_FALLBACK )
					si->si_lastchange = last;
			} else {
				/* should be an error; changelog plugin not enabled on provider */
				si->si_logstate = SYNCLOG_FALLBACK;
			}
		} else
539
540
		if ( si->si_logstate == SYNCLOG_LOGGING && !si->si_syncCookie.numcsns &&
				!si->si_refreshDone ) {
541
542
			si->si_logstate = SYNCLOG_FALLBACK;
		}
543
	}
544
545
546

	/* 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
547
548
549
550
551
552
553
554
555
556
557
		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;
558
559
560
561
562
563
564
565
566
567
568
569
570
571
		if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
			lattrs[6] = ls->ls_controls.bv_val;
			lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
			lattrs[8] = NULL;
			filter = si->si_logfilterstr.bv_val;
			scope = LDAP_SCOPE_SUBTREE;
		} else {
			lattrs[6] = ls->ls_uuid.bv_val;
			lattrs[7] = ls->ls_changenum.bv_val;
			lattrs[8] = NULL;
			sprintf( filterbuf, "(changeNumber>=%lu)", si->si_lastchange+1 );
			filter = filterbuf;
			scope = LDAP_SCOPE_ONELEVEL;
		}
Howard Chu's avatar
Howard Chu committed
572

573
574
		rhint = 0;
		base = si->si_logbase.bv_val;
Howard Chu's avatar
Howard Chu committed
575
		attrs = lattrs;
576
577
578
579
580
581
582
583
584
585
		attrsonly = 0;
	} 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
586
		si->si_type = LDAP_SYNC_REFRESH_ONLY;
587
	} else {
Howard Chu's avatar
Howard Chu committed
588
		si->si_type = si->si_ctype;
589
590
	}

Howard Chu's avatar
Howard Chu committed
591
592
593
594
595
596
597
598
599
600
601
602
#ifdef LDAP_CONTROL_X_DIRSYNC
	if ( si->si_ctype == MSAD_DIRSYNC ) {
		ber_printf( ber, "{iiO}", LDAP_CONTROL_X_DIRSYNC_INCREMENTAL_VALUES, 0, &si->si_dirSyncCookie );

		if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
			ber_free_buf( ber );
			return rc;
		}
		c[0].ldctl_oid = LDAP_CONTROL_X_DIRSYNC;
		c[0].ldctl_iscritical = 1;
		ctrls[0] = &c[0];

Howard Chu's avatar
Howard Chu committed
603
604
605
606
607
608
609
610
611
		if ( !BER_BVISEMPTY( &si->si_dirSyncCookie )) {
			c[1].ldctl_oid = LDAP_CONTROL_X_SHOW_DELETED;
			BER_BVZERO( &c[1].ldctl_value );
			c[1].ldctl_iscritical = 1;
			ctrls[1] = &c[1];
			ctrls[2] = NULL;
		} else {
			ctrls[1] = NULL;
		}
Howard Chu's avatar
Howard Chu committed
612
	} else
613
614
#endif
	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
Howard Chu's avatar
Howard Chu committed
615
616
617
618
619
620
621
622
623
624
		if ( si->si_logstate == SYNCLOG_LOGGING && si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
			c[0].ldctl_oid = LDAP_CONTROL_PERSIST_REQUEST;
			c[0].ldctl_iscritical = 0;
			rc = ldap_create_persistentsearch_control_value( si->si_ld, LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD,
				0, 1, &c[0].ldctl_value );
			ctrls[0] = &c[0];
			ctrls[1] = NULL;
		} else {
			ctrls[0] = NULL;
		}
625
	} else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
626
	{
Howard Chu's avatar
Howard Chu committed
627
628
629
630
631
632
633
634
		if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
		{
			ber_printf( ber, "{eOb}",
				abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
		} else {
			ber_printf( ber, "{eb}",
				abs(si->si_type), rhint );
		}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
635

Howard Chu's avatar
Howard Chu committed
636
637
638
639
		if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
			ber_free_buf( ber );
			return rc;
		}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
640

Howard Chu's avatar
Howard Chu committed
641
642
643
		c[0].ldctl_oid = LDAP_CONTROL_SYNC;
		c[0].ldctl_iscritical = si->si_type < 0;
		ctrls[0] = &c[0];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
644

Howard Chu's avatar
Howard Chu committed
645
646
647
648
		c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
		BER_BVZERO( &c[1].ldctl_value );
		c[1].ldctl_iscritical = 1;
		ctrls[1] = &c[1];
649

Howard Chu's avatar
Howard Chu committed
650
651
652
653
654
655
656
657
658
		if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
			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;
		} else {
			ctrls[2] = NULL;
		}
659
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
660

661
	rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
662
		ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
663
	ber_free_buf( ber );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
664
665
666
	return rc;
}

667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
static int
merge_state( syncinfo_t *si )
{
	int i, j = 0, k, numcsns = 0, alloc = 0, changed = 0;
	BerVarray new_ctxcsn = si->si_syncCookie.ctxcsn;
	int *new_sids = NULL;

	/* Count and set up sids */
	for ( i=0; i < si->si_cookieState->cs_num; i++ ) {
		if ( si->si_cookieState->cs_sids[i] == -1 ) {
			continue;
		}

		for ( ; j < si->si_syncCookie.numcsns &&
					si->si_syncCookie.sids[j] == -1;
				j++ )
			alloc = 1; /* Just skip over them */

		for ( ; j < si->si_syncCookie.numcsns &&
					si->si_syncCookie.sids[j] < si->si_cookieState->cs_sids[i];
				j++ ) {
			if ( si->si_syncCookie.sids[j] != -1 ) {
				new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) );
				new_sids[numcsns++] = si->si_syncCookie.sids[j];
			}
		}

		if ( j < si->si_syncCookie.numcsns &&
				si->si_syncCookie.sids[j] == si->si_cookieState->cs_sids[i] ) j++;

		new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) );
		new_sids[numcsns++] = si->si_cookieState->cs_sids[i];
	}

	for ( ; j < si->si_syncCookie.numcsns; j++ ) {
		if ( si->si_syncCookie.sids[j] != -1 ) {
			new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) );
			new_sids[numcsns++] = si->si_syncCookie.sids[j];
		}
	}

	if ( alloc || numcsns != si->si_syncCookie.numcsns ) {
		/* Short circuit allocations if we don't need to start over */
		alloc = 1;
		new_ctxcsn = ch_calloc( numcsns + 1, sizeof( BerValue ) );
	}

	i = j = 0;
	for ( k=0; k < numcsns; k++ ) {
		while ( i < si->si_cookieState->cs_num &&
				si->si_cookieState->cs_sids[i] < new_sids[k] )
			i++;

		while ( j < si->si_syncCookie.numcsns &&
				si->si_syncCookie.sids[j] < new_sids[k] )
			j++;

		if ( j < si->si_syncCookie.numcsns &&
				si->si_cookieState->cs_sids[i] == si->si_syncCookie.sids[j] ) {
			assert( si->si_cookieState->cs_sids[i] == new_sids[k] );
			if ( !bvmatch( &si->si_syncCookie.ctxcsn[j],
					&si->si_cookieState->cs_vals[i] )) {
				ber_bvreplace( &new_ctxcsn[k], &si->si_cookieState->cs_vals[i] );
				changed = 1;
			} else if ( alloc ) {
				ber_dupbv( &new_ctxcsn[k], &si->si_syncCookie.ctxcsn[j] );
			}
			i++;
			j++;
		} else if ( si->si_cookieState->cs_sids[i] == new_sids[k] ) {
			changed = 1;
			ber_bvreplace( &new_ctxcsn[k], &si->si_cookieState->cs_vals[i] );
			i++;
		} else {
			if ( alloc ) {
				ber_dupbv( &new_ctxcsn[k], &si->si_syncCookie.ctxcsn[j] );
			}
			j++;
		}
	}
	assert( i == si->si_cookieState->cs_num );
	assert( j == si->si_syncCookie.numcsns );

	si->si_syncCookie.numcsns = numcsns;
	if ( alloc ) {
		changed = 1;
		ch_free( si->si_syncCookie.sids );
		si->si_syncCookie.sids = new_sids;

		ber_bvarray_free( si->si_syncCookie.ctxcsn );
		si->si_syncCookie.ctxcsn = new_ctxcsn;
	} else {
		ch_free( new_sids );
	}
	return changed;
}

764
765
766
767
768
769
770
771
static int
check_syncprov(
	Operation *op,
	syncinfo_t *si )
{
	AttributeName at[2];
	Attribute a = {0};
	Entry e = {0};
772
	SlapReply rs = {REP_SEARCH};
773
774
775
776
777
778
779
780
781
782
	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;
783
784
	e.e_name = si->si_contextdn;
	e.e_nname = si->si_contextdn;
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
	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] )) {
805
					changed = 1;
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
					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;
834
835
		} else if ( merge_state( si ) ) {
			changed = 1;
836
837
838
839
840
841
842
		}
	}
	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,
843
			si->si_syncCookie.sid, NULL );
Howard Chu's avatar
Howard Chu committed
844
845
		ch_free( si->si_syncCookie.sids );
		slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx );
846
847
848
849
850
	}
	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
	return changed;
}

851
852
853
854
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
855
856
{
	int	rc;
857
	int cmdline_cookie_found = 0;
858

859
	struct sync_cookie	*sc = NULL;
860
861
862
#ifdef HAVE_TLS
	void	*ssl;
#endif
863

864
	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
865
	if ( rc != LDAP_SUCCESS ) {
866
		goto done;
867
	}
868
	op->o_protocol = LDAP_VERSION3;
869

870
871
872
	/* Set SSF to strongest of TLS, SASL SSFs */
	op->o_sasl_ssf = 0;
	op->o_tls_ssf = 0;
873
	op->o_transport_ssf = 0;
874
#ifdef HAVE_TLS
875
876
877
	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
		== LDAP_SUCCESS && ssl != NULL )
	{
878
879
880
		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
	}
#endif /* HAVE_TLS */
881
882
883
	{
		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
884
885
886
		if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
			== LDAP_SUCCESS )
			op->o_sasl_ssf = ssf;
887
	}
888
889
	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
		?  op->o_sasl_ssf : op->o_tls_ssf;
890

891
892
	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );

893
894
895
	rc = LDAP_DEREF_NEVER;	/* actually could allow DEREF_FINDING */
	ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );

896
897
	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );

898
	si->si_syncCookie.rid = si->si_rid;
899
900

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

Howard Chu's avatar
Howard Chu committed
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
#ifdef LDAP_CONTROL_X_DIRSYNC
	if ( si->si_ctype == MSAD_DIRSYNC ) {
		if ( BER_BVISEMPTY( &si->si_dirSyncCookie )) {
			BerVarray cookies = NULL;
			void *ctx = op->o_tmpmemctx;

			op->o_req_ndn = si->si_contextdn;
			op->o_req_dn = op->o_req_ndn;

			/* try to read stored cookie */
			op->o_tmpmemctx = NULL;
			backend_attribute( op, NULL, &op->o_req_ndn,
				sy_ad_dirSyncCookie, &cookies, ACL_READ );
			op->o_tmpmemctx = ctx;
			if ( cookies )
				si->si_dirSyncCookie = cookies[0];
		}
	} else
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
#endif
	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
		if ( !si->si_lastchange ) {
			BerVarray vals = NULL;

			op->o_req_ndn = si->si_contextdn;
			op->o_req_dn = op->o_req_ndn;
			/* try to read last change number */
			backend_attribute( op, NULL, &op->o_req_ndn,
				sy_ad_dseeLastChange, &vals, ACL_READ );
			if ( vals ) {
				si->si_lastchange = strtoul( vals[0].bv_val, NULL, 0 );
				si->si_prevchange = si->si_lastchange;
			}
		}
	} else
Howard Chu's avatar
Howard Chu committed
938
939
	{

940
941
942
	/* We've just started up, or the remote server hasn't sent us
	 * any meaningful state.
	 */
943
	if ( !si->si_syncCookie.ctxcsn ) {
944
		int i;
945

946
947
948
949
950
951
952
953
954
		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 */
955

956
957
958
			LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );

			slap_sync_cookie_free( &si->si_syncCookie, 0 );
959
960
961
962
			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 );
963
964
965
966
		} 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
967
				BerVarray csn = NULL;
968
969
				void *ctx = op->o_tmpmemctx;

970
				op->o_req_ndn = si->si_contextdn;
Howard Chu's avatar
Howard Chu committed
971
972
973
974
975
976
977
978
979
980
981
982
				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 );
983
					slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
984
985
986
987
988
989
990
				}
			}
			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
991
					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
992
993
994
995
996
997
998
999
1000
					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 );
1001
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1002

1003
		ch_free( si->si_syncCookie.octet_str.bv_val );
Howard Chu's avatar
Howard Chu committed
1004
		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
1005
			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
1006
			si->si_syncCookie.sid, NULL );
1007
	} else {
1008
1009
		/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
		ch_free( si->si_syncCookie.octet_str.bv_val );
1010
		BER_BVZERO( &si->si_syncCookie.octet_str );
1011
1012
		/* Look for contextCSN from syncprov overlay. */
		check_syncprov( op, si );
1013
1014
1015
		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,
1016
				si->si_syncCookie.sid, NULL );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
1017
1018
	}

Howard Chu's avatar
Howard Chu committed
1019
1020
	}

1021
	si->si_refreshDone = 0;
1022
1023
	Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n",
		si->si_ridtxt, si->si_syncCookie.octet_str.bv_val );
1024

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

1027
	if( rc != LDAP_SUCCESS ) {
1028
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
1029
			"ldap_search_ext: %s (%d)\n",
1030
			si->si_ridtxt, ldap_err2string( rc ), rc );
1031
1032
1033
1034
1035
	}

done:
	if ( rc ) {
		if ( si->si_ld ) {
1036
			ldap_unbind_ext( si->si_ld, NULL, NULL );
1037
1038
1039
1040
1041
1042
1043
			si->si_ld = NULL;
		}
	}

	return rc;
}

1044
1045
1046
1047
1048
1049
1050
1051
static int
compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
{
	int i, j, match = 0;
	const char *text;

	*which = 0;

1052
1053
1054
1055
1056
	if ( sc1->numcsns < sc2->numcsns ) {
		*which = sc1->numcsns;
		return -1;
	}

1057
1058
	for (j=0; j<sc2->numcsns; j++) {
		for (i=0; i<sc1->numcsns; i++) {
1059
1060
1061
1062
1063
			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
1064
				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
1065
1066
1067
1068
1069
1070
			if ( match < 0 ) {
				*which = j;
				return match;
			}
			break;
		}
1071
1072
1073
1074
1075
		if ( i == sc1->numcsns ) {
			/* sc2 has a sid sc1 lacks */
			*which = j;
			return -1;
		}
1076
1077
1078
1079
	}
	return match;
}

1080
1081
1082
1083
1084
#define SYNC_TIMEOUT	0
#define SYNC_SHUTDOWN	-100
#define SYNC_ERROR		-101
#define SYNC_REPOLL		-102
#define SYNC_PAUSED		-103
1085

1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*msg = NULL;

1096
1097
	struct sync_cookie	syncCookie = { NULL };
	struct sync_cookie	syncCookie_req = { NULL };
1098

1099
1100
	int		rc,
			err = LDAP_SUCCESS;
1101
1102
1103

	Modifications	*modlist = NULL;

1104
	int				m;
1105
1106
1107

	struct timeval tout = { 0, 0 };

1108
	int		refreshDeletes = 0;
Howard Chu's avatar
Howard Chu committed
1109
	char empty[6] = "empty";
1110

1111
	if ( slapd_shutdown ) {
1112
		rc = SYNC_SHUTDOWN;
1113
		goto done;
1114
1115
	}

1116
1117
1118
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

1119
	Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt );
1120

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

1123
	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
1124
		&tout, &msg ) ) > 0 )
1125
	{
1126
		int				match, punlock, syncstate;
1127
		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
1128
1129
1130
1131
1132
1133
		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
1134
		struct berval	bdn;
1135

1136
		if ( slapd_shutdown ) {
1137
			rc = SYNC_SHUTDOWN;
1138
			goto done;
1139
		}
1140
1141
		switch( ldap_msgtype( msg ) ) {
		case LDAP_RES_SEARCH_ENTRY:
Howard Chu's avatar
Howard Chu committed
1142
1143
1144