syncrepl.c 164 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;
127
	int			si_is_configdb;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
128
	ber_int_t	si_msgid;
129
130
	Avlnode			*si_presentlist;
	LDAP			*si_ld;
131
	Connection		*si_conn;
132
	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
133
134
135
136
#ifdef ENABLE_REWRITE
	struct rewrite_info *si_rewrite;
	struct berval	si_suffixm;
#endif
Howard Chu's avatar
Howard Chu committed
137
	ldap_pvt_thread_mutex_t	si_mutex;
138
139
} syncinfo_t;

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

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

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

170
static AttributeDescription *sync_descs[4];
171

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

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

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

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

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

Howard Chu's avatar
Howard Chu committed
233
234
235
236
237
238
	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 );
	}

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

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

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

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

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

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

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

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

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

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

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

	exattrs = anlist2attrs( si->si_exanlist );

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

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

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

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

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

	si->si_exattrs = exattrs;	
406
407
}

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

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

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

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

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

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

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

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

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

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

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

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

513
static int
Howard Chu's avatar
Howard Chu committed
514
merge_state( syncinfo_t *si, struct sync_cookie *sc1, struct sync_cookie *sc2 )
515
{
Howard Chu's avatar
Howard Chu committed
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
543
	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
544
				if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[i] ) < 0 ) {
Howard Chu's avatar
Howard Chu committed
545
546
547
548
549
550
551
552
553
554
555
556
					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 ));
557

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

605
606
607
	return changed;
}

Howard Chu's avatar
Howard Chu committed
608
609
610
611
612
613
#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
614
615
616
	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
617
	sc1.sids[0] = 1;
Howard Chu's avatar
Howard Chu committed
618
619
620
621
	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
622
	ber_dupbv( &sc1.ctxcsn[0], &bv ); }
Howard Chu's avatar
Howard Chu committed
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
	{ 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
639
	ber_dupbv( &sc2.ctxcsn[0], &bv ); }
Howard Chu's avatar
Howard Chu committed
640
	{ struct berval bv = BER_BVC("20200331000000.100000Z#sc2#003#000000");	/* higher */
Howard Chu's avatar
Howard Chu committed
641
	ber_dupbv( &sc2.ctxcsn[1], &bv ); }
Howard Chu's avatar
Howard Chu committed
642
	{ struct berval bv = BER_BVC("20200501000000.100000Z#sc2#004#000000");	/* lower */
Howard Chu's avatar
Howard Chu committed
643
	ber_dupbv( &sc2.ctxcsn[2], &bv ); }
Howard Chu's avatar
Howard Chu committed
644
645
646
	{ 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
647
648
649
650
651

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

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

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

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

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

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

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

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

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

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

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

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

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

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

857
858
859
860
861
862
863
864
865
866
867
		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
868

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
869
	si->si_refreshDone = 0;
870
871
	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
872

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

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

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

	return rc;
}

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

	*which = 0;

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

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

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
966
#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;
}

967
968
969
970
971
#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
972

Howard Chu's avatar
Howard Chu committed
973
974
975
976
977
static int
get_pmutex(
	syncinfo_t *si
)
{
978
979
980
981
982
983
984
985
986
987
	if ( !si->si_is_configdb ) {
		ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_pmutex );
	} else {
		/* avoid deadlock when replicating cn=config */
		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();
		}
Howard Chu's avatar
Howard Chu committed
988
	}
989

Howard Chu's avatar
Howard Chu committed
990
991
992
	return 0;
}

993
994
995
996
997
998
999
1000
1001
1002
static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*msg = NULL;

1003
1004
	struct sync_cookie	syncCookie = { NULL };
	struct sync_cookie	syncCookie_req = { NULL };
1005

1006
1007
	int		rc,
			err = LDAP_SUCCESS;
1008
1009
1010

	Modifications	*modlist = NULL;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1011
	int				m;
1012
1013
1014

	struct timeval tout = { 0, 0 };

1015
	int		refreshDeletes = 0;
Howard Chu's avatar
Howard Chu committed
1016
	char empty[6] = "empty";
1017

1018
	if ( slapd_shutdown ) {
1019
		rc = SYNC_SHUTDOWN;
1020
		goto done;
1021
1022
	}

1023
1024
1025
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

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

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

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1030
	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
1031
		&tout, &msg ) ) > 0 )
1032
	{
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1033
		int				match, punlock, syncstate;
1034
		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1035
1036
1037
1038
1039
1040
		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
1041
		struct berval	bdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1042

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