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
typedef struct cookie_state {
	ldap_pvt_thread_mutex_t	cs_mutex;
49
	ldap_pvt_thread_cond_t cs_cond;
50
51
	struct berval *cs_vals;
	int *cs_sids;
52
53
	int	cs_num;
	int cs_age;
54
	int cs_ref;
55
	int cs_updating;
56

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
57
58
59
60
	/* pending changes, not yet committed */
	ldap_pvt_thread_mutex_t	cs_pmutex;
	struct berval *cs_pvals;
	int *cs_psids;
61
	int	cs_pnum;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
62
63
} cookie_state;

64
65
66
67
#define	SYNCDATA_DEFAULT	0	/* entries are plain LDAP entries */
#define	SYNCDATA_ACCESSLOG	1	/* entries are accesslog format */
#define	SYNCDATA_CHANGELOG	2	/* entries are changelog format */

68
69
70
#define	SYNCLOG_LOGGING		0	/* doing a log-based update */
#define	SYNCLOG_FALLBACK	1	/* doing a full refresh */

71
72
73
74
75
#define RETRYNUM_FOREVER	(-1)	/* retry forever */
#define RETRYNUM_TAIL		(-2)	/* end of retrynum array */
#define RETRYNUM_VALID(n)	((n) >= RETRYNUM_FOREVER)	/* valid retrynum */
#define RETRYNUM_FINITE(n)	((n) > RETRYNUM_FOREVER)	/* not forever */

76
typedef struct syncinfo_s {
77
	struct syncinfo_s	*si_next;
78
79
80
81
	BackendDB		*si_be;
	BackendDB		*si_wbe;
	struct re_s		*si_re;
	int			si_rid;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
82
	char			si_ridtxt[ STRLENOF("rid=999") + 1 ];
Howard Chu's avatar
Howard Chu committed
83
84
	slap_bindconf		si_bindconf;
	struct berval		si_base;
85
86
87
	struct berval		si_logbase;
	struct berval		si_filterstr;
	struct berval		si_logfilterstr;
88
89
	Filter			*si_filter;
	Filter			*si_logfilter;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
90
	struct berval		si_contextdn;
91
92
93
	int			si_scope;
	int			si_attrsonly;
	char			*si_anfile;
Howard Chu's avatar
Howard Chu committed
94
95
	AttributeName		*si_anlist;
	AttributeName		*si_exanlist;
96
97
98
99
100
101
102
103
104
105
106
	char 			**si_attrs;
	char			**si_exattrs;
	int			si_allattrs;
	int			si_allopattrs;
	int			si_schemachecking;
	int			si_type;	/* the active type */
	int			si_ctype;	/* the configured type */
	time_t			si_interval;
	time_t			*si_retryinterval;
	int			*si_retrynum_init;
	int			*si_retrynum;
Howard Chu's avatar
Howard Chu committed
107
	struct sync_cookie	si_syncCookie;
108
	cookie_state		*si_cookieState;
109
110
111
112
113
114
	int			si_cookieAge;
	int			si_manageDSAit;
	int			si_slimit;
	int			si_tlimit;
	int			si_refreshDelete;
	int			si_refreshPresent;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
115
	int			si_refreshDone;
116
117
	int			si_syncdata;
	int			si_logstate;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
118
	int			si_got;
Howard Chu's avatar
Howard Chu committed
119
	int			si_strict_refresh;	/* stop listening during fallback refresh */
120
	int			si_too_old;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
121
	ber_int_t	si_msgid;
122
123
	Avlnode			*si_presentlist;
	LDAP			*si_ld;
124
	Connection		*si_conn;
125
	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
126
127
128
129
#ifdef ENABLE_REWRITE
	struct rewrite_info *si_rewrite;
	struct berval	si_suffixm;
#endif
Howard Chu's avatar
Howard Chu committed
130
	ldap_pvt_thread_mutex_t	si_mutex;
131
132
} syncinfo_t;

