syncrepl.c 61.3 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
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 2003-2004 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
 * Portions Copyright 2003 by IBM Corporation.
 * Portions Copyright 2003 by Howard Chu, Symas Corporation.
 * 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 "ldap_rq.h"

32
33
34
35
/* FIXME: for ldap_ld_free() */
#undef ldap_debug
#include "../../libraries/libldap/ldap-int.h"

36
37
38
39
40
#define SYNCREPL_STR	"syncreplxxx"
#define CN_STR	"cn="

static const struct berval slap_syncrepl_bvc = BER_BVC(SYNCREPL_STR);
static const struct berval slap_syncrepl_cn_bvc = BER_BVC(CN_STR SYNCREPL_STR);
41

42
static int syncuuid_cmp( const void *, const void * );
43
static void avl_ber_bvfree( void * );
44
static void syncrepl_del_nonpresent( Operation *, syncinfo_t * );
45

46
/* callback functions */
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
47
static int dn_callback( struct slap_op *, struct slap_rep * );
48
49
static int nonpresent_callback( struct slap_op *, struct slap_rep * );
static int null_callback( struct slap_op *, struct slap_rep * );
50

51
static AttributeDescription *sync_descs[4];
52

53
54
struct runqueue_s syncrepl_rq;

55
void
56
init_syncrepl(syncinfo_t *si)
57
{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
58
	int i, j, k, l, n;
59
	char **attrs, **exattrs;
60
61
62
63
64
65
66
67

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

68
69
70
71
	if ( si->si_allattrs && si->si_allopattrs )
		attrs = NULL;
	else
		attrs = anlist2attrs( si->si_anlist );
72

73
74
75
76
77
78
79
80
81
	if ( attrs ) {
		if ( si->si_allattrs ) {
			i = 0;
			while ( attrs[i] ) {
				if ( !is_at_operational( at_find( attrs[i] ))) {
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
82
					}
83
84
				} else {
					i++;
85
86
				}
			}
87
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
88
89
			attrs[i] = ch_strdup("*");
			attrs[i + 1] = NULL;
90

91
92
93
94
95
96
97
98
99
100
101
102
103
		} else if ( si->si_allopattrs ) {
			i = 0;
			while ( attrs[i] ) {
				if ( is_at_operational( at_find( attrs[i] ))) {
					for ( j = i; attrs[j] != NULL; j++ ) {
						if ( j == i )
							ch_free( attrs[i] );
						attrs[j] = attrs[j+1];
					}
				} else {
					i++;
				}
			}
104
			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
105
106
			attrs[i] = ch_strdup("+");
			attrs[i + 1] = NULL;
107
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
108

109
110
111
112
113
114
115
116
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
			j = 0;
			while ( attrs[j] ) {
				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val )) {
					for ( k = j; attrs[k] != NULL; k++ ) {
						if ( k == j )
							ch_free( attrs[k] );
						attrs[k] = attrs[k+1];
117
					}
118
119
				} else {
					j++;
120
121
				}
			}
122
123
124
125
126
127
128
		}

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

		if ( si->si_allopattrs ) {
			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ));
		} else {
129
			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ));
130
131
132
133
134
135
136
137
138
139
		}

		if ( attrs == NULL ) {
			Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
		}

		/* Add Attributes */
		if ( si->si_allopattrs ) {
			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
		} else {
140
141
142
			for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
				attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
			}
143
		}
144
		attrs[ n ] = NULL;
145

146
	} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
147

148
		i = 0;
149
150
		if ( si->si_allattrs == si->si_allopattrs ) {
			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
151
152
			attrs[i++] = ch_strdup( "*" );
			attrs[i++] = ch_strdup( "+" );
153
154
155
156
157
158
		} 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
159
			}
160
161
162
163
		} 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 );
164
165
		}
		attrs[i] = NULL;
166
167
	}
	
