syncrepl.c 51 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
30

#include "portable.h"

#include <stdio.h>

#include <ac/string.h>
#include <ac/socket.h>

#include "ldap_pvt.h"
#include "lutil.h"
#include "slap.h"
#include "lutil_ldap.h"

31
32
#include "ldap_rq.h"

33
34
35
36
37
#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);
38

39
static int syncuuid_cmp( const void *, const void * );
40
static void avl_ber_bvfree( void * );
41
static void syncrepl_del_nonpresent( Operation *, syncinfo_t * );
42

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

48
static AttributeDescription *sync_descs[4];
49

50
51
struct runqueue_s syncrepl_rq;

52
void
53
init_syncrepl(syncinfo_t *si)
54
{
55
56
57
58
59
60
61
62
63
64
	int i, j, k, n;
	char **tmp;

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

65
	for ( n = 0; si->si_attrs[ n ] != NULL; n++ ) /* empty */;
66
67
68
69

	if ( n ) {
		/* Delete Attributes */
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
70
71
72
73
74
75
76
			for ( j = 0; si->si_attrs[j] != NULL; j++ ) {
				if ( strcmp( si->si_attrs[j], sync_descs[i]->ad_cname.bv_val )
					== 0 )
				{
					ch_free( si->si_attrs[j] );
					for ( k = j; si->si_attrs[k] != NULL; k++ ) {
						si->si_attrs[k] = si->si_attrs[k+1];
77
78
79
80
					}
				}
			}
		}
81
82
		for ( n = 0; si->si_attrs[ n ] != NULL; n++ ) /* empty */;
		tmp = ( char ** ) ch_realloc( si->si_attrs, (n + 4)*sizeof( char * ));
83
84
85
		if ( tmp == NULL ) {
			Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
86

87
88
89
90
91
92
		/* Add Attributes */
		for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
			tmp[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
			tmp[ n ] = NULL;
		}

93
	} else {
94
		tmp = ( char ** ) ch_realloc( si->si_attrs, 3 * sizeof( char * ));
95
96
97
98
		if ( tmp == NULL ) {
			Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
		}
		tmp[ n++ ] = ch_strdup( "*" );
99
100
		tmp[ n++ ] = ch_strdup( "+" );
		tmp[ n ] = NULL;
101
102
	}
	
103
	si->si_attrs = tmp;
104

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
	for ( n = 0; si->si_exattrs[ n ] != NULL; n++ ) /* empty */;
	if ( n ) {
		/* Delete Attributes from exattrs list */
		for ( i = 0; sync_descs[i] != NULL; i++ ) {
			for ( j = 0; si->si_exattrs[j] != NULL; j++ ) {
				if ( strcmp( si->si_exattrs[j], sync_descs[i]->ad_cname.bv_val )
					== 0 )
				{
					ch_free( si->si_exattrs[j] );
					for ( k = j; si->si_exattrs[k] != NULL; k++ ) {
						si->si_exattrs[k] = si->si_exattrs[k+1];
					}
				}
			}
		}
	}
121
122
}