133
static int syncuuid_cmp( const void *, const void * );
Howard Chu's avatar
Howard Chu committed
134
135
136
137
static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
static void presentlist_delete( Avlnode **av, struct berval *syncUUID );
static char *presentlist_find( Avlnode *av, struct berval *syncUUID );
static int presentlist_free( Avlnode *av );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
138
static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
139
140
static int syncrepl_message_to_op(
					syncinfo_t *, Operation *, LDAPMessage * );
141
142
static int syncrepl_message_to_entry(
					syncinfo_t *, Operation *, LDAPMessage *,
143
					Modifications **, Entry **, int, struct berval* );
144
145
static int syncrepl_entry(
					syncinfo_t *, Operation*, Entry*,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
146
147
					Modifications**,int, struct berval*,
					struct berval *cookieCSN );
148
static int syncrepl_updateCookie(
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
149
					syncinfo_t *, Operation *,
150
					struct sync_cookie *, int save );
151
152
static struct berval * slap_uuidstr_from_normalized(
					struct berval *, struct berval *, void * );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
153
154
static int syncrepl_add_glue_ancestors(
	Operation* op, Entry *e );
155

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

159
/* callback functions */
160
161
static int dn_callback( Operation *, SlapReply * );
static int nonpresent_callback( Operation *, SlapReply * );
162

163
static AttributeDescription *sync_descs[4];
164

165
/* delta-mpr */
Howard Chu's avatar
Howard Chu committed
166
167
168
169
170
171
172
173
174
static AttributeDescription *ad_reqMod, *ad_reqDN;

typedef struct logschema {
	struct berval ls_dn;
	struct berval ls_req;
	struct berval ls_mod;
	struct berval ls_newRdn;
	struct berval ls_delRdn;
	struct berval ls_newSup;
175
	struct berval ls_controls;
Howard Chu's avatar
Howard Chu committed
176
177
178
179
180
181
182
183
} logschema;

static logschema changelog_sc = {
	BER_BVC("targetDN"),
	BER_BVC("changeType"),
	BER_BVC("changes"),
	BER_BVC("newRDN"),
	BER_BVC("deleteOldRDN"),
184
185
	BER_BVC("newSuperior"),
	BER_BVC("controls")
Howard Chu's avatar
Howard Chu committed
186
187
188
189
190
191
192
193
};

static logschema accesslog_sc = {
	BER_BVC("reqDN"),
	BER_BVC("reqType"),
	BER_BVC("reqMod"),
	BER_BVC("reqNewRDN"),
	BER_BVC("reqDeleteOldRDN"),
194
195
	BER_BVC("reqNewSuperior"),
	BER_BVC("reqControls")
Howard Chu's avatar
Howard Chu committed
196
197
};

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
static const char *
syncrepl_state2str( int state )
{
	switch ( state ) {
	case LDAP_SYNC_PRESENT:
		return "PRESENT";

	case LDAP_SYNC_ADD:
		return "ADD";

	case LDAP_SYNC_MODIFY:
		return "MODIFY";

	case LDAP_SYNC_DELETE:
		return "DELETE";
	}

	return "UNKNOWN";
}

Howard Chu's avatar
Howard Chu committed
218
219
static slap_overinst syncrepl_ov;

220
static void
221
init_syncrepl(syncinfo_t *si)
222
{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
223
	int i, j, k, l, n;
224
	char **attrs, **exattrs;
225

Howard Chu's avatar
Howard Chu committed
226
227
228
229
230
231
	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 );
	}

232
	/* delta-MPR needs the overlay, nothing else does.
Howard Chu's avatar
Howard Chu committed
233
234
235
236
237
	 * This must happen before accesslog overlay is configured.
	 */
	if ( si->si_syncdata &&
		!overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
		overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
Howard Chu's avatar
Howard Chu committed
238
239
240
241
242
243
244
		if ( !ad_reqMod ) {
			const char *text;
			logschema *ls = &accesslog_sc;

			slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
			slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
		}
Howard Chu's avatar
Howard Chu committed
245
246
	}

