syncrepl.c 163 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
49
50
51
52
typedef struct cookie_vals {
	struct berval *cv_vals;
	int *cv_sids;
	int cv_num;
} cookie_vals;

53
54
typedef struct cookie_state {
	ldap_pvt_thread_mutex_t	cs_mutex;
55
	ldap_pvt_thread_cond_t cs_cond;
56
57
	struct berval *cs_vals;
	int *cs_sids;
58
59
	int	cs_num;
	int cs_age;
60
	int cs_ref;
61
	int cs_updating;
62

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
63
64
65
66
	/* pending changes, not yet committed */
	ldap_pvt_thread_mutex_t	cs_pmutex;
	struct berval *cs_pvals;
	int *cs_psids;
67
	int	cs_pnum;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
68
69
} cookie_state;

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

74
75
76
#define	SYNCLOG_LOGGING		0	/* doing a log-based update */
#define	SYNCLOG_FALLBACK	1	/* doing a full refresh */

77
78
79
80
81
#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 */

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

139
static int syncuuid_cmp( const void *, const void * );
Howard Chu's avatar
Howard Chu committed
140
141
142
143
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
144
static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
145
static int syncrepl_message_to_op(
Howard Chu's avatar
Howard Chu committed
146
					syncinfo_t *, Operation *, LDAPMessage *, int );
147
148
static int syncrepl_message_to_entry(
					syncinfo_t *, Operation *, LDAPMessage *,
149
					Modifications **, Entry **, int, struct berval* );
150
151
static int syncrepl_entry(
					syncinfo_t *, Operation*, Entry*,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
152
153
					Modifications**,int, struct berval*,
					struct berval *cookieCSN );
154
static int syncrepl_updateCookie(
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
155
					syncinfo_t *, Operation *,
156
					struct sync_cookie *, int save );
157
158
static struct berval * slap_uuidstr_from_normalized(
					struct berval *, struct berval *, void * );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
159
160
static int syncrepl_add_glue_ancestors(
	Operation* op, Entry *e );
161

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

165
/* callback functions */
166
167
static int dn_callback( Operation *, SlapReply * );
static int nonpresent_callback( Operation *, SlapReply * );
168

169
static AttributeDescription *sync_descs[4];
170

171
/* delta-mpr */
Howard Chu's avatar
Howard Chu committed
172
173
174
175
176
177
178
179
180
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;
181
	struct berval ls_controls;
Howard Chu's avatar
Howard Chu committed
182
183
184
185
186
187
188
189
} logschema;

static logschema changelog_sc = {
	BER_BVC("targetDN"),
	BER_BVC("changeType"),
	BER_BVC("changes"),
	BER_BVC("newRDN"),
	BER_BVC("deleteOldRDN"),
190
191
	BER_BVC("newSuperior"),
	BER_BVC("controls")
Howard Chu's avatar
Howard Chu committed
192
193
194
195
196
197
198
199
};

static logschema accesslog_sc = {
	BER_BVC("reqDN"),
	BER_BVC("reqType"),
	BER_BVC("reqMod"),
	BER_BVC("reqNewRDN"),
	BER_BVC("reqDeleteOldRDN"),
200
201
	BER_BVC("reqNewSuperior"),
	BER_BVC("reqControls")
Howard Chu's avatar
Howard Chu committed
202
203
};

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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
224
225
static slap_overinst syncrepl_ov;

226
static void
227
init_syncrepl(syncinfo_t *si)
228
{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
229
	int i, j, k, l, n;
230
	char **attrs, **exattrs;
231

Howard Chu's avatar
Howard Chu committed
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 );
	}

238
	/* delta-MPR needs the overlay, nothing else does.
Howard Chu's avatar
Howard Chu committed
239
240
241
242
243
	 * 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
244
245
246
247
248
249
250
		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
251
252
	}

253
254
255
256
257
258
259
	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;
	}

260
261
262
263
	if ( si->si_allattrs && si->si_allopattrs )
		attrs = NULL;
	else
		attrs = anlist2attrs( si->si_anlist );
264

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

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

301
302
303
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
			j = 0;
			while ( attrs[j] ) {
304
				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
305
306
307
308
					for ( k = j; attrs[k] != NULL; k++ ) {
						if ( k == j )
							ch_free( attrs[k] );
						attrs[k] = attrs[k+1];
309
					}
310
311
				} else {
					j++;
312
313
				}
			}
314
315
316
317
318
		}

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

		if ( si->si_allopattrs ) {
319
			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
320
		} else {
321
			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
322
323
324
325
326
327
		}

		/* Add Attributes */
		if ( si->si_allopattrs ) {
			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
		} else {
328
329
330
			for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
				attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
			}