123
static int
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
124
125
ldap_sync_search(
	syncinfo_t *si,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
126
	void *ctx )
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
127
{
128
129
130
	BerElementBuffer berbuf;
	BerElement *ber = (BerElement *)&berbuf;
	LDAPControl c[2], *ctrls[3];
131
	struct timeval timeout;
132
	ber_int_t	msgid;
133
	int rc;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
134

135
136
137
	/* 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
138

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
139
	if ( si->si_syncCookie.octet_str &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
140
141
142
143
144
		si->si_syncCookie.octet_str[0].bv_val )
	{
		ber_printf( ber, "{eO}",
			abs(si->si_type),
			&si->si_syncCookie.octet_str[0] );
145
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
146
147
		ber_printf( ber, "{e}",
			abs(si->si_type) );
148
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
149

150
151
152
153
	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
154

155
	c[0].ldctl_oid = LDAP_CONTROL_SYNC;
156
	c[0].ldctl_iscritical = si->si_type < 0;
157
	ctrls[0] = &c[0];
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
158

159
	if ( si->si_authzId ) {
160
		c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
161
		ber_str2bv( si->si_authzId, 0, 0, &c[1].ldctl_value );
162
163
164
165
166
167
		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
168

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
169
	timeout.tv_sec = si->si_tlimit;
170
	timeout.tv_usec = 0;
171

172
	rc = ldap_search_ext( si->si_ld, si->si_base.bv_val, si->si_scope,
173
		si->si_filterstr.bv_val, si->si_attrs, si->si_attrsonly,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
174
		ctrls, NULL, si->si_tlimit > 0 ? &timeout : NULL,
175
		si->si_slimit, &msgid );
176
	ber_free_buf( ber );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
177
178
179
	return rc;
}

180
181
182
183
static int
do_syncrep1(
	Operation *op,
	syncinfo_t *si )
184
185
{
	int	rc;
186
	int cmdline_cookie_found = 0;
187

188
	char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
Howard Chu's avatar
Howard Chu committed
189
	struct berval syncrepl_cn_bv;
190
	struct sync_cookie	*sc = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
191
	struct sync_cookie	syncCookie = { NULL, -1, NULL };
192
	struct berval	*psub;
193
194
195
#ifdef HAVE_TLS
	void	*ssl;
#endif
196
197

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

	/* Init connection to master */
200
	rc = ldap_initialize( &si->si_ld, si->si_provideruri );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
201
	if ( rc != LDAP_SUCCESS ) {
202
		Debug( LDAP_DEBUG_ANY,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
203
			"do_syncrep1: ldap_initialize failed (%s)\n",
204
			si->si_provideruri, 0, 0 );
205
		return rc;
206
207
	}

208
209
	op->o_protocol = LDAP_VERSION3;
	ldap_set_option( si->si_ld, LDAP_OPT_PROTOCOL_VERSION, &op->o_protocol );
210
211
212

	/* Bind to master */

213
	if ( si->si_tls ) {
214
		rc = ldap_start_tls_s( si->si_ld, NULL, NULL );
215
216
217
		if( rc != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_ANY,
				"%s: ldap_start_tls failed (%d)\n",
218
				si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning",
219
				rc, 0 );
220
			if( si->si_tls == SYNCINFO_TLS_CRITICAL ) goto done;
221
222
223
		}
	}

224
	if ( si->si_bindmethod == LDAP_AUTH_SASL ) {
225
226
227
#ifdef HAVE_CYRUS_SASL
		void *defaults;

228
		if ( si->si_secprops != NULL ) {
229
			rc = ldap_set_option( si->si_ld,
230
				LDAP_OPT_X_SASL_SECPROPS, si->si_secprops);
231

232
			if( rc != LDAP_OPT_SUCCESS ) {
233
234
				Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
					"(%s,SECPROPS,\"%s\") failed!\n",
235
					si->si_provideruri, si->si_secprops, 0 );
236
				goto done;
237
238
239
			}
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
240
241
		defaults = lutil_sasl_defaults( si->si_ld, si->si_saslmech,
			si->si_realm, si->si_authcId, si->si_passwd, si->si_authzId );
242

243
		rc = ldap_sasl_interactive_bind_s( si->si_ld,
244
245
				si->si_binddn,
				si->si_saslmech,
246
				NULL, NULL,
247
				LDAP_SASL_QUIET,
248
249
250
				lutil_sasl_interact,
				defaults );

251
252
		lutil_sasl_freedefs( defaults );

253
		/* FIXME: different error behaviors according to
254
255
256
		 *	1) return code
		 *	2) on err policy : exit, retry, backoff ...
		 */
257
		if ( rc != LDAP_SUCCESS ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
258
			Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
259
260
				"ldap_sasl_interactive_bind_s failed (%d)\n",
				rc, 0, 0 );
261
262
263
264
265
266
267
268
269

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

270
			goto done;
271
272
		}
#else /* HAVE_CYRUS_SASL */
273
		/* Should never get here, we trapped this at config time */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
274
		assert(0);
275
		fprintf( stderr, "not compiled with SASL support\n" );
276
277
		rc = LDAP_OTHER;
		goto done;
278
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
279

280
	} else {
281
282
		rc = ldap_bind_s( si->si_ld,
			si->si_binddn, si->si_passwd, si->si_bindmethod );
283
		if ( rc != LDAP_SUCCESS ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
284
			Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
285
				"ldap_bind_s failed (%d)\n", rc, 0, 0 );
286
			goto done;
287
288
289
		}
	}

