syncrepl.c 184 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 ) ;

Howard Chu's avatar
Howard Chu committed
187
188
189
/* delta-mmr overlay handler */
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];

Howard Chu's avatar
Howard Chu committed
198
199
200
201
202
203
204
205
206
207
/* 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;
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
276
277
278
279
	/* 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 )) {
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
static int
check_syncprov(
	Operation *op,
	syncinfo_t *si )
{
	AttributeName at[2];
	Attribute a = {0};
	Entry e = {0};
675
	SlapReply rs = {REP_SEARCH};
676
677
678
679
680
681
682
683
684
685
	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;
686
687
	e.e_name = si->si_contextdn;
	e.e_nname = si->si_contextdn;
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
	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] )) {
708
					changed = 1;
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
764
765
766
					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,
767
			si->si_syncCookie.sid, NULL );
Howard Chu's avatar
Howard Chu committed
768
769
		ch_free( si->si_syncCookie.sids );
		slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx );
770
771
772
773
774
	}
	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
	return changed;
}

775
776
777
778
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
779
780
{
	int	rc;
781
	int cmdline_cookie_found = 0;
782

783
	struct sync_cookie	*sc = NULL;
784
785
786
#ifdef HAVE_TLS
	void	*ssl;
#endif
787

788
	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
789
	if ( rc != LDAP_SUCCESS ) {
790
		goto done;
791
	}
792
	op->o_protocol = LDAP_VERSION3;
793

794
795
796
	/* Set SSF to strongest of TLS, SASL SSFs */
	op->o_sasl_ssf = 0;
	op->o_tls_ssf = 0;
797
	op->o_transport_ssf = 0;
798
#ifdef HAVE_TLS
799
800
801
	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
		== LDAP_SUCCESS && ssl != NULL )
	{
802
803
804
		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
	}
#endif /* HAVE_TLS */
805
806
807
	{
		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
808
809
810
		if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
			== LDAP_SUCCESS )
			op->o_sasl_ssf = ssf;
811
	}
812
813
	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
		?  op->o_sasl_ssf : op->o_tls_ssf;
814

815
816
	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );

817
818
819
	rc = LDAP_DEREF_NEVER;	/* actually could allow DEREF_FINDING */
	ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );

820
821
	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );

822
	si->si_syncCookie.rid = si->si_rid;
823
824

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

Howard Chu's avatar
Howard Chu committed
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
#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
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
#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
862
863
	{

864
865
866
	/* We've just started up, or the remote server hasn't sent us
	 * any meaningful state.
	 */
867
	if ( !si->si_syncCookie.ctxcsn ) {
868
		int i;
869

870
871
872
873
874
875
876
877
878
		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 */
879

880
881
882
			LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );

			slap_sync_cookie_free( &si->si_syncCookie, 0 );
883
884
885
886
			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 );
887
888
889
890
		} 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
891
				BerVarray csn = NULL;
892
893
				void *ctx = op->o_tmpmemctx;

894
				op->o_req_ndn = si->si_contextdn;
Howard Chu's avatar
Howard Chu committed
895
896
897
898
899
900
901
902
903
904
905
906
				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 );
907
					slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
908
909
910
911
912
913
914
				}
			}
			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
915
					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
916
917
918
919
920
921
922
923
924
					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 );
925
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
926

927
		ch_free( si->si_syncCookie.octet_str.bv_val );
Howard Chu's avatar
Howard Chu committed
928
		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
929
			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
930
			si->si_syncCookie.sid, NULL );
931
	} else {
932
933
		/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
		ch_free( si->si_syncCookie.octet_str.bv_val );
934
		BER_BVZERO( &si->si_syncCookie.octet_str );
935
936
		/* Look for contextCSN from syncprov overlay. */
		check_syncprov( op, si );
937
938
939
		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,
940
				si->si_syncCookie.sid, NULL );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
941
942
	}

Howard Chu's avatar
Howard Chu committed
943
944
	}

945
	si->si_refreshDone = 0;
946
947
	Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n",
		si->si_ridtxt, si->si_syncCookie.octet_str.bv_val );
948

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

951
	if( rc != LDAP_SUCCESS ) {
952
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
953
			"ldap_search_ext: %s (%d)\n",
954
			si->si_ridtxt, ldap_err2string( rc ), rc );
955
956
957
958
959
	}

done:
	if ( rc ) {
		if ( si->si_ld ) {
960
			ldap_unbind_ext( si->si_ld, NULL, NULL );
961
962
963
964
965
966
967
			si->si_ld = NULL;
		}
	}

	return rc;
}