331
		}
332
		attrs[ n ] = NULL;
333

334
	} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
335

336
		i = 0;
337
338
		if ( si->si_allattrs == si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
339
340
			attrs[i++] = ch_strdup( "*" );
			attrs[i++] = ch_strdup( "+" );
341
			si->si_allattrs = si->si_allopattrs = 1;
342
343
344
345
346
347
		} 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
348
			}
349
350
351
352
		} 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 );
353
354
		}
		attrs[i] = NULL;
355
356
	}
	
357
358
359
360
361
	si->si_attrs = attrs;

	exattrs = anlist2attrs( si->si_exanlist );

	if ( exattrs ) {
362
363
		for ( n = 0; exattrs[n] != NULL; n++ ) ;

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

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

		for ( i = 0; exattrs[i] != NULL; i++ ) ;
399
400

		if ( i != n )
401
			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
402
	}
403
404

	si->si_exattrs = exattrs;	
405
406
}

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

423
424
425
	/* 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
426

427
428
429
	/* If we're using a log but we have no state, then fallback to
	 * normal mode for a full refresh.
	 */
430
	if ( si->si_syncdata && !si->si_syncCookie.numcsns && !si->si_refreshDone ) {
431
		si->si_logstate = SYNCLOG_FALLBACK;
432
	}
433
434
435

	/* 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
436
437
438
439
440
441
442
443
444
445
446
		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;
447
448
449
		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
450

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

471
	if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
472
	{
Howard Chu's avatar
Howard Chu committed
473
		ber_printf( ber, "{eOb}",
Howard Chu's avatar
Howard Chu committed
474
			abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
475
	} else {
Howard Chu's avatar
Howard Chu committed
476
		ber_printf( ber, "{eb}",
Howard Chu's avatar
Howard Chu committed
477
			abs(si->si_type), rhint );
478
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
479

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
480
	if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
481
482
483
		ber_free_buf( ber );
		return rc;
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
484

485
	c[0].ldctl_oid = LDAP_CONTROL_SYNC;
486
	c[0].ldctl_iscritical = si->si_type < 0;
487
	ctrls[0] = &c[0];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
488

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
489
490
491
492
493
	c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
	BER_BVZERO( &c[1].ldctl_value );
	c[1].ldctl_iscritical = 1;
	ctrls[1] = &c[1];

494
	if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
495
496
497
498
499
		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;
500
	} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
501
		ctrls[2] = NULL;
502
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
503

504
	rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
505
		ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
506
	ber_free_buf( ber );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
507
508
509
	return rc;
}

Howard Chu's avatar
Howard Chu committed
510
511
/* #define DEBUG_MERGE_STATE	1 */

512
static int
Howard Chu's avatar
Howard Chu committed
513
merge_state( syncinfo_t *si, struct sync_cookie *sc1, struct sync_cookie *sc2 )
514
{
Howard Chu's avatar
Howard Chu committed
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
	int i, j, k, changed = 0;
	int ei, ej;
	int *newsids;
	struct berval *newcsns;

	ei = sc1->numcsns;
	ej = sc2->numcsns;
#ifdef DEBUG_MERGE_STATE
	for ( i=0; i<ei; i++ ) {
		fprintf(stderr, "merge_state: %s si_syncCookie [%d] %d %s\n",
			si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val );
	}
	for ( i=0; i<ej; i++ ) {
		fprintf(stderr, "merge_state: %s si_cookieState [%d] %d %s\n",
			si->si_ridtxt, i, sc2->sids[i], sc2->ctxcsn[i].bv_val );
	}
#endif
	/* see if they cover the same SIDs */
	if ( ei == ej ) {
		for ( i = 0; i < ei; i++ ) {
			if ( sc1->sids[i] != sc2->sids[i] ) {
				changed = 1;
				break;
			}
		}
		/* SIDs are the same, take fast path */
		if ( !changed ) {
			for ( i = 0; i > ei; i++ ) {
Howard Chu's avatar
Howard Chu committed
543
				if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[i] ) < 0 ) {
Howard Chu's avatar
Howard Chu committed
544
545
546
547
548
549
550
551
552
553
554
555
					ber_bvreplace( &sc1->ctxcsn[i], &sc2->ctxcsn[i] );
					changed = 1;
				}
			}
			return changed;
		}
		changed = 0;
	}

	i = ei + ej;
	newsids = ch_malloc( sizeof(int) * i );
	newcsns = ch_malloc( sizeof(struct berval) * ( i + 1 ));
556