168
169
170
171
172
	si->si_attrs = attrs;

	exattrs = anlist2attrs( si->si_exanlist );

	if ( exattrs ) {
173
174
		for ( n = 0; exattrs[n] != NULL; n++ ) ;

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
175
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
176
177
178
179
			j = 0;
			while ( exattrs[j] != NULL ) {
				if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val )) {
					for ( k = j; exattrs[k] != NULL; k++ ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
180
						if ( k == j )
181
182
							ch_free( exattrs[k] );
						exattrs[k] = exattrs[k+1];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
183
					}
184
185
				} else {
					j++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
186
187
188
				}
			}
		}
189
190
191

		for ( i = 0; exattrs[i] != NULL; i++ ) {
			for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
192
193
				ObjectClass	*oc;
				if ( ( oc = si->si_anlist[j].an_oc ) ) {
194
195
196
197
198
199
200
201
202
203
204
					k = 0;
					while ( oc->soc_required[k] ) {
						if ( !strcmp( exattrs[i],
							 oc->soc_required[k]->sat_cname.bv_val )) {
							for ( l = i; exattrs[l]; l++ ) {
								if ( l == i )
									ch_free( exattrs[i] );
								exattrs[l] = exattrs[l+1];
							}
						} else {
							k++;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
205
206
207
208
209
						}
					}
				}
			}
		}
210
211

		for ( i = 0; exattrs[i] != NULL; i++ ) ;
212
213
214

		if ( i != n )
			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *));
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
215
	}
216
217

	si->si_exattrs = exattrs;	
218
219
}

220
static int
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
221
222
ldap_sync_search(
	syncinfo_t *si,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
223
	void *ctx )
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
224
{
225
226
227
	BerElementBuffer berbuf;
	BerElement *ber = (BerElement *)&berbuf;
	LDAPControl c[2], *ctrls[3];
228
	struct timeval timeout;
229
	ber_int_t	msgid;
230
	int rc;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
231

232
233
234
	/* 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
235

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
236
	if ( si->si_syncCookie.octet_str &&
237
		!BER_BVISNULL( &si->si_syncCookie.octet_str[0] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
238
239
240
241
	{
		ber_printf( ber, "{eO}",
			abs(si->si_type),
			&si->si_syncCookie.octet_str[0] );
242
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
243
244
		ber_printf( ber, "{e}",
			abs(si->si_type) );
245
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
246

247
248
249
250
	if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 )) == LBER_ERROR ) {
		ber_free_buf( ber );
		return rc;
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
251

252
	c[0].ldctl_oid = LDAP_CONTROL_SYNC;
253
	c[0].ldctl_iscritical = si->si_type < 0;
254
	ctrls[0] = &c[0];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
255

256
	if ( si->si_authzId ) {
257
		c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
258
		ber_str2bv( si->si_authzId, 0, 0, &c[1].ldctl_value );
259
260
261
262
263
264
		c[1].ldctl_iscritical = 1;
		ctrls[1] = &c[1];
		ctrls[2] = NULL;
	} else {
		ctrls[1] = NULL;
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
265

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
266
	timeout.tv_sec = si->si_tlimit;
267
	timeout.tv_usec = 0;
268

269
	rc = ldap_search_ext( si->si_ld, si->si_base.bv_val, si->si_scope,
270
		si->si_filterstr.bv_val, si->si_attrs, si->si_attrsonly,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
271
		ctrls, NULL, si->si_tlimit > 0 ? &timeout : NULL,
272
		si->si_slimit, &msgid );
273
	ber_free_buf( ber );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
274
275
276
	return rc;
}

277
278
279
280
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
281
282
{
	int	rc;
283
	int cmdline_cookie_found = 0;
284

285
	char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
Howard Chu's avatar
Howard Chu committed
286
	struct berval syncrepl_cn_bv;
287
	struct sync_cookie	*sc = NULL;
288
	struct berval	*psub;
289
290
291
#ifdef HAVE_TLS
	void	*ssl;
#endif
292
293

	psub = &si->si_be->be_nsuffix[0];
294
295

	/* Init connection to master */
296
	rc = ldap_initialize( &si->si_ld, si->si_provideruri );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
297
	if ( rc != LDAP_SUCCESS ) {
298
		Debug( LDAP_DEBUG_ANY,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
299
			"do_syncrep1: ldap_initialize failed (%s)\n",
300
			si->si_provideruri, 0, 0 );
301
		return rc;
302
303
	}

304
305
	op->o_protocol = LDAP_VERSION3;
	ldap_set_option( si->si_ld, LDAP_OPT_PROTOCOL_VERSION, &op->o_protocol );
306
307
308

	/* Bind to master */

309
	if ( si->si_tls ) {
310
		rc = ldap_start_tls_s( si->si_ld, NULL, NULL );
311
312
313
		if( rc != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_ANY,
				"%s: ldap_start_tls failed (%d)\n",
314
				si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning",
315
				rc, 0 );
316
			if( si->si_tls == SYNCINFO_TLS_CRITICAL ) goto done;
317
318
319
		}
	}