290
291
292
	/* Set SSF to strongest of TLS, SASL SSFs */
	op->o_sasl_ssf = 0;
	op->o_tls_ssf = 0;
293
	op->o_transport_ssf = 0;
294
#ifdef HAVE_TLS
295
296
297
	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
		== LDAP_SUCCESS && ssl != NULL )
	{
298
299
300
301
		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 );
302
303
	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
		?  op->o_sasl_ssf : op->o_tls_ssf;
304

305
	/* get syncrepl cookie of shadow replica from subentry */
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
306
	assert( si->si_rid < 1000 );
Howard Chu's avatar
Howard Chu committed
307
308
	syncrepl_cn_bv.bv_val = syncrepl_cbuf;
	syncrepl_cn_bv.bv_len = snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf),
309
		CN_STR "syncrepl%ld", si->si_rid );
310
	build_new_dn( &op->o_req_ndn, psub, &syncrepl_cn_bv, op->o_tmpmemctx );
311
	op->o_req_dn = op->o_req_ndn;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
312

313
	LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
314
		if ( si->si_rid == sc->rid ) {
315
316
317
318
			cmdline_cookie_found = 1;
			break;
		}
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
319

320
321
	if ( cmdline_cookie_found ) {
		/* cookie is supplied in the command line */
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
322
323
		BerVarray cookie = NULL;
		struct berval cookie_bv;
324

325
		LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
326
327
328
		slap_sync_cookie_free( &si->si_syncCookie, 0 );

		/* read stored cookie if it exists */
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
329
		backend_attribute( op, NULL, &op->o_req_ndn,
330
			slap_schema.si_ad_syncreplCookie, &cookie, ACL_READ );
331
332
333

		if ( !cookie ) {
			/* no stored cookie */
334
335
336
337
338
			if ( sc->ctxcsn == NULL ||
				 sc->ctxcsn->bv_val == NULL ) {
				/* if cmdline cookie does not have ctxcsn */
				/* component, set it to an initial value */
				slap_init_sync_cookie_ctxcsn( sc );
339
			}
340
341
342
			slap_dup_sync_cookie( &si->si_syncCookie, sc );
			slap_sync_cookie_free( sc, 1 );
			sc = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
343

344
345
		} else {
			/* stored cookie */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
346
			struct berval newcookie = BER_BVNULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
347
348
349
			ber_dupbv( &cookie_bv, &cookie[0] );
			ber_bvarray_add( &si->si_syncCookie.octet_str, &cookie_bv );
			slap_parse_sync_cookie( &si->si_syncCookie );
350
351
			ber_bvarray_free( si->si_syncCookie.octet_str );
			si->si_syncCookie.octet_str = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
352
			ber_bvarray_free_x( cookie, op->o_tmpmemctx );
353
			if ( sc->sid != -1 ) {
354
				/* command line cookie wins */
355
				si->si_syncCookie.sid = sc->sid;
356
			}
357
			if ( sc->ctxcsn != NULL ) {
358
359
360
361
362
				/* command line cookie wins */
				if ( si->si_syncCookie.ctxcsn ) {
					ber_bvarray_free( si->si_syncCookie.ctxcsn );
					si->si_syncCookie.ctxcsn = NULL;
				}
363
				ber_dupbv( &cookie_bv, &sc->ctxcsn[0] );
364
365
				ber_bvarray_add( &si->si_syncCookie.ctxcsn, &cookie_bv );
			}
366
367
368
369
370
371
			if ( sc->rid != -1 ) {
				/* command line cookie wins */
				si->si_syncCookie.rid = sc->rid;
			}
			slap_sync_cookie_free( sc, 1 );
			sc = NULL;
372
373
374
375
			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 );
376
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
377

378
379
380
381
382
383
384
	} 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,
385
				slap_schema.si_ad_syncreplCookie, &cookie, ACL_READ );
386
387
388
389
390
391
			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
392
393
394
395
		}
	}

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

397
	if( rc != LDAP_SUCCESS ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
398
		Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
399
			"ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
400
401
402
403
404
405
406
407
408
409
	}

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
410
411
	slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
	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
435
	struct berval	syncUUID = BER_BVNULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
436
437
	struct sync_cookie	syncCookie = { NULL, -1, NULL };
	struct sync_cookie	syncCookie_req = { NULL, -1, NULL };