Howard Chu's avatar
Howard Chu committed
557
558
559
	for ( i=0, j=0, k=0; i < ei || j < ej ; ) {
		if ( sc1->sids[i] == -1 ) {
			i++;
560
561
			continue;
		}
Howard Chu's avatar
Howard Chu committed
562
563
564
565
566
567
568
569
		if ( j >= ej || (i < ei && sc1->sids[i] < sc2->sids[j] )) {
			newsids[k] = sc1->sids[i];
			ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] );
			i++; k++;
			continue;
		}
		if ( i < ei && sc1->sids[i] == sc2->sids[j] ) {
			newsids[k] = sc1->sids[i];
Howard Chu's avatar
Howard Chu committed
570
			if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[j] ) < 0 ) {
571
				changed = 1;
Howard Chu's avatar
Howard Chu committed
572
573
574
575
				ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] );
			} else {
				ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] );
			}
Howard Chu's avatar
Howard Chu committed
576
			i++; j++; k++;
577
			continue;
578
		}
Howard Chu's avatar
Howard Chu committed
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
		if ( j < ej ) {
			if ( sc2->sids[j] == -1 ) {
				j++;
				continue;
			}
			newsids[k] = sc2->sids[j];
			ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] );
			changed = 1;
			j++; k++;
		}
	}

	ber_bvarray_free( sc1->ctxcsn );
	ch_free( sc1->sids );
	sc1->numcsns = k;
	sc1->sids = ch_realloc( newsids, sizeof(int) * k );
	sc1->ctxcsn = ch_realloc( newcsns, sizeof(struct berval) * (k+1) );
	BER_BVZERO( &sc1->ctxcsn[k] );
#ifdef DEBUG_MERGE_STATE
	for ( i=0; i<sc1->numcsns; i++ ) {
		fprintf(stderr, "merge_state: %s si_syncCookie2 [%d] %d %s\n",
			si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val );
601
	}
Howard Chu's avatar
Howard Chu committed
602
#endif
603

604
605
606
	return changed;
}

Howard Chu's avatar
Howard Chu committed
607
608
609
610
611
612
#ifdef DEBUG_MERGE_STATE
static void
merge_test( syncinfo_t *si ) {
	struct sync_cookie sc1, sc2;
	int ret;

Howard Chu's avatar
Howard Chu committed
613
614
615
	sc1.numcsns = 4;
	sc1.sids = malloc( sizeof( int ) * sc1.numcsns );
	sc1.ctxcsn = malloc( sizeof( struct berval ) * ( sc1.numcsns + 1 ));
Howard Chu's avatar
Howard Chu committed
616
	sc1.sids[0] = 1;
Howard Chu's avatar
Howard Chu committed
617
618
619
620
	sc1.sids[1] = 3;
	sc1.sids[2] = 4;
	sc1.sids[3] = 5;
	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc1#001#000000");	/* unique */
Howard Chu's avatar
Howard Chu committed
621
	ber_dupbv( &sc1.ctxcsn[0], &bv ); }
Howard Chu's avatar
Howard Chu committed
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc1#003#000000");	/* lower */
	ber_dupbv( &sc1.ctxcsn[1], &bv ); }
	{ struct berval bv = BER_BVC("20201231000000.100000Z#sc1#004#000000");	/* higher */
	ber_dupbv( &sc1.ctxcsn[2], &bv ); }
	{ struct berval bv = BER_BVC("20200228000000.100000Z#sc1#005#000000");	/* unique */
	ber_dupbv( &sc1.ctxcsn[3], &bv ); }
	BER_BVZERO( &sc1.ctxcsn[sc1.numcsns] );

	sc2.numcsns = 4;
	sc2.sids = malloc( sizeof( int ) * sc2.numcsns );
	sc2.ctxcsn = malloc( sizeof( struct berval ) * ( sc2.numcsns + 1 ));
	sc2.sids[0] = 2;
	sc2.sids[1] = 3;
	sc2.sids[2] = 4;
	sc2.sids[3] = 6;
	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc2#002#000000");	/* unique */
Howard Chu's avatar
Howard Chu committed
638
	ber_dupbv( &sc2.ctxcsn[0], &bv ); }
Howard Chu's avatar
Howard Chu committed
639
	{ struct berval bv = BER_BVC("20200331000000.100000Z#sc2#003#000000");	/* higher */
Howard Chu's avatar
Howard Chu committed
640
	ber_dupbv( &sc2.ctxcsn[1], &bv ); }
Howard Chu's avatar
Howard Chu committed
641
	{ struct berval bv = BER_BVC("20200501000000.100000Z#sc2#004#000000");	/* lower */
Howard Chu's avatar
Howard Chu committed
642
	ber_dupbv( &sc2.ctxcsn[2], &bv ); }