320
	if ( si->si_bindmethod == LDAP_AUTH_SASL ) {
321
322
323
#ifdef HAVE_CYRUS_SASL
		void *defaults;

324
		if ( si->si_secprops != NULL ) {
325
			rc = ldap_set_option( si->si_ld,
326
				LDAP_OPT_X_SASL_SECPROPS, si->si_secprops);
327

328
			if( rc != LDAP_OPT_SUCCESS ) {
329
330
				Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
					"(%s,SECPROPS,\"%s\") failed!\n",
331
					si->si_provideruri, si->si_secprops, 0 );
332
				goto done;
333
334
335
			}
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
336
337
		defaults = lutil_sasl_defaults( si->si_ld, si->si_saslmech,
			si->si_realm, si->si_authcId, si->si_passwd, si->si_authzId );
338

339
		rc = ldap_sasl_interactive_bind_s( si->si_ld,
340
341
				si->si_binddn,
				si->si_saslmech,
342
				NULL, NULL,
343
				LDAP_SASL_QUIET,
344
345
346
				lutil_sasl_interact,
				defaults );

347
348
		lutil_sasl_freedefs( defaults );

349
		/* FIXME: different error behaviors according to
350
351
352
		 *	1) return code
		 *	2) on err policy : exit, retry, backoff ...
		 */
353
		if ( rc != LDAP_SUCCESS ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
354
			Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
355
356
				"ldap_sasl_interactive_bind_s failed (%d)\n",
				rc, 0, 0 );
357
358
359
360
361
362
363
364
365

			/* FIXME (see above comment) */
			/* if Kerberos credentials cache is not active, retry */
			if ( strcmp( si->si_saslmech, "GSSAPI" ) == 0 &&
				rc == LDAP_LOCAL_ERROR )
			{
				rc = LDAP_SERVER_DOWN;
			}

366
			goto done;
367
368
		}
#else /* HAVE_CYRUS_SASL */
369
		/* Should never get here, we trapped this at config time */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
370
		assert(0);
371
		fprintf( stderr, "not compiled with SASL support\n" );
372
373
		rc = LDAP_OTHER;
		goto done;
374
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
375

376
	} else {
377
378
		rc = ldap_bind_s( si->si_ld,
			si->si_binddn, si->si_passwd, si->si_bindmethod );
379
		if ( rc != LDAP_SUCCESS ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
380
			Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
381
				"ldap_bind_s failed (%d)\n", rc, 0, 0 );
382
			goto done;
383
384
385
		}
	}

386
387
388
	/* Set SSF to strongest of TLS, SASL SSFs */
	op->o_sasl_ssf = 0;
	op->o_tls_ssf = 0;
389
	op->o_transport_ssf = 0;
390
#ifdef HAVE_TLS
391
392
393
	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
		== LDAP_SUCCESS && ssl != NULL )
	{
394
395
396
397
		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
	}
#endif /* HAVE_TLS */
	ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