Kurt Zeilenga's avatar
Kurt Zeilenga committed
438
	struct berval		cookie = BER_BVNULL;
439

440
	int	rc, err, i;
441
442
	ber_len_t	len;

443
	int rc_efree = 1;
444
445
446
447
448
449
450
451
452
453

	struct berval	*psub;
	Modifications	*modlist = NULL;

	const char		*text;
	int				match;

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

454
455
	int		refreshDeletes = 0;
	int		refreshDone = 1;
456
	BerVarray syncUUIDs = NULL;
457
458
	ber_tag_t si_tag;

459
	if ( slapd_shutdown ) {
460
		rc = -2;
461
		goto done;
462
463
	}

464
465
466
	ber_init2( ber, NULL, LBER_USE_DER );
	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

467
468
469
470
	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
471
	slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
472

Kurt Zeilenga's avatar
Kurt Zeilenga committed
473
	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
474
475
476
477
478
		tout_p = &tout;
	} else {
		tout_p = NULL;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
479
480
	while (( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE,
		tout_p, &res )) > 0 )
481
	{
482
		if ( slapd_shutdown ) {
483
484
			rc = -2;
			goto done;
485
		}
486
		for( msg = ldap_first_message( si->si_ld, res );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
487
488
			msg != NULL;
			msg = ldap_next_message( si->si_ld, msg ) )
489
490
491
		{
			switch( ldap_msgtype( msg ) ) {
			case LDAP_RES_SEARCH_ENTRY:
492
				ldap_get_entry_controls( si->si_ld, msg, &rctrls );
Howard Chu's avatar
Howard Chu committed
493
494
495
496
497
498
499
				/* we can't work without the control */
				if ( !rctrls ) {
					rc = -1;
					goto done;
				}
				rctrlp = *rctrls;
				ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
				ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
501
				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
					ber_scanf( ber, /*"{"*/ "m}", &cookie );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
503
504
505
506
507
508
509
510
					if ( cookie.bv_val ) {
						struct berval tmp_bv;
						ber_dupbv( &tmp_bv, &cookie );
						ber_bvarray_add( &syncCookie.octet_str, &tmp_bv );
					}
					if ( syncCookie.octet_str &&
							syncCookie.octet_str[0].bv_val )
						slap_parse_sync_cookie( &syncCookie );
511
				}
512
513
514
				if ( syncrepl_message_to_entry( si, op, msg,
					&modlist, &entry, syncstate ) == LDAP_SUCCESS ) {
					rc_efree = syncrepl_entry( si, op, entry, modlist,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
515
						syncstate, &syncUUID, &syncCookie_req );
516
					if ( syncCookie.octet_str &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
518
						syncCookie.octet_str[0].bv_val )
					{
519
520
						syncrepl_updateCookie( si, op, psub, &syncCookie );
					}
521
				}
Howard Chu's avatar
Howard Chu committed
522
				ldap_controls_free( rctrls );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
523
524
525
				if ( modlist ) {
					slap_mods_free( modlist );
				}
526
				if ( rc_efree && entry ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
527
					entry_free( entry );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
528
				}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
529
				entry = NULL;
530
531
532
533
				break;

			case LDAP_RES_SEARCH_REFERENCE:
				Debug( LDAP_DEBUG_ANY,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
534
					"do_syncrep2 : reference received\n", 0, 0, 0 );
535
536
537
				break;

			case LDAP_RES_SEARCH_RESULT:
538
				ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
539
					&rctrls, 0 );
540
541
				if ( rctrls ) {
					rctrlp = *rctrls;
542
					ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
543

544
					ber_scanf( ber, "{" /*"}"*/);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
545
					if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
546
547
548
549
550
551
552
						ber_scanf( ber, "m", &cookie );
						if ( cookie.bv_val ) {
							struct berval tmp_bv;
							ber_dupbv( &tmp_bv, &cookie );
							ber_bvarray_add( &syncCookie.octet_str, &tmp_bv);
						}
						if ( syncCookie.octet_str &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
553
554
							syncCookie.octet_str[0].bv_val )
						{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
555
							slap_parse_sync_cookie( &syncCookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
						}
557
					}
558
559
560
561
					if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
					{
						ber_scanf( ber, "b", &refreshDeletes );
					}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
562
					ber_scanf( ber, /*"{"*/ "}" );
563
				}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
564
565
566
567
568
569
570
571
				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
572
573
						&syncCookie_req.ctxcsn[0], &syncCookie.ctxcsn[0],
						&text );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