247
248
249
250
251
252
253
	if ( !sync_descs[0] ) {
		sync_descs[0] = slap_schema.si_ad_objectClass;
		sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
		sync_descs[2] = slap_schema.si_ad_entryCSN;
		sync_descs[3] = NULL;
	}

254
255
256
257
	if ( si->si_allattrs && si->si_allopattrs )
		attrs = NULL;
	else
		attrs = anlist2attrs( si->si_anlist );
258

259
260
261
262
	if ( attrs ) {
		if ( si->si_allattrs ) {
			i = 0;
			while ( attrs[i] ) {
263
				if ( !is_at_operational( at_find( attrs[i] ) ) ) {
264
265
266
267
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
268
					}
269
270
				} else {
					i++;
271
272
				}
			}
273
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
274
275
			attrs[i] = ch_strdup("*");
			attrs[i + 1] = NULL;
276

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

295
296
297
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
			j = 0;
			while ( attrs[j] ) {
298
				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
299
300
301
302
					for ( k = j; attrs[k] != NULL; k++ ) {
						if ( k == j )
							ch_free( attrs[k] );
						attrs[k] = attrs[k+1];
303
					}
304
305
				} else {
					j++;
306
307
				}
			}
308
309
310
311
312
		}

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

		if ( si->si_allopattrs ) {
313
			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
314
		} else {
315
			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
316
317
318
319
320
321
		}

		/* Add Attributes */
		if ( si->si_allopattrs ) {
			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
		} else {
322
323
324
			for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
				attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
			}
325
		}
326
		attrs[ n ] = NULL;
327

328
	} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
329

330
		i = 0;
331
332
		if ( si->si_allattrs == si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
333
334
			attrs[i++] = ch_strdup( "*" );
			attrs[i++] = ch_strdup( "+" );
335
			si->si_allattrs = si->si_allopattrs = 1;
336
337
338
339
340
341
		} else if ( si->si_allattrs && !si->si_allopattrs ) {
			for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
			attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
			attrs[i++] = ch_strdup( "*" );
			for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
				attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
342
			}
343
344
345
346
		} else if ( !si->si_allattrs && si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
			attrs[i++] = ch_strdup( "+" );
			attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
347
348
		}
		attrs[i] = NULL;
349
350
	}
	
351
352
353
354
355
	si->si_attrs = attrs;

	exattrs = anlist2attrs( si->si_exanlist );

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

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

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

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

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

	si->si_exattrs = exattrs;	
399
400
}

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

417
418
419
	/* setup LDAP SYNC control */
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
420

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

	/* Use the log parameters if we're in log mode */
	if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
Howard Chu's avatar
Howard Chu committed
430
431
432
433
434
435
436
437
438
439
440
		logschema *ls;
		if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
			ls = &accesslog_sc;
		else
			ls = &changelog_sc;
		lattrs[0] = ls->ls_dn.bv_val;
		lattrs[1] = ls->ls_req.bv_val;
		lattrs[2] = ls->ls_mod.bv_val;
		lattrs[3] = ls->ls_newRdn.bv_val;
		lattrs[4] = ls->ls_delRdn.bv_val;
		lattrs[5] = ls->ls_newSup.bv_val;
441
442
443
		lattrs[6] = ls->ls_controls.bv_val;
		lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
		lattrs[8] = NULL;
Howard Chu's avatar
Howard Chu committed
444

445
446
447
		rhint = 0;
		base = si->si_logbase.bv_val;
		filter = si->si_logfilterstr.bv_val;
Howard Chu's avatar
Howard Chu committed
448
		attrs = lattrs;
449
		attrsonly = 0;
450
		scope = LDAP_SCOPE_SUBTREE;