398
399
	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
		?  op->o_sasl_ssf : op->o_tls_ssf;
400

401
	/* get syncrepl cookie of shadow replica from subentry */
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
402
	assert( si->si_rid < 1000 );
Howard Chu's avatar
Howard Chu committed
403
	syncrepl_cn_bv.bv_val = syncrepl_cbuf;
404
	syncrepl_cn_bv.bv_len = snprintf( syncrepl_cbuf, sizeof(syncrepl_cbuf),
405
		CN_STR "syncrepl%ld", si->si_rid );
406
	build_new_dn( &op->o_req_ndn, psub, &syncrepl_cn_bv, op->o_tmpmemctx );
407
	op->o_req_dn = op->o_req_ndn;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
408

409
	LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
410
		if ( si->si_rid == sc->rid ) {
411
412
413
414
			cmdline_cookie_found = 1;
			break;
		}
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
415

416
417
	if ( cmdline_cookie_found ) {
		/* cookie is supplied in the command line */
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
418
419
		BerVarray cookie = NULL;
		struct berval cookie_bv;
420

421
		LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
422
423
424
		slap_sync_cookie_free( &si->si_syncCookie, 0 );

		/* read stored cookie if it exists */
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
425
		backend_attribute( op, NULL, &op->o_req_ndn,
426
			slap_schema.si_ad_syncreplCookie, &cookie, ACL_READ );
427
428
429

		if ( !cookie ) {
			/* no stored cookie */
430
			if ( sc->ctxcsn == NULL ||
431
				 BER_BVISNULL( sc->ctxcsn ) ) {
432
433
434
				/* if cmdline cookie does not have ctxcsn */
				/* component, set it to an initial value */
				slap_init_sync_cookie_ctxcsn( sc );
435
			}
436
437
438
			slap_dup_sync_cookie( &si->si_syncCookie, sc );
			slap_sync_cookie_free( sc, 1 );
			sc = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
439

440
441
		} else {
			/* stored cookie */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
442
			struct berval newcookie = BER_BVNULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
443
444
445
			ber_dupbv( &cookie_bv, &cookie[0] );
			ber_bvarray_add( &si->si_syncCookie.octet_str, &cookie_bv );
			slap_parse_sync_cookie( &si->si_syncCookie );
446
447
			ber_bvarray_free( si->si_syncCookie.octet_str );
			si->si_syncCookie.octet_str = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
448
			ber_bvarray_free_x( cookie, op->o_tmpmemctx );
449
			if ( sc->sid != -1 ) {
450
				/* command line cookie wins */
451
				si->si_syncCookie.sid = sc->sid;
452
			}
453
			if ( sc->ctxcsn != NULL ) {
454
455
456
457
458
				/* command line cookie wins */
				if ( si->si_syncCookie.ctxcsn ) {
					ber_bvarray_free( si->si_syncCookie.ctxcsn );
					si->si_syncCookie.ctxcsn = NULL;
				}
459
				ber_dupbv( &cookie_bv, &sc->ctxcsn[0] );
460
461
				ber_bvarray_add( &si->si_syncCookie.ctxcsn, &cookie_bv );
			}
462
463
464
465
466
467
			if ( sc->rid != -1 ) {
				/* command line cookie wins */
				si->si_syncCookie.rid = sc->rid;
			}
			slap_sync_cookie_free( sc, 1 );
			sc = NULL;
468
469
470
471
			slap_compose_sync_cookie( NULL, &newcookie,
					&si->si_syncCookie.ctxcsn[0],
					si->si_syncCookie.sid, si->si_syncCookie.rid );
			ber_bvarray_add( &si->si_syncCookie.octet_str, &newcookie );
472
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
473

474
475
476
477
478
479
480
	} else {
		/* no command line cookie is specified */
		if ( si->si_syncCookie.octet_str == NULL ) {
			BerVarray cookie = NULL;
			struct berval cookie_bv;
			/* try to read stored cookie */
			backend_attribute( op, NULL, &op->o_req_ndn,
481
				slap_schema.si_ad_syncreplCookie, &cookie, ACL_READ );
482
483
484
485
486
487
			if ( cookie ) {
				ber_dupbv( &cookie_bv, &cookie[0] );
				ber_bvarray_add( &si->si_syncCookie.octet_str, &cookie_bv );
				slap_parse_sync_cookie( &si->si_syncCookie );
				ber_bvarray_free_x( cookie, op->o_tmpmemctx );
			}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
488
489
490
491
		}
	}

	rc = ldap_sync_search( si, op->o_tmpmemctx );
492

493
	if( rc != LDAP_SUCCESS ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
494
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
495
			"ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
496
497
498
499
500
501
502
503
504
505
	}

done:
	if ( rc ) {
		if ( si->si_ld ) {
			ldap_unbind( si->si_ld );
			si->si_ld = NULL;
		}
	}

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
506
507
	slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
	return rc;
}