574
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
575
576
577
				if ( syncCookie.octet_str && syncCookie.octet_str->bv_val &&
					match < 0 && err == LDAP_SUCCESS )
				{
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
578
					syncrepl_updateCookie( si, op, psub, &syncCookie );
579
580
581
582
583
				}
				if ( rctrls ) {
					ldap_controls_free( rctrls );
				}
				if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
584
					/* FIXME : different error behaviors according to
585
586
587
					 *	1) err code : LDAP_BUSY ...
					 *	2) on err policy : stop service, stop sync, retry
					 */
588
					if ( refreshDeletes == 0 && match < 0 &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
589
590
						err == LDAP_SUCCESS )
					{
591
						syncrepl_del_nonpresent( op, si );
592
593
594
					} else {
						avl_free( si->si_presentlist, avl_ber_bvfree );
						si->si_presentlist = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
595
					}
596
				}
597
598
				rc = -2;
				goto done;
599
600
				break;

601
			case LDAP_RES_INTERMEDIATE:
602
				rc = ldap_parse_intermediate( si->si_ld, msg,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
603
604
					&retoid, &retdata, NULL, 0 );
				if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
605
606
					int		si_refreshDelete = 0;
					int		si_refreshPresent = 0;
607
					ber_init2( ber, retdata, LBER_USE_DER );
608

609
610
611
612
613
614
615
616
617
					switch ( si_tag = ber_peek_tag( ber, &len )) {
					ber_tag_t tag;
					case LDAP_TAG_SYNC_NEW_COOKIE:
						ber_scanf( ber, "tm", &tag, &cookie );
						break;
					case LDAP_TAG_SYNC_REFRESH_DELETE:
						si_refreshDelete = 1;
					case LDAP_TAG_SYNC_REFRESH_PRESENT:
						si_refreshPresent = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
618
						ber_scanf( ber, "t{" /*"}"*/, &tag );
619
620
						if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
						{
621
622
623
624
							ber_scanf( ber, "m", &cookie );
							if ( cookie.bv_val ) {
								struct berval tmp_bv;
								ber_dupbv( &tmp_bv, &cookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
625
626
								ber_bvarray_add( &syncCookie.octet_str,
									&tmp_bv);
627
628
							}
							if ( syncCookie.octet_str &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
629
630
								syncCookie.octet_str[0].bv_val )
							{
631
								slap_parse_sync_cookie( &syncCookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
632
							}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
633
						}
634
						if ( ber_peek_tag( ber, &len ) ==
Kurt Zeilenga's avatar
Kurt Zeilenga committed
635
							LDAP_TAG_REFRESHDONE )
636
637
638
						{
							ber_scanf( ber, "b", &refreshDone );
						}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
639
						ber_scanf( ber, /*"{"*/ "}" );
640
641
						break;
					case LDAP_TAG_SYNC_ID_SET:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
642
						ber_scanf( ber, "t{" /*"}"*/, &tag );
643
						if ( ber_peek_tag( ber, &len ) ==
Kurt Zeilenga's avatar
Kurt Zeilenga committed
644
645
							LDAP_TAG_SYNC_COOKIE )
						{
646
647
648
649
							ber_scanf( ber, "m", &cookie );
							if ( cookie.bv_val ) {
								struct berval tmp_bv;
								ber_dupbv( &tmp_bv, &cookie );
650
								ber_bvarray_add( &syncCookie.octet_str,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
651
									&tmp_bv );
652
653
							}
							if ( syncCookie.octet_str &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
654
655
								syncCookie.octet_str[0].bv_val )
							{
656
								slap_parse_sync_cookie( &syncCookie );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
657
							}
658
659
						}
						if ( ber_peek_tag( ber, &len ) ==
Kurt Zeilenga's avatar
Kurt Zeilenga committed
660
							LDAP_TAG_REFRESHDELETES )
661
662
663
664
						{
							ber_scanf( ber, "b", &refreshDeletes );
						}
						ber_scanf( ber, "[W]", &syncUUIDs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
665
						ber_scanf( ber, /*"{"*/ "}" );
666
667
668
						for ( i = 0; syncUUIDs[i].bv_val; i++ ) {
							struct berval *syncuuid_bv;
							syncuuid_bv = ber_dupbv( NULL, &syncUUIDs[i] );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
669
							slap_sl_free( syncUUIDs[i].bv_val,op->o_tmpmemctx );
670
							avl_insert( &si->si_presentlist,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
671
672
								(caddr_t) syncuuid_bv,
								syncuuid_cmp, avl_dup_error );
673
						}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
674
						slap_sl_free( syncUUIDs, op->o_tmpmemctx );
675
676
677
						break;
					default:
					Debug( LDAP_DEBUG_ANY,
678
679
						"do_syncrep2 : unknown syncinfo tag (%ld)\n",
						(long) si_tag, 0, 0 );
680
681
682
						ldap_memfree( retoid );
						ber_bvfree( retdata );
						continue;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
683
684
					}

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
685
686
687
688
689
690
691
692
693
694
695
					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
696

Kurt Zeilenga's avatar
Kurt Zeilenga committed
697
698
699
					if ( syncCookie.ctxcsn && syncCookie.ctxcsn[0].bv_val &&
						match < 0 )
					{
700
						syncrepl_updateCookie( si, op, psub, &syncCookie);
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
701
702
					}

703
					if ( si_refreshPresent == 1 ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
704
						if ( match < 0 ) {
705
							syncrepl_del_nonpresent( op, si );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
706
						}
707
					} 
708
709
710
711

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

713
				} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
714
					Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
Kurt Zeilenga's avatar
Kurt Zeilenga committed
715
716
						"unknown intermediate response (%d)\n",
						rc, 0, 0 );
717
718
719
720
721
					ldap_memfree( retoid );
					ber_bvfree( retdata );
					break;
				}
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
722