451
452
453
454
455
456
457
458
459
	} else {
		rhint = 1;
		base = si->si_base.bv_val;
		filter = si->si_filterstr.bv_val;
		attrs = si->si_attrs;
		attrsonly = si->si_attrsonly;
		scope = si->si_scope;
	}
	if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
Howard Chu's avatar
Howard Chu committed
460
		si->si_type = LDAP_SYNC_REFRESH_ONLY;
461
	} else {
Howard Chu's avatar
Howard Chu committed
462
		si->si_type = si->si_ctype;
463
464
	}

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

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

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

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

488
	if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
489
490
491
492
493
		c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
		c[2].ldctl_value = si->si_bindconf.sb_authzId;
		c[2].ldctl_iscritical = 1;
		ctrls[2] = &c[2];
		ctrls[3] = NULL;
494
	} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
495
		ctrls[2] = NULL;
496
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
497

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

Howard Chu's avatar
Howard Chu committed
504
505
/* #define DEBUG_MERGE_STATE	1 */

506
static int
Howard Chu's avatar
Howard Chu committed
507
merge_state( syncinfo_t *si, struct sync_cookie *sc1, struct sync_cookie *sc2 )
508
{
Howard Chu's avatar
Howard Chu committed
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
	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
537
				if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[i] ) < 0 ) {
Howard Chu's avatar
Howard Chu committed
538
539
540
541
542
543
544
545
546
547
548
549
					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 ));
550

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

598
599
600
	return changed;
}

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

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

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
645
646
647
648
649
650
651
652
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
653
	SlapReply rs = {REP_SEARCH};
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
654
655
656
657
658
659
660
661
662
663
	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
664
665
	e.e_name = si->si_contextdn;
	e.e_nname = si->si_contextdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
	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
686
					changed = 1;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
					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
715
716
717
		} 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
718
719
720
721
722
723
724
725
		}
	}
	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
726
727
		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
728
729
730
731
732
	}
	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
	return changed;
}

733
734
735
736
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
737
738
{
	int	rc;
739
	int cmdline_cookie_found = 0;
740

741
	struct sync_cookie	*sc = NULL;
742
743
744
#ifdef HAVE_TLS
	void	*ssl;
#endif
745

746
	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
747
	if ( rc != LDAP_SUCCESS ) {
748
		goto done;
749
	}
750
	op->o_protocol = LDAP_VERSION3;
751

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

773
774
	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
775
776
777
	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
778
779
	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );

Howard Chu's avatar
Howard Chu committed
780
	si->si_syncCookie.rid = si->si_rid;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
781
782
783
784

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

786
787
788
	/* We've just started up, or the remote server hasn't sent us
	 * any meaningful state.
	 */
789
	if ( !si->si_syncCookie.ctxcsn ) {
790
		int i;
791

792
793
794
795
796
797
798
799
800
		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 */
801

802
803
804
			LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );

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

849
		ch_free( si->si_syncCookie.octet_str.bv_val );
Howard Chu's avatar
Howard Chu committed
850
		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
851
			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
852
			si->si_syncCookie.sid );
853
	} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
854
855
		/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
		ch_free( si->si_syncCookie.octet_str.bv_val );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
856
		BER_BVZERO( &si->si_syncCookie.octet_str );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
857
858
		/* Look for contextCSN from syncprov overlay. */
		check_syncprov( op, si );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
859
860
861
862
		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
863
864
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
865
866
	si->si_refreshDone = 0;

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

869
	if( rc != LDAP_SUCCESS ) {
870
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
871
			"ldap_search_ext: %s (%d)\n",
872
			si->si_ridtxt, ldap_err2string( rc ), rc );
873
874
875
876
877
	}

done:
	if ( rc ) {
		if ( si->si_ld ) {
878
			ldap_unbind_ext( si->si_ld, NULL, NULL );
879
880
881
882
883
884
885
			si->si_ld = NULL;
		}
	}

	return rc;
}