Howard Chu's avatar
Howard Chu committed
643
644
645
	{ struct berval bv = BER_BVC("20200628000000.100000Z#sc2#006#000000");	/* unique */
	ber_dupbv( &sc2.ctxcsn[3], &bv ); }
	BER_BVZERO( &sc2.ctxcsn[sc2.numcsns] );
Howard Chu's avatar
Howard Chu committed
646
647
648
649
650

	ret = merge_state( si, &sc1, &sc2 );
}
#endif

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
651
652
653
654
655
656
657
658
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
659
	SlapReply rs = {REP_SEARCH};
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
660
661
662
663
664
665
666
667
668
669
	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
670
671
	e.e_name = si->si_contextdn;
	e.e_nname = si->si_contextdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
	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
692
					changed = 1;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
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
					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;
Howard Chu's avatar
Howard Chu committed
721
722
723
		} else {
			changed = merge_state( si, &si->si_syncCookie,
				(struct sync_cookie *)&si->si_cookieState->cs_vals );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
724
725
726
727
728
729
730
731
		}
	}
	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
732
733
		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
734
735
736
737
738
	}
	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
	return changed;
}

739
740
741
742
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
743
744
{
	int	rc;
745
	int cmdline_cookie_found = 0;
746

747
	struct sync_cookie	*sc = NULL;
748
749
750
#ifdef HAVE_TLS
	void	*ssl;
#endif
751

752
	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
753
	if ( rc != LDAP_SUCCESS ) {
754
		goto done;
755
	}
756
	op->o_protocol = LDAP_VERSION3;
757

758
759
760
	/* Set SSF to strongest of TLS, SASL SSFs */
	op->o_sasl_ssf = 0;
	op->o_tls_ssf = 0;
761
	op->o_transport_ssf = 0;
762
#ifdef HAVE_TLS
763
764
765
	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
		== LDAP_SUCCESS && ssl != NULL )
	{
766
767
768
		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
	}
#endif /* HAVE_TLS */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
769
770
771
	{
		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
772
773
774
		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
775
	}
776
777
	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
		?  op->o_sasl_ssf : op->o_tls_ssf;
778

779
780
	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
781
782
783
	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
784
785
	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );

Howard Chu's avatar
Howard Chu committed
786
	si->si_syncCookie.rid = si->si_rid;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
787
788
789
790

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

792
793
794
	/* We've just started up, or the remote server hasn't sent us
	 * any meaningful state.
	 */
795
	if ( !si->si_syncCookie.ctxcsn ) {
796
		int i;
797

798
799
800
801
802
803
804
805
806
		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 */
807

808
809
810
			LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );

			slap_sync_cookie_free( &si->si_syncCookie, 0 );
811
812
813
814
			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 );
815
816
817
818
819
820
821
		} 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
822
				op->o_req_ndn = si->si_contextdn;
823
824
825
826
827
828
829
830
831
832
833
				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
834
					si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
835
					slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
836
837
838
839
840
841
842
				}
			}
			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
843
					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
844
845
846
847
848
849
850
851
852
					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 );
853
		}
854
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
855

856
857
858
859
860
861
862
863
864
865
866
		if ( !cmdline_cookie_found ) {
			/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
			ch_free( si->si_syncCookie.octet_str.bv_val );
			BER_BVZERO( &si->si_syncCookie.octet_str );
			/* Look for contextCSN from syncprov overlay. */
			check_syncprov( op, si );
			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
867

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
868
	si->si_refreshDone = 0;
869
870
	Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n",
		si->si_ridtxt, si->si_syncCookie.octet_str.bv_val, 0 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
871

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

874
	if( rc != LDAP_SUCCESS ) {
875
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
876
			"ldap_search_ext: %s (%d)\n",
877
			si->si_ridtxt, ldap_err2string( rc ), rc );
878
879
880
881
882
	}

done:
	if ( rc ) {
		if ( si->si_ld ) {
883
			ldap_unbind_ext( si->si_ld, NULL, NULL );
884
885
886
887
888
889
890
			si->si_ld = NULL;
		}
	}

	return rc;
}