723
			default:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
724
				Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
725
726
727
728
					"unknown message\n", 0, 0, 0 );
				break;

			}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
729
730
731
732
733
			if ( syncCookie.octet_str ) {
				slap_sync_cookie_free( &syncCookie_req, 0 );
				slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
				slap_sync_cookie_free( &syncCookie, 0 );
			}
734
735
		}
		ldap_msgfree( res );
736
		res = NULL;
737
738
739
	}

	if ( rc == -1 ) {
740
741
		const char *errstr;

Howard Chu's avatar
Howard Chu committed
742
743
		ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
		errstr = ldap_err2string( rc );
744
		
745
		Debug( LDAP_DEBUG_ANY,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
746
			"do_syncrep2 : %s\n", errstr, 0, 0 );
747
748
749
	}

done:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
750
751
752
	slap_sync_cookie_free( &syncCookie, 0 );
	slap_sync_cookie_free( &syncCookie_req, 0 );

753
	if ( res ) ldap_msgfree( res );
754

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
	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};
	Operation op = {0};
	int rc = LDAP_SUCCESS;
	int first = 0;
Howard Chu's avatar
Howard Chu committed
774
775
	int dostop = 0;
	ber_socket_t s;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
776
	int i, defer = 1;
777
	Backend *be;
778
779
780
781
782

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

	if ( si == NULL )
		return NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
783

784
785
786
787
788
789
	switch( abs( si->si_type )) {
	case LDAP_SYNC_REFRESH_ONLY:
	case LDAP_SYNC_REFRESH_AND_PERSIST:
		break;
	default:
		return NULL;
790
	}
791

792
	if ( slapd_shutdown && si->si_ld ) {
Howard Chu's avatar
Howard Chu committed
793
794
795
796
797
798
799
		ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
		connection_client_stop( s );
		ldap_unbind( si->si_ld );
		si->si_ld = NULL;
		return NULL;
	}

Howard Chu's avatar
Howard Chu committed
800
	connection_fake_init( &conn, &op, ctx );
801

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
802
803
804
805
	/* use global malloc for now */
	op.o_tmpmemctx = NULL;
	op.o_tmpmfuncs = &ch_mfuncs;

806
807
808
	op.o_dn = si->si_updatedn;
	op.o_ndn = si->si_updatedn;
	op.o_managedsait = 1;
809
	op.o_bd = be = si->si_be;