886
887
888
889
890
891
892
893
static int
compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
{
	int i, j, match = 0;
	const char *text;

	*which = 0;

894
895
896
897
898
	if ( sc1->numcsns < sc2->numcsns ) {
		*which = sc1->numcsns;
		return -1;
	}

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

922
923
924
925
926
#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
927

928
929
930
931
932
933
934
935
936
937
static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*msg = NULL;

938
939
	struct sync_cookie	syncCookie = { NULL };
	struct sync_cookie	syncCookie_req = { NULL };
940

941
942
	int		rc,
			err = LDAP_SUCCESS;
943
944
945

	Modifications	*modlist = NULL;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
946
	int				m;
947
948
949

	struct timeval tout = { 0, 0 };

950
	int		refreshDeletes = 0;
Howard Chu's avatar
Howard Chu committed
951
	char empty[6] = "empty";
952

953
	if ( slapd_shutdown ) {
954
		rc = SYNC_SHUTDOWN;
955
		goto done;
956
957
	}

958
959
960
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

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

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

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
965
	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
966
		&tout, &msg ) ) > 0 )
967
	{
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
968
		int				match, punlock, syncstate;
969
		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
970
971
972
973
974
975
		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
976
		struct berval	bdn;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
977

978
		if ( slapd_shutdown ) {
979
			rc = SYNC_SHUTDOWN;
980
			goto done;
981
		}
Howard Chu's avatar
Howard Chu committed
982
983
984
		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
985
986
987
988
989
			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
990
991
			/* we can't work without the control */
			if ( rctrls ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
992
				LDAPControl **next = NULL;
Howard Chu's avatar
Howard Chu committed
993
994
995
				/* 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
996
997
998
999
				/* 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
1000
1001
1002
				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
1003
					bdn.bv_val[bdn.bv_len] = '\0';
1004
					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
Howard Chu's avatar
Howard Chu committed
1005
						"got search entry with multiple "
Howard Chu's avatar
Howard Chu committed
1006
						"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1007
					ldap_controls_free( rctrls );
Howard Chu's avatar
Howard Chu committed
1008
1009
1010
					rc = -1;
					goto done;
				}
Howard Chu's avatar
Howard Chu committed
1011
1012
			}
			if ( rctrlp == NULL ) {
Howard Chu's avatar
Howard Chu committed
1013
				bdn.bv_val[bdn.bv_len] = '\0';
Howard Chu's avatar
Howard Chu committed
1014
1015
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
					"got search entry without "
Howard Chu's avatar
Howard Chu committed
1016
					"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
Howard Chu's avatar
Howard Chu committed
1017
1018
1019
1020
				rc = -1;
				goto done;
			}
			ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
1021
			if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1022
					== LBER_ERROR ) {
Howard Chu's avatar
Howard Chu committed
1023
1024
1025
				bdn.bv_val[bdn.bv_len] = '\0';
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
					si->si_ridtxt, bdn.bv_val, 0 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1026
1027
1028
1029
				ldap_controls_free( rctrls );
				rc = -1;
				goto done;
			}
Howard Chu's avatar
Howard Chu committed
1030
1031
			/* FIXME: what if syncUUID is NULL or empty?
			 * (happens with back-sql...) */
Howard Chu's avatar
Howard Chu committed
1032
			if ( syncUUID[0].bv_len != UUIDLEN ) {
Howard Chu's avatar
Howard Chu committed
1033
				bdn.bv_val[bdn.bv_len] = '\0';
Howard Chu's avatar
Howard Chu committed
1034
				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
Howard Chu's avatar
Howard Chu committed
1035
					"got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n",
Howard Chu's avatar
Howard Chu committed
1036
					si->si_ridtxt,
Howard Chu's avatar
Howard Chu committed
1037
					syncrepl_state2str( syncstate ), bdn.bv_val