static int
do_syncrep2(
	Operation *op,
	syncinfo_t *si )
{
	LDAPControl	**rctrls = NULL;
	LDAPControl	*rctrlp;

	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *)&berbuf;

	LDAPMessage	*res = NULL;
	LDAPMessage	*msg = NULL;

	char		*retoid = NULL;
	struct berval	*retdata = NULL;

	Entry		*entry = NULL;

	int		syncstate;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
531
	struct berval	syncUUID = BER_BVNULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
532
533
	struct sync_cookie	syncCookie = { NULL, -1, NULL };
	struct sync_cookie	syncCookie_req = { NULL, -1, NULL };
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534
	struct berval		cookie = BER_BVNULL;
535

536
	int	rc, err, i;
537
538
	ber_len_t	len;

539
	int rc_efree = 1;
540
541
542
543
544
545
546
547
548
549

	struct berval	*psub;
	Modifications	*modlist = NULL;

	const char		*text;
	int				match;

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

550
551
	int		refreshDeletes = 0;
	int		refreshDone = 1;
552
	BerVarray syncUUIDs = NULL;
553
554
	ber_tag_t si_tag;

555
	if ( slapd_shutdown ) {
556
		rc = -2;
557
		goto done;
558
559
	}

560
561
562
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

563
564
565
566
	Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2\n", 0, 0, 0 );

	psub = &si->si_be->be_nsuffix[0];

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
569
	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
570
571
572
573
574
		tout_p = &tout;
	} else {
		tout_p = NULL;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
575
576
	while (( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE,
		tout_p, &res )) > 0 )