891
892
893
894
895
896
897
898
static int
compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
{
	int i, j, match = 0;
	const char *text;

	*which = 0;

899
900
901
902
903
	if ( sc1->numcsns < sc2->numcsns ) {
		*which = sc1->numcsns;
		return -1;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
904
905
	for (j=0; j<sc2->numcsns; j++) {
		for (i=0; i<sc1->numcsns; i++) {
906
907
908
909
910
			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
911
				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
912
913
914
915
916
917
			if ( match < 0 ) {
				*which = j;
				return match;
			}
			break;
		}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
918
919
920
921
922
		if ( i == sc1->numcsns ) {
			/* sc2 has a sid sc1 lacks */
			*which = j;
			return -1;
		}
923
924
925
926
	}
	return match;
}

927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
#define CV_CSN_OK	0
#define CV_CSN_OLD	1
#define CV_SID_NEW	2

static int
check_csn_age(
	syncinfo_t *si,
	struct berval *dn,
	struct berval *csn,
	int sid,
	cookie_vals *cv,
	int *slot )
{
	int i, rc = CV_SID_NEW;

	for ( i =0; i<cv->cv_num; i++ ) {
#ifdef CHATTY_SYNCLOG
		Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n",
			si->si_ridtxt, i, cv->cv_vals[i].bv_val );
#endif
		/* new SID */
		if ( sid < cv->cv_sids[i] )
			break;
		if ( cv->cv_sids[i] == sid ) {
			if ( ber_bvcmp( csn, &cv->cv_vals[i] ) <= 0 ) {
				dn->bv_val[dn->bv_len] = '\0';
				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
					si->si_ridtxt, csn->bv_val, dn->bv_val );
				return CV_CSN_OLD;
			}
			rc = CV_CSN_OK;
			break;
		}
	}
	if ( slot )
		*slot = i;
	return rc;
}

966
967
968
969
970
#define SYNC_TIMEOUT	0
#define SYNC_SHUTDOWN	-100
#define SYNC_ERROR		-101
#define SYNC_REPOLL		-102
#define SYNC_PAUSED		-103
Howard Chu's avatar
Howard Chu committed
971

Howard Chu's avatar
Howard Chu committed
972
973
974
975
976
977
978
979
980
981
982
983
984
985
static int
get_pmutex(
	syncinfo_t *si
)
{
	while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
		if ( slapd_shutdown )
			return SYNC_SHUTDOWN;
		if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
			ldap_pvt_thread_yield();
	}
	return 0;
}

986
987
988
989
990
991
992
993
994
995
static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*msg = NULL;

996
997
	struct sync_cookie	syncCookie = { NULL };
	struct sync_cookie	syncCookie_req = { NULL };
998

999
1000
	int		rc,
			err = LDAP_SUCCESS;
1001
1002
1003

	Modifications	*modlist = NULL;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1004
	int				m;
1005
1006
1007

	struct timeval tout = { 0, 0 };

1008
	int		refreshDeletes = 0;
Howard Chu's avatar
Howard Chu committed
1009
	char empty[6] = "empty";
1010

1011
	if ( slapd_shutdown ) {
1012
		rc = SYNC_SHUTDOWN;
1013
		goto done;
1014
1015
	}

1016
1017
1018
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

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

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

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1023
	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
1024
		&tout, &msg ) ) > 0 )
1025
	{
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1026
		int				match, punlock, syncstate;
1027
		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1028
1029
1030
1031
1032
1033
		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
1034
		struct berval	bdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1035

1036
		if ( slapd_shutdown ) {
1037
			rc = SYNC_SHUTDOWN;
1038
			goto done;
1039
		}
Howard Chu's avatar
Howard Chu committed
1040
1041
1042
		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
1043
1044
1045
1046
1047
			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
1048
1049
			/* we can't work without the control */
			if ( rctrls ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1050
				LDAPControl **next = NULL;
Howard Chu's avatar
Howard Chu committed
1051
1052
1053
				/* 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
1054
1055
1056
1057
				/* 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
1058
1059
1060
				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
1061
					bdn.bv_val[bdn.bv_len] = '\0';
1062
					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
Howard Chu's avatar
Howard Chu committed
1063
						"got search entry with multiple "
Howard Chu's avatar
Howard Chu committed
1064
						"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1065
					ldap_controls_free( rctrls );
Howard Chu's avatar
Howard Chu committed
1066
1067
1068
					rc = -1;
					goto done;
				}
Howard Chu's avatar
Howard Chu committed
1069
1070
			}
			if ( rctrlp == NULL ) {
Howard Chu's avatar
Howard Chu committed
1071
				bdn.bv_val[bdn.bv_len] = '\0';
Howard Chu's avatar
Howard Chu committed
1072
1073
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
					"got search entry without "
Howard Chu's avatar
Howard Chu committed
1074
					"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
Howard Chu's avatar
Howard Chu committed
1075
1076
1077
1078
				rc = -1;
				goto done;
			}
			ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
1079
			if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1080
					== LBER_ERROR ) {