810

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
811
812
813
814
815
816
817
	op.o_sync_state.ctxcsn = NULL;
	op.o_sync_state.sid = -1;
	op.o_sync_state.octet_str = NULL;
	op.o_sync_slog_size = -1;
	LDAP_STAILQ_FIRST( &op.o_sync_slog_list ) = NULL;
	op.o_sync_slog_list.stqh_last = &LDAP_STAILQ_FIRST(&op.o_sync_slog_list);

818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
	/* Establish session, do search */
	if ( !si->si_ld ) {
		first = 1;
		rc = do_syncrep1( &op, si );
	}

	/* Process results */
	if ( rc == LDAP_SUCCESS ) {
		ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );

		rc = do_syncrep2( &op, si );

		if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
			/* If we succeeded, enable the connection for further listening.
			 * If we failed, tear down the connection and reschedule.
			 */
			if ( rc == LDAP_SUCCESS ) {
				if ( first ) {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
836
					rc = connection_client_setup( s, do_syncrepl, arg );
837
838
				} else {
					connection_client_enable( s );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
839
				} 
Howard Chu's avatar
Howard Chu committed
840
			} else if ( !first ) {
Howard Chu's avatar
Howard Chu committed
841
				dostop = 1;
842
843
			}
		} else {
Howard Chu's avatar
Howard Chu committed
844
			if ( rc == -2 ) rc = 0;
845
846
847
		}
	}

848
849
850
851
852
853
854
	/* At this point, we have 4 cases:
	 * 1) for any hard failure, give up and remove this task
	 * 2) for ServerDown, reschedule this task to run
	 * 3) for Refresh and Success, reschedule to run
	 * 4) for Persist and Success, reschedule to defer
	 */
	ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
855

856
	if ( ldap_pvt_runqueue_isrunning( &syncrepl_rq, rtask )) {
857
858
		ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
859

860
861
862
863
	if ( dostop ) {
		connection_client_stop( s );
	}

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
864
865
866
867
868
869
870
871
872
873
874
875
	if ( rc == LDAP_SUCCESS ) {
		if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
			defer = 0;
		}
		rtask->interval.tv_sec = si->si_interval;
		ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, defer );
		if ( si->si_retrynum ) {
			for ( i = 0; si->si_retrynum_init[i] != -2; i++ ) {
				si->si_retrynum[i] = si->si_retrynum_init[i];
			}
			si->si_retrynum[i] = -2;
		}
876
	} else {
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
877
878
879
880
881
882
883
		for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
			if ( si->si_retrynum[i] == -1  || si->si_retrynum[i] == -2 )
				break;
		}

		if ( !si->si_retrynum || si->si_retrynum[i] == -2 ) {
			ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
884
885
			LDAP_STAILQ_REMOVE( &be->be_syncinfo, si, syncinfo_s, si_next );
			syncinfo_free( si );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
886
887
888
889
890
		} else if ( si->si_retrynum[i] >= -1 ) {
			if ( si->si_retrynum[i] > 0 )
				si->si_retrynum[i]--;
			rtask->interval.tv_sec = si->si_retryinterval[i];
			ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, 0 );
891
			slap_wake_listener();
Howard Chu's avatar
Howard Chu committed
892
		}
893
	}
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
894
	
895
896
	ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );

897
898
899
	return NULL;
}

900
int
901
syncrepl_message_to_entry(
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
902
	syncinfo_t	*si,
903
	Operation	*op,
904
	LDAPMessage	*msg,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
905
	Modifications	**modlist,
906
	Entry			**entry,
907
	int		syncstate
908
909
)
{
910
	Entry		*e = NULL;
911
912
913
	BerElement	*ber = NULL;
	Modifications	tmp;
	Modifications	*mod;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
914
	Modifications	**modtail = modlist;
915
916
917
918
919

	const char	*text;
	char txtbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof txtbuf;

920
	struct berval	bdn = {0, NULL}, dn, ndn;
921
922
	int		rc;

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
923
	*modlist = NULL;
924

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
925
	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
926
		Debug( LDAP_DEBUG_ANY,
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
927
			"Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
928
		return -1;
929
930
	}

931
	op->o_tag = LDAP_REQ_ADD;
932

933
	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
934
935
936
937

	if ( rc != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_ANY,
			"syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
938
		return rc;
939
940
	}

941
942
943
	dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
	ber_dupbv( &op->o_req_dn, &dn );
	ber_dupbv( &op->o_req_ndn, &ndn );
944
945