968
969
970
971
972
973
974
975
static int
compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
{
	int i, j, match = 0;
	const char *text;

	*which = 0;

976
977
978
979
980
	if ( sc1->numcsns < sc2->numcsns ) {
		*which = sc1->numcsns;
		return -1;
	}

981
982
	for (j=0; j<sc2->numcsns; j++) {
		for (i=0; i<sc1->numcsns; i++) {
983
984
985
986
987
			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
988
				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
989
990
991
992
993
994
			if ( match < 0 ) {
				*which = j;
				return match;
			}
			break;
		}
995
996
997
998
999
		if ( i == sc1->numcsns ) {
			/* sc2 has a sid sc1 lacks */
			*which = j;
			return -1;
		}
1000
1001
1002
1003
	}
	return match;
}

1004
1005
#define	SYNC_PAUSED	-3

1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*msg = NULL;

1016
1017
	struct sync_cookie	syncCookie = { NULL };
	struct sync_cookie	syncCookie_req = { NULL };
1018

1019
1020
	int		rc,
			err = LDAP_SUCCESS;
1021
1022
1023

	Modifications	*modlist = NULL;

1024
	int				m;
1025
1026
1027
1028

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

1029
	int		refreshDeletes = 0;
Howard Chu's avatar
Howard Chu committed
1030
	char empty[6] = "empty";
1031

1032
	if ( slapd_shutdown ) {
1033
		rc = -2;
1034
		goto done;
1035
1036
	}

1037
1038
1039
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

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

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

1044
	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
1045
1046
1047
1048
1049
		tout_p = &tout;
	} else {
		tout_p = NULL;
	}

1050
	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
1051
		tout_p, &msg ) ) > 0 )
1052
	{
1053
		int				match, punlock, syncstate;
1054
		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
1055
1056
1057
1058
1059
1060
		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
1061
		struct berval	bdn;
1062

1063
		if ( slapd_shutdown ) {
1064
1065
			rc = -2;
			goto done;
1066
		}
1067
1068
		switch( ldap_msgtype( msg ) ) {
		case LDAP_RES_SEARCH_ENTRY:
Howard Chu's avatar
Howard Chu committed
1069
1070
1071
1072
1073
1074
1075
#ifdef LDAP_CONTROL_X_DIRSYNC
			if ( si->si_ctype == MSAD_DIRSYNC ) {
				BER_BVZERO( &syncUUID[0] );
				rc = syncrepl_dirsync_message( si, op, msg, &modlist, &entry, &syncstate, syncUUID );
				if ( rc == 0 )
					rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL );
				op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx );
Howard Chu's avatar
Howard Chu committed
1076
1077
				if ( modlist )
					slap_mods_free( modlist, 1);
Howard Chu's avatar
Howard Chu committed
1078
1079
1080
1081
				if ( rc )
					goto done;
				break;
			}
1082
#endif
Howard Chu's avatar
Howard Chu committed
1083
1084
1085
1086
1087
1088
			ldap_get_entry_controls( si->si_ld, msg, &rctrls );
			ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
			if (!bdn.bv_len) {
				bdn.bv_val = empty;
				bdn.bv_len = sizeof(empty)-1;
			}
1089
1090
1091
1092
			if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
				if ( si->si_logstate == SYNCLOG_LOGGING ) {
					rc = syncrepl_message_to_op( si, op, msg );
					if ( rc )
Howard Chu's avatar
Howard Chu committed
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
						goto logerr;
					if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST && rctrls ) {
						LDAPControl **next = NULL;
						/* The notification control is only sent during persist phase */
						rctrlp = ldap_control_find( LDAP_CONTROL_PERSIST_ENTRY_CHANGE_NOTICE, rctrls, &next );
						if ( rctrlp ) {
							if ( !si->si_refreshDone )
								si->si_refreshDone = 1;
							if ( si->si_refreshDone )
								syncrepl_dsee_update( si, op );
						}
					}

1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
				} else {
					syncstate = DSEE_SYNC_ADD;
					rc = syncrepl_message_to_entry( si, op, msg,
						&modlist, &entry, syncstate, syncUUID );
					if ( rc == 0 )
						rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL );
					op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx );
					if ( modlist )
						slap_mods_free( modlist, 1);
				}
				if ( rc )
					goto done;
				break;
			}
1120
1121
			/* we can't work without the control */
			if ( rctrls ) {
Howard Chu's avatar
Howard Chu committed
1122
				LDAPControl **next = NULL;
1123
1124
1125
				/* NOTE: make sure we use the right one;
				 * a better approach would be to run thru
				 * the whole list and take care of all */
1126
1127
1128
1129
				/* 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 */
1130
1131
1132
				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
				{