577
	{
578
		if ( slapd_shutdown ) {
579
580
			rc = -2;
			goto done;
581
		}
582
		for( msg = ldap_first_message( si->si_ld, res );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
583
584
			msg != NULL;
			msg = ldap_next_message( si->si_ld, msg ) )
585
586
587
		{
			switch( ldap_msgtype( msg ) ) {
			case LDAP_RES_SEARCH_ENTRY:
588
				ldap_get_entry_controls( si->si_ld, msg, &rctrls );
Howard Chu's avatar
Howard Chu committed
589
590
				/* we can't work without the control */
				if ( !rctrls ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
591
					Debug( LDAP_DEBUG_ANY, "do_syncrep2: "
592
593
						"got search entry without "
						"control\n", 0, 0, 0 );
Howard Chu's avatar
Howard Chu committed
594
595
596
597
598
					rc = -1;
					goto done;
				}
				rctrlp = *rctrls;
				ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
599
				ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
600
				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
601
					ber_scanf( ber, /*"{"*/ "m}", &cookie );
602
					if ( !BER_BVISNULL( &cookie ) ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
603
604
605
606
607
						struct berval tmp_bv;
						ber_dupbv( &tmp_bv, &cookie );
						ber_bvarray_add( &syncCookie.octet_str, &tmp_bv );
					}
					if ( syncCookie.octet_str &&
608
609
							!BER_BVISNULL( &syncCookie.octet_str[0] ) )
					{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
610
						slap_parse_sync_cookie( &syncCookie );
611
					}
612
				}
613
614
				if ( syncrepl_message_to_entry( si, op, msg,
					&modlist, &entry, syncstate ) == LDAP_SUCCESS ) {
615
					rc_efree = syncrepl_entry( si, op, entry, &modlist,
616
						syncstate, &syncUUID, &syncCookie_req, syncCookie.ctxcsn );
617
					if ( syncCookie.octet_str &&
618
						!BER_BVISNULL( &syncCookie.octet_str[0] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
619
					{
620
621
						syncrepl_updateCookie( si, op, psub, &syncCookie );
					}
622
				}
Howard Chu's avatar
Howard Chu committed
623
				ldap_controls_free( rctrls );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
624
625
626
				if ( modlist ) {
					slap_mods_free( modlist );
				}
627
				if ( rc_efree && entry ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
628
					entry_free( entry );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
629
				}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
630
				entry = NULL;
631
632
633
634
				break;

			case LDAP_RES_SEARCH_REFERENCE:
				Debug( LDAP_DEBUG_ANY,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
635
					"do_syncrep2: reference received error\n", 0, 0, 0 );
636
637
638
				break;

			case LDAP_RES_SEARCH_RESULT:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
639
640
				Debug( LDAP_DEBUG_SYNC,
					"do_syncrep2: LDAP_RES_SEARCH_RESULT\n", 0, 0, 0 );
641
				ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
642
					&rctrls, 0 );
643
644
				if ( rctrls ) {
					rctrlp = *rctrls;
645
					ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
646

647
					ber_scanf( ber, "{" /*"}"*/);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
648
					if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
649
						ber_scanf( ber, "m", &cookie );
650
						if ( !BER_BVISNULL( &cookie ) ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
651
652
653
654
655
							struct berval tmp_bv;
							ber_dupbv( &tmp_bv, &cookie );
							ber_bvarray_add( &syncCookie.octet_str, &tmp_bv);
						}
						if ( syncCookie.octet_str &&
656
							!BER_BVISNULL( &syncCookie.octet_str[0] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
657
						{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
658
							slap_parse_sync_cookie( &syncCookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
659
						}
660
					}
661
662
663
664
					if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
					{
						ber_scanf( ber, "b", &refreshDeletes );
					}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
665
					ber_scanf( ber, /*"{"*/ "}" );
666
				}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
667
668
669
670
671
672
673
674
				if ( syncCookie_req.ctxcsn == NULL ) {
					match = -1;
				} else if ( syncCookie.ctxcsn == NULL ) {
					match = 1;
				} else {
					value_match( &match, slap_schema.si_ad_entryCSN,
						slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
						SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
675
676
						&syncCookie_req.ctxcsn[0], &syncCookie.ctxcsn[0],
						&text );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
677
				}
678
				if ( syncCookie.octet_str && !BER_BVISNULL( syncCookie.octet_str ) &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
679
680
					match < 0 && err == LDAP_SUCCESS )
				{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
681
					syncrepl_updateCookie( si, op, psub, &syncCookie );
682
683
684
685
686
				}
				if ( rctrls ) {
					ldap_controls_free( rctrls );
				}
				if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
687
					/* FIXME : different error behaviors according to
688
689
690
					 *	1) err code : LDAP_BUSY ...
					 *	2) on err policy : stop service, stop sync, retry
					 */
691
					if ( refreshDeletes == 0 && match < 0 &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
692
693
						err == LDAP_SUCCESS )
					{
694
						syncrepl_del_nonpresent( op, si );
695
696
697
					} else {
						avl_free( si->si_presentlist, avl_ber_bvfree );
						si->si_presentlist = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
698
					}
699
				}
700
701
				rc = -2;
				goto done;
702
703
				break;

704
			case LDAP_RES_INTERMEDIATE:
705
				rc = ldap_parse_intermediate( si->si_ld, msg,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
706
707
					&retoid, &retdata, NULL, 0 );
				if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
708
					ber_init2( ber, retdata, LBER_USE_DER );
709

710
711
712
					switch ( si_tag = ber_peek_tag( ber, &len )) {
					ber_tag_t tag;
					case LDAP_TAG_SYNC_NEW_COOKIE:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
713
714
715
716
						Debug( LDAP_DEBUG_SYNC,
							"do_syncrep2: %s - %s%s\n", 
							"LDAP_RES_INTERMEDIATE", 
							"NEW_COOKIE", "\n" );
717
718
719
						ber_scanf( ber, "tm", &tag, &cookie );
						break;
					case LDAP_TAG_SYNC_REFRESH_DELETE:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
720
721
722
723
						Debug( LDAP_DEBUG_SYNC,
							"do_syncrep2: %s - %s%s\n", 
							"LDAP_RES_INTERMEDIATE", 
							"REFRESH_DELETE\n", "\n" );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
724
						si->si_refreshDelete = 1;
725
					case LDAP_TAG_SYNC_REFRESH_PRESENT:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
726
727
728
729
730
731
						Debug( LDAP_DEBUG_SYNC,
							"do_syncrep2: %s - %s%s\n", 
							"LDAP_RES_INTERMEDIATE", 
							si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
							"REFRESH_PRESENT" : "REFRESH_DELETE",
							"\n" );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
732
733
						si->si_refreshDelete = 1;
						si->si_refreshPresent = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
734
						ber_scanf( ber, "t{" /*"}"*/, &tag );
735
736
						if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
						{
737
							ber_scanf( ber, "m", &cookie );
738
							if ( !BER_BVISNULL( &cookie ) ) {
739
740
								struct berval tmp_bv;
								ber_dupbv( &tmp_bv, &cookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
741
742
								ber_bvarray_add( &syncCookie.octet_str,
									&tmp_bv);
743
744
							}
							if ( syncCookie.octet_str &&
745
								!BER_BVISNULL( &syncCookie.octet_str[0] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
746
							{
747
								slap_parse_sync_cookie( &syncCookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
748
							}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
749
						}
750
						if ( ber_peek_tag( ber, &len ) ==
Kurt Zeilenga's avatar
Kurt Zeilenga committed
751
							LDAP_TAG_REFRESHDONE )
752
753
754
						{
							ber_scanf( ber, "b", &refreshDone );
						}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
755
						ber_scanf( ber, /*"{"*/ "}" );
756
757
						break;
					case LDAP_TAG_SYNC_ID_SET:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
758
759
760
761
762
						Debug( LDAP_DEBUG_SYNC,
							"do_syncrep2: %s - %s%s\n", 
							"LDAP_RES_INTERMEDIATE", 
							"SYNC_ID_SET",
							"\n" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
763
						ber_scanf( ber, "t{" /*"}"*/, &tag );
764
						if ( ber_peek_tag( ber, &len ) ==
Kurt Zeilenga's avatar
Kurt Zeilenga committed
765
766
							LDAP_TAG_SYNC_COOKIE )
						{
767
							ber_scanf( ber, "m", &cookie );
768
							if ( !BER_BVISNULL( &cookie ) ) {
769
770
								struct berval tmp_bv;
								ber_dupbv( &tmp_bv, &cookie );
771
								ber_bvarray_add( &syncCookie.octet_str,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
772
									&tmp_bv );
773
774
							}
							if ( syncCookie.octet_str &&
775
									!BER_BVISNULL( &syncCookie.octet_str[0] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
776
							{
777
								slap_parse_sync_cookie( &syncCookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
778
							}
779
780
						}
						if ( ber_peek_tag( ber, &len ) ==
Kurt Zeilenga's avatar
Kurt Zeilenga committed
781
							LDAP_TAG_REFRESHDELETES )
782
783
784
785
						{
							ber_scanf( ber, "b", &refreshDeletes );
						}
						ber_scanf( ber, "[W]", &syncUUIDs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
786
						ber_scanf( ber, /*"{"*/ "}" );
787
						for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
788
789
							struct berval *syncuuid_bv;
							syncuuid_bv = ber_dupbv( NULL, &syncUUIDs[i] );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
790
							slap_sl_free( syncUUIDs[i].bv_val,op->o_tmpmemctx );
791
							avl_insert( &si->si_presentlist,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
792
793
								(caddr_t) syncuuid_bv,
								syncuuid_cmp, avl_dup_error );
794
						}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
795
						slap_sl_free( syncUUIDs, op->o_tmpmemctx );
796
797
						break;
					default:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
798
799
						Debug( LDAP_DEBUG_ANY,
							"do_syncrep2 : unknown syncinfo tag (%ld)\n",
800
						(long) si_tag, 0, 0 );
801
802
803
						ldap_memfree( retoid );
						ber_bvfree( retdata );
						continue;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
804
805
					}

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
806
807
808
809
810
811
812
813
814
815
816
					if ( syncCookie_req.ctxcsn == NULL ) {
						match = -1;
					} else if ( syncCookie.ctxcsn == NULL ) {
						match = 1;
					} else {
						value_match( &match, slap_schema.si_ad_entryCSN,
							slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
							SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
							&syncCookie_req.ctxcsn[0],
							&syncCookie.ctxcsn[0], &text );
					}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
817

818
					if ( syncCookie.ctxcsn && !BER_BVISNULL( &syncCookie.ctxcsn[0] ) &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
819
820
						match < 0 )
					{
821
						syncrepl_updateCookie( si, op, psub, &syncCookie);
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
822
823
					}

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
824
					if ( si->si_refreshPresent == 1 ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
825
						if ( match < 0 ) {
826
							syncrepl_del_nonpresent( op, si );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
827
						}
828
					} 
829
830
831
832

					ldap_memfree( retoid );
					ber_bvfree( retdata );
					break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
833

834
				} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
835
					Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
Kurt Zeilenga's avatar
Kurt Zeilenga committed
836
837
						"unknown intermediate response (%d)\n",
						rc, 0, 0 );
838
839
840
841
842
					ldap_memfree( retoid );
					ber_bvfree( retdata );
					break;
				}
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
843

844
			default:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
845
				Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
846
847
848
849
					"unknown message\n", 0, 0, 0 );
				break;

			}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
850
851
852
853
854
			if ( syncCookie.octet_str ) {
				slap_sync_cookie_free( &syncCookie_req, 0 );
				slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
				slap_sync_cookie_free( &syncCookie, 0 );
			}
855
856
		}
		ldap_msgfree( res );
857
		res = NULL;
858
859
860
	}

	if ( rc == -1 ) {
861
862
		const char *errstr;

Howard Chu's avatar
Howard Chu committed
863
864
		ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
		errstr = ldap_err2string( rc );
865
		
866
		Debug( LDAP_DEBUG_ANY,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
867
			"do_syncrep2 : %s\n", errstr, 0, 0 );
868
869
870
	}

done:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
871
872
873
	slap_sync_cookie_free( &syncCookie, 0 );
	slap_sync_cookie_free( &syncCookie_req, 0 );

874
	if ( res ) ldap_msgfree( res );
875

876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
	if ( rc && si->si_ld ) {
		ldap_unbind( si->si_ld );
		si->si_ld = NULL;
	}

	return rc;
}

void *
do_syncrepl(
	void	*ctx,
	void	*arg )
{
	struct re_s* rtask = arg;
	syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
	Connection conn = {0};
892
893
	char opbuf[OPERATION_BUFFER_SIZE];
	Operation *op;
894
895
	int rc = LDAP_SUCCESS;
	int first = 0;
Howard Chu's avatar
Howard Chu committed
896
897
	int dostop = 0;
	ber_socket_t s;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
898
	int i, defer = 1;
899
	Backend *be;
900
901
902
903
904

	Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );