xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/syncrepl.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: syncrepl.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
2 
3 /* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2003-2021 The OpenLDAP Foundation.
8  * Portions Copyright 2003 by IBM Corporation.
9  * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 
21 #include <sys/cdefs.h>
22 __RCSID("$NetBSD: syncrepl.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
23 
24 #include "portable.h"
25 
26 #include <stdio.h>
27 
28 #include <ac/string.h>
29 #include <ac/socket.h>
30 
31 #include "lutil.h"
32 #include "slap.h"
33 #include "lutil_ldap.h"
34 
35 #include "slap-config.h"
36 
37 #include "ldap_rq.h"
38 
39 #include "rewrite.h"
40 
41 #include "back-monitor/back-monitor.h"
42 
43 #define SUFFIXM_CTX	"<suffix massage>"
44 
45 #ifdef LDAP_CONTROL_X_DIRSYNC
46 #define MSAD_DIRSYNC	0x04
47 #define MSAD_DIRSYNC_MODIFY	0x10
48 
49 static AttributeDescription *sy_ad_objectGUID;
50 static AttributeDescription *sy_ad_instanceType;
51 static AttributeDescription *sy_ad_isDeleted;
52 static AttributeDescription *sy_ad_whenCreated;
53 static AttributeDescription *sy_ad_dirSyncCookie;
54 
55 static struct berval msad_addval = BER_BVC("range=1-1");
56 static struct berval msad_delval = BER_BVC("range=0-0");
57 #endif
58 
59 static AttributeDescription *sy_ad_nsUniqueId;
60 static AttributeDescription *sy_ad_dseeLastChange;
61 
62 #define DSEE_SYNC_ADD	0x20
63 
64 #define	UUIDLEN	16
65 
66 struct nonpresent_entry {
67 	struct berval *npe_name;
68 	struct berval *npe_nname;
69 	LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
70 };
71 
72 typedef struct cookie_vals {
73 	struct berval *cv_vals;
74 	int *cv_sids;
75 	int cv_num;
76 } cookie_vals;
77 
78 typedef struct cookie_state {
79 	ldap_pvt_thread_mutex_t	cs_mutex;
80 	ldap_pvt_thread_cond_t cs_cond;
81 	struct berval *cs_vals;
82 	int *cs_sids;
83 	int	cs_num;
84 	int cs_age;
85 	int cs_ref;
86 	int cs_updating;
87 
88 	/* pending changes, not yet committed */
89 	ldap_pvt_thread_mutex_t	cs_pmutex;
90 	struct berval *cs_pvals;
91 	int *cs_psids;
92 	int	cs_pnum;
93 } cookie_state;
94 
95 #define	SYNCDATA_DEFAULT	0	/* entries are plain LDAP entries */
96 #define	SYNCDATA_ACCESSLOG	1	/* entries are accesslog format */
97 #define	SYNCDATA_CHANGELOG	2	/* entries are changelog format */
98 
99 #define	SYNCLOG_LOGGING		0	/* doing a log-based update */
100 #define	SYNCLOG_FALLBACK	1	/* doing a full refresh */
101 
102 #define RETRYNUM_FOREVER	(-1)	/* retry forever */
103 #define RETRYNUM_TAIL		(-2)	/* end of retrynum array */
104 #define RETRYNUM_VALID(n)	((n) >= RETRYNUM_FOREVER)	/* valid retrynum */
105 #define RETRYNUM_FINITE(n)	((n) > RETRYNUM_FOREVER)	/* not forever */
106 
107 typedef struct syncinfo_s {
108 	struct syncinfo_s	*si_next;
109 	BackendDB		*si_be;
110 	BackendDB		*si_wbe;
111 	struct re_s		*si_re;
112 	int			si_rid;
113 	char			si_ridtxt[ STRLENOF("rid=999") + 1 ];
114 	slap_bindconf		si_bindconf;
115 	struct berval		si_base;
116 	struct berval		si_logbase;
117 	struct berval		si_filterstr;
118 	struct berval		si_logfilterstr;
119 	Filter			*si_filter;
120 	Filter			*si_logfilter;
121 	struct berval		si_contextdn;
122 	int			si_scope;
123 	int			si_attrsonly;
124 	char			*si_anfile;
125 	AttributeName		*si_anlist;
126 	AttributeName		*si_exanlist;
127 	char 			**si_attrs;
128 	char			**si_exattrs;
129 	int			si_allattrs;
130 	int			si_allopattrs;
131 	int			si_schemachecking;
132 	int			si_type;	/* the active type */
133 	int			si_ctype;	/* the configured type */
134 	time_t			si_interval;
135 	time_t			*si_retryinterval;
136 	int			*si_retrynum_init;
137 	int			*si_retrynum;
138 	struct sync_cookie	si_syncCookie;
139 	cookie_state		*si_cookieState;
140 	int			si_cookieAge;
141 	int			si_manageDSAit;
142 	int			si_slimit;
143 	int			si_tlimit;
144 	int			si_refreshDelete;
145 	int			si_refreshPresent;
146 	int			si_refreshDone;
147 	int			si_syncdata;
148 	int			si_logstate;
149 	int			si_lazyCommit;
150 	int			si_got;
151 	int			si_strict_refresh;	/* stop listening during fallback refresh */
152 	int			si_too_old;
153 	int			si_is_configdb;
154 	ber_int_t	si_msgid;
155 	Avlnode			*si_presentlist;
156 	LDAP			*si_ld;
157 	Connection		*si_conn;
158 	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
159 	struct rewrite_info *si_rewrite;
160 	struct berval	si_suffixm;
161 #ifdef LDAP_CONTROL_X_DIRSYNC
162 	struct berval		si_dirSyncCookie;
163 #endif
164 	unsigned long	si_prevchange;
165 	unsigned long	si_lastchange;
166 
167 	/* monitor info */
168 	int		si_monitorInited;
169 	time_t	si_lastconnect;
170 	time_t	si_lastcontact;
171 	struct berval	si_connaddr;
172 	struct berval	si_lastCookieRcvd;
173 	struct berval	si_lastCookieSent;
174 	struct berval	si_monitor_ndn;
175 	char	si_connaddrbuf[LDAP_IPADDRLEN];
176 
177 	ldap_pvt_thread_mutex_t	si_monitor_mutex;
178 	ldap_pvt_thread_mutex_t	si_mutex;
179 } syncinfo_t;
180 
181 static int syncuuid_cmp( const void *, const void * );
182 static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
183 static void presentlist_delete( Avlnode **av, struct berval *syncUUID );
184 static char *presentlist_find( Avlnode *av, struct berval *syncUUID );
185 static int presentlist_free( Avlnode *av );
186 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
187 static int syncrepl_message_to_op(
188 					syncinfo_t *, Operation *, LDAPMessage *, int );
189 static int syncrepl_message_to_entry(
190 					syncinfo_t *, Operation *, LDAPMessage *,
191 					Modifications **, Entry **, int, struct berval* );
192 static int syncrepl_entry(
193 					syncinfo_t *, Operation*, Entry*,
194 					Modifications**,int, struct berval*,
195 					struct berval *cookieCSN );
196 static int syncrepl_updateCookie(
197 					syncinfo_t *, Operation *,
198 					struct sync_cookie *, int save );
199 static struct berval * slap_uuidstr_from_normalized(
200 					struct berval *, struct berval *, void * );
201 static int syncrepl_add_glue_ancestors(
202 	Operation* op, Entry *e );
203 
204 #ifdef LDAP_CONTROL_X_DIRSYNC
205 static int syncrepl_dirsync_message(
206 					syncinfo_t *, Operation *, LDAPMessage *,
207 					Modifications **, Entry **, int *, struct berval* );
208 static int syncrepl_dirsync_cookie(
209 					syncinfo_t *, Operation *, LDAPControl ** );
210 #endif
211 
212 static int syncrepl_dsee_update( syncinfo_t *si, Operation *op ) ;
213 
214 /* delta-mpr overlay handler */
215 static int syncrepl_op_modify( Operation *op, SlapReply *rs );
216 
217 /* callback functions */
218 static int dn_callback( Operation *, SlapReply * );
219 static int nonpresent_callback( Operation *, SlapReply * );
220 
221 static AttributeDescription *sync_descs[4];
222 
223 static AttributeDescription *dsee_descs[7];
224 
225 /* delta-mpr */
226 static AttributeDescription *ad_reqMod, *ad_reqDN;
227 
228 typedef struct logschema {
229 	struct berval ls_dn;
230 	struct berval ls_req;
231 	struct berval ls_mod;
232 	struct berval ls_newRdn;
233 	struct berval ls_delRdn;
234 	struct berval ls_newSup;
235 	struct berval ls_controls;
236 	struct berval ls_uuid;
237 	struct berval ls_changenum;
238 } logschema;
239 
240 static logschema changelog_sc = {
241 	BER_BVC("targetDN"),
242 	BER_BVC("changeType"),
243 	BER_BVC("changes"),
244 	BER_BVC("newRDN"),
245 	BER_BVC("deleteOldRDN"),
246 	BER_BVC("newSuperior"),
247 	BER_BVNULL,
248 	BER_BVC("targetUniqueId"),
249 	BER_BVC("changeNumber")
250 };
251 
252 static logschema accesslog_sc = {
253 	BER_BVC("reqDN"),
254 	BER_BVC("reqType"),
255 	BER_BVC("reqMod"),
256 	BER_BVC("reqNewRDN"),
257 	BER_BVC("reqDeleteOldRDN"),
258 	BER_BVC("reqNewSuperior"),
259 	BER_BVC("reqControls")
260 };
261 
262 static const char *
syncrepl_state2str(int state)263 syncrepl_state2str( int state )
264 {
265 	switch ( state ) {
266 	case LDAP_SYNC_PRESENT:
267 		return "PRESENT";
268 
269 	case LDAP_SYNC_ADD:
270 		return "ADD";
271 
272 	case LDAP_SYNC_MODIFY:
273 		return "MODIFY";
274 
275 	case LDAP_SYNC_DELETE:
276 		return "DELETE";
277 #ifdef LDAP_CONTROL_X_DIRSYNC
278 	case MSAD_DIRSYNC_MODIFY:
279 		return "DIRSYNC_MOD";
280 #endif
281 	case DSEE_SYNC_ADD:
282 		return "DSEE_ADD";
283 	}
284 
285 	return "UNKNOWN";
286 }
287 
288 static slap_overinst syncrepl_ov;
289 
290 static void
init_syncrepl(syncinfo_t * si)291 init_syncrepl(syncinfo_t *si)
292 {
293 	int i, j, k, l, n;
294 	char **attrs, **exattrs;
295 
296 	if ( !syncrepl_ov.on_bi.bi_type ) {
297 		syncrepl_ov.on_bi.bi_type = "syncrepl";
298 		syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify;
299 		overlay_register( &syncrepl_ov );
300 	}
301 
302 	/* delta-MPR needs the overlay, nothing else does.
303 	 * This must happen before accesslog overlay is configured.
304 	 */
305 	if ( si->si_syncdata &&
306 		!overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
307 		overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
308 		if ( !ad_reqMod ) {
309 			const char *text;
310 			logschema *ls = &accesslog_sc;
311 
312 			slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
313 			slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
314 		}
315 	}
316 
317 	if ( !sync_descs[0] ) {
318 		sync_descs[0] = slap_schema.si_ad_objectClass;
319 		sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
320 		sync_descs[2] = slap_schema.si_ad_entryCSN;
321 		sync_descs[3] = NULL;
322 	}
323 
324 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
325 		/* DSEE doesn't support allopattrs */
326 		si->si_allopattrs = 0;
327 		if ( !dsee_descs[0] ) {
328 			dsee_descs[0] = slap_schema.si_ad_objectClass;
329 			dsee_descs[1] = slap_schema.si_ad_creatorsName;
330 			dsee_descs[2] = slap_schema.si_ad_createTimestamp;
331 			dsee_descs[3] = slap_schema.si_ad_modifiersName;
332 			dsee_descs[4] = slap_schema.si_ad_modifyTimestamp;
333 			dsee_descs[5] = sy_ad_nsUniqueId;
334 			dsee_descs[6] = NULL;
335 		}
336 	}
337 
338 	if ( si->si_allattrs && si->si_allopattrs )
339 		attrs = NULL;
340 	else
341 		attrs = anlist2attrs( si->si_anlist );
342 
343 	if ( attrs ) {
344 		if ( si->si_allattrs ) {
345 			i = 0;
346 			while ( attrs[i] ) {
347 				if ( !is_at_operational( at_find( attrs[i] ) ) ) {
348 					for ( j = i; attrs[j] != NULL; j++ ) {
349 						if ( j == i )
350 							ch_free( attrs[i] );
351 						attrs[j] = attrs[j+1];
352 					}
353 				} else {
354 					i++;
355 				}
356 			}
357 			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
358 			attrs[i] = ch_strdup("*");
359 			attrs[i + 1] = NULL;
360 
361 		} else if ( si->si_allopattrs ) {
362 			i = 0;
363 			while ( attrs[i] ) {
364 				if ( is_at_operational( at_find( attrs[i] ) ) ) {
365 					for ( j = i; attrs[j] != NULL; j++ ) {
366 						if ( j == i )
367 							ch_free( attrs[i] );
368 						attrs[j] = attrs[j+1];
369 					}
370 				} else {
371 					i++;
372 				}
373 			}
374 			attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
375 			attrs[i] = ch_strdup("+");
376 			attrs[i + 1] = NULL;
377 		}
378 
379 		for ( i = 0; sync_descs[i] != NULL; i++ ) {
380 			j = 0;
381 			while ( attrs[j] ) {
382 				if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
383 					for ( k = j; attrs[k] != NULL; k++ ) {
384 						if ( k == j )
385 							ch_free( attrs[k] );
386 						attrs[k] = attrs[k+1];
387 					}
388 				} else {
389 					j++;
390 				}
391 			}
392 		}
393 
394 		for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
395 
396 		if ( si->si_allopattrs ) {
397 			attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
398 		} else {
399 			attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
400 		}
401 
402 		/* Add Attributes */
403 		if ( si->si_allopattrs ) {
404 			attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
405 		} else {
406 			if ( si->si_syncdata != SYNCDATA_CHANGELOG ) {
407 				for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
408 					attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
409 				}
410 			}
411 		}
412 		attrs[ n ] = NULL;
413 
414 	} else {
415 
416 		i = 0;
417 		if ( si->si_allattrs == si->si_allopattrs ) {
418 			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
419 			attrs[i++] = ch_strdup( "*" );
420 			attrs[i++] = ch_strdup( "+" );
421 			si->si_allattrs = si->si_allopattrs = 1;
422 		} else if ( si->si_allattrs && !si->si_allopattrs ) {
423 			for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
424 			attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
425 			attrs[i++] = ch_strdup( "*" );
426 			for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
427 				attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
428 			}
429 		} else if ( !si->si_allattrs && si->si_allopattrs ) {
430 			attrs = (char**) ch_malloc( 3 * sizeof(char*) );
431 			attrs[i++] = ch_strdup( "+" );
432 			attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
433 		}
434 		attrs[i] = NULL;
435 	}
436 
437 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
438 		for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
439 		attrs = ( char ** ) ch_realloc( attrs, (n + 6)*sizeof( char * ) );
440 		for ( i = 0; dsee_descs[ i ] != NULL; i++ ) {
441 			attrs[ n++ ] = ch_strdup ( dsee_descs[i]->ad_cname.bv_val );
442 		}
443 		attrs[n] = NULL;
444 	}
445 
446 	si->si_attrs = attrs;
447 
448 	exattrs = anlist2attrs( si->si_exanlist );
449 
450 	if ( exattrs ) {
451 		for ( n = 0; exattrs[n] != NULL; n++ ) ;
452 
453 		for ( i = 0; sync_descs[i] != NULL; i++ ) {
454 			j = 0;
455 			while ( exattrs[j] != NULL ) {
456 				if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
457 					ch_free( exattrs[j] );
458 					for ( k = j; exattrs[k] != NULL; k++ ) {
459 						exattrs[k] = exattrs[k+1];
460 					}
461 				} else {
462 					j++;
463 				}
464 			}
465 		}
466 
467 		for ( i = 0; exattrs[i] != NULL; i++ ) {
468 			for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
469 				ObjectClass	*oc;
470 				if ( ( oc = si->si_anlist[j].an_oc ) ) {
471 					k = 0;
472 					while ( oc->soc_required[k] ) {
473 						if ( !strcmp( exattrs[i],
474 							 oc->soc_required[k]->sat_cname.bv_val ) ) {
475 							ch_free( exattrs[i] );
476 							for ( l = i; exattrs[l]; l++ ) {
477 								exattrs[l] = exattrs[l+1];
478 							}
479 						} else {
480 							k++;
481 						}
482 					}
483 				}
484 			}
485 		}
486 
487 		for ( i = 0; exattrs[i] != NULL; i++ ) ;
488 
489 		if ( i != n )
490 			exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
491 	}
492 
493 	si->si_exattrs = exattrs;
494 }
495 
496 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
497 
498 static int
ldap_sync_search(syncinfo_t * si,void * ctx)499 ldap_sync_search(
500 	syncinfo_t *si,
501 	void *ctx )
502 {
503 	BerElementBuffer berbuf;
504 	BerElement *ber = (BerElement *)&berbuf;
505 	LDAPControl c[3], *ctrls[4];
506 	int rc;
507 	int rhint;
508 	char *base;
509 	char **attrs, *lattrs[9];
510 	char *filter;
511 	int attrsonly;
512 	int scope;
513 	char filterbuf[sizeof("(changeNumber>=18446744073709551615)")];
514 
515 	/* setup LDAP SYNC control */
516 	ber_init2( ber, NULL, LBER_USE_DER );
517 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
518 
519 	/* If we're using a log but we have no state, then fallback to
520 	 * normal mode for a full refresh.
521 	 */
522 	if ( si->si_syncdata ) {
523 		if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
524 			LDAPMessage *res, *msg;
525 			unsigned long first = 0, last = 0;
526 			int gotfirst = 0, gotlast = 0;
527 			/* See if we're new enough for the remote server */
528 			lattrs[0] = "firstchangenumber";
529 			lattrs[1] = "lastchangenumber";
530 			lattrs[2] = NULL;
531 			rc = ldap_search_ext_s( si->si_ld, "", LDAP_SCOPE_BASE, generic_filterstr.bv_val, lattrs, 0,
532 				NULL, NULL, NULL, si->si_slimit, &res );
533 			if ( rc )
534 				return rc;
535 			msg = ldap_first_message( si->si_ld, res );
536 			if ( msg && ldap_msgtype( msg ) == LDAP_RES_SEARCH_ENTRY ) {
537 				BerElement *ber = NULL;
538 				struct berval bv, *bvals, **bvp = &bvals;;
539 				rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bv );
540 				for ( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp );
541 					rc == LDAP_SUCCESS;
542 					rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp ) ) {
543 					if ( bv.bv_val == NULL )
544 						break;
545 					if ( !strcasecmp( bv.bv_val, "firstchangenumber" )) {
546 						first = strtoul( bvals[0].bv_val, NULL, 0 );
547 						gotfirst = 1;
548 					} else if ( !strcasecmp( bv.bv_val, "lastchangenumber" )) {
549 						last = strtoul( bvals[0].bv_val, NULL, 0 );
550 						gotlast = 1;
551 					}
552 				}
553 			}
554 			ldap_msgfree( res );
555 			if ( gotfirst && gotlast ) {
556 				if ( si->si_lastchange < first || (!si->si_lastchange && !si->si_refreshDone ))
557 					si->si_logstate = SYNCLOG_FALLBACK;
558 				/* if we're in logging mode, it will update si_lastchange itself */
559 				if ( si->si_logstate == SYNCLOG_FALLBACK )
560 					si->si_lastchange = last;
561 			} else {
562 				/* should be an error; changelog plugin not enabled on provider */
563 				si->si_logstate = SYNCLOG_FALLBACK;
564 			}
565 		} else
566 		if ( si->si_logstate == SYNCLOG_LOGGING && !si->si_syncCookie.numcsns &&
567 				!si->si_refreshDone ) {
568 			si->si_logstate = SYNCLOG_FALLBACK;
569 		}
570 	}
571 
572 	/* Use the log parameters if we're in log mode */
573 	if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
574 		logschema *ls;
575 		if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
576 			ls = &accesslog_sc;
577 		else
578 			ls = &changelog_sc;
579 		lattrs[0] = ls->ls_dn.bv_val;
580 		lattrs[1] = ls->ls_req.bv_val;
581 		lattrs[2] = ls->ls_mod.bv_val;
582 		lattrs[3] = ls->ls_newRdn.bv_val;
583 		lattrs[4] = ls->ls_delRdn.bv_val;
584 		lattrs[5] = ls->ls_newSup.bv_val;
585 		if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
586 			lattrs[6] = ls->ls_controls.bv_val;
587 			lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
588 			lattrs[8] = NULL;
589 			filter = si->si_logfilterstr.bv_val;
590 			scope = LDAP_SCOPE_SUBTREE;
591 		} else {
592 			lattrs[6] = ls->ls_uuid.bv_val;
593 			lattrs[7] = ls->ls_changenum.bv_val;
594 			lattrs[8] = NULL;
595 			sprintf( filterbuf, "(changeNumber>=%lu)", si->si_lastchange+1 );
596 			filter = filterbuf;
597 			scope = LDAP_SCOPE_ONELEVEL;
598 		}
599 
600 		rhint = 0;
601 		base = si->si_logbase.bv_val;
602 		attrs = lattrs;
603 		attrsonly = 0;
604 	} else {
605 		rhint = 1;
606 		base = si->si_base.bv_val;
607 		filter = si->si_filterstr.bv_val;
608 		attrs = si->si_attrs;
609 		attrsonly = si->si_attrsonly;
610 		scope = si->si_scope;
611 	}
612 	if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
613 		si->si_type = LDAP_SYNC_REFRESH_ONLY;
614 	} else {
615 		si->si_type = si->si_ctype;
616 	}
617 
618 #ifdef LDAP_CONTROL_X_DIRSYNC
619 	if ( si->si_ctype == MSAD_DIRSYNC ) {
620 		ber_printf( ber, "{iiO}", LDAP_CONTROL_X_DIRSYNC_INCREMENTAL_VALUES, 0, &si->si_dirSyncCookie );
621 
622 		if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
623 			ber_free_buf( ber );
624 			return rc;
625 		}
626 		c[0].ldctl_oid = LDAP_CONTROL_X_DIRSYNC;
627 		c[0].ldctl_iscritical = 1;
628 		ctrls[0] = &c[0];
629 
630 		if ( !BER_BVISEMPTY( &si->si_dirSyncCookie )) {
631 			c[1].ldctl_oid = LDAP_CONTROL_X_SHOW_DELETED;
632 			BER_BVZERO( &c[1].ldctl_value );
633 			c[1].ldctl_iscritical = 1;
634 			ctrls[1] = &c[1];
635 			ctrls[2] = NULL;
636 		} else {
637 			ctrls[1] = NULL;
638 		}
639 	} else
640 #endif
641 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
642 		if ( si->si_logstate == SYNCLOG_LOGGING && si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
643 			c[0].ldctl_oid = LDAP_CONTROL_PERSIST_REQUEST;
644 			c[0].ldctl_iscritical = 0;
645 			rc = ldap_create_persistentsearch_control_value( si->si_ld, LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD,
646 				0, 1, &c[0].ldctl_value );
647 			ctrls[0] = &c[0];
648 			ctrls[1] = NULL;
649 		} else {
650 			ctrls[0] = NULL;
651 		}
652 	} else
653 	{
654 		if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
655 		{
656 			ber_printf( ber, "{eOb}",
657 				abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
658 		} else {
659 			ber_printf( ber, "{eb}",
660 				abs(si->si_type), rhint );
661 		}
662 
663 		if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
664 			ber_free_buf( ber );
665 			return rc;
666 		}
667 
668 		c[0].ldctl_oid = LDAP_CONTROL_SYNC;
669 		c[0].ldctl_iscritical = si->si_type < 0;
670 		ctrls[0] = &c[0];
671 
672 		c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
673 		BER_BVZERO( &c[1].ldctl_value );
674 		c[1].ldctl_iscritical = 1;
675 		ctrls[1] = &c[1];
676 
677 		if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
678 			c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
679 			c[2].ldctl_value = si->si_bindconf.sb_authzId;
680 			c[2].ldctl_iscritical = 1;
681 			ctrls[2] = &c[2];
682 			ctrls[3] = NULL;
683 		} else {
684 			ctrls[2] = NULL;
685 		}
686 	}
687 
688 	rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
689 		ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
690 	ber_free_buf( ber );
691 	return rc;
692 }
693 
694 /* #define DEBUG_MERGE_STATE	1 */
695 
696 static int
merge_state(syncinfo_t * si,struct sync_cookie * sc1,struct sync_cookie * sc2)697 merge_state( syncinfo_t *si, struct sync_cookie *sc1, struct sync_cookie *sc2 )
698 {
699 	int i, j, k, changed = 0;
700 	int ei, ej;
701 	int *newsids;
702 	struct berval *newcsns;
703 
704 	ei = sc1->numcsns;
705 	ej = sc2->numcsns;
706 #ifdef DEBUG_MERGE_STATE
707 	for ( i=0; i<ei; i++ ) {
708 		fprintf(stderr, "merge_state: %s si_syncCookie [%d] %d %s\n",
709 			si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val );
710 	}
711 	for ( i=0; i<ej; i++ ) {
712 		fprintf(stderr, "merge_state: %s si_cookieState [%d] %d %s\n",
713 			si->si_ridtxt, i, sc2->sids[i], sc2->ctxcsn[i].bv_val );
714 	}
715 #endif
716 	/* see if they cover the same SIDs */
717 	if ( ei == ej ) {
718 		for ( i = 0; i < ei; i++ ) {
719 			if ( sc1->sids[i] != sc2->sids[i] ) {
720 				changed = 1;
721 				break;
722 			}
723 		}
724 		/* SIDs are the same, take fast path */
725 		if ( !changed ) {
726 			for ( i = 0; i < ei; i++ ) {
727 				if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[i] ) < 0 ) {
728 					ber_bvreplace( &sc1->ctxcsn[i], &sc2->ctxcsn[i] );
729 					changed = 1;
730 				}
731 			}
732 			return changed;
733 		}
734 		changed = 0;
735 	}
736 
737 	i = ei + ej;
738 	newsids = ch_malloc( sizeof(int) * i );
739 	newcsns = ch_malloc( sizeof(struct berval) * ( i + 1 ));
740 
741 	for ( i=0, j=0, k=0; i < ei || j < ej ; ) {
742 		if ( i < ei && sc1->sids[i] == -1 ) {
743 			i++;
744 			continue;
745 		}
746 		if ( j >= ej || (i < ei && sc1->sids[i] < sc2->sids[j] )) {
747 			newsids[k] = sc1->sids[i];
748 			ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] );
749 			i++; k++;
750 			continue;
751 		}
752 		if ( i < ei && sc1->sids[i] == sc2->sids[j] ) {
753 			newsids[k] = sc1->sids[i];
754 			if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[j] ) < 0 ) {
755 				changed = 1;
756 				ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] );
757 			} else {
758 				ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] );
759 			}
760 			i++; j++; k++;
761 			continue;
762 		}
763 		if ( j < ej ) {
764 			if ( sc2->sids[j] == -1 ) {
765 				j++;
766 				continue;
767 			}
768 			newsids[k] = sc2->sids[j];
769 			ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] );
770 			changed = 1;
771 			j++; k++;
772 		}
773 	}
774 
775 	ber_bvarray_free( sc1->ctxcsn );
776 	ch_free( sc1->sids );
777 	sc1->numcsns = k;
778 	sc1->sids = ch_realloc( newsids, sizeof(int) * k );
779 	sc1->ctxcsn = ch_realloc( newcsns, sizeof(struct berval) * (k+1) );
780 	BER_BVZERO( &sc1->ctxcsn[k] );
781 #ifdef DEBUG_MERGE_STATE
782 	for ( i=0; i<sc1->numcsns; i++ ) {
783 		fprintf(stderr, "merge_state: %s si_syncCookie2 [%d] %d %s\n",
784 			si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val );
785 	}
786 #endif
787 
788 	return changed;
789 }
790 
791 #ifdef DEBUG_MERGE_STATE
792 static void
merge_test(syncinfo_t * si)793 merge_test( syncinfo_t *si ) {
794 	struct sync_cookie sc1, sc2;
795 	int ret;
796 
797 	sc1.numcsns = 4;
798 	sc1.sids = malloc( sizeof( int ) * sc1.numcsns );
799 	sc1.ctxcsn = malloc( sizeof( struct berval ) * ( sc1.numcsns + 1 ));
800 	sc1.sids[0] = 1;
801 	sc1.sids[1] = 3;
802 	sc1.sids[2] = 4;
803 	sc1.sids[3] = 5;
804 	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc1#001#000000");	/* unique */
805 	ber_dupbv( &sc1.ctxcsn[0], &bv ); }
806 	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc1#003#000000");	/* lower */
807 	ber_dupbv( &sc1.ctxcsn[1], &bv ); }
808 	{ struct berval bv = BER_BVC("20201231000000.100000Z#sc1#004#000000");	/* higher */
809 	ber_dupbv( &sc1.ctxcsn[2], &bv ); }
810 	{ struct berval bv = BER_BVC("20200228000000.100000Z#sc1#005#000000");	/* unique */
811 	ber_dupbv( &sc1.ctxcsn[3], &bv ); }
812 	BER_BVZERO( &sc1.ctxcsn[sc1.numcsns] );
813 
814 	sc2.numcsns = 4;
815 	sc2.sids = malloc( sizeof( int ) * sc2.numcsns );
816 	sc2.ctxcsn = malloc( sizeof( struct berval ) * ( sc2.numcsns + 1 ));
817 	sc2.sids[0] = 2;
818 	sc2.sids[1] = 3;
819 	sc2.sids[2] = 4;
820 	sc2.sids[3] = 6;
821 	{ struct berval bv = BER_BVC("20200101000000.100000Z#sc2#002#000000");	/* unique */
822 	ber_dupbv( &sc2.ctxcsn[0], &bv ); }
823 	{ struct berval bv = BER_BVC("20200331000000.100000Z#sc2#003#000000");	/* higher */
824 	ber_dupbv( &sc2.ctxcsn[1], &bv ); }
825 	{ struct berval bv = BER_BVC("20200501000000.100000Z#sc2#004#000000");	/* lower */
826 	ber_dupbv( &sc2.ctxcsn[2], &bv ); }
827 	{ struct berval bv = BER_BVC("20200628000000.100000Z#sc2#006#000000");	/* unique */
828 	ber_dupbv( &sc2.ctxcsn[3], &bv ); }
829 	BER_BVZERO( &sc2.ctxcsn[sc2.numcsns] );
830 
831 	ret = merge_state( si, &sc1, &sc2 );
832 }
833 #endif
834 
835 static int
check_syncprov(Operation * op,syncinfo_t * si)836 check_syncprov(
837 	Operation *op,
838 	syncinfo_t *si )
839 {
840 	AttributeName at[2];
841 	Attribute a = {0};
842 	Entry e = {0};
843 	SlapReply rs = {REP_SEARCH};
844 	int i, j, changed = 0;
845 
846 	/* Look for contextCSN from syncprov overlay. If
847 	 * there's no overlay, this will be a no-op. That means
848 	 * this is a pure consumer, so local changes will not be
849 	 * allowed, and all changes will already be reflected in
850 	 * the cookieState.
851 	 */
852 	a.a_desc = slap_schema.si_ad_contextCSN;
853 	e.e_attrs = &a;
854 	e.e_name = si->si_contextdn;
855 	e.e_nname = si->si_contextdn;
856 	at[0].an_name = a.a_desc->ad_cname;
857 	at[0].an_desc = a.a_desc;
858 	BER_BVZERO( &at[1].an_name );
859 	rs.sr_entry = &e;
860 	rs.sr_flags = REP_ENTRY_MODIFIABLE;
861 	rs.sr_attrs = at;
862 	op->o_req_dn = e.e_name;
863 	op->o_req_ndn = e.e_nname;
864 
865 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
866 	i = backend_operational( op, &rs );
867 	if ( i == LDAP_SUCCESS && a.a_nvals ) {
868 		int num = a.a_numvals;
869 		/* check for differences */
870 		if ( num != si->si_cookieState->cs_num ) {
871 			changed = 1;
872 		} else {
873 			for ( i=0; i<num; i++ ) {
874 				if ( ber_bvcmp( &a.a_nvals[i],
875 					&si->si_cookieState->cs_vals[i] )) {
876 					changed = 1;
877 					break;
878 				}
879 			}
880 		}
881 		if ( changed ) {
882 			ber_bvarray_free( si->si_cookieState->cs_vals );
883 			ch_free( si->si_cookieState->cs_sids );
884 			si->si_cookieState->cs_num = num;
885 			si->si_cookieState->cs_vals = a.a_nvals;
886 			si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
887 				num, NULL );
888 			si->si_cookieState->cs_age++;
889 		} else {
890 			ber_bvarray_free( a.a_nvals );
891 		}
892 		ber_bvarray_free( a.a_vals );
893 	}
894 	/* See if the cookieState has changed due to anything outside
895 	 * this particular consumer. That includes other consumers in
896 	 * the same context, or local changes detected above.
897 	 */
898 	if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
899 		si->si_cookieState->cs_age ) {
900 		if ( !si->si_syncCookie.numcsns ) {
901 			ber_bvarray_free( si->si_syncCookie.ctxcsn );
902 			ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
903 				si->si_cookieState->cs_vals, NULL );
904 			changed = 1;
905 		} else {
906 			changed = merge_state( si, &si->si_syncCookie,
907 				(struct sync_cookie *)&si->si_cookieState->cs_vals );
908 		}
909 	}
910 	if ( changed ) {
911 		si->si_cookieAge = si->si_cookieState->cs_age;
912 		ch_free( si->si_syncCookie.octet_str.bv_val );
913 		slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
914 			si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
915 			si->si_syncCookie.sid, NULL );
916 		ch_free( si->si_syncCookie.sids );
917 		slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx );
918 	}
919 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
920 	return changed;
921 }
922 
923 static int
do_syncrep1(Operation * op,syncinfo_t * si)924 do_syncrep1(
925 	Operation *op,
926 	syncinfo_t *si )
927 {
928 	int	rc;
929 	int cmdline_cookie_found = 0;
930 
931 	struct sync_cookie	*sc = NULL;
932 #ifdef HAVE_TLS
933 	void	*ssl;
934 #endif
935 
936 	si->si_lastconnect = slap_get_time();
937 	si->si_refreshDone = 0;
938 	rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
939 	if ( rc != LDAP_SUCCESS ) {
940 		goto done;
941 	}
942 	op->o_protocol = LDAP_VERSION3;
943 
944 	/* Set SSF to strongest of TLS, SASL SSFs */
945 	op->o_sasl_ssf = 0;
946 	op->o_tls_ssf = 0;
947 	op->o_transport_ssf = 0;
948 #ifdef HAVE_TLS
949 	if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
950 		== LDAP_SUCCESS && ssl != NULL )
951 	{
952 		op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
953 	}
954 #endif /* HAVE_TLS */
955 	{
956 		ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
957 						  to use sasl_ssf_t but currently uses ber_len_t */
958 		if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
959 			== LDAP_SUCCESS )
960 			op->o_sasl_ssf = ssf;
961 	}
962 	op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
963 		?  op->o_sasl_ssf : op->o_tls_ssf;
964 
965 	ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
966 
967 	rc = LDAP_DEREF_NEVER;	/* actually could allow DEREF_FINDING */
968 	ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
969 
970 	ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
971 
972 	si->si_syncCookie.rid = si->si_rid;
973 
974 	/* whenever there are multiple data sources possible, advertise sid */
975 	si->si_syncCookie.sid = ( SLAP_MULTIPROVIDER( si->si_be ) || si->si_be != si->si_wbe ) ?
976 		slap_serverID : -1;
977 
978 #ifdef LDAP_CONTROL_X_DIRSYNC
979 	if ( si->si_ctype == MSAD_DIRSYNC ) {
980 		if ( BER_BVISEMPTY( &si->si_dirSyncCookie )) {
981 			BerVarray cookies = NULL;
982 			void *ctx = op->o_tmpmemctx;
983 
984 			op->o_req_ndn = si->si_contextdn;
985 			op->o_req_dn = op->o_req_ndn;
986 
987 			/* try to read stored cookie */
988 			op->o_tmpmemctx = NULL;
989 			backend_attribute( op, NULL, &op->o_req_ndn,
990 				sy_ad_dirSyncCookie, &cookies, ACL_READ );
991 			op->o_tmpmemctx = ctx;
992 			if ( cookies )
993 				si->si_dirSyncCookie = cookies[0];
994 		}
995 	} else
996 #endif
997 	if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
998 		if ( !si->si_lastchange ) {
999 			BerVarray vals = NULL;
1000 
1001 			op->o_req_ndn = si->si_contextdn;
1002 			op->o_req_dn = op->o_req_ndn;
1003 			/* try to read last change number */
1004 			backend_attribute( op, NULL, &op->o_req_ndn,
1005 				sy_ad_dseeLastChange, &vals, ACL_READ );
1006 			if ( vals ) {
1007 				si->si_lastchange = strtoul( vals[0].bv_val, NULL, 0 );
1008 				si->si_prevchange = si->si_lastchange;
1009 			}
1010 		}
1011 	} else
1012 	{
1013 
1014 		/* We've just started up, or the remote server hasn't sent us
1015 		 * any meaningful state.
1016 		 */
1017 		if ( !si->si_syncCookie.ctxcsn ) {
1018 			int i;
1019 
1020 			LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
1021 				if ( si->si_rid == sc->rid ) {
1022 					cmdline_cookie_found = 1;
1023 					break;
1024 				}
1025 			}
1026 
1027 			if ( cmdline_cookie_found ) {
1028 				/* cookie is supplied in the command line */
1029 
1030 				LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
1031 
1032 				slap_sync_cookie_free( &si->si_syncCookie, 0 );
1033 				si->si_syncCookie.octet_str = sc->octet_str;
1034 				ch_free( sc );
1035 				/* ctxcsn wasn't parsed yet, do it now */
1036 				slap_parse_sync_cookie( &si->si_syncCookie, NULL );
1037 			} else {
1038 				ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
1039 				if ( !si->si_cookieState->cs_num ) {
1040 					/* get contextCSN shadow replica from database */
1041 					BerVarray csn = NULL;
1042 					void *ctx = op->o_tmpmemctx;
1043 
1044 					op->o_req_ndn = si->si_contextdn;
1045 					op->o_req_dn = op->o_req_ndn;
1046 
1047 					/* try to read stored contextCSN */
1048 					op->o_tmpmemctx = NULL;
1049 					backend_attribute( op, NULL, &op->o_req_ndn,
1050 						slap_schema.si_ad_contextCSN, &csn, ACL_READ );
1051 					op->o_tmpmemctx = ctx;
1052 					if ( csn ) {
1053 						si->si_cookieState->cs_vals = csn;
1054 						for (i=0; !BER_BVISNULL( &csn[i] ); i++);
1055 						si->si_cookieState->cs_num = i;
1056 						si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
1057 						slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
1058 					}
1059 				}
1060 				if ( si->si_cookieState->cs_num ) {
1061 					ber_bvarray_free( si->si_syncCookie.ctxcsn );
1062 					if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
1063 						si->si_cookieState->cs_vals, NULL )) {
1064 						rc = LDAP_NO_MEMORY;
1065 						ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
1066 						goto done;
1067 					}
1068 					si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
1069 					si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num *
1070 						sizeof(int) );
1071 					for ( i=0; i<si->si_syncCookie.numcsns; i++ )
1072 						si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
1073 				}
1074 				ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
1075 			}
1076 		}
1077 
1078 		if ( !cmdline_cookie_found ) {
1079 			/* ITS#6367: recreate the cookie so it has our SID, not our peer's */
1080 			ch_free( si->si_syncCookie.octet_str.bv_val );
1081 			BER_BVZERO( &si->si_syncCookie.octet_str );
1082 			/* Look for contextCSN from syncprov overlay. */
1083 			check_syncprov( op, si );
1084 			if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
1085 				slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
1086 					si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
1087 					si->si_syncCookie.sid, NULL );
1088 		}
1089 	}
1090 
1091 	Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n",
1092 		si->si_ridtxt, si->si_syncCookie.octet_str.bv_val );
1093 
1094 	ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
1095 	ber_bvreplace( &si->si_lastCookieSent, &si->si_syncCookie.octet_str );
1096 	ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
1097 
1098 	rc = ldap_sync_search( si, op->o_tmpmemctx );
1099 
1100 	if( rc != LDAP_SUCCESS ) {
1101 		Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
1102 			"ldap_search_ext: %s (%d)\n",
1103 			si->si_ridtxt, ldap_err2string( rc ), rc );
1104 	}
1105 
1106 done:
1107 	if ( rc ) {
1108 		if ( si->si_ld ) {
1109 			ldap_unbind_ext( si->si_ld, NULL, NULL );
1110 			si->si_ld = NULL;
1111 		}
1112 	}
1113 
1114 	return rc;
1115 }
1116 
1117 static int
compare_csns(struct sync_cookie * sc1,struct sync_cookie * sc2,int * which)1118 compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
1119 {
1120 	int i, j, match = 0;
1121 	const char *text;
1122 
1123 	*which = 0;
1124 
1125 	if ( sc1->numcsns < sc2->numcsns ) {
1126 		*which = sc1->numcsns;
1127 		return -1;
1128 	}
1129 
1130 	for (j=0; j<sc2->numcsns; j++) {
1131 		for (i=0; i<sc1->numcsns; i++) {
1132 			if ( sc1->sids[i] != sc2->sids[j] )
1133 				continue;
1134 			value_match( &match, slap_schema.si_ad_entryCSN,
1135 				slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
1136 				SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1137 				&sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
1138 			if ( match < 0 ) {
1139 				*which = j;
1140 				return match;
1141 			}
1142 			break;
1143 		}
1144 		if ( i == sc1->numcsns ) {
1145 			/* sc2 has a sid sc1 lacks */
1146 			*which = j;
1147 			return -1;
1148 		}
1149 	}
1150 	return match;
1151 }
1152 
1153 #define CV_CSN_OK	0
1154 #define CV_CSN_OLD	1
1155 #define CV_SID_NEW	2
1156 
1157 static int
check_csn_age(syncinfo_t * si,struct berval * dn,struct berval * csn,int sid,cookie_vals * cv,int * slot)1158 check_csn_age(
1159 	syncinfo_t *si,
1160 	struct berval *dn,
1161 	struct berval *csn,
1162 	int sid,
1163 	cookie_vals *cv,
1164 	int *slot )
1165 {
1166 	int i, rc = CV_SID_NEW;
1167 
1168 	for ( i =0; i<cv->cv_num; i++ ) {
1169 #ifdef CHATTY_SYNCLOG
1170 		Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n",
1171 			si->si_ridtxt, i, cv->cv_vals[i].bv_val );
1172 #endif
1173 		/* new SID */
1174 		if ( sid < cv->cv_sids[i] )
1175 			break;
1176 		if ( cv->cv_sids[i] == sid ) {
1177 			if ( ber_bvcmp( csn, &cv->cv_vals[i] ) <= 0 ) {
1178 				dn->bv_val[dn->bv_len] = '\0';
1179 				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
1180 					si->si_ridtxt, csn->bv_val, dn->bv_val );
1181 				return CV_CSN_OLD;
1182 			}
1183 			rc = CV_CSN_OK;
1184 			break;
1185 		}
1186 	}
1187 	if ( slot )
1188 		*slot = i;
1189 	return rc;
1190 }
1191 
1192 #define SYNC_TIMEOUT	0
1193 #define SYNC_SHUTDOWN	-100
1194 #define SYNC_ERROR		-101
1195 #define SYNC_REPOLL		-102
1196 #define SYNC_PAUSED		-103
1197 
1198 static int
get_pmutex(syncinfo_t * si)1199 get_pmutex(
1200 	syncinfo_t *si
1201 )
1202 {
1203 	if ( !si->si_is_configdb ) {
1204 		ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_pmutex );
1205 	} else {
1206 		/* avoid deadlock when replicating cn=config */
1207 		while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
1208 			if ( slapd_shutdown )
1209 				return SYNC_SHUTDOWN;
1210 			if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
1211 				ldap_pvt_thread_yield();
1212 		}
1213 	}
1214 
1215 	return 0;
1216 }
1217 
1218 static int
do_syncrep2(Operation * op,syncinfo_t * si)1219 do_syncrep2(
1220 	Operation *op,
1221 	syncinfo_t *si )
1222 {
1223 	BerElementBuffer berbuf;
1224 	BerElement	*ber = (BerElement *)&berbuf;
1225 
1226 	LDAPMessage	*msg = NULL;
1227 
1228 	struct sync_cookie	syncCookie = { NULL };
1229 	struct sync_cookie	syncCookie_req = { NULL };
1230 
1231 	int		rc,
1232 			err = LDAP_SUCCESS;
1233 
1234 	Modifications	*modlist = NULL;
1235 
1236 	int				m;
1237 
1238 	struct timeval tout = { 0, 0 };
1239 
1240 	int		refreshDeletes = 0;
1241 	char empty[6] = "empty";
1242 
1243 	if ( slapd_shutdown ) {
1244 		rc = SYNC_SHUTDOWN;
1245 		goto done;
1246 	}
1247 
1248 	ber_init2( ber, NULL, LBER_USE_DER );
1249 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
1250 
1251 	Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt );
1252 
1253 	slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
1254 
1255 	if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
1256 		tout.tv_sec = 0;
1257 	} else {
1258 		/* Give some time for refresh response to arrive */
1259 		tout.tv_sec = si->si_bindconf.sb_timeout_api;
1260 	}
1261 
1262 	while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
1263 		&tout, &msg ) ) > 0 )
1264 	{
1265 		int				match, punlock, syncstate;
1266 		struct berval	*retdata, syncUUID[2], cookie = BER_BVNULL;
1267 		char			*retoid;
1268 		LDAPControl		**rctrls = NULL, *rctrlp = NULL;
1269 		BerVarray		syncUUIDs;
1270 		ber_len_t		len;
1271 		ber_tag_t		si_tag;
1272 		Entry			*entry;
1273 		struct berval	bdn;
1274 
1275 		if ( slapd_shutdown ) {
1276 			rc = SYNC_SHUTDOWN;
1277 			goto done;
1278 		}
1279 		si->si_lastcontact = slap_get_time();
1280 		switch( ldap_msgtype( msg ) ) {
1281 		case LDAP_RES_SEARCH_ENTRY:
1282 #ifdef LDAP_CONTROL_X_DIRSYNC
1283 			if ( si->si_ctype == MSAD_DIRSYNC ) {
1284 				BER_BVZERO( &syncUUID[0] );
1285 				rc = syncrepl_dirsync_message( si, op, msg, &modlist, &entry, &syncstate, syncUUID );
1286 				if ( rc == 0 )
1287 					rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL );
1288 				op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx );
1289 				if ( modlist )
1290 					slap_mods_free( modlist, 1);
1291 				if ( rc )
1292 					goto done;
1293 				break;
1294 			}
1295 #endif
1296 			ldap_get_entry_controls( si->si_ld, msg, &rctrls );
1297 			ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
1298 			if (!bdn.bv_len) {
1299 				bdn.bv_val = empty;
1300 				bdn.bv_len = sizeof(empty)-1;
1301 			}
1302 			if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
1303 				if ( si->si_logstate == SYNCLOG_LOGGING ) {
1304 					rc = syncrepl_message_to_op( si, op, msg, 1 );
1305 					if ( rc )
1306 						goto logerr;
1307 					if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST && rctrls ) {
1308 						LDAPControl **next = NULL;
1309 						/* The notification control is only sent during persist phase */
1310 						rctrlp = ldap_control_find( LDAP_CONTROL_PERSIST_ENTRY_CHANGE_NOTICE, rctrls, &next );
1311 						if ( rctrlp ) {
1312 							if ( !si->si_refreshDone )
1313 								si->si_refreshDone = 1;
1314 							if ( si->si_refreshDone )
1315 								syncrepl_dsee_update( si, op );
1316 						}
1317 					}
1318 
1319 				} else {
1320 					syncstate = DSEE_SYNC_ADD;
1321 					rc = syncrepl_message_to_entry( si, op, msg,
1322 						&modlist, &entry, syncstate, syncUUID );
1323 					if ( rc == 0 )
1324 						rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL );
1325 					op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx );
1326 					if ( modlist )
1327 						slap_mods_free( modlist, 1);
1328 				}
1329 				if ( rc )
1330 					goto done;
1331 				break;
1332 			}
1333 			/* we can't work without the control */
1334 			if ( rctrls ) {
1335 				LDAPControl **next = NULL;
1336 				/* NOTE: make sure we use the right one;
1337 				 * a better approach would be to run thru
1338 				 * the whole list and take care of all */
1339 				/* NOTE: since we issue the search request,
1340 				 * we should know what controls to expect,
1341 				 * and there should be none apart from the
1342 				 * sync-related control */
1343 				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
1344 				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
1345 				{
1346 					bdn.bv_val[bdn.bv_len] = '\0';
1347 					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1348 						"got search entry with multiple "
1349 						"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val );
1350 					ldap_controls_free( rctrls );
1351 					rc = -1;
1352 					goto done;
1353 				}
1354 			}
1355 			if ( rctrlp == NULL ) {
1356 				bdn.bv_val[bdn.bv_len] = '\0';
1357 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1358 					"got search entry without "
1359 					"Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val );
1360 				rc = -1;
1361 				goto done;
1362 			}
1363 			ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
1364 			if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
1365 					== LBER_ERROR ) {
1366 				bdn.bv_val[bdn.bv_len] = '\0';
1367 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
1368 					si->si_ridtxt, bdn.bv_val );
1369 				ldap_controls_free( rctrls );
1370 				rc = -1;
1371 				goto done;
1372 			}
1373 			/* FIXME: what if syncUUID is NULL or empty?
1374 			 * (happens with back-sql...) */
1375 			if ( syncUUID[0].bv_len != UUIDLEN ) {
1376 				bdn.bv_val[bdn.bv_len] = '\0';
1377 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1378 					"got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n",
1379 					si->si_ridtxt,
1380 					syncrepl_state2str( syncstate ), bdn.bv_val );
1381 				ldap_controls_free( rctrls );
1382 				rc = -1;
1383 				goto done;
1384 			}
1385 			punlock = -1;
1386 			if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
1387 				if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) != LBER_ERROR ) {
1388 
1389 				Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1390 					si->si_ridtxt,
1391 					BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
1392 
1393 				if ( !BER_BVISNULL( &cookie ) ) {
1394 					ch_free( syncCookie.octet_str.bv_val );
1395 					ber_dupbv( &syncCookie.octet_str, &cookie );
1396 
1397 					ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
1398 					ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
1399 					ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
1400 				}
1401 				if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1402 				{
1403 					slap_parse_sync_cookie( &syncCookie, NULL );
1404 					if ( syncCookie.ctxcsn ) {
1405 						int i, slot, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
1406 						check_syncprov( op, si );
1407 						ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
1408 						i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL );
1409 						ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
1410 						if ( i == CV_CSN_OLD ) {
1411 							si->si_too_old = 1;
1412 							ldap_controls_free( rctrls );
1413 							rc = 0;
1414 							goto done;
1415 						}
1416 						si->si_too_old = 0;
1417 
1418 						/* check pending CSNs too */
1419 						if (( rc = get_pmutex( si )))
1420 							goto done;
1421 
1422 						i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_pvals, &slot );
1423 						if ( i == CV_CSN_OK ) {
1424 							ber_bvreplace( &si->si_cookieState->cs_pvals[slot],
1425 								syncCookie.ctxcsn );
1426 						} else if ( i == CV_CSN_OLD ) {
1427 							ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
1428 							ldap_controls_free( rctrls );
1429 							rc = 0;
1430 							goto done;
1431 						} else {
1432 						/* new SID, add it */
1433 							slap_insert_csn_sids(
1434 								(struct sync_cookie *)&si->si_cookieState->cs_pvals,
1435 								slot, sid, syncCookie.ctxcsn );
1436 						}
1437 						assert( punlock < 0 );
1438 						punlock = slot;
1439 					} else if (si->si_too_old) {
1440 						bdn.bv_val[bdn.bv_len] = '\0';
1441 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring (%s)\n",
1442 							si->si_ridtxt, bdn.bv_val );
1443 						ldap_controls_free( rctrls );
1444 						rc = 0;
1445 						goto done;
1446 					}
1447 					op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1448 				}
1449 				}
1450 			}
1451 			rc = 0;
1452 			if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
1453 				modlist = NULL;
1454 				if ( ( rc = syncrepl_message_to_op( si, op, msg, punlock < 0 ) ) == LDAP_SUCCESS &&
1455 					syncCookie.ctxcsn )
1456 				{
1457 					rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
1458 				} else
1459 logerr:
1460 					switch ( rc ) {
1461 					case LDAP_ALREADY_EXISTS:
1462 					case LDAP_NO_SUCH_OBJECT:
1463 					case LDAP_NO_SUCH_ATTRIBUTE:
1464 					case LDAP_TYPE_OR_VALUE_EXISTS:
1465 					case LDAP_NOT_ALLOWED_ON_NONLEAF:
1466 						rc = LDAP_SYNC_REFRESH_REQUIRED;
1467 						si->si_logstate = SYNCLOG_FALLBACK;
1468 						ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
1469 						bdn.bv_val[bdn.bv_len] = '\0';
1470 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
1471 							si->si_ridtxt, bdn.bv_val );
1472 						if (si->si_strict_refresh) {
1473 							slap_suspend_listeners();
1474 							connections_drop();
1475 						}
1476 						break;
1477 					default:
1478 						break;
1479 					}
1480 			} else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
1481 				&modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS )
1482 			{
1483 				if ( punlock < 0 ) {
1484 					if (( rc = get_pmutex( si )))
1485 						goto done;
1486 				}
1487 				if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
1488 					syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
1489 					syncCookie.ctxcsn )
1490 				{
1491 					rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
1492 				}
1493 				if ( punlock < 0 )
1494 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
1495 			}
1496 			if ( punlock >= 0 ) {
1497 				/* on failure, revert pending CSN */
1498 				if ( rc != LDAP_SUCCESS ) {
1499 					int i;
1500 					ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
1501 					for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
1502 						if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
1503 							ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
1504 								&si->si_cookieState->cs_vals[i] );
1505 							break;
1506 						}
1507 					}
1508 					if ( i == si->si_cookieState->cs_num )
1509 						si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
1510 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
1511 				}
1512 				ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
1513 			}
1514 			ldap_controls_free( rctrls );
1515 			if ( modlist ) {
1516 				slap_mods_free( modlist, 1 );
1517 			}
1518 			if ( rc )
1519 				goto done;
1520 			break;
1521 
1522 		case LDAP_RES_SEARCH_REFERENCE:
1523 			Debug( LDAP_DEBUG_ANY,
1524 				"do_syncrep2: %s reference received error\n",
1525 				si->si_ridtxt );
1526 			break;
1527 
1528 		case LDAP_RES_SEARCH_RESULT:
1529 			Debug( LDAP_DEBUG_SYNC,
1530 				"do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
1531 				si->si_ridtxt );
1532 			err = LDAP_OTHER; /* FIXME check parse result properly */
1533 			ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
1534 				&rctrls, 0 );
1535 #ifdef LDAP_X_SYNC_REFRESH_REQUIRED
1536 			if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
1537 				/* map old result code to registered code */
1538 				err = LDAP_SYNC_REFRESH_REQUIRED;
1539 			}
1540 #endif
1541 			if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
1542 				if ( si->si_logstate == SYNCLOG_LOGGING ) {
1543 					si->si_logstate = SYNCLOG_FALLBACK;
1544 					Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
1545 						si->si_ridtxt );
1546 					if (si->si_strict_refresh) {
1547 						slap_suspend_listeners();
1548 						connections_drop();
1549 					}
1550 				}
1551 				rc = err;
1552 				goto done;
1553 			}
1554 			if ( err ) {
1555 				Debug( LDAP_DEBUG_ANY,
1556 					"do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
1557 					si->si_ridtxt, err, ldap_err2string( err ) );
1558 			}
1559 			if ( si->si_syncdata == SYNCDATA_CHANGELOG && err == LDAP_SUCCESS ) {
1560 				rc = syncrepl_dsee_update( si, op );
1561 				if ( rc == LDAP_SUCCESS ) {
1562 					if ( si->si_logstate == SYNCLOG_FALLBACK ) {
1563 						si->si_logstate = SYNCLOG_LOGGING;
1564 						si->si_refreshDone = 1;
1565 						rc = LDAP_SYNC_REFRESH_REQUIRED;
1566 					} else {
1567 						rc = SYNC_REPOLL;
1568 					}
1569 				}
1570 				goto done;
1571 			}
1572 			if ( rctrls ) {
1573 				LDAPControl **next = NULL;
1574 #ifdef LDAP_CONTROL_X_DIRSYNC
1575 				if ( si->si_ctype == MSAD_DIRSYNC ) {
1576 					rc = syncrepl_dirsync_cookie( si, op, rctrls );
1577 					if ( rc == LDAP_SUCCESS )
1578 						rc = SYNC_REPOLL;	/* schedule a re-poll */
1579 					goto done;
1580 				}
1581 #endif
1582 				/* NOTE: make sure we use the right one;
1583 				 * a better approach would be to run thru
1584 				 * the whole list and take care of all */
1585 				/* NOTE: since we issue the search request,
1586 				 * we should know what controls to expect,
1587 				 * and there should be none apart from the
1588 				 * sync-related control */
1589 				rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next );
1590 				if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) )
1591 				{
1592 					Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1593 						"got search result with multiple "
1594 						"Sync State control\n", si->si_ridtxt );
1595 					ldap_controls_free( rctrls );
1596 					rc = SYNC_ERROR;
1597 					goto done;
1598 				}
1599 			}
1600 			if ( rctrlp ) {
1601 				ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
1602 
1603 				ber_scanf( ber, "{" /*"}"*/);
1604 				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
1605 					ber_scanf( ber, "m", &cookie );
1606 
1607 					Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1608 						si->si_ridtxt,
1609 						BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
1610 
1611 					if ( !BER_BVISNULL( &cookie ) ) {
1612 						ch_free( syncCookie.octet_str.bv_val );
1613 						ber_dupbv( &syncCookie.octet_str, &cookie);
1614 
1615 						ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
1616 						ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
1617 						ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
1618 					}
1619 					if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1620 					{
1621 						slap_parse_sync_cookie( &syncCookie, NULL );
1622 						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1623 					}
1624 				}
1625 				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
1626 				{
1627 					ber_scanf( ber, "b", &refreshDeletes );
1628 				}
1629 				ber_scanf( ber, /*"{"*/ "}" );
1630 			}
1631 			if ( SLAP_MULTIPROVIDER( op->o_bd ) && check_syncprov( op, si )) {
1632 				slap_sync_cookie_free( &syncCookie_req, 0 );
1633 				slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
1634 			}
1635 			if ( !syncCookie.ctxcsn ) {
1636 				match = 1;
1637 			} else if ( !syncCookie_req.ctxcsn ) {
1638 				match = -1;
1639 				m = 0;
1640 			} else {
1641 				match = compare_csns( &syncCookie_req, &syncCookie, &m );
1642 			}
1643 			if ( rctrls ) {
1644 				ldap_controls_free( rctrls );
1645 			}
1646 			if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
1647 				/* FIXME : different error behaviors according to
1648 				 *	1) err code : LDAP_BUSY ...
1649 				 *	2) on err policy : stop service, stop sync, retry
1650 				 */
1651 				if ( refreshDeletes == 0 && match < 0 && err == LDAP_SUCCESS )
1652 				{
1653 					syncrepl_del_nonpresent( op, si, NULL,
1654 						&syncCookie, m );
1655 				} else if ( si->si_presentlist ) {
1656 					presentlist_free( si->si_presentlist );
1657 					si->si_presentlist = NULL;
1658 				}
1659 			}
1660 			if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
1661 			{
1662 				rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
1663 			}
1664 			if ( err == LDAP_SUCCESS
1665 				&& si->si_logstate == SYNCLOG_FALLBACK ) {
1666 				si->si_logstate = SYNCLOG_LOGGING;
1667 				si->si_refreshDone = 1;
1668 				rc = LDAP_SYNC_REFRESH_REQUIRED;
1669 				slap_resume_listeners();
1670 			} else {
1671 				/* for persist, we shouldn't get a SearchResult so this is an error */
1672 				if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST )
1673 					rc = SYNC_ERROR;
1674 				else
1675 					rc = SYNC_REPOLL;
1676 			}
1677 			goto done;
1678 
1679 		case LDAP_RES_INTERMEDIATE:
1680 			retoid = NULL;
1681 			retdata = NULL;
1682 			rc = ldap_parse_intermediate( si->si_ld, msg,
1683 				&retoid, &retdata, NULL, 0 );
1684 			if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
1685 				ber_init2( ber, retdata, LBER_USE_DER );
1686 
1687 				switch ( si_tag = ber_peek_tag( ber, &len ) ) {
1688 				ber_tag_t tag;
1689 				case LDAP_TAG_SYNC_NEW_COOKIE:
1690 					Debug( LDAP_DEBUG_SYNC,
1691 						"do_syncrep2: %s %s - %s\n",
1692 						si->si_ridtxt,
1693 						"LDAP_RES_INTERMEDIATE",
1694 						"NEW_COOKIE" );
1695 					ber_scanf( ber, "tm", &tag, &cookie );
1696 					Debug( LDAP_DEBUG_SYNC,
1697 						"do_syncrep2: %s NEW_COOKIE: %s\n",
1698 						si->si_ridtxt,
1699 						cookie.bv_val );
1700 					if ( !BER_BVISNULL( &cookie ) ) {
1701 						ch_free( syncCookie.octet_str.bv_val );
1702 						ber_dupbv( &syncCookie.octet_str, &cookie );
1703 
1704 						ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
1705 						ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
1706 						ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
1707 					}
1708 					if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
1709 						slap_parse_sync_cookie( &syncCookie, NULL );
1710 						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1711 					}
1712 					break;
1713 				case LDAP_TAG_SYNC_REFRESH_DELETE:
1714 				case LDAP_TAG_SYNC_REFRESH_PRESENT:
1715 					Debug( LDAP_DEBUG_SYNC,
1716 						"do_syncrep2: %s %s - %s\n",
1717 						si->si_ridtxt,
1718 						"LDAP_RES_INTERMEDIATE",
1719 						si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
1720 						"REFRESH_PRESENT" : "REFRESH_DELETE" );
1721 					if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
1722 						si->si_refreshDelete = 1;
1723 					} else {
1724 						si->si_refreshPresent = 1;
1725 					}
1726 					ber_scanf( ber, "t{" /*"}"*/, &tag );
1727 					if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
1728 					{
1729 						ber_scanf( ber, "m", &cookie );
1730 
1731 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1732 							si->si_ridtxt,
1733 							BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
1734 
1735 						if ( !BER_BVISNULL( &cookie ) ) {
1736 							ch_free( syncCookie.octet_str.bv_val );
1737 							ber_dupbv( &syncCookie.octet_str, &cookie );
1738 
1739 							ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
1740 							ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
1741 							ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
1742 						}
1743 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1744 						{
1745 							slap_parse_sync_cookie( &syncCookie, NULL );
1746 							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1747 						}
1748 					}
1749 					/* Defaults to TRUE */
1750 					if ( ber_peek_tag( ber, &len ) ==
1751 						LDAP_TAG_REFRESHDONE )
1752 					{
1753 						ber_scanf( ber, "b", &si->si_refreshDone );
1754 					} else
1755 					{
1756 						si->si_refreshDone = 1;
1757 					}
1758 					ber_scanf( ber, /*"{"*/ "}" );
1759 					if ( si->si_refreshDone ) {
1760 						Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s finished refresh\n",
1761 							si->si_ridtxt );
1762 					}
1763 					break;
1764 				case LDAP_TAG_SYNC_ID_SET:
1765 					Debug( LDAP_DEBUG_SYNC,
1766 						"do_syncrep2: %s %s - %s\n",
1767 						si->si_ridtxt,
1768 						"LDAP_RES_INTERMEDIATE",
1769 						"SYNC_ID_SET" );
1770 					ber_scanf( ber, "t{" /*"}"*/, &tag );
1771 					if ( ber_peek_tag( ber, &len ) ==
1772 						LDAP_TAG_SYNC_COOKIE )
1773 					{
1774 						ber_scanf( ber, "m", &cookie );
1775 
1776 						Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1777 							si->si_ridtxt,
1778 							BER_BVISNULL( &cookie ) ? "" : cookie.bv_val );
1779 
1780 						if ( !BER_BVISNULL( &cookie ) ) {
1781 							ch_free( syncCookie.octet_str.bv_val );
1782 							ber_dupbv( &syncCookie.octet_str, &cookie );
1783 
1784 							ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
1785 							ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
1786 							ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
1787 						}
1788 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1789 						{
1790 							slap_parse_sync_cookie( &syncCookie, NULL );
1791 							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1792 							compare_csns( &syncCookie_req, &syncCookie, &m );
1793 						}
1794 					}
1795 					if ( ber_peek_tag( ber, &len ) ==
1796 						LDAP_TAG_REFRESHDELETES )
1797 					{
1798 						ber_scanf( ber, "b", &refreshDeletes );
1799 					}
1800 					syncUUIDs = NULL;
1801 					rc = ber_scanf( ber, "[W]", &syncUUIDs );
1802 					ber_scanf( ber, /*"{"*/ "}" );
1803 					if ( rc != LBER_ERROR ) {
1804 						if ( refreshDeletes ) {
1805 							syncrepl_del_nonpresent( op, si, syncUUIDs,
1806 								&syncCookie, m );
1807 							ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
1808 						} else {
1809 							int i;
1810 							for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
1811 								(void)presentlist_insert( si, &syncUUIDs[i] );
1812 								slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
1813 							}
1814 							slap_sl_free( syncUUIDs, op->o_tmpmemctx );
1815 						}
1816 					}
1817 					rc = 0;
1818 					slap_sync_cookie_free( &syncCookie, 0 );
1819 					break;
1820 				default:
1821 					Debug( LDAP_DEBUG_ANY,
1822 						"do_syncrep2: %s unknown syncinfo tag (%ld)\n",
1823 						si->si_ridtxt, (long) si_tag );
1824 					ldap_memfree( retoid );
1825 					ber_bvfree( retdata );
1826 					continue;
1827 				}
1828 
1829 				if ( SLAP_MULTIPROVIDER( op->o_bd ) && check_syncprov( op, si )) {
1830 					slap_sync_cookie_free( &syncCookie_req, 0 );
1831 					slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
1832 				}
1833 				if ( !syncCookie.ctxcsn ) {
1834 					match = 1;
1835 				} else if ( !syncCookie_req.ctxcsn ) {
1836 					match = -1;
1837 					m = 0;
1838 				} else {
1839 					match = compare_csns( &syncCookie_req, &syncCookie, &m );
1840 				}
1841 
1842 				if ( match < 0 ) {
1843 					if ( si->si_refreshPresent == 1 &&
1844 						si_tag != LDAP_TAG_SYNC_NEW_COOKIE ) {
1845 						syncrepl_del_nonpresent( op, si, NULL,
1846 							&syncCookie, m );
1847 					}
1848 
1849 					if ( syncCookie.ctxcsn )
1850 					{
1851 						rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
1852 					}
1853 					if ( si->si_presentlist ) {
1854 						presentlist_free( si->si_presentlist );
1855 						si->si_presentlist = NULL;
1856 					}
1857 				}
1858 
1859 				ldap_memfree( retoid );
1860 				ber_bvfree( retdata );
1861 
1862 				if ( rc )
1863 					goto done;
1864 
1865 			} else {
1866 				Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1867 					"unknown intermediate response (%d)\n",
1868 					si->si_ridtxt, rc );
1869 				ldap_memfree( retoid );
1870 				ber_bvfree( retdata );
1871 			}
1872 			break;
1873 
1874 		default:
1875 			Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1876 				"unknown message (0x%02lx)\n",
1877 				si->si_ridtxt,
1878 				(unsigned long)ldap_msgtype( msg ) );
1879 			break;
1880 
1881 		}
1882 		if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
1883 			slap_sync_cookie_free( &syncCookie_req, 0 );
1884 			syncCookie_req = syncCookie;
1885 			memset( &syncCookie, 0, sizeof( syncCookie ));
1886 		}
1887 		ldap_msgfree( msg );
1888 		msg = NULL;
1889 		if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
1890 			slap_sync_cookie_free( &syncCookie, 0 );
1891 			slap_sync_cookie_free( &syncCookie_req, 0 );
1892 			return SYNC_PAUSED;
1893 		}
1894 	}
1895 
1896 	if ( rc == SYNC_ERROR ) {
1897 		rc = LDAP_OTHER;
1898 		ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
1899 		err = rc;
1900 	}
1901 
1902 done:
1903 	if ( err != LDAP_SUCCESS ) {
1904 		Debug( LDAP_DEBUG_ANY,
1905 			"do_syncrep2: %s (%d) %s\n",
1906 			si->si_ridtxt, err, ldap_err2string( err ) );
1907 	}
1908 
1909 	slap_sync_cookie_free( &syncCookie, 0 );
1910 	slap_sync_cookie_free( &syncCookie_req, 0 );
1911 
1912 	if ( msg ) ldap_msgfree( msg );
1913 
1914 	if ( rc ) {
1915 		if ( rc == LDAP_SYNC_REFRESH_REQUIRED && si->si_logstate == SYNCLOG_LOGGING && si->si_ld )
1916 			return rc;
1917 		/* never reuse existing connection */
1918 		if ( si->si_conn ) {
1919 			connection_client_stop( si->si_conn );
1920 			si->si_conn = NULL;
1921 		}
1922 		ldap_unbind_ext( si->si_ld, NULL, NULL );
1923 		si->si_ld = NULL;
1924 	}
1925 
1926 	return rc;
1927 }
1928 
1929 static int
1930 syncrepl_monitor_add( syncinfo_t *si );
1931 
1932 static int
1933 syncrepl_monitor_del( syncinfo_t *si );
1934 
1935 static void *
do_syncrepl(void * ctx,void * arg)1936 do_syncrepl(
1937 	void	*ctx,
1938 	void	*arg )
1939 {
1940 	struct re_s* rtask = arg;
1941 	syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
1942 	Connection conn = {0};
1943 	OperationBuffer opbuf;
1944 	Operation *op;
1945 	int rc = LDAP_SUCCESS;
1946 	int dostop = 0;
1947 	ber_socket_t s;
1948 	int i, fail = 0, freeinfo = 0;
1949 	Backend *be;
1950 
1951 	if ( si == NULL )
1952 		return NULL;
1953 	if ( slapd_shutdown )
1954 		return NULL;
1955 
1956 	if ( !si->si_monitorInited ) {
1957 		syncrepl_monitor_add( si );
1958 		si->si_monitorInited = 1;
1959 	}
1960 
1961 	Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt );
1962 
1963 	/* Don't get stuck here while a pause is initiated */
1964 	while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
1965 		if ( slapd_shutdown )
1966 			return NULL;
1967 		if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
1968 			ldap_pvt_thread_yield();
1969 	}
1970 
1971 	si->si_too_old = 0;
1972 
1973 	if ( si->si_ctype < 1 ) {
1974 		goto deleted;
1975 	}
1976 
1977 	switch( abs( si->si_type ) ) {
1978 	case LDAP_SYNC_REFRESH_ONLY:
1979 	case LDAP_SYNC_REFRESH_AND_PERSIST:
1980 #ifdef LDAP_CONTROL_X_DIRSYNC
1981 	case MSAD_DIRSYNC:
1982 #endif
1983 		break;
1984 	default:
1985 		ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1986 		return NULL;
1987 	}
1988 
1989 	if ( slapd_shutdown ) {
1990 		if ( si->si_ld ) {
1991 			if ( si->si_conn ) {
1992 				connection_client_stop( si->si_conn );
1993 				si->si_conn = NULL;
1994 			}
1995 			ldap_unbind_ext( si->si_ld, NULL, NULL );
1996 			si->si_ld = NULL;
1997 		}
1998 		ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1999 		return NULL;
2000 	}
2001 
2002 	connection_fake_init( &conn, &opbuf, ctx );
2003 	op = &opbuf.ob_op;
2004 	/* o_connids must be unique for slap_graduate_commit_csn */
2005 	op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
2006 
2007 	op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
2008 	be = si->si_be;
2009 
2010 	/* Coordinate contextCSN updates with any syncprov overlays
2011 	 * in use. This may be complicated by the use of the glue
2012 	 * overlay.
2013 	 *
2014 	 * Typically there is a single syncprov controlling the entire
2015 	 * glued tree. In that case, our contextCSN updates should
2016 	 * go to the primary DB. But if there is no syncprov on the
2017 	 * primary DB, then nothing special is needed here.
2018 	 *
2019 	 * Alternatively, there may be individual syncprov overlays
2020 	 * on each glued branch. In that case, each syncprov only
2021 	 * knows about changes within its own branch. And so our
2022 	 * contextCSN updates should only go to the local DB.
2023 	 */
2024 	if ( !si->si_wbe ) {
2025 		if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
2026 			BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
2027 			if ( overlay_is_inst( top_be, "syncprov" ))
2028 				si->si_wbe = top_be;
2029 			else
2030 				si->si_wbe = be;
2031 		} else {
2032 			si->si_wbe = be;
2033 		}
2034 		if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) {
2035 			build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0],
2036 				(struct berval *)&slap_ldapsync_cn_bv, NULL );
2037 		} else {
2038 			si->si_contextdn = si->si_wbe->be_nsuffix[0];
2039 		}
2040 	}
2041 	if ( !si->si_schemachecking )
2042 		op->o_no_schema_check = 1;
2043 
2044 	/* Establish session, do search */
2045 	if ( !si->si_ld ) {
2046 		si->si_refreshDelete = 0;
2047 		si->si_refreshPresent = 0;
2048 
2049 		if ( si->si_presentlist ) {
2050 		    presentlist_free( si->si_presentlist );
2051 		    si->si_presentlist = NULL;
2052 		}
2053 
2054 		/* use main DB when retrieving contextCSN */
2055 		op->o_bd = si->si_wbe;
2056 		op->o_dn = op->o_bd->be_rootdn;
2057 		op->o_ndn = op->o_bd->be_rootndn;
2058 		rc = do_syncrep1( op, si );
2059 	}
2060 
2061 reload:
2062 	/* Process results */
2063 	if ( rc == LDAP_SUCCESS ) {
2064 		ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
2065 
2066 		if ( !BER_BVISEMPTY( &si->si_monitor_ndn ))
2067 		{
2068 			Sockaddr addr;
2069 			socklen_t len = sizeof( addr );
2070 			if ( !getsockname( s, &addr.sa_addr, &len )) {
2071 				si->si_connaddr.bv_val = si->si_connaddrbuf;
2072 				si->si_connaddr.bv_len = sizeof( si->si_connaddrbuf );
2073 				ldap_pvt_sockaddrstr( &addr, &si->si_connaddr );
2074 			}
2075 		}
2076 
2077 		/* use current DB */
2078 		op->o_bd = be;
2079 		op->o_dn = op->o_bd->be_rootdn;
2080 		op->o_ndn = op->o_bd->be_rootndn;
2081 		rc = do_syncrep2( op, si );
2082 		if ( rc == LDAP_SYNC_REFRESH_REQUIRED )	{
2083 			if ( si->si_logstate == SYNCLOG_LOGGING ) {
2084 				if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
2085 					slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
2086 						si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
2087 						si->si_syncCookie.sid, NULL );
2088 				rc = ldap_sync_search( si, op->o_tmpmemctx );
2089 				goto reload;
2090 			}
2091 			/* give up but schedule an immedite retry */
2092 			rc = SYNC_PAUSED;
2093 		}
2094 
2095 deleted:
2096 		/* We got deleted while running on cn=config */
2097 		if ( si->si_ctype < 1 ) {
2098 			if ( si->si_ctype == -1 ) {
2099 				si->si_ctype = 0;
2100 				freeinfo = 1;
2101 			}
2102 			if ( si->si_conn )
2103 				dostop = 1;
2104 			rc = SYNC_SHUTDOWN;
2105 		}
2106 
2107 		if ( rc != SYNC_PAUSED ) {
2108 			if ( rc == SYNC_TIMEOUT ) {
2109 				/* there was nothing to read, try to listen for more */
2110 				if ( si->si_conn ) {
2111 					connection_client_enable( si->si_conn );
2112 				} else {
2113 					si->si_conn = connection_client_setup( s, do_syncrepl, arg );
2114 				}
2115 			} else if ( si->si_conn ) {
2116 				dostop = 1;
2117 			}
2118 		}
2119 	}
2120 
2121 	/* At this point, we have 5 cases:
2122 	 * 1) for any hard failure, give up and remove this task
2123 	 * 2) for ServerDown, reschedule this task to run later
2124 	 * 3) for threadpool pause, reschedule to run immediately
2125 	 * 4) for SYNC_REPOLL, reschedule to run later
2126 	 * 5) for SYNC_TIMEOUT, reschedule to defer
2127 	 */
2128 	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
2129 
2130 	if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask ) ) {
2131 		ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
2132 	}
2133 
2134 	if ( dostop ) {
2135 		connection_client_stop( si->si_conn );
2136 		si->si_conn = NULL;
2137 	}
2138 
2139 	if ( rc == SYNC_PAUSED ) {
2140 		rtask->interval.tv_sec = 0;
2141 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
2142 		rtask->interval.tv_sec = si->si_interval;
2143 		rc = 0;
2144 	} else if ( rc == SYNC_TIMEOUT ) {
2145 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, 1 );
2146 	} else if ( rc == SYNC_REPOLL ) {
2147 		rtask->interval.tv_sec = si->si_interval;
2148 		ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
2149 		if ( si->si_retrynum ) {
2150 			for ( i = 0; si->si_retrynum_init[i] != RETRYNUM_TAIL; i++ ) {
2151 				si->si_retrynum[i] = si->si_retrynum_init[i];
2152 			}
2153 			si->si_retrynum[i] = RETRYNUM_TAIL;
2154 		}
2155 		slap_wake_listener();
2156 		rc = 0;
2157 	} else {
2158 		for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
2159 			if ( si->si_retrynum[i] == RETRYNUM_FOREVER || si->si_retrynum[i] == RETRYNUM_TAIL )
2160 				break;
2161 		}
2162 
2163 		if ( si->si_ctype < 1 || rc == SYNC_SHUTDOWN
2164 			|| !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
2165 			if ( si->si_re ) {
2166 				ldap_pvt_runqueue_remove( &slapd_rq, rtask );
2167 				si->si_re = NULL;
2168 			}
2169 			fail = RETRYNUM_TAIL;
2170 		} else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) {
2171 			if ( si->si_retrynum[i] > 0 )
2172 				si->si_retrynum[i]--;
2173 			fail = si->si_retrynum[i];
2174 			rtask->interval.tv_sec = si->si_retryinterval[i];
2175 			ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
2176 			slap_wake_listener();
2177 		}
2178 	}
2179 
2180 	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
2181 	ldap_pvt_thread_mutex_unlock( &si->si_mutex );
2182 
2183 	if ( rc ) {
2184 		if ( fail == RETRYNUM_TAIL ) {
2185 			Debug( LDAP_DEBUG_ANY,
2186 				"do_syncrepl: %s rc %d quitting\n",
2187 				si->si_ridtxt, rc );
2188 		} else if ( fail > 0 ) {
2189 			Debug( LDAP_DEBUG_ANY,
2190 				"do_syncrepl: %s rc %d retrying (%d retries left)\n",
2191 				si->si_ridtxt, rc, fail );
2192 		} else {
2193 			Debug( LDAP_DEBUG_ANY,
2194 				"do_syncrepl: %s rc %d retrying\n",
2195 				si->si_ridtxt, rc );
2196 		}
2197 	}
2198 
2199 	/* Do final delete cleanup */
2200 	if ( freeinfo ) {
2201 		syncinfo_free( si, 0 );
2202 	}
2203 	return NULL;
2204 }
2205 
2206 static int
syncrepl_rewrite_dn(syncinfo_t * si,struct berval * dn,struct berval * sdn)2207 syncrepl_rewrite_dn(
2208 	syncinfo_t *si,
2209 	struct berval *dn,
2210 	struct berval *sdn )
2211 {
2212 	char nul;
2213 	int rc;
2214 
2215 	nul = dn->bv_val[dn->bv_len];
2216 	dn->bv_val[dn->bv_len] = 0;
2217 	rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
2218 	dn->bv_val[dn->bv_len] = nul;
2219 
2220 	if ( sdn->bv_val == dn->bv_val )
2221 		sdn->bv_val = NULL;
2222 	else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
2223 		sdn->bv_len = strlen( sdn->bv_val );
2224 	return rc;
2225 }
2226 #define	REWRITE_VAL(si, ad, bv, bv2)	\
2227 	BER_BVZERO( &bv2 );	\
2228 	if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
2229 		syncrepl_rewrite_dn( si, &bv, &bv2); \
2230 	if ( BER_BVISNULL( &bv2 ))  \
2231 		ber_dupbv( &bv2, &bv )
2232 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
2233 	BER_BVZERO( &bv2 );	\
2234 	if (si->si_rewrite) \
2235 		syncrepl_rewrite_dn(si, &bv, &bv2); \
2236 	rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
2237 	ch_free(bv2.bv_val)
2238 
2239 static slap_verbmasks modops[] = {
2240 	{ BER_BVC("add"), LDAP_REQ_ADD },
2241 	{ BER_BVC("delete"), LDAP_REQ_DELETE },
2242 	{ BER_BVC("modify"), LDAP_REQ_MODIFY },
2243 	{ BER_BVC("modrdn"), LDAP_REQ_MODRDN},
2244 	{ BER_BVNULL, 0 }
2245 };
2246 
2247 static int
syncrepl_accesslog_mods(syncinfo_t * si,struct berval * vals,struct Modifications ** modres)2248 syncrepl_accesslog_mods(
2249 	syncinfo_t *si,
2250 	struct berval *vals,
2251 	struct Modifications **modres
2252 )
2253 {
2254 	char *colon;
2255 	const char *text;
2256 	AttributeDescription *ad;
2257 	struct berval bv, bv2;
2258 	short op;
2259 	Modifications *mod = NULL, *modlist = NULL, **modtail;
2260 	int i, rc = 0;
2261 
2262 	modtail = &modlist;
2263 
2264 	for (i=0; !BER_BVISNULL( &vals[i] ); i++) {
2265 		ad = NULL;
2266 		bv = vals[i];
2267 
2268 		colon = ber_bvchr( &bv, ':' );
2269 		if ( !colon ) {
2270 			/* Invalid */
2271 			continue;
2272 		} else if ( colon == bv.bv_val ) {
2273 			/* ITS#6545: An empty attribute signals that a new mod
2274 			 * is about to start */
2275 			mod = NULL;
2276 			continue;
2277 		}
2278 
2279 		bv.bv_len = colon - bv.bv_val;
2280 		if ( slap_bv2ad( &bv, &ad, &text ) ) {
2281 			/* Invalid */
2282 			Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
2283 				"Invalid attribute %s, %s\n",
2284 				si->si_ridtxt, bv.bv_val, text );
2285 			slap_mods_free( modlist, 1 );
2286 			modlist = NULL;
2287 			rc = -1;
2288 			break;
2289 		}
2290 
2291 		/* Ignore dynamically generated attrs */
2292 		if ( ad->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
2293 			continue;
2294 		}
2295 
2296 		/* Ignore excluded attrs */
2297 		if ( ldap_charray_inlist( si->si_exattrs,
2298 			ad->ad_type->sat_cname.bv_val ) )
2299 		{
2300 			continue;
2301 		}
2302 
2303 		switch(colon[1]) {
2304 		case '+':	op = LDAP_MOD_ADD; break;
2305 		case '-':	op = LDAP_MOD_DELETE; break;
2306 		case '=':	op = LDAP_MOD_REPLACE; break;
2307 		case '#':	op = LDAP_MOD_INCREMENT; break;
2308 		default:	continue;
2309 		}
2310 
2311 		if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) {
2312 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
2313 			mod->sml_flags = 0;
2314 			mod->sml_op = op;
2315 			mod->sml_next = NULL;
2316 			mod->sml_desc = ad;
2317 			mod->sml_type = ad->ad_cname;
2318 			mod->sml_values = NULL;
2319 			mod->sml_nvalues = NULL;
2320 			mod->sml_numvals = 0;
2321 
2322 			if ( is_at_single_value( ad->ad_type ) ) {
2323 				if ( op == LDAP_MOD_ADD ) {
2324 					/* ITS#9295 an ADD might conflict with an existing value */
2325 					mod->sml_op = LDAP_MOD_REPLACE;
2326 				} else if ( op == LDAP_MOD_DELETE ) {
2327 					/* ITS#9295 the above REPLACE could invalidate subsequent
2328 					 * DELETEs */
2329 					mod->sml_op = SLAP_MOD_SOFTDEL;
2330 				}
2331 			}
2332 
2333 			*modtail = mod;
2334 			modtail = &mod->sml_next;
2335 		}
2336 		if ( colon[2] == ' ' ) {
2337 			bv.bv_val = colon + 3;
2338 			bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
2339 			REWRITE_VAL( si, ad, bv, bv2 );
2340 			ber_bvarray_add( &mod->sml_values, &bv2 );
2341 			mod->sml_numvals++;
2342 		}
2343 	}
2344 	*modres = modlist;
2345 	return rc;
2346 }
2347 
2348 static int
syncrepl_dsee_uuid(struct berval * dseestr,struct berval * syncUUID,void * ctx)2349 syncrepl_dsee_uuid(
2350 	struct berval *dseestr,
2351 	struct berval *syncUUID,
2352 	void *ctx
2353 )
2354 {
2355 	slap_mr_normalize_func *normf;
2356 	/* DSEE UUID is of form 12345678-12345678-12345678-12345678 */
2357 	if ( dseestr->bv_len != 35 )
2358 		return -1;
2359 	dseestr->bv_len++;
2360 	dseestr->bv_val[35] = '-';
2361 	normf = slap_schema.si_ad_entryUUID->ad_type->sat_equality->smr_normalize;
2362 	if ( normf( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, NULL, NULL,
2363 		dseestr, &syncUUID[0], ctx ))
2364 		return -1;
2365 	(void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], ctx );
2366 	return LDAP_SUCCESS;
2367 }
2368 
2369 static int
syncrepl_changelog_mods(syncinfo_t * si,ber_tag_t req,struct berval * vals,struct Modifications ** modres,struct berval * uuid,void * ctx)2370 syncrepl_changelog_mods(
2371 	syncinfo_t *si,
2372 	ber_tag_t req,
2373 	struct berval *vals,
2374 	struct Modifications **modres,
2375 	struct berval *uuid,
2376 	void *ctx
2377 )
2378 {
2379 	LDIFRecord lr;
2380 	struct berval rbuf = vals[0];
2381 	int i, rc;
2382 	int lrflags = LDIF_NO_DN;
2383 	Modifications *mod = NULL, *modlist = NULL, **modtail = &modlist;
2384 
2385 	if ( req == LDAP_REQ_ADD )
2386 		lrflags |= LDIF_ENTRIES_ONLY|LDIF_DEFAULT_ADD;
2387 	else
2388 		lrflags |= LDIF_MODS_ONLY;
2389 
2390 	rc = ldap_parse_ldif_record_x( &rbuf, 0, &lr, "syncrepl", lrflags, ctx );
2391 	for (i = 0; lr.lrop_mods[i] != NULL; i++) {
2392 		AttributeDescription *ad = NULL;
2393 		const char *text;
2394 		int j;
2395 		if ( slap_str2ad( lr.lrop_mods[i]->mod_type, &ad, &text ) ) {
2396 			/* Invalid */
2397 			Debug( LDAP_DEBUG_ANY, "syncrepl_changelog_mods: %s "
2398 				"Invalid attribute %s, %s\n",
2399 				si->si_ridtxt, lr.lrop_mods[i]->mod_type, text );
2400 			slap_mods_free( modlist, 1 );
2401 			modlist = NULL;
2402 			rc = -1;
2403 			break;
2404 		}
2405 		mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
2406 		mod->sml_flags = 0;
2407 		mod->sml_op = lr.lrop_mods[i]->mod_op ^ LDAP_MOD_BVALUES;
2408 		mod->sml_next = NULL;
2409 		mod->sml_desc = ad;
2410 		mod->sml_type = ad->ad_cname;
2411 		mod->sml_values = NULL;
2412 		mod->sml_nvalues = NULL;
2413 		j = 0;
2414 		if ( lr.lrop_mods[i]->mod_bvalues != NULL ) {
2415 			for (; lr.lrop_mods[i]->mod_bvalues[j] != NULL; j++ ) {
2416 				struct berval bv, bv2;
2417 				bv = *(lr.lrop_mods[i]->mod_bvalues[j]);
2418 				REWRITE_VAL( si, ad, bv, bv2 );
2419 				ber_bvarray_add( &mod->sml_values, &bv2 );
2420 			}
2421 		}
2422 		mod->sml_numvals = j;
2423 
2424 		*modtail = mod;
2425 		modtail = &mod->sml_next;
2426 	}
2427 	ldap_ldif_record_done( &lr );
2428 
2429 	if ( req == LDAP_REQ_ADD && !BER_BVISNULL( uuid )) {
2430 		struct berval uuids[2];
2431 		if ( !syncrepl_dsee_uuid( uuid, uuids, ctx )) {
2432 			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
2433 			mod->sml_flags = 0;
2434 			mod->sml_op = LDAP_MOD_ADD;
2435 			mod->sml_next = NULL;
2436 			mod->sml_desc = slap_schema.si_ad_entryUUID;
2437 			mod->sml_type = slap_schema.si_ad_entryUUID->ad_cname;
2438 			mod->sml_values = ch_malloc( 2 * sizeof(struct berval));
2439 			mod->sml_nvalues = NULL;
2440 			ber_dupbv( &mod->sml_values[0], &uuids[1] );
2441 			BER_BVZERO( &mod->sml_values[1] );
2442 			slap_sl_free( uuids[0].bv_val, ctx );
2443 			slap_sl_free( uuids[1].bv_val, ctx );
2444 			mod->sml_numvals = 1;
2445 			*modtail = mod;
2446 			modtail = &mod->sml_next;
2447 		}
2448 	}
2449 
2450 	*modres = modlist;
2451 	return rc;
2452 }
2453 
2454 typedef struct OpExtraSync {
2455 	OpExtra oe;
2456 	syncinfo_t *oe_si;
2457 } OpExtraSync;
2458 
2459 /* Copy the original modlist, split Replace ops into Delete/Add,
2460  * and drop mod opattrs since this modification is in the past.
2461  */
mods_dup(Operation * op,Modifications * modlist,int match)2462 static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
2463 {
2464 	Modifications *mod, *modnew = NULL, *modtail = NULL;
2465 	int size;
2466 	for ( ; modlist; modlist = modlist->sml_next ) {
2467 		/* older ops */
2468 		if ( match < 0 ) {
2469 			if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
2470 				modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
2471 				modlist->sml_desc == slap_schema.si_ad_entryCSN )
2472 				continue;
2473 			if ( modlist->sml_values == NULL && modlist->sml_op == LDAP_MOD_REPLACE ) {
2474 				/* ITS#9359 This adds no values, just change to a delete op */
2475 				modlist->sml_op = LDAP_MOD_DELETE;
2476 			} else if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
2477 				mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
2478 				mod->sml_desc = modlist->sml_desc;
2479 				mod->sml_values = NULL;
2480 				mod->sml_nvalues = NULL;
2481 				mod->sml_op = LDAP_MOD_DELETE;
2482 				mod->sml_numvals = 0;
2483 				mod->sml_flags = 0;
2484 				if ( !modnew )
2485 					modnew = mod;
2486 				if ( modtail )
2487 					modtail->sml_next = mod;
2488 				modtail = mod;
2489 			}
2490 		}
2491 		if ( modlist->sml_numvals ) {
2492 			size = (modlist->sml_numvals+1) * sizeof(struct berval);
2493 			if ( modlist->sml_nvalues ) size *= 2;
2494 		} else {
2495 			size = 0;
2496 		}
2497 		size += sizeof(Modifications);
2498 		mod = op->o_tmpalloc( size, op->o_tmpmemctx );
2499 		if ( !modnew )
2500 			modnew = mod;
2501 		if ( modtail )
2502 			modtail->sml_next = mod;
2503 		modtail = mod;
2504 		mod->sml_desc = modlist->sml_desc;
2505 		mod->sml_numvals = modlist->sml_numvals;
2506 		mod->sml_flags = 0;
2507 		if ( modlist->sml_numvals ) {
2508 			int i;
2509 			mod->sml_values = (BerVarray)(mod+1);
2510 			for (i=0; i<mod->sml_numvals; i++)
2511 				mod->sml_values[i] = modlist->sml_values[i];
2512 			BER_BVZERO(&mod->sml_values[i]);
2513 			if ( modlist->sml_nvalues ) {
2514 				mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
2515 				for (i=0; i<mod->sml_numvals; i++)
2516 					mod->sml_nvalues[i] = modlist->sml_nvalues[i];
2517 				BER_BVZERO(&mod->sml_nvalues[i]);
2518 			} else {
2519 				mod->sml_nvalues = NULL;
2520 			}
2521 		} else {
2522 			mod->sml_values = NULL;
2523 			mod->sml_nvalues = NULL;
2524 		}
2525 		if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
2526 			mod->sml_op = LDAP_MOD_ADD;
2527 		else
2528 			mod->sml_op = modlist->sml_op;
2529 		mod->sml_next = NULL;
2530 	}
2531 	return modnew;
2532 }
2533 
2534 typedef struct resolve_ctxt {
2535 	syncinfo_t *rx_si;
2536 	Modifications *rx_mods;
2537 } resolve_ctxt;
2538 
2539 static void
compare_vals(Modifications * m1,Modifications * m2)2540 compare_vals( Modifications *m1, Modifications *m2 )
2541 {
2542 	int i, j;
2543 	struct berval *bv1, *bv2;
2544 
2545 	if ( m2->sml_nvalues ) {
2546 		bv2 = m2->sml_nvalues;
2547 		bv1 = m1->sml_nvalues;
2548 	} else {
2549 		bv2 = m2->sml_values;
2550 		bv1 = m1->sml_values;
2551 	}
2552 	for ( j=0; j<m2->sml_numvals; j++ ) {
2553 		for ( i=0; i<m1->sml_numvals; i++ ) {
2554 			if ( !ber_bvcmp( &bv1[i], &bv2[j] )) {
2555 				int k;
2556 				for ( k=i; k<m1->sml_numvals-1; k++ ) {
2557 					m1->sml_values[k] = m1->sml_values[k+1];
2558 					if ( m1->sml_nvalues )
2559 						m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
2560 				}
2561 				BER_BVZERO(&m1->sml_values[k]);
2562 				if ( m1->sml_nvalues ) {
2563 					BER_BVZERO(&m1->sml_nvalues[k]);
2564 				}
2565 				m1->sml_numvals--;
2566 				i--;
2567 			}
2568 		}
2569 	}
2570 }
2571 
2572 static int
syncrepl_resolve_cb(Operation * op,SlapReply * rs)2573 syncrepl_resolve_cb( Operation *op, SlapReply *rs )
2574 {
2575 	if ( rs->sr_type == REP_SEARCH ) {
2576 		resolve_ctxt *rx = op->o_callback->sc_private;
2577 		Attribute *a = attr_find( rs->sr_entry->e_attrs, ad_reqMod );
2578 		if ( a ) {
2579 			Modifications *oldmods, *newmods, *m1, *m2, **prev;
2580 			oldmods = rx->rx_mods;
2581 			syncrepl_accesslog_mods( rx->rx_si, a->a_vals, &newmods );
2582 			for ( m2 = newmods; m2; m2=m2->sml_next ) {
2583 				for ( prev = &oldmods, m1 = *prev; m1; m1 = *prev ) {
2584 					if ( m1->sml_desc != m2->sml_desc ) {
2585 						prev = &m1->sml_next;
2586 						continue;
2587 					}
2588 					if ( m2->sml_op == LDAP_MOD_DELETE ||
2589 						m2->sml_op == SLAP_MOD_SOFTDEL ||
2590 						m2->sml_op == LDAP_MOD_REPLACE ) {
2591 						int numvals = m2->sml_numvals;
2592 						if ( m2->sml_op == LDAP_MOD_REPLACE )
2593 							numvals = 0;
2594 						/* New delete All cancels everything */
2595 						if ( numvals == 0 ) {
2596 drop:
2597 							*prev = m1->sml_next;
2598 							op->o_tmpfree( m1, op->o_tmpmemctx );
2599 							continue;
2600 						}
2601 						if ( m1->sml_op == LDAP_MOD_DELETE ||
2602 							m1->sml_op == SLAP_MOD_SOFTDEL ) {
2603 							if ( m1->sml_numvals == 0 ) {
2604 								/* turn this to SOFTDEL later */
2605 								m1->sml_flags = SLAP_MOD_INTERNAL;
2606 							} else {
2607 								compare_vals( m1, m2 );
2608 								if ( !m1->sml_numvals )
2609 									goto drop;
2610 							}
2611 						} else if ( m1->sml_op == LDAP_MOD_ADD ) {
2612 							compare_vals( m1, m2 );
2613 							if ( !m1->sml_numvals )
2614 								goto drop;
2615 						}
2616 					}
2617 
2618 					if ( m2->sml_op == LDAP_MOD_ADD ||
2619 						m2->sml_op == LDAP_MOD_REPLACE ) {
2620 						if ( m1->sml_op == LDAP_MOD_DELETE ) {
2621 							if ( !m1->sml_numvals ) goto drop;
2622 							compare_vals( m1, m2 );
2623 							if ( !m1->sml_numvals )
2624 								goto drop;
2625 						}
2626 						if ( m2->sml_desc->ad_type->sat_atype.at_single_value )
2627 							goto drop;
2628 						compare_vals( m1, m2 );
2629 						if ( !m1->sml_numvals )
2630 							goto drop;
2631 					}
2632 					prev = &m1->sml_next;
2633 				}
2634 			}
2635 			slap_mods_free( newmods, 1 );
2636 			rx->rx_mods = oldmods;
2637 		}
2638 	}
2639 	return LDAP_SUCCESS;
2640 }
2641 
2642 typedef struct modify_ctxt {
2643 	Modifications *mx_orig;
2644 	Modifications *mx_free;
2645 } modify_ctxt;
2646 
2647 static int
syncrepl_modify_cb(Operation * op,SlapReply * rs)2648 syncrepl_modify_cb( Operation *op, SlapReply *rs )
2649 {
2650 	slap_callback *sc = op->o_callback;
2651 	modify_ctxt *mx = sc->sc_private;
2652 	Modifications *ml;
2653 
2654 	op->orm_no_opattrs = 0;
2655 	op->orm_modlist = mx->mx_orig;
2656 	for ( ml = mx->mx_free; ml; ml = mx->mx_free ) {
2657 		mx->mx_free = ml->sml_next;
2658 		op->o_tmpfree( ml, op->o_tmpmemctx );
2659 	}
2660 	op->o_callback = sc->sc_next;
2661 	op->o_tmpfree( sc, op->o_tmpmemctx );
2662 	return SLAP_CB_CONTINUE;
2663 }
2664 
2665 static int
syncrepl_op_modify(Operation * op,SlapReply * rs)2666 syncrepl_op_modify( Operation *op, SlapReply *rs )
2667 {
2668 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
2669 	OpExtra *oex;
2670 	syncinfo_t *si;
2671 	Entry *e;
2672 	int rc, match = 0;
2673 	Modifications *mod, *newlist;
2674 
2675 	LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
2676 		if ( oex->oe_key == (void *)syncrepl_message_to_op )
2677 			break;
2678 	}
2679 	if ( !oex )
2680 		return SLAP_CB_CONTINUE;
2681 
2682 	si = ((OpExtraSync *)oex)->oe_si;
2683 
2684 	/* Check if entryCSN in modlist is newer than entryCSN in entry.
2685 	 * We do it here because the op has been serialized by accesslog
2686 	 * by the time we get here. If the CSN is new enough, just do the
2687 	 * mod. If not, we need to resolve conflicts.
2688 	 */
2689 
2690 	for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
2691 		if ( mod->sml_desc == slap_schema.si_ad_entryCSN ) break;
2692 	}
2693 	/* FIXME: what should we do if entryCSN is missing from the mod? */
2694 	if ( !mod )
2695 		return SLAP_CB_CONTINUE;
2696 
2697 	{
2698 		int sid = slap_parse_csn_sid( &mod->sml_nvalues[0] );
2699 		ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
2700 		rc = check_csn_age( si, &op->o_req_dn, &mod->sml_nvalues[0],
2701 			sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL );
2702 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
2703 		if ( rc == CV_CSN_OLD ) {
2704 			slap_graduate_commit_csn( op );
2705 			/* tell accesslog this was a failure */
2706 			rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
2707 			return LDAP_SUCCESS;
2708 		}
2709 	}
2710 
2711 	rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
2712 	if ( rc == 0 ) {
2713 		Attribute *a;
2714 		const char *text;
2715 		a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
2716 		if ( a ) {
2717 			value_match( &match, slap_schema.si_ad_entryCSN,
2718 				slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
2719 				SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
2720 				&mod->sml_nvalues[0], &a->a_nvals[0], &text );
2721 		} else {
2722 			/* no entryCSN? shouldn't happen. assume mod is newer. */
2723 			match = 1;
2724 		}
2725 		overlay_entry_release_ov( op, e, 0, on );
2726 	} else {
2727 		return SLAP_CB_CONTINUE;
2728 	}
2729 
2730 	/* equal? Should never happen */
2731 	if ( match == 0 ) {
2732 		slap_graduate_commit_csn( op );
2733 		/* tell accesslog this was a failure */
2734 		rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
2735 		return LDAP_SUCCESS;
2736 	}
2737 
2738 	/* mod is older: resolve conflicts...
2739 	 * 1. Save/copy original modlist. Split Replace to Del/Add.
2740 	 * 2. Find all mods to this reqDN newer than the mod stamp.
2741 	 * 3. Resolve any mods in this request that affect attributes
2742 	 *    touched by newer mods.
2743 	 *    old         new
2744 	 *    delete all  delete all  drop
2745 	 *    delete all  delete X    SOFTDEL
2746 	 *    delete X    delete all  drop
2747 	 *    delete X    delete X    drop
2748 	 *    delete X    delete Y    OK
2749 	 *    delete all  add X       drop
2750 	 *    delete X    add X       drop
2751 	 *    delete X    add Y       OK
2752 	 *    add X       delete all  drop
2753 	 *    add X       delete X    drop
2754 	 *    add X       add X       drop
2755 	 *    add X       add Y       if SV, drop else OK
2756 	 *
2757 	 * 4. Swap original modlist back in response callback so
2758 	 *    that accesslog logs the original mod.
2759 	 *
2760 	 * Even if the mod is newer, other out-of-order changes may
2761 	 * have been committed, forcing us to tweak the modlist:
2762 	 * 1. Save/copy original modlist.
2763 	 * 2. Change deletes to soft deletes.
2764 	 * 3. Change Adds of single-valued attrs to Replace.
2765 	 */
2766 
2767 	newlist = mods_dup( op, op->orm_modlist, match );
2768 
2769 	/* mod is older */
2770 	if ( match < 0 ) {
2771 		Operation op2 = *op;
2772 		AttributeName an[2];
2773 		struct berval bv;
2774 		int size;
2775 		SlapReply rs1 = {0};
2776 		resolve_ctxt rx;
2777 		slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
2778         Filter lf[3] = {0};
2779         AttributeAssertion aa[2] = {0};
2780 
2781 		rx.rx_si = si;
2782 		rx.rx_mods = newlist;
2783 		cb.sc_private = &rx;
2784 
2785 		op2.o_tag = LDAP_REQ_SEARCH;
2786 		op2.ors_scope = LDAP_SCOPE_SUBTREE;
2787 		op2.ors_deref = LDAP_DEREF_NEVER;
2788 		op2.o_req_dn = si->si_logbase;
2789 		op2.o_req_ndn = si->si_logbase;
2790 		op2.ors_tlimit = SLAP_NO_LIMIT;
2791 		op2.ors_slimit = SLAP_NO_LIMIT;
2792 		op2.ors_limit = NULL;
2793 		memset( an, 0, sizeof(an));
2794 		an[0].an_desc = ad_reqMod;
2795 		an[0].an_name = ad_reqMod->ad_cname;
2796 		op2.ors_attrs = an;
2797 		op2.ors_attrsonly = 0;
2798 
2799 		bv = mod->sml_nvalues[0];
2800 
2801 		size = sizeof("(&(entryCSN>=)(reqDN=))");
2802 		size += bv.bv_len + op->o_req_ndn.bv_len + si->si_logfilterstr.bv_len;
2803 		op2.ors_filterstr.bv_val = op->o_tmpalloc( size, op->o_tmpmemctx );
2804 		op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
2805 			"(&(entryCSN>=%s)(reqDN=%s)%s)",
2806 			bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
2807 
2808         lf[0].f_choice = LDAP_FILTER_AND;
2809         lf[0].f_and = lf+1;
2810         lf[1].f_choice = LDAP_FILTER_GE;
2811         lf[1].f_ava = aa;
2812         lf[1].f_av_desc = slap_schema.si_ad_entryCSN;
2813         lf[1].f_av_value = bv;
2814         lf[1].f_next = lf+2;
2815         lf[2].f_choice = LDAP_FILTER_EQUALITY;
2816         lf[2].f_ava = aa+1;
2817         lf[2].f_av_desc = ad_reqDN;
2818         lf[2].f_av_value = op->o_req_ndn;
2819         lf[2].f_next = si->si_logfilter;
2820 
2821 		op2.ors_filter = lf;
2822 
2823 		op2.o_callback = &cb;
2824 		op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
2825 		op2.o_bd->be_search( &op2, &rs1 );
2826 		newlist = rx.rx_mods;
2827 	}
2828 
2829 	{
2830 		slap_callback *sc = op->o_tmpalloc( sizeof(slap_callback) +
2831 			sizeof(modify_ctxt), op->o_tmpmemctx );
2832 		modify_ctxt *mx = (modify_ctxt *)(sc+1);
2833 		Modifications *ml;
2834 
2835 		sc->sc_response = syncrepl_modify_cb;
2836 		sc->sc_private = mx;
2837 		sc->sc_next = op->o_callback;
2838 		sc->sc_cleanup = NULL;
2839 		sc->sc_writewait = NULL;
2840 		op->o_callback = sc;
2841 		op->orm_no_opattrs = 1;
2842 		mx->mx_orig = op->orm_modlist;
2843 		mx->mx_free = newlist;
2844 		for ( ml = newlist; ml; ml=ml->sml_next ) {
2845 			if ( ml->sml_flags == SLAP_MOD_INTERNAL ) {
2846 				ml->sml_flags = 0;
2847 				ml->sml_op = SLAP_MOD_SOFTDEL;
2848 			}
2849 			else if ( ml->sml_op == LDAP_MOD_DELETE )
2850 				ml->sml_op = SLAP_MOD_SOFTDEL;
2851 			else if ( ml->sml_op == LDAP_MOD_ADD &&
2852 				ml->sml_desc->ad_type->sat_atype.at_single_value )
2853 				ml->sml_op = LDAP_MOD_REPLACE;
2854 		}
2855 		op->orm_modlist = newlist;
2856 		op->o_csn = mod->sml_nvalues[0];
2857 	}
2858 	return SLAP_CB_CONTINUE;
2859 }
2860 
2861 static int
syncrepl_null_callback(Operation * op,SlapReply * rs)2862 syncrepl_null_callback(
2863 	Operation *op,
2864 	SlapReply *rs )
2865 {
2866 	/* If we're not the last callback in the chain, move to the end */
2867 	if ( op->o_callback->sc_next ) {
2868 		slap_callback **sc, *s1;
2869 		s1 = op->o_callback;
2870 		op->o_callback = op->o_callback->sc_next;
2871 		for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) ;
2872 		*sc = s1;
2873 		s1->sc_next = NULL;
2874 		return SLAP_CB_CONTINUE;
2875 	}
2876 	if ( rs->sr_err != LDAP_SUCCESS &&
2877 		rs->sr_err != LDAP_REFERRAL &&
2878 		rs->sr_err != LDAP_ALREADY_EXISTS &&
2879 		rs->sr_err != LDAP_NO_SUCH_OBJECT &&
2880 		rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
2881 	{
2882 		Debug( LDAP_DEBUG_ANY,
2883 			"syncrepl_null_callback : error code 0x%x\n",
2884 			rs->sr_err );
2885 	}
2886 	return LDAP_SUCCESS;
2887 }
2888 
2889 static int
syncrepl_message_to_op(syncinfo_t * si,Operation * op,LDAPMessage * msg,int do_lock)2890 syncrepl_message_to_op(
2891 	syncinfo_t	*si,
2892 	Operation	*op,
2893 	LDAPMessage	*msg,
2894 	int do_lock
2895 )
2896 {
2897 	BerElement	*ber = NULL;
2898 	Modifications	*modlist = NULL;
2899 	logschema *ls;
2900 	SlapReply rs = { REP_RESULT };
2901 	slap_callback cb = { NULL, syncrepl_null_callback, NULL, NULL };
2902 
2903 	const char	*text;
2904 	char txtbuf[SLAP_TEXT_BUFLEN];
2905 	size_t textlen = sizeof txtbuf;
2906 
2907 	struct berval	bdn, dn = BER_BVNULL, ndn;
2908 	struct berval	bv, bv2, *bvals = NULL;
2909 	struct berval	rdn = BER_BVNULL, sup = BER_BVNULL,
2910 		prdn = BER_BVNULL, nrdn = BER_BVNULL,
2911 		psup = BER_BVNULL, nsup = BER_BVNULL;
2912 	struct berval	dsee_uuid = BER_BVNULL, dsee_mods = BER_BVNULL;
2913 	int		rc, deleteOldRdn = 0, freeReqDn = 0;
2914 	int		do_graduate = 0, do_unlock = 0;
2915 	unsigned long changenum = 0;
2916 
2917 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
2918 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
2919 			"Message type should be entry (%d)",
2920 			si->si_ridtxt, ldap_msgtype( msg ) );
2921 		return -1;
2922 	}
2923 
2924 	if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
2925 		ls = &accesslog_sc;
2926 	else
2927 		ls = &changelog_sc;
2928 
2929 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
2930 
2931 	if ( rc != LDAP_SUCCESS ) {
2932 		Debug( LDAP_DEBUG_ANY,
2933 			"syncrepl_message_to_op: %s dn get failed (%d)",
2934 			si->si_ridtxt, rc );
2935 		return rc;
2936 	}
2937 
2938 	op->o_tag = LBER_DEFAULT;
2939 	op->o_bd = si->si_wbe;
2940 
2941 	if ( BER_BVISEMPTY( &bdn )) {
2942 		Debug( LDAP_DEBUG_ANY,
2943 			"syncrepl_message_to_op: %s got empty dn",
2944 			si->si_ridtxt );
2945 		return LDAP_OTHER;
2946 	}
2947 
2948 	while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
2949 		== LDAP_SUCCESS ) {
2950 		if ( bv.bv_val == NULL )
2951 			break;
2952 
2953 		if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
2954 			bdn = bvals[0];
2955 			REWRITE_DN( si, bdn, bv2, dn, ndn );
2956 			if ( rc != LDAP_SUCCESS ) {
2957 				Debug( LDAP_DEBUG_ANY,
2958 					"syncrepl_message_to_op: %s "
2959 					"dn \"%s\" normalization failed (%d)",
2960 					si->si_ridtxt, bdn.bv_val, rc );
2961 				rc = -1;
2962 				ch_free( bvals );
2963 				goto done;
2964 			}
2965 			ber_dupbv( &op->o_req_dn, &dn );
2966 			ber_dupbv( &op->o_req_ndn, &ndn );
2967 			slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
2968 			slap_sl_free( dn.bv_val, op->o_tmpmemctx );
2969 			freeReqDn = 1;
2970 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_req ) ) {
2971 			int i = verb_to_mask( bvals[0].bv_val, modops );
2972 			if ( i < 0 ) {
2973 				Debug( LDAP_DEBUG_ANY,
2974 					"syncrepl_message_to_op: %s unknown op %s",
2975 					si->si_ridtxt, bvals[0].bv_val );
2976 				ch_free( bvals );
2977 				rc = -1;
2978 				goto done;
2979 			}
2980 			op->o_tag = modops[i].mask;
2981 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
2982 			/* Parse attribute into modlist */
2983 			if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
2984 				rc = syncrepl_accesslog_mods( si, bvals, &modlist );
2985 			} else {
2986 				dsee_mods = bvals[0];
2987 			}
2988 			if ( rc ) goto done;
2989 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
2990 			rdn = bvals[0];
2991 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
2992 			if ( !ber_bvstrcasecmp( &slap_true_bv, bvals ) ) {
2993 				deleteOldRdn = 1;
2994 			}
2995 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) {
2996 			sup = bvals[0];
2997 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_controls ) ) {
2998 			int i;
2999 			struct berval rel_ctrl_bv;
3000 
3001 			(void)ber_str2bv( "{" LDAP_CONTROL_RELAX, 0, 0, &rel_ctrl_bv );
3002 			for ( i = 0; bvals[i].bv_val; i++ ) {
3003 				struct berval cbv, tmp;
3004 
3005 				ber_bvchr_post( &cbv, &bvals[i], '}' );
3006 				ber_bvchr_post( &tmp, &cbv, '{' );
3007 				ber_bvchr_pre( &cbv, &tmp, ' ' );
3008 				if ( cbv.bv_len == tmp.bv_len )		/* control w/o value */
3009 					ber_bvchr_pre( &cbv, &tmp, '}' );
3010 				if ( !ber_bvcmp( &cbv, &rel_ctrl_bv ) )
3011 					op->o_relax = SLAP_CONTROL_CRITICAL;
3012 			}
3013 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_uuid ) ) {
3014 			dsee_uuid = bvals[0];
3015 		} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_changenum ) ) {
3016 			changenum = strtoul( bvals->bv_val, NULL, 0 );
3017 		} else if ( !ber_bvstrcasecmp( &bv,
3018 			&slap_schema.si_ad_entryCSN->ad_cname ) )
3019 		{
3020 			slap_queue_csn( op, bvals );
3021 			do_graduate = 1;
3022 		}
3023 		ch_free( bvals );
3024 	}
3025 
3026 	/* don't parse mods until we've gotten the uuid */
3027 	if ( si->si_syncdata == SYNCDATA_CHANGELOG && !BER_BVISNULL( &dsee_mods )) {
3028 		rc = syncrepl_changelog_mods( si, op->o_tag,
3029 			&dsee_mods, &modlist, &dsee_uuid, op->o_tmpmemctx );
3030 		if ( rc )
3031 			goto done;
3032 	}
3033 
3034 	/* If we didn't get a mod type or a target DN, bail out */
3035 	if ( op->o_tag == LBER_DEFAULT || BER_BVISNULL( &dn ) ) {
3036 		rc = -1;
3037 		goto done;
3038 	}
3039 
3040 	if ( do_lock ) {
3041 		if (( rc = get_pmutex( si )))
3042 			goto done;
3043 		do_unlock = 1;
3044 	}
3045 
3046 	op->o_callback = &cb;
3047 	slap_op_time( &op->o_time, &op->o_tincr );
3048 
3049 	Debug( LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s tid %p\n",
3050 		si->si_ridtxt, (void *)op->o_tid );
3051 
3052 	switch( op->o_tag ) {
3053 	case LDAP_REQ_ADD:
3054 	case LDAP_REQ_MODIFY:
3055 		/* If we didn't get required data, bail */
3056 		if ( !modlist ) goto done;
3057 
3058 		rc = slap_mods_check( op, modlist, &text, txtbuf, textlen, NULL );
3059 
3060 		if ( rc != LDAP_SUCCESS ) {
3061 			Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
3062 				"mods check (%s)\n",
3063 				si->si_ridtxt, text );
3064 			goto done;
3065 		}
3066 
3067 		if ( op->o_tag == LDAP_REQ_ADD ) {
3068 			Entry *e = entry_alloc();
3069 			op->ora_e = e;
3070 			op->ora_e->e_name = op->o_req_dn;
3071 			op->ora_e->e_nname = op->o_req_ndn;
3072 			freeReqDn = 0;
3073 			rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen);
3074 			if( rc != LDAP_SUCCESS ) {
3075 				Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
3076 				"mods2entry (%s)\n",
3077 					si->si_ridtxt, text );
3078 			} else {
3079 				rc = op->o_bd->be_add( op, &rs );
3080 				Debug( LDAP_DEBUG_SYNC,
3081 					"syncrepl_message_to_op: %s be_add %s (%d)\n",
3082 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
3083 				do_graduate = 0;
3084 				if ( rc == LDAP_ALREADY_EXISTS ) {
3085 					Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
3086 					struct berval *vals;
3087 					if ( a && backend_attribute( op, NULL, &op->o_req_ndn,
3088 						slap_schema.si_ad_entryCSN, &vals, ACL_READ ) == LDAP_SUCCESS ) {
3089 						if ( ber_bvcmp( &vals[0], &a->a_vals[0] ) >= 0 )
3090 							rc = LDAP_SUCCESS;
3091 						ber_bvarray_free_x( vals, op->o_tmpmemctx );
3092  					}
3093 				}
3094 			}
3095 			if ( e == op->ora_e )
3096 				be_entry_release_w( op, op->ora_e );
3097 		} else {
3098 			OpExtraSync oes;
3099 			op->orm_modlist = modlist;
3100 			op->o_bd = si->si_wbe;
3101 			/* delta-mpr needs additional checks in syncrepl_op_modify */
3102 			if ( SLAP_MULTIPROVIDER( op->o_bd )) {
3103 				oes.oe.oe_key = (void *)syncrepl_message_to_op;
3104 				oes.oe_si = si;
3105 				LDAP_SLIST_INSERT_HEAD( &op->o_extra, &oes.oe, oe_next );
3106 			}
3107 			rc = op->o_bd->be_modify( op, &rs );
3108 			if ( SLAP_MULTIPROVIDER( op->o_bd )) {
3109 				LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
3110 				BER_BVZERO( &op->o_csn );
3111 			}
3112 			modlist = op->orm_modlist;
3113 			Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
3114 				"syncrepl_message_to_op: %s be_modify %s (%d)\n",
3115 				si->si_ridtxt, op->o_req_dn.bv_val, rc );
3116 			op->o_bd = si->si_be;
3117 			do_graduate = 0;
3118 		}
3119 		break;
3120 	case LDAP_REQ_MODRDN:
3121 		if ( BER_BVISNULL( &rdn ) ) goto done;
3122 
3123 		if ( rdnPretty( NULL, &rdn, &prdn, NULL ) ) {
3124 			goto done;
3125 		}
3126 		if ( rdnNormalize( 0, NULL, NULL, &rdn, &nrdn, NULL ) ) {
3127 			goto done;
3128 		}
3129 		if ( !BER_BVISNULL( &sup ) ) {
3130 			REWRITE_DN( si, sup, bv2, psup, nsup );
3131 			if ( rc )
3132 				goto done;
3133 			op->orr_newSup = &psup;
3134 			op->orr_nnewSup = &nsup;
3135 		} else {
3136 			op->orr_newSup = NULL;
3137 			op->orr_nnewSup = NULL;
3138 		}
3139 		op->orr_newrdn = prdn;
3140 		op->orr_nnewrdn = nrdn;
3141 		op->orr_deleteoldrdn = deleteOldRdn;
3142 		op->orr_modlist = NULL;
3143 		if ( slap_modrdn2mods( op, &rs ) ) {
3144 			goto done;
3145 		}
3146 
3147 		/* Append modlist for operational attrs */
3148 		{
3149 			Modifications *m;
3150 
3151 			for ( m = op->orr_modlist; m->sml_next; m = m->sml_next )
3152 				;
3153 			m->sml_next = modlist;
3154 			modlist = NULL;
3155 		}
3156 		rc = op->o_bd->be_modrdn( op, &rs );
3157 		slap_mods_free( op->orr_modlist, 1 );
3158 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
3159 			"syncrepl_message_to_op: %s be_modrdn %s (%d)\n",
3160 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
3161 		do_graduate = 0;
3162 		break;
3163 	case LDAP_REQ_DELETE:
3164 		rc = op->o_bd->be_delete( op, &rs );
3165 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
3166 			"syncrepl_message_to_op: %s be_delete %s (%d)\n",
3167 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
3168 		/* silently ignore this */
3169 		if ( rc == LDAP_NO_SUCH_OBJECT )
3170 			rc = LDAP_SUCCESS;
3171 		do_graduate = 0;
3172 		break;
3173 	}
3174 	if ( si->si_syncdata == SYNCDATA_CHANGELOG && !rc )
3175 		si->si_lastchange = changenum;
3176 
3177 done:
3178 	if ( do_graduate )
3179 		slap_graduate_commit_csn( op );
3180 	if ( do_unlock )
3181 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
3182 	op->o_bd = si->si_be;
3183 	op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
3184 	BER_BVZERO( &op->o_csn );
3185 	if ( modlist ) {
3186 		slap_mods_free( modlist, op->o_tag != LDAP_REQ_ADD );
3187 	}
3188 	if ( !BER_BVISNULL( &rdn ) ) {
3189 		if ( !BER_BVISNULL( &nsup ) ) {
3190 			ch_free( nsup.bv_val );
3191 		}
3192 		if ( !BER_BVISNULL( &psup ) ) {
3193 			ch_free( psup.bv_val );
3194 		}
3195 		if ( !BER_BVISNULL( &nrdn ) ) {
3196 			ch_free( nrdn.bv_val );
3197 		}
3198 		if ( !BER_BVISNULL( &prdn ) ) {
3199 			ch_free( prdn.bv_val );
3200 		}
3201 	}
3202 	if ( freeReqDn ) {
3203 		ch_free( op->o_req_ndn.bv_val );
3204 		ch_free( op->o_req_dn.bv_val );
3205 	}
3206 	ber_free( ber, 0 );
3207 	return rc;
3208 }
3209 
3210 static int
syncrepl_message_to_entry(syncinfo_t * si,Operation * op,LDAPMessage * msg,Modifications ** modlist,Entry ** entry,int syncstate,struct berval * syncUUID)3211 syncrepl_message_to_entry(
3212 	syncinfo_t	*si,
3213 	Operation	*op,
3214 	LDAPMessage	*msg,
3215 	Modifications	**modlist,
3216 	Entry			**entry,
3217 	int		syncstate,
3218 	struct berval	*syncUUID
3219 )
3220 {
3221 	Entry		*e = NULL;
3222 	BerElement	*ber = NULL;
3223 	Modifications	tmp;
3224 	Modifications	*mod;
3225 	Modifications	**modtail = modlist;
3226 
3227 	const char	*text;
3228 	char txtbuf[SLAP_TEXT_BUFLEN];
3229 	size_t textlen = sizeof txtbuf;
3230 
3231 	struct berval	bdn = BER_BVNULL, dn, ndn, bv2;
3232 	int		rc, is_ctx;
3233 
3234 	*modlist = NULL;
3235 
3236 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
3237 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s "
3238 			"Message type should be entry (%d)",
3239 			si->si_ridtxt, ldap_msgtype( msg ) );
3240 		return -1;
3241 	}
3242 
3243 	op->o_tag = LDAP_REQ_ADD;
3244 
3245 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
3246 	if ( rc != LDAP_SUCCESS ) {
3247 		Debug( LDAP_DEBUG_ANY,
3248 			"syncrepl_message_to_entry: %s dn get failed (%d)",
3249 			si->si_ridtxt, rc );
3250 		return rc;
3251 	}
3252 
3253 	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
3254 		Debug( LDAP_DEBUG_ANY,
3255 			"syncrepl_message_to_entry: %s got empty dn",
3256 			si->si_ridtxt );
3257 		return LDAP_OTHER;
3258 	}
3259 
3260 	if ( si->si_syncdata != SYNCDATA_CHANGELOG ) {
3261 		/* syncUUID[0] is normalized UUID received over the wire
3262 		 * syncUUID[1] is denormalized UUID, generated here
3263 		 */
3264 		(void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
3265 		Debug( LDAP_DEBUG_SYNC,
3266 			"syncrepl_message_to_entry: %s DN: %s, UUID: %s\n",
3267 			si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
3268 	}
3269 
3270 	if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
3271 		/* NOTE: this could be done even before decoding the DN,
3272 		 * although encoding errors wouldn't be detected */
3273 		rc = LDAP_SUCCESS;
3274 		goto done;
3275 	}
3276 
3277 	if ( entry == NULL ) {
3278 		return -1;
3279 	}
3280 
3281 	REWRITE_DN( si, bdn, bv2, dn, ndn );
3282 	if ( rc != LDAP_SUCCESS ) {
3283 		/* One of the things that could happen is that the schema
3284 		 * is not lined-up; this could result in unknown attributes.
3285 		 * A value non conformant to the syntax should be unlikely,
3286 		 * except when replicating between different versions
3287 		 * of the software, or when syntax validation bugs are fixed
3288 		 */
3289 		Debug( LDAP_DEBUG_ANY,
3290 			"syncrepl_message_to_entry: "
3291 			"%s dn \"%s\" normalization failed (%d)",
3292 			si->si_ridtxt, bdn.bv_val, rc );
3293 		return rc;
3294 	}
3295 
3296 	ber_dupbv( &op->o_req_dn, &dn );
3297 	ber_dupbv( &op->o_req_ndn, &ndn );
3298 	slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
3299 	slap_sl_free( dn.bv_val, op->o_tmpmemctx );
3300 
3301 	is_ctx = dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] );
3302 
3303 	e = entry_alloc();
3304 	e->e_name = op->o_req_dn;
3305 	e->e_nname = op->o_req_ndn;
3306 
3307 	while ( ber_remaining( ber ) ) {
3308 		if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
3309 			LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
3310 		{
3311 			break;
3312 		}
3313 
3314 		/* Drop all updates to the contextCSN of the context entry
3315 		 * (ITS#4622, etc.)
3316 		 */
3317 		if ( is_ctx && !strcasecmp( tmp.sml_type.bv_val,
3318 			slap_schema.si_ad_contextCSN->ad_cname.bv_val )) {
3319 			ber_bvarray_free( tmp.sml_values );
3320 			continue;
3321 		}
3322 
3323 		/* map nsUniqueId to entryUUID, drop nsUniqueId */
3324 		if ( si->si_syncdata == SYNCDATA_CHANGELOG &&
3325 			!strcasecmp( tmp.sml_type.bv_val, sy_ad_nsUniqueId->ad_cname.bv_val )) {
3326 			rc = syncrepl_dsee_uuid( &tmp.sml_values[0], syncUUID, op->o_tmpmemctx );
3327 			ber_bvarray_free( tmp.sml_values );
3328 			if ( rc )
3329 				goto done;
3330 			continue;
3331 		}
3332 
3333 		mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
3334 
3335 		mod->sml_op = LDAP_MOD_REPLACE;
3336 		mod->sml_flags = 0;
3337 		mod->sml_next = NULL;
3338 		mod->sml_desc = NULL;
3339 		mod->sml_type = tmp.sml_type;
3340 		mod->sml_values = tmp.sml_values;
3341 		mod->sml_nvalues = NULL;
3342 		mod->sml_numvals = 0;	/* slap_mods_check will set this */
3343 
3344 		if (si->si_rewrite) {
3345 			AttributeDescription *ad = NULL;
3346 			slap_bv2ad( &tmp.sml_type, &ad, &text );
3347 			if ( ad ) {
3348 				mod->sml_desc = ad;
3349 				mod->sml_type = ad->ad_cname;
3350 				if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
3351 					int i;
3352 					for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
3353 						syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
3354 						if ( !BER_BVISNULL( &bv2 )) {
3355 							ber_memfree( tmp.sml_values[i].bv_val );
3356 							tmp.sml_values[i] = bv2;
3357 						}
3358 					}
3359 				}
3360 			}
3361 		}
3362 		*modtail = mod;
3363 		modtail = &mod->sml_next;
3364 	}
3365 
3366 	if ( *modlist == NULL ) {
3367 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s no attributes\n",
3368 			si->si_ridtxt );
3369 		rc = -1;
3370 		goto done;
3371 	}
3372 
3373 	rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
3374 
3375 	if ( rc != LDAP_SUCCESS ) {
3376 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods check (%s)\n",
3377 			si->si_ridtxt, text );
3378 		goto done;
3379 	}
3380 
3381 	/* Strip out dynamically generated attrs */
3382 	for ( modtail = modlist; *modtail ; ) {
3383 		mod = *modtail;
3384 		if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
3385 			*modtail = mod->sml_next;
3386 			slap_mod_free( &mod->sml_mod, 0 );
3387 			ch_free( mod );
3388 		} else {
3389 			modtail = &mod->sml_next;
3390 		}
3391 	}
3392 
3393 	/* Strip out attrs in exattrs list */
3394 	for ( modtail = modlist; *modtail ; ) {
3395 		mod = *modtail;
3396 		if ( ldap_charray_inlist( si->si_exattrs,
3397 			mod->sml_desc->ad_type->sat_cname.bv_val ) )
3398 		{
3399 			*modtail = mod->sml_next;
3400 			slap_mod_free( &mod->sml_mod, 0 );
3401 			ch_free( mod );
3402 		} else {
3403 			modtail = &mod->sml_next;
3404 		}
3405 	}
3406 
3407 	rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
3408 	if( rc != LDAP_SUCCESS ) {
3409 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods2entry (%s)\n",
3410 			si->si_ridtxt, text );
3411 	}
3412 
3413 done:
3414 	ber_free( ber, 0 );
3415 	if ( rc != LDAP_SUCCESS ) {
3416 		if ( e ) {
3417 			entry_free( e );
3418 			e = NULL;
3419 		}
3420 	}
3421 	if ( entry )
3422 		*entry = e;
3423 
3424 	return rc;
3425 }
3426 
3427 #ifdef LDAP_CONTROL_X_DIRSYNC
3428 static int
syncrepl_dirsync_message(syncinfo_t * si,Operation * op,LDAPMessage * msg,Modifications ** modlist,Entry ** entry,int * syncstate,struct berval * syncUUID)3429 syncrepl_dirsync_message(
3430 	syncinfo_t	*si,
3431 	Operation	*op,
3432 	LDAPMessage	*msg,
3433 	Modifications	**modlist,
3434 	Entry			**entry,
3435 	int		*syncstate,
3436 	struct berval	*syncUUID
3437 )
3438 {
3439 	Entry		*e = NULL;
3440 	BerElement	*ber = NULL;
3441 	Modifications	tmp;
3442 	Modifications	*mod, *rangeMod = NULL;
3443 	Modifications	**modtail = modlist;
3444 
3445 	const char	*text;
3446 	char txtbuf[SLAP_TEXT_BUFLEN];
3447 	size_t textlen = sizeof txtbuf;
3448 
3449 	struct berval	bdn = BER_BVNULL, dn, ndn, bv2;
3450 	int		rc;
3451 
3452 	*modlist = NULL;
3453 	*syncstate = MSAD_DIRSYNC_MODIFY;
3454 
3455 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
3456 		Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s "
3457 			"Message type should be entry (%d)\n",
3458 			si->si_ridtxt, ldap_msgtype( msg ) );
3459 		return -1;
3460 	}
3461 
3462 	rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
3463 	if ( rc != LDAP_SUCCESS ) {
3464 		Debug( LDAP_DEBUG_ANY,
3465 			"syncrepl_dirsync_message: %s dn get failed (%d)\n",
3466 			si->si_ridtxt, rc );
3467 		return rc;
3468 	}
3469 
3470 	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
3471 		Debug( LDAP_DEBUG_ANY,
3472 			"syncrepl_dirsync_message: %s got empty dn\n",
3473 			si->si_ridtxt );
3474 		return LDAP_OTHER;
3475 	}
3476 
3477 	while ( ber_remaining( ber ) ) {
3478 		AttributeDescription *ad = NULL;
3479 
3480 		if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
3481 			LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
3482 		{
3483 			break;
3484 		}
3485 		if ( tmp.sml_values == NULL )
3486 			continue;
3487 
3488 		mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
3489 
3490 		mod->sml_op = LDAP_MOD_REPLACE;
3491 		mod->sml_flags = 0;
3492 		mod->sml_next = NULL;
3493 		mod->sml_desc = NULL;
3494 		mod->sml_type = tmp.sml_type;
3495 		mod->sml_values = tmp.sml_values;
3496 		mod->sml_nvalues = NULL;
3497 		mod->sml_numvals = 0;	/* slap_mods_check will set this */
3498 
3499 		rc = slap_bv2ad( &tmp.sml_type, &ad, &text );
3500 		if ( !ad ) {
3501 			Debug( LDAP_DEBUG_ANY,
3502 				"syncrepl_dirsync_message: %s unknown attributeType %s\n",
3503 				si->si_ridtxt, tmp.sml_type.bv_val );
3504 			return rc;
3505 		}
3506 		mod->sml_desc = ad;
3507 		mod->sml_type = ad->ad_cname;
3508 		if (( ad->ad_flags & SLAP_DESC_TAG_RANGE ) && rangeMod == NULL)
3509 			rangeMod = mod;
3510 		if (si->si_rewrite) {
3511 			if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
3512 				int i;
3513 				for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
3514 					syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
3515 					if ( !BER_BVISNULL( &bv2 )) {
3516 						ber_memfree( tmp.sml_values[i].bv_val );
3517 						tmp.sml_values[i] = bv2;
3518 					}
3519 				}
3520 			}
3521 		}
3522 		if ( mod->sml_desc == sy_ad_objectGUID ) {
3523 			ber_dupbv_x( &syncUUID[0], &tmp.sml_values[0], op->o_tmpmemctx );
3524 			/* syncUUID[0] is normalized UUID received over the wire
3525 			 * syncUUID[1] is denormalized UUID, generated here
3526 			 */
3527 			(void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
3528 			Debug( LDAP_DEBUG_SYNC,
3529 				"syncrepl_dirsync_message: %s DN: %s, UUID: %s\n",
3530 				si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
3531 		} else if ( mod->sml_desc == sy_ad_isDeleted ) {
3532 			*syncstate = LDAP_SYNC_DELETE;
3533 		} else if ( mod->sml_desc == sy_ad_whenCreated ) {
3534 			*syncstate = LDAP_SYNC_ADD;
3535 			*modtail = mod;
3536 			modtail = &mod->sml_next;
3537 			mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
3538 
3539 			mod->sml_op = LDAP_MOD_REPLACE;
3540 			mod->sml_flags = 0;
3541 			mod->sml_next = NULL;
3542 			mod->sml_desc = slap_schema.si_ad_createTimestamp;
3543 			mod->sml_type = mod->sml_desc->ad_cname;
3544 			ber_bvarray_dup_x( &mod->sml_values, tmp.sml_values, NULL );
3545 			mod->sml_nvalues = NULL;
3546 			mod->sml_numvals = 0;	/* slap_mods_check will set this */
3547 		}	/* else is a modify or modrdn */
3548 
3549 		*modtail = mod;
3550 		modtail = &mod->sml_next;
3551 	}
3552 
3553 	if ( *modlist == NULL ) {
3554 		Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s no attributes\n",
3555 			si->si_ridtxt );
3556 		rc = -1;
3557 		goto done;
3558 	}
3559 
3560 	if ( *syncstate == LDAP_SYNC_DELETE ) {
3561 		e = NULL;
3562 		slap_mods_free( *modlist, 1 );
3563 		*modlist = NULL;
3564 	} else {
3565 		/* check for incremental multival mods */
3566 		if ( *syncstate == MSAD_DIRSYNC_MODIFY && rangeMod != NULL ) {
3567 			for (; rangeMod; rangeMod = rangeMod->sml_next) {
3568 				if ( rangeMod->sml_desc->ad_flags & SLAP_DESC_TAG_RANGE ) {
3569 					if ( bvmatch( &rangeMod->sml_desc->ad_tags, &msad_addval ))
3570 						rangeMod->sml_op = SLAP_MOD_SOFTADD;
3571 					else if ( bvmatch( &rangeMod->sml_desc->ad_tags, &msad_delval ))
3572 						rangeMod->sml_op = SLAP_MOD_SOFTDEL;
3573 					/* turn the tagged attr into a normal one */
3574 					if ( rangeMod->sml_op != LDAP_MOD_REPLACE ) {
3575 						AttributeDescription *ad = NULL;
3576 						slap_bv2ad( &rangeMod->sml_desc->ad_type->sat_cname, &ad, &text );
3577 						rangeMod->sml_desc = ad;
3578 					}
3579 				}
3580 			}
3581 		}
3582 		rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
3583 
3584 		if ( rc != LDAP_SUCCESS ) {
3585 			Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s mods check (%s)\n",
3586 				si->si_ridtxt, text );
3587 			goto done;
3588 		}
3589 
3590 		REWRITE_DN( si, bdn, bv2, dn, ndn );
3591 		if ( rc != LDAP_SUCCESS ) {
3592 			/* One of the things that could happen is that the schema
3593 			 * is not lined-up; this could result in unknown attributes.
3594 			 * A value non conformant to the syntax should be unlikely,
3595 			 * except when replicating between different versions
3596 			 * of the software, or when syntax validation bugs are fixed
3597 			 */
3598 			Debug( LDAP_DEBUG_ANY,
3599 				"syncrepl_dirsync_message: "
3600 				"%s dn \"%s\" normalization failed (%d)",
3601 				si->si_ridtxt, bdn.bv_val, rc );
3602 			return rc;
3603 		}
3604 
3605 		ber_dupbv( &op->o_req_dn, &dn );
3606 		ber_dupbv( &op->o_req_ndn, &ndn );
3607 		slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
3608 		slap_sl_free( dn.bv_val, op->o_tmpmemctx );
3609 
3610 		e = entry_alloc();
3611 		e->e_name = op->o_req_dn;
3612 		e->e_nname = op->o_req_ndn;
3613 
3614 		/* Strip out redundant attrs */
3615 		if ( *syncstate == MSAD_DIRSYNC_MODIFY ) {
3616 			for ( modtail = modlist; *modtail ; ) {
3617 				mod = *modtail;
3618 				if ( mod->sml_desc == sy_ad_objectGUID ||
3619 					 mod->sml_desc == sy_ad_instanceType ) {
3620 					*modtail = mod->sml_next;
3621 					slap_mod_free( &mod->sml_mod, 0 );
3622 					ch_free( mod );
3623 				} else {
3624 					modtail = &mod->sml_next;
3625 				}
3626 			}
3627 		}
3628 
3629 		/* Strip out dynamically generated attrs */
3630 		for ( modtail = modlist; *modtail ; ) {
3631 			mod = *modtail;
3632 			if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
3633 				*modtail = mod->sml_next;
3634 				slap_mod_free( &mod->sml_mod, 0 );
3635 				ch_free( mod );
3636 			} else {
3637 				modtail = &mod->sml_next;
3638 			}
3639 		}
3640 
3641 		/* Strip out attrs in exattrs list */
3642 		for ( modtail = modlist; *modtail ; ) {
3643 			mod = *modtail;
3644 			if ( ldap_charray_inlist( si->si_exattrs,
3645 				mod->sml_desc->ad_type->sat_cname.bv_val ) )
3646 			{
3647 				*modtail = mod->sml_next;
3648 				slap_mod_free( &mod->sml_mod, 0 );
3649 				ch_free( mod );
3650 			} else {
3651 				modtail = &mod->sml_next;
3652 			}
3653 		}
3654 
3655 		rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
3656 		if( rc != LDAP_SUCCESS ) {
3657 			Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s mods2entry (%s)\n",
3658 				si->si_ridtxt, text );
3659 		}
3660 	}
3661 
3662 done:
3663 	ber_free( ber, 0 );
3664 	if ( rc != LDAP_SUCCESS ) {
3665 		if ( e ) {
3666 			entry_free( e );
3667 			e = NULL;
3668 		}
3669 	}
3670 	if ( entry )
3671 		*entry = e;
3672 
3673 	return rc;
3674 }
3675 
3676 static int
syncrepl_dirsync_cookie(syncinfo_t * si,Operation * op,LDAPControl ** ctrls)3677 syncrepl_dirsync_cookie(
3678 	syncinfo_t	*si,
3679 	Operation	*op,
3680 	LDAPControl	**ctrls
3681 )
3682 {
3683 	LDAPControl *ctrl, **next;
3684 	Backend *be = op->o_bd;
3685 	Modifications mod;
3686 	struct berval vals[2];
3687 
3688 	int rc, continueFlag;
3689 
3690 	slap_callback cb = { NULL };
3691 	SlapReply	rs_modify = {REP_RESULT};
3692 
3693 	ctrl = ldap_control_find( LDAP_CONTROL_X_DIRSYNC, ctrls, &next );
3694 	if ( ctrl == NULL ) {
3695 		ldap_controls_free( ctrls );
3696 		return -1;
3697 	}
3698 	rc = ldap_parse_dirsync_control( si->si_ld, ctrl, &continueFlag, &vals[0] );
3699 	if ( !bvmatch( &vals[0], &si->si_dirSyncCookie )) {
3700 
3701 		BER_BVZERO( &vals[1] );
3702 		mod.sml_op = LDAP_MOD_REPLACE;
3703 		mod.sml_desc = sy_ad_dirSyncCookie;
3704 		mod.sml_type = mod.sml_desc->ad_cname;
3705 		mod.sml_flags = SLAP_MOD_INTERNAL;
3706 		mod.sml_nvalues = NULL;
3707 		mod.sml_next = NULL;
3708 
3709 		op->o_bd = si->si_wbe;
3710 		op->o_tag = LDAP_REQ_MODIFY;
3711 
3712 		cb.sc_response = syncrepl_null_callback;
3713 		cb.sc_private = si;
3714 
3715 		op->o_callback = &cb;
3716 		op->o_req_dn = si->si_contextdn;
3717 		op->o_req_ndn = si->si_contextdn;
3718 
3719 		op->o_dont_replicate = 0;
3720 
3721 		slap_op_time( &op->o_time, &op->o_tincr );
3722 
3723 		mod.sml_numvals = 1;
3724 		mod.sml_values = vals;
3725 
3726 		op->orm_modlist = &mod;
3727 		op->orm_no_opattrs = 1;
3728 		rc = op->o_bd->be_modify( op, &rs_modify );
3729 		op->orm_no_opattrs = 0;
3730 
3731 		op->o_bd = be;
3732 		if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
3733 
3734 		if ( rc == LDAP_SUCCESS ) {
3735 			ber_bvreplace( &si->si_dirSyncCookie, &vals[0] );
3736 			/* there are more changes still remaining */
3737 			if ( continueFlag )
3738 				rc = LDAP_SYNC_REFRESH_REQUIRED;
3739 		}
3740 	}
3741 
3742 	ch_free( vals[0].bv_val );
3743 	ldap_controls_free( ctrls );
3744 	return rc;
3745 }
3746 
syncrepl_dirsync_schema()3747 static int syncrepl_dirsync_schema()
3748 {
3749 	const char *text;
3750 	int rc;
3751 
3752 	rc = slap_str2ad( "objectGUID", &sy_ad_objectGUID, &text );
3753 	if ( rc )
3754 		return rc;
3755 	rc = slap_str2ad( "instanceType", &sy_ad_instanceType, &text );
3756 	if ( rc )
3757 		return rc;
3758 	rc = slap_str2ad( "isDeleted", &sy_ad_isDeleted, &text );
3759 	if ( rc )
3760 		return rc;
3761 	rc = slap_str2ad( "whenCreated", &sy_ad_whenCreated, &text );
3762 	if ( rc )
3763 		return rc;
3764 	return register_at( "( 1.3.6.1.4.1.4203.666.1.27 "		/* OpenLDAP-specific */
3765 		"NAME 'dirSyncCookie' "
3766 		"DESC 'DirSync Cookie for shadow copy' "
3767 		"EQUALITY octetStringMatch "
3768 		"ORDERING octetStringOrderingMatch "
3769 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
3770 		"SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )", &sy_ad_dirSyncCookie, 0);
3771 }
3772 #endif /* LDAP_CONTROL_X_DIRSYNC */
3773 
syncrepl_dsee_schema()3774 static int syncrepl_dsee_schema()
3775 {
3776 	const char *text;
3777 	int rc;
3778 
3779 	rc = slap_str2ad( "nsUniqueId", &sy_ad_nsUniqueId, &text );
3780 	if ( rc )
3781 		return rc;
3782 	return register_at( "( 1.3.6.1.4.1.4203.666.1.28 "		/* OpenLDAP-specific */
3783 		"NAME 'lastChangeNumber' "
3784 		"DESC 'RetroChangelog latest change record' "
3785 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
3786 		"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", &sy_ad_dseeLastChange, 0);
3787 }
3788 
3789 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
3790  * entry if a previous refresh was interrupted before sending us a new
3791  * context state. We try to compare the new entry to the existing entry
3792  * and ignore the new entry if they are the same.
3793  *
3794  * Also, we may get an update where the entryDN has changed, due to
3795  * a ModDn on the provider. We detect this as well, so we can issue
3796  * the corresponding operation locally.
3797  *
3798  * In the case of a modify, we get a list of all the attributes
3799  * in the original entry. Rather than deleting the entry and re-adding it,
3800  * we issue a Modify request that deletes all the attributes and adds all
3801  * the new ones. This avoids the issue of trying to delete/add a non-leaf
3802  * entry.
3803  *
3804  * We otherwise distinguish ModDN from Modify; in the case of
3805  * a ModDN we just use the CSN, modifyTimestamp and modifiersName
3806  * operational attributes from the entry, and do a regular ModDN.
3807  */
3808 typedef struct dninfo {
3809 	syncinfo_t *si;
3810 	Entry *new_entry;
3811 	struct berval dn;
3812 	struct berval ndn;
3813 	struct berval nnewSup;
3814 	int syncstate;
3815 	int renamed;	/* Was an existing entry renamed? */
3816 	int delOldRDN;	/* Was old RDN deleted? */
3817 	Modifications **modlist;	/* the modlist we received */
3818 	Modifications *mods;	/* the modlist we compared */
3819 	int oldNcount;		/* #values of old naming attr */
3820 	AttributeDescription *oldDesc;	/* for renames */
3821 	AttributeDescription *newDesc;	/* for renames */
3822 } dninfo;
3823 
3824 #define HASHUUID	1
3825 
3826 /* return 1 if inserted, 0 otherwise */
3827 static int
presentlist_insert(syncinfo_t * si,struct berval * syncUUID)3828 presentlist_insert(
3829 	syncinfo_t* si,
3830 	struct berval *syncUUID )
3831 {
3832 	char *val;
3833 
3834 #ifdef HASHUUID
3835 	Avlnode **av;
3836 	unsigned short s;
3837 
3838 	if ( !si->si_presentlist )
3839 		si->si_presentlist = ch_calloc(65536, sizeof( Avlnode * ));
3840 
3841 	av = (Avlnode **)si->si_presentlist;
3842 
3843 	val = ch_malloc(UUIDLEN-2);
3844 	memcpy(&s, syncUUID->bv_val, 2);
3845 	memcpy(val, syncUUID->bv_val+2, UUIDLEN-2);
3846 
3847 	if ( ldap_avl_insert( &av[s], val,
3848 		syncuuid_cmp, ldap_avl_dup_error ) )
3849 	{
3850 		ch_free( val );
3851 		return 0;
3852 	}
3853 #else
3854 	val = ch_malloc(UUIDLEN);
3855 
3856 	AC_MEMCPY( val, syncUUID->bv_val, UUIDLEN );
3857 
3858 	if ( ldap_avl_insert( &si->si_presentlist, val,
3859 		syncuuid_cmp, ldap_avl_dup_error ) )
3860 	{
3861 		ch_free( val );
3862 		return 0;
3863 	}
3864 #endif
3865 
3866 	return 1;
3867 }
3868 
3869 static char *
presentlist_find(Avlnode * av,struct berval * val)3870 presentlist_find(
3871 	Avlnode *av,
3872 	struct berval *val )
3873 {
3874 #ifdef HASHUUID
3875 	Avlnode **a2 = (Avlnode **)av;
3876 	unsigned short s;
3877 
3878 	if (!av)
3879 		return NULL;
3880 
3881 	memcpy(&s, val->bv_val, 2);
3882 	return ldap_avl_find( a2[s], val->bv_val+2, syncuuid_cmp );
3883 #else
3884 	return ldap_avl_find( av, val->bv_val, syncuuid_cmp );
3885 #endif
3886 }
3887 
3888 static int
presentlist_free(Avlnode * av)3889 presentlist_free( Avlnode *av )
3890 {
3891 #ifdef HASHUUID
3892 	Avlnode **a2 = (Avlnode **)av;
3893 	int i, count = 0;
3894 
3895 	if ( av ) {
3896 		for (i=0; i<65536; i++) {
3897 			if (a2[i])
3898 				count += ldap_avl_free( a2[i], ch_free );
3899 		}
3900 		ch_free( av );
3901 	}
3902 	return count;
3903 #else
3904 	return ldap_avl_free( av, ch_free );
3905 #endif
3906 }
3907 
3908 static void
presentlist_delete(Avlnode ** av,struct berval * val)3909 presentlist_delete(
3910 	Avlnode **av,
3911 	struct berval *val )
3912 {
3913 #ifdef HASHUUID
3914 	Avlnode **a2 = *(Avlnode ***)av;
3915 	unsigned short s;
3916 
3917 	memcpy(&s, val->bv_val, 2);
3918 	ldap_avl_delete( &a2[s], val->bv_val+2, syncuuid_cmp );
3919 #else
3920 	ldap_avl_delete( av, val->bv_val, syncuuid_cmp );
3921 #endif
3922 }
3923 
3924 static int
syncrepl_entry(syncinfo_t * si,Operation * op,Entry * entry,Modifications ** modlist,int syncstate,struct berval * syncUUID,struct berval * syncCSN)3925 syncrepl_entry(
3926 	syncinfo_t* si,
3927 	Operation *op,
3928 	Entry* entry,
3929 	Modifications** modlist,
3930 	int syncstate,
3931 	struct berval* syncUUID,
3932 	struct berval* syncCSN )
3933 {
3934 	Backend *be = op->o_bd;
3935 	slap_callback	cb = { NULL, NULL, NULL, NULL };
3936 	int syncuuid_inserted = 0;
3937 
3938 	SlapReply	rs_search = {REP_RESULT};
3939 	Filter f = {0};
3940 	AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
3941 	int rc = LDAP_SUCCESS;
3942 
3943 	struct berval pdn = BER_BVNULL;
3944 	dninfo dni = {0};
3945 	int	retry = 1;
3946 	int	freecsn = 1;
3947 
3948 	Debug( LDAP_DEBUG_SYNC,
3949 		"syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) csn=%s tid %p\n",
3950 		si->si_ridtxt, syncrepl_state2str( syncstate ), syncCSN ? syncCSN->bv_val : "(none)", (void *)op->o_tid );
3951 
3952 	if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
3953 		if ( !si->si_refreshPresent && !si->si_refreshDone ) {
3954 			syncuuid_inserted = presentlist_insert( si, syncUUID );
3955 		}
3956 	}
3957 
3958 	if ( syncstate == LDAP_SYNC_PRESENT ) {
3959 		return 0;
3960 	} else if ( syncstate != LDAP_SYNC_DELETE ) {
3961 		if ( entry == NULL ) {
3962 			return 0;
3963 		}
3964 	}
3965 
3966 	if ( syncstate != LDAP_SYNC_DELETE ) {
3967 		Attribute	*a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
3968 
3969 		if ( a == NULL ) {
3970 			/* add if missing */
3971 			attr_merge_one( entry, slap_schema.si_ad_entryUUID,
3972 				&syncUUID[1], syncUUID );
3973 
3974 		} else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
3975 			/* replace only if necessary */
3976 			if ( a->a_nvals != a->a_vals ) {
3977 				ber_memfree( a->a_nvals[0].bv_val );
3978 				ber_dupbv( &a->a_nvals[0], syncUUID );
3979 			}
3980 			ber_memfree( a->a_vals[0].bv_val );
3981 			ber_dupbv( &a->a_vals[0], &syncUUID[1] );
3982 		}
3983 	}
3984 
3985 	f.f_choice = LDAP_FILTER_EQUALITY;
3986 	f.f_ava = &ava;
3987 	ava.aa_desc = slap_schema.si_ad_entryUUID;
3988 	ava.aa_value = *syncUUID;
3989 
3990 	if ( syncuuid_inserted ) {
3991 		Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
3992 			si->si_ridtxt, syncUUID[1].bv_val );
3993 	}
3994 	op->ors_filter = &f;
3995 
3996 	op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID[1].bv_len;
3997 	op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
3998 		op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
3999 	AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
4000 	AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
4001 		syncUUID[1].bv_val, syncUUID[1].bv_len );
4002 	op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
4003 	op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
4004 
4005 	op->o_tag = LDAP_REQ_SEARCH;
4006 	op->ors_scope = LDAP_SCOPE_SUBTREE;
4007 	op->ors_deref = LDAP_DEREF_NEVER;
4008 
4009 	/* get the entry for this UUID */
4010 	if ( si->si_rewrite ) {
4011 		op->o_req_dn = si->si_suffixm;
4012 		op->o_req_ndn = si->si_suffixm;
4013 	} else
4014 	{
4015 		op->o_req_dn = si->si_base;
4016 		op->o_req_ndn = si->si_base;
4017 	}
4018 
4019 	op->o_time = slap_get_time();
4020 	op->ors_tlimit = SLAP_NO_LIMIT;
4021 	op->ors_slimit = 1;
4022 	op->ors_limit = NULL;
4023 
4024 	op->ors_attrs = slap_anlist_all_attributes;
4025 	op->ors_attrsonly = 0;
4026 
4027 	/* set callback function */
4028 	op->o_callback = &cb;
4029 	cb.sc_response = dn_callback;
4030 	cb.sc_private = &dni;
4031 	dni.si = si;
4032 	dni.new_entry = entry;
4033 	dni.modlist = modlist;
4034 	dni.syncstate = syncstate;
4035 
4036 	rc = be->be_search( op, &rs_search );
4037 	Debug( LDAP_DEBUG_SYNC,
4038 			"syncrepl_entry: %s be_search (%d)\n",
4039 			si->si_ridtxt, rc );
4040 
4041 	if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
4042 		slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
4043 	}
4044 
4045 	cb.sc_response = syncrepl_null_callback;
4046 	cb.sc_private = si;
4047 
4048 	if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
4049 		Debug( LDAP_DEBUG_SYNC,
4050 				"syncrepl_entry: %s %s\n",
4051 				si->si_ridtxt, entry->e_name.bv_val );
4052 	} else {
4053 		Debug( LDAP_DEBUG_SYNC,
4054 				"syncrepl_entry: %s %s\n",
4055 				si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)" );
4056 	}
4057 
4058 	assert( BER_BVISNULL( &op->o_csn ) );
4059 	if ( syncCSN ) {
4060 		slap_queue_csn( op, syncCSN );
4061 	}
4062 
4063 #ifdef SLAP_CONTROL_X_LAZY_COMMIT
4064 	if ( !si->si_refreshDone && si->si_lazyCommit )
4065 		op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL;
4066 #endif
4067 
4068 	slap_op_time( &op->o_time, &op->o_tincr );
4069 	switch ( syncstate ) {
4070 	case LDAP_SYNC_ADD:
4071 	case LDAP_SYNC_MODIFY:
4072 	case DSEE_SYNC_ADD:
4073 		if ( BER_BVISNULL( &op->o_csn ))
4074 		{
4075 
4076 			Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryCSN );
4077 			if ( a ) {
4078 				/* FIXME: op->o_csn is assumed to be
4079 				 * on the thread's slab; this needs
4080 				 * to be cleared ASAP.
4081 				 */
4082 				op->o_csn = a->a_vals[0];
4083 				freecsn = 0;
4084 			}
4085 		}
4086 retry_add:;
4087 		if ( BER_BVISNULL( &dni.dn ) ) {
4088 			SlapReply	rs_add = {REP_RESULT};
4089 
4090 			op->o_req_dn = entry->e_name;
4091 			op->o_req_ndn = entry->e_nname;
4092 			op->o_tag = LDAP_REQ_ADD;
4093 			op->ora_e = entry;
4094 			op->o_bd = si->si_wbe;
4095 
4096 			rc = op->o_bd->be_add( op, &rs_add );
4097 			Debug( LDAP_DEBUG_SYNC,
4098 					"syncrepl_entry: %s be_add %s (%d)\n",
4099 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
4100 			switch ( rs_add.sr_err ) {
4101 			case LDAP_SUCCESS:
4102 				if ( op->ora_e == entry ) {
4103 					be_entry_release_w( op, entry );
4104 				}
4105 				entry = NULL;
4106 				break;
4107 
4108 			case LDAP_REFERRAL:
4109 			/* we assume that LDAP_NO_SUCH_OBJECT is returned
4110 			 * only if the suffix entry is not present.
4111 			 * This should not happen during Persist phase.
4112 			 */
4113 			case LDAP_NO_SUCH_OBJECT:
4114 				if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
4115 					si->si_refreshDone ) {
4116 					/* Something's wrong, start over */
4117 					ber_bvarray_free( si->si_syncCookie.ctxcsn );
4118 					si->si_syncCookie.ctxcsn = NULL;
4119 					entry_free( entry );
4120 					ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
4121 					ber_bvarray_free( si->si_cookieState->cs_vals );
4122 					ch_free( si->si_cookieState->cs_sids );
4123 					si->si_cookieState->cs_vals = NULL;
4124 					si->si_cookieState->cs_sids = 0;
4125 					si->si_cookieState->cs_num = 0;
4126 					ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
4127 					return LDAP_NO_SUCH_OBJECT;
4128 				}
4129 				rc = syncrepl_add_glue( op, entry );
4130 				entry = NULL;
4131 				break;
4132 
4133 			/* if an entry was added via syncrepl_add_glue(),
4134 			 * it likely has no entryUUID, so the previous
4135 			 * be_search() doesn't find it.  In this case,
4136 			 * give syncrepl a chance to modify it. Also
4137 			 * allow for entries that were recreated with the
4138 			 * same DN but a different entryUUID.
4139 			 */
4140 			case LDAP_ALREADY_EXISTS:
4141 				if ( retry ) {
4142 					Operation	op2 = *op;
4143 					SlapReply	rs2 = { REP_RESULT };
4144 					slap_callback	cb2 = { 0 };
4145 
4146 					op2.o_bd = be;
4147 					op2.o_tag = LDAP_REQ_SEARCH;
4148 					op2.o_req_dn = entry->e_name;
4149 					op2.o_req_ndn = entry->e_nname;
4150 					op2.ors_scope = LDAP_SCOPE_BASE;
4151 					op2.ors_deref = LDAP_DEREF_NEVER;
4152 					op2.ors_attrs = slap_anlist_all_attributes;
4153 					op2.ors_attrsonly = 0;
4154 					op2.ors_limit = NULL;
4155 					op2.ors_slimit = 1;
4156 					op2.ors_tlimit = SLAP_NO_LIMIT;
4157 
4158 					f.f_choice = LDAP_FILTER_PRESENT;
4159 					f.f_desc = slap_schema.si_ad_objectClass;
4160 					op2.ors_filter = &f;
4161 					op2.ors_filterstr = generic_filterstr;
4162 
4163 					op2.o_callback = &cb2;
4164 					cb2.sc_response = dn_callback;
4165 					cb2.sc_private = &dni;
4166 
4167 					rc = be->be_search( &op2, &rs2 );
4168 					if ( rc ) goto done;
4169 
4170 					retry = 0;
4171 					slap_op_time( &op->o_time, &op->o_tincr );
4172 					goto retry_add;
4173 				}
4174 				/* FALLTHRU */
4175 
4176 			default:
4177 				Debug( LDAP_DEBUG_ANY,
4178 					"syncrepl_entry: %s be_add %s failed (%d)\n",
4179 					si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
4180 				break;
4181 			}
4182 			syncCSN = NULL;
4183 			op->o_bd = be;
4184 			goto done;
4185 		}
4186 		/* FALLTHRU */
4187 #ifdef LDAP_CONTROL_X_DIRSYNC
4188 	case MSAD_DIRSYNC_MODIFY:
4189 #endif
4190 		op->o_req_dn = dni.dn;
4191 		op->o_req_ndn = dni.ndn;
4192 		if ( dni.renamed ) {
4193 			struct berval noldp, newp;
4194 			Modifications *mod, **modtail, **ml, *m2 = NULL;
4195 			int i, got_replace = 0, just_rename = 0;
4196 			SlapReply rs_modify = {REP_RESULT};
4197 
4198 			op->o_tag = LDAP_REQ_MODRDN;
4199 			dnRdn( &entry->e_name, &op->orr_newrdn );
4200 			dnRdn( &entry->e_nname, &op->orr_nnewrdn );
4201 
4202 			if ( !BER_BVISNULL( &dni.nnewSup )) {
4203 				dnParent( &entry->e_name, &newp );
4204 				op->orr_newSup = &newp;
4205 				op->orr_nnewSup = &dni.nnewSup;
4206 			} else {
4207 				op->orr_newSup = NULL;
4208 				op->orr_nnewSup = NULL;
4209 			}
4210 			op->orr_deleteoldrdn = dni.delOldRDN;
4211 			op->orr_modlist = NULL;
4212 #ifdef LDAP_CONTROL_X_DIRSYNC
4213 			if ( syncstate != MSAD_DIRSYNC_MODIFY )
4214 #endif
4215 			{
4216 				if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
4217 					goto done;
4218 				}
4219 			}
4220 
4221 			/* Drop the RDN-related mods from this op, because their
4222 			 * equivalents were just setup by slap_modrdn2mods.
4223 			 *
4224 			 * If delOldRDN is TRUE then we should see a delete modop
4225 			 * for oldDesc. We might see a replace instead.
4226 			 *  delete with no values: therefore newDesc != oldDesc.
4227 			 *   if oldNcount == 1, then Drop this op.
4228 			 *  delete with 1 value: can only be the oldRDN value. Drop op.
4229 			 *  delete with N values: Drop oldRDN value, keep remainder.
4230 			 *  replace with 1 value: if oldNcount == 1 and
4231 			 *     newDesc == oldDesc, Drop this op.
4232 			 * Any other cases must be left intact.
4233 			 *
4234 			 * We should also see an add modop for newDesc. (But not if
4235 			 * we got a replace modop due to delOldRDN.) If it has
4236 			 * multiple values, we'll have to drop the new RDN value.
4237 			 */
4238 			modtail = &op->orr_modlist;
4239 			if ( dni.delOldRDN ) {
4240 				for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
4241 					if ( (*ml)->sml_desc == dni.oldDesc ) {
4242 						mod = *ml;
4243 						if ( mod->sml_op == LDAP_MOD_REPLACE &&
4244 							dni.oldDesc != dni.newDesc ) {
4245 							/* This Replace is due to other Mods.
4246 							 * Just let it ride.
4247 							 */
4248 							continue;
4249 						}
4250 						if ( mod->sml_numvals <= 1 &&
4251 							dni.oldNcount == 1 &&
4252 							( mod->sml_op == LDAP_MOD_DELETE ||
4253 							  mod->sml_op == LDAP_MOD_REPLACE )) {
4254 							if ( mod->sml_op == LDAP_MOD_REPLACE )
4255 								got_replace = 1;
4256 							/* Drop this op */
4257 							*ml = mod->sml_next;
4258 							mod->sml_next = NULL;
4259 							slap_mods_free( mod, 1 );
4260 							break;
4261 						}
4262 						if ( mod->sml_op != LDAP_MOD_DELETE || mod->sml_numvals == 0 )
4263 							continue;
4264 						for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
4265 							if ( m2->sml_desc == dni.oldDesc &&
4266 								m2->sml_op == LDAP_MOD_DELETE ) break;
4267 						}
4268 						for ( i=0; i<mod->sml_numvals; i++ ) {
4269 							if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
4270 								mod->sml_numvals--;
4271 								ch_free( mod->sml_values[i].bv_val );
4272 								mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
4273 								BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
4274 								if ( mod->sml_nvalues ) {
4275 									ch_free( mod->sml_nvalues[i].bv_val );
4276 									mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
4277 									BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
4278 								}
4279 								break;
4280 							}
4281 						}
4282 						if ( !mod->sml_numvals ) {
4283 							/* Drop this op */
4284 							*ml = mod->sml_next;
4285 							mod->sml_next = NULL;
4286 							slap_mods_free( mod, 1 );
4287 						}
4288 						break;
4289 					}
4290 				}
4291 			}
4292 			if ( !got_replace ) {
4293 				for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
4294 					if ( (*ml)->sml_desc == dni.newDesc ) {
4295 						mod = *ml;
4296 						if ( mod->sml_op != LDAP_MOD_ADD )
4297 							continue;
4298 						if ( mod->sml_numvals == 1 ) {
4299 							/* Drop this op */
4300 							*ml = mod->sml_next;
4301 							mod->sml_next = NULL;
4302 							slap_mods_free( mod, 1 );
4303 							break;
4304 						}
4305 						for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
4306 							if ( m2->sml_desc == dni.oldDesc &&
4307 								m2->sml_op == SLAP_MOD_SOFTADD ) break;
4308 						}
4309 						for ( i=0; i<mod->sml_numvals; i++ ) {
4310 							if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
4311 								mod->sml_numvals--;
4312 								ch_free( mod->sml_values[i].bv_val );
4313 								mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
4314 								BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
4315 								if ( mod->sml_nvalues ) {
4316 									ch_free( mod->sml_nvalues[i].bv_val );
4317 									mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
4318 									BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
4319 								}
4320 								break;
4321 							}
4322 						}
4323 						break;
4324 					}
4325 				}
4326 			}
4327 
4328 			/* RDNs must be NUL-terminated for back-ldap */
4329 			noldp = op->orr_newrdn;
4330 			ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
4331 			noldp = op->orr_nnewrdn;
4332 			ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
4333 
4334 			/* Setup opattrs too */
4335 			{
4336 				static AttributeDescription *nullattr = NULL;
4337 				static AttributeDescription **const opattrs[] = {
4338 					&slap_schema.si_ad_entryCSN,
4339 					&slap_schema.si_ad_modifiersName,
4340 					&slap_schema.si_ad_modifyTimestamp,
4341 					&nullattr
4342 				};
4343 				AttributeDescription *opattr;
4344 				int i;
4345 
4346 				modtail = &m2;
4347 				/* pull mod off incoming modlist */
4348 				for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
4349 					for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next )
4350 					{
4351 						if ( (*ml)->sml_desc == opattr ) {
4352 							mod = *ml;
4353 							*ml = mod->sml_next;
4354 							mod->sml_next = NULL;
4355 							*modtail = mod;
4356 							modtail = &mod->sml_next;
4357 							break;
4358 						}
4359 					}
4360 				}
4361 				/* If there are still Modifications left, put the opattrs
4362 				 * back, and let be_modify run. Otherwise, append the opattrs
4363 				 * to the orr_modlist.
4364 				 */
4365 				if ( dni.mods ) {
4366 					mod = dni.mods;
4367 					/* don't set a CSN for the rename op */
4368 					if ( syncCSN )
4369 						slap_graduate_commit_csn( op );
4370 				} else {
4371 					mod = op->orr_modlist;
4372 					just_rename = 1;
4373 				}
4374 				for ( ; mod->sml_next; mod=mod->sml_next );
4375 				mod->sml_next = m2;
4376 			}
4377 			op->o_bd = si->si_wbe;
4378 retry_modrdn:;
4379 			rs_reinit( &rs_modify, REP_RESULT );
4380 			rc = op->o_bd->be_modrdn( op, &rs_modify );
4381 
4382 			/* NOTE: noSuchObject should result because the new superior
4383 			 * has not been added yet (ITS#6472) */
4384 			if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
4385 				Operation op2 = *op;
4386 				rc = syncrepl_add_glue_ancestors( &op2, entry );
4387 				if ( rc == LDAP_SUCCESS ) {
4388 					goto retry_modrdn;
4389 				}
4390 			}
4391 
4392 			op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
4393 			op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
4394 
4395 			slap_mods_free( op->orr_modlist, 1 );
4396 			Debug( LDAP_DEBUG_SYNC,
4397 					"syncrepl_entry: %s be_modrdn %s (%d)\n",
4398 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
4399 			op->o_bd = be;
4400 			/* Renamed entries may still have other mods so just fallthru */
4401 			op->o_req_dn = entry->e_name;
4402 			op->o_req_ndn = entry->e_nname;
4403 			/* Use CSN on the modify */
4404 			if ( just_rename )
4405 				syncCSN = NULL;
4406 			else if ( syncCSN )
4407 				slap_queue_csn( op, syncCSN );
4408 		}
4409 		if ( dni.mods ) {
4410 			SlapReply rs_modify = {REP_RESULT};
4411 
4412 			op->o_tag = LDAP_REQ_MODIFY;
4413 			op->orm_modlist = dni.mods;
4414 			op->orm_no_opattrs = 1;
4415 			op->o_bd = si->si_wbe;
4416 
4417 			rc = op->o_bd->be_modify( op, &rs_modify );
4418 			slap_mods_free( op->orm_modlist, 1 );
4419 			op->orm_no_opattrs = 0;
4420 			Debug( LDAP_DEBUG_SYNC,
4421 					"syncrepl_entry: %s be_modify %s (%d)\n",
4422 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
4423 			if ( rs_modify.sr_err != LDAP_SUCCESS ) {
4424 				Debug( LDAP_DEBUG_ANY,
4425 					"syncrepl_entry: %s be_modify failed (%d)\n",
4426 					si->si_ridtxt, rs_modify.sr_err );
4427 			}
4428 			syncCSN = NULL;
4429 			op->o_bd = be;
4430 		} else if ( !dni.renamed ) {
4431 			Debug( LDAP_DEBUG_SYNC,
4432 					"syncrepl_entry: %s entry unchanged, ignored (%s)\n",
4433 					si->si_ridtxt, op->o_req_dn.bv_val );
4434 			if ( syncCSN ) {
4435 				slap_graduate_commit_csn( op );
4436 				syncCSN = NULL;
4437 			}
4438 		}
4439 		goto done;
4440 	case LDAP_SYNC_DELETE :
4441 		if ( !BER_BVISNULL( &dni.dn ) ) {
4442 			SlapReply	rs_delete = {REP_RESULT};
4443 			op->o_req_dn = dni.dn;
4444 			op->o_req_ndn = dni.ndn;
4445 			op->o_tag = LDAP_REQ_DELETE;
4446 			op->o_bd = si->si_wbe;
4447 			if ( !syncCSN && si->si_syncCookie.ctxcsn ) {
4448 				slap_queue_csn( op, si->si_syncCookie.ctxcsn );
4449 			}
4450 			rc = op->o_bd->be_delete( op, &rs_delete );
4451 			Debug( LDAP_DEBUG_SYNC,
4452 					"syncrepl_entry: %s be_delete %s (%d)\n",
4453 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
4454 			if ( rc == LDAP_NO_SUCH_OBJECT )
4455 				rc = LDAP_SUCCESS;
4456 
4457 			while ( rs_delete.sr_err == LDAP_SUCCESS
4458 				&& op->o_delete_glue_parent ) {
4459 				op->o_delete_glue_parent = 0;
4460 				if ( !be_issuffix( be, &op->o_req_ndn ) ) {
4461 					slap_callback cb = { NULL };
4462 					cb.sc_response = syncrepl_null_callback;
4463 					dnParent( &op->o_req_ndn, &pdn );
4464 					op->o_req_dn = pdn;
4465 					op->o_req_ndn = pdn;
4466 					op->o_callback = &cb;
4467 					rs_reinit( &rs_delete, REP_RESULT );
4468 					op->o_bd->be_delete( op, &rs_delete );
4469 				} else {
4470 					break;
4471 				}
4472 			}
4473 			syncCSN = NULL;
4474 			op->o_bd = be;
4475 		}
4476 		goto done;
4477 
4478 	default :
4479 		Debug( LDAP_DEBUG_ANY,
4480 			"syncrepl_entry: %s unknown syncstate\n", si->si_ridtxt );
4481 		goto done;
4482 	}
4483 
4484 done:
4485 	slap_sl_free( syncUUID[1].bv_val, op->o_tmpmemctx );
4486 	BER_BVZERO( &syncUUID[1] );
4487 	if ( !BER_BVISNULL( &dni.ndn ) ) {
4488 		op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
4489 	}
4490 	if ( !BER_BVISNULL( &dni.dn ) ) {
4491 		op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
4492 	}
4493 	if ( entry ) {
4494 		entry_free( entry );
4495 	}
4496 	if ( syncCSN ) {
4497 		slap_graduate_commit_csn( op );
4498 	}
4499 	if ( !BER_BVISNULL( &op->o_csn ) && freecsn ) {
4500 		op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
4501 	}
4502 	BER_BVZERO( &op->o_csn );
4503 	return rc;
4504 }
4505 
4506 static struct berval gcbva[] = {
4507 	BER_BVC("top"),
4508 	BER_BVC("glue"),
4509 	BER_BVNULL
4510 };
4511 
4512 #define NP_DELETE_ONE	2
4513 
4514 static void
syncrepl_del_nonpresent(Operation * op,syncinfo_t * si,BerVarray uuids,struct sync_cookie * sc,int m)4515 syncrepl_del_nonpresent(
4516 	Operation *op,
4517 	syncinfo_t *si,
4518 	BerVarray uuids,
4519 	struct sync_cookie *sc,
4520 	int m )
4521 {
4522 	Backend* be = op->o_bd;
4523 	slap_callback	cb = { NULL };
4524 	struct nonpresent_entry *np_list, *np_prev;
4525 	int rc;
4526 	AttributeName	an[3]; /* entryUUID, entryCSN, NULL */
4527 
4528 	struct berval pdn = BER_BVNULL;
4529 	struct berval csn;
4530 
4531 	if ( si->si_rewrite ) {
4532 		op->o_req_dn = si->si_suffixm;
4533 		op->o_req_ndn = si->si_suffixm;
4534 	} else
4535 	{
4536 		op->o_req_dn = si->si_base;
4537 		op->o_req_ndn = si->si_base;
4538 	}
4539 
4540 	cb.sc_response = nonpresent_callback;
4541 	cb.sc_private = si;
4542 
4543 	op->o_callback = &cb;
4544 	op->o_tag = LDAP_REQ_SEARCH;
4545 	op->ors_scope = si->si_scope;
4546 	op->ors_deref = LDAP_DEREF_NEVER;
4547 	op->o_time = slap_get_time();
4548 	op->ors_tlimit = SLAP_NO_LIMIT;
4549 
4550 
4551 	if ( uuids ) {
4552 		Filter uf;
4553 		AttributeAssertion eq = ATTRIBUTEASSERTION_INIT;
4554 		int i;
4555 
4556 		op->ors_attrsonly = 1;
4557 		op->ors_attrs = slap_anlist_no_attrs;
4558 		op->ors_limit = NULL;
4559 		op->ors_filter = &uf;
4560 
4561 		uf.f_ava = &eq;
4562 		uf.f_av_desc = slap_schema.si_ad_entryUUID;
4563 		uf.f_next = NULL;
4564 		uf.f_choice = LDAP_FILTER_EQUALITY;
4565 		si->si_refreshDelete |= NP_DELETE_ONE;
4566 
4567 		for (i=0; uuids[i].bv_val; i++) {
4568 			SlapReply rs_search = {REP_RESULT};
4569 
4570 			op->ors_slimit = 1;
4571 			uf.f_av_value = uuids[i];
4572 			filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
4573 			Debug( LDAP_DEBUG_SYNC, "syncrepl_del_nonpresent: %s "
4574 				"checking non-present filter=%s\n",
4575 				si->si_ridtxt, op->ors_filterstr.bv_val );
4576 			rc = be->be_search( op, &rs_search );
4577 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
4578 		}
4579 		si->si_refreshDelete ^= NP_DELETE_ONE;
4580 	} else {
4581 		Filter *cf, *of;
4582 		Filter mmf[2];
4583 		AttributeAssertion mmaa;
4584 		SlapReply rs_search = {REP_RESULT};
4585 
4586 		memset( &an[0], 0, 3 * sizeof( AttributeName ) );
4587 		an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
4588 		an[0].an_desc = slap_schema.si_ad_entryUUID;
4589 		an[1].an_name = slap_schema.si_ad_entryCSN->ad_cname;
4590 		an[1].an_desc = slap_schema.si_ad_entryCSN;
4591 		op->ors_attrs = an;
4592 		op->ors_slimit = SLAP_NO_LIMIT;
4593 		op->ors_tlimit = SLAP_NO_LIMIT;
4594 		op->ors_limit = NULL;
4595 		op->ors_attrsonly = 0;
4596 		op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
4597 		/* In multi-provider, updates can continue to arrive while
4598 		 * we're searching. Limit the search result to entries
4599 		 * older than our newest cookie CSN.
4600 		 */
4601 		if ( SLAP_MULTIPROVIDER( op->o_bd )) {
4602 			Filter *f;
4603 			int i;
4604 
4605 			f = mmf;
4606 			f->f_choice = LDAP_FILTER_AND;
4607 			f->f_next = op->ors_filter;
4608 			f->f_and = f+1;
4609 			of = f->f_and;
4610 			f = of;
4611 			f->f_choice = LDAP_FILTER_LE;
4612 			f->f_ava = &mmaa;
4613 			f->f_av_desc = slap_schema.si_ad_entryCSN;
4614 			f->f_next = NULL;
4615 			BER_BVZERO( &f->f_av_value );
4616 			for ( i=0; i<sc->numcsns; i++ ) {
4617 				if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 )
4618 					f->f_av_value = sc->ctxcsn[i];
4619 			}
4620 			of = op->ors_filter;
4621 			op->ors_filter = mmf;
4622 			filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
4623 		} else {
4624 			cf = NULL;
4625 			op->ors_filterstr = si->si_filterstr;
4626 		}
4627 		op->o_nocaching = 1;
4628 
4629 
4630 		rc = be->be_search( op, &rs_search );
4631 		if ( SLAP_MULTIPROVIDER( op->o_bd )) {
4632 			op->ors_filter = of;
4633 		}
4634 		if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
4635 		if ( op->ors_filterstr.bv_val != si->si_filterstr.bv_val ) {
4636 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
4637 		}
4638 
4639 	}
4640 
4641 	op->o_nocaching = 0;
4642 
4643 	if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
4644 
4645 		if ( !BER_BVISNULL( &sc->delcsn ) ) {
4646 			Debug( LDAP_DEBUG_SYNC, "syncrepl_del_nonpresent: %s "
4647 					"using delcsn=%s\n",
4648 					si->si_ridtxt, sc->delcsn.bv_val );
4649 			csn = sc->delcsn;
4650 		} else if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
4651 			csn = sc->ctxcsn[m];
4652 		} else {
4653 			csn = si->si_syncCookie.ctxcsn[0];
4654 		}
4655 
4656 		op->o_bd = si->si_wbe;
4657 		slap_queue_csn( op, &csn );
4658 
4659 		np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
4660 		while ( np_list != NULL ) {
4661 			SlapReply rs_delete = {REP_RESULT};
4662 
4663 			LDAP_LIST_REMOVE( np_list, npe_link );
4664 			np_prev = np_list;
4665 			np_list = LDAP_LIST_NEXT( np_list, npe_link );
4666 			op->o_tag = LDAP_REQ_DELETE;
4667 			op->o_callback = &cb;
4668 			cb.sc_response = syncrepl_null_callback;
4669 			cb.sc_private = si;
4670 			op->o_req_dn = *np_prev->npe_name;
4671 			op->o_req_ndn = *np_prev->npe_nname;
4672 			rc = op->o_bd->be_delete( op, &rs_delete );
4673 			Debug( LDAP_DEBUG_SYNC,
4674 				"syncrepl_del_nonpresent: %s be_delete %s (%d)\n",
4675 				si->si_ridtxt, op->o_req_dn.bv_val, rc );
4676 
4677 			if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
4678 				SlapReply rs_modify = {REP_RESULT};
4679 				Modifications mod1, mod2;
4680 				mod1.sml_op = LDAP_MOD_REPLACE;
4681 				mod1.sml_flags = 0;
4682 				mod1.sml_desc = slap_schema.si_ad_objectClass;
4683 				mod1.sml_type = mod1.sml_desc->ad_cname;
4684 				mod1.sml_numvals = 2;
4685 				mod1.sml_values = &gcbva[0];
4686 				mod1.sml_nvalues = NULL;
4687 				mod1.sml_next = &mod2;
4688 
4689 				mod2.sml_op = LDAP_MOD_REPLACE;
4690 				mod2.sml_flags = 0;
4691 				mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
4692 				mod2.sml_type = mod2.sml_desc->ad_cname;
4693 				mod2.sml_numvals = 1;
4694 				mod2.sml_values = &gcbva[1];
4695 				mod2.sml_nvalues = NULL;
4696 				mod2.sml_next = NULL;
4697 
4698 				op->o_tag = LDAP_REQ_MODIFY;
4699 				op->orm_modlist = &mod1;
4700 
4701 				rc = op->o_bd->be_modify( op, &rs_modify );
4702 				if ( mod2.sml_next ) slap_mods_free( mod2.sml_next, 1 );
4703 			}
4704 
4705 			while ( rs_delete.sr_err == LDAP_SUCCESS &&
4706 					op->o_delete_glue_parent ) {
4707 				op->o_delete_glue_parent = 0;
4708 				if ( !be_issuffix( be, &op->o_req_ndn ) ) {
4709 					slap_callback cb = { NULL };
4710 					cb.sc_response = syncrepl_null_callback;
4711 					dnParent( &op->o_req_ndn, &pdn );
4712 					op->o_req_dn = pdn;
4713 					op->o_req_ndn = pdn;
4714 					op->o_callback = &cb;
4715 					rs_reinit( &rs_delete, REP_RESULT );
4716 					/* give it a root privil ? */
4717 					op->o_bd->be_delete( op, &rs_delete );
4718 				} else {
4719 					break;
4720 				}
4721 			}
4722 
4723 			op->o_delete_glue_parent = 0;
4724 
4725 			ber_bvfree( np_prev->npe_name );
4726 			ber_bvfree( np_prev->npe_nname );
4727 			ch_free( np_prev );
4728 
4729 			if ( slapd_shutdown ) {
4730 				break;
4731 			}
4732 		}
4733 
4734 		slap_graduate_commit_csn( op );
4735 		op->o_bd = be;
4736 
4737 		op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
4738 		BER_BVZERO( &op->o_csn );
4739 	}
4740 
4741 	return;
4742 }
4743 
4744 static int
syncrepl_add_glue_ancestors(Operation * op,Entry * e)4745 syncrepl_add_glue_ancestors(
4746 	Operation* op,
4747 	Entry *e )
4748 {
4749 	Backend *be = op->o_bd;
4750 	slap_callback cb = { NULL };
4751 	Attribute	*a;
4752 	int	rc = LDAP_SUCCESS;
4753 	int suffrdns;
4754 	int i;
4755 	struct berval dn = BER_BVNULL;
4756 	struct berval ndn = BER_BVNULL;
4757 	Entry	*glue;
4758 	struct berval	ptr, nptr;
4759 	char		*comma;
4760 
4761 	op->o_tag = LDAP_REQ_ADD;
4762 	op->o_callback = &cb;
4763 	cb.sc_response = syncrepl_null_callback;
4764 	cb.sc_private = NULL;
4765 
4766 	dn = e->e_name;
4767 	ndn = e->e_nname;
4768 
4769 	/* count RDNs in suffix */
4770 	if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) {
4771 		for ( i = 0, ptr = be->be_nsuffix[0], comma = ptr.bv_val; comma != NULL; comma = ber_bvchr( &ptr, ',' ) ) {
4772 			comma++;
4773 			ptr.bv_len -= comma - ptr.bv_val;
4774 			ptr.bv_val = comma;
4775 			i++;
4776 		}
4777 		suffrdns = i;
4778 	} else {
4779 		/* suffix is "" */
4780 		suffrdns = 0;
4781 	}
4782 
4783 	/* Start with BE suffix */
4784 	ptr = dn;
4785 	for ( i = 0; i < suffrdns; i++ ) {
4786 		comma = ber_bvrchr( &ptr, ',' );
4787 		if ( comma != NULL ) {
4788 			ptr.bv_len = comma - ptr.bv_val;
4789 		} else {
4790 			ptr.bv_len = 0;
4791 			break;
4792 		}
4793 	}
4794 
4795 	if ( !BER_BVISEMPTY( &ptr ) ) {
4796 		dn.bv_len -= ptr.bv_len + ( suffrdns != 0 );
4797 		dn.bv_val += ptr.bv_len + ( suffrdns != 0 );
4798 	}
4799 
4800 	/* the normalizedDNs are always the same length, no counting
4801 	 * required.
4802 	 */
4803 	nptr = ndn;
4804 	if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
4805 		ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
4806 		ndn.bv_len = be->be_nsuffix[0].bv_len;
4807 
4808 		nptr.bv_len = ndn.bv_val - nptr.bv_val - 1;
4809 
4810 	} else {
4811 		nptr.bv_len = 0;
4812 	}
4813 
4814 	while ( ndn.bv_val > e->e_nname.bv_val ) {
4815 		SlapReply	rs_add = {REP_RESULT};
4816 
4817 		glue = entry_alloc();
4818 		ber_dupbv( &glue->e_name, &dn );
4819 		ber_dupbv( &glue->e_nname, &ndn );
4820 
4821 		a = attr_alloc( slap_schema.si_ad_objectClass );
4822 
4823 		a->a_numvals = 2;
4824 		a->a_vals = ch_calloc( 3, sizeof( struct berval ) );
4825 		ber_dupbv( &a->a_vals[0], &gcbva[0] );
4826 		ber_dupbv( &a->a_vals[1], &gcbva[1] );
4827 		ber_dupbv( &a->a_vals[2], &gcbva[2] );
4828 
4829 		a->a_nvals = a->a_vals;
4830 
4831 		a->a_next = glue->e_attrs;
4832 		glue->e_attrs = a;
4833 
4834 		a = attr_alloc( slap_schema.si_ad_structuralObjectClass );
4835 
4836 		a->a_numvals = 1;
4837 		a->a_vals = ch_calloc( 2, sizeof( struct berval ) );
4838 		ber_dupbv( &a->a_vals[0], &gcbva[1] );
4839 		ber_dupbv( &a->a_vals[1], &gcbva[2] );
4840 
4841 		a->a_nvals = a->a_vals;
4842 
4843 		a->a_next = glue->e_attrs;
4844 		glue->e_attrs = a;
4845 
4846 		op->o_req_dn = glue->e_name;
4847 		op->o_req_ndn = glue->e_nname;
4848 		op->ora_e = glue;
4849 		rc = be->be_add ( op, &rs_add );
4850 		if ( rs_add.sr_err == LDAP_SUCCESS ) {
4851 			if ( op->ora_e == glue )
4852 				be_entry_release_w( op, glue );
4853 		} else {
4854 		/* incl. ALREADY EXIST */
4855 			entry_free( glue );
4856 			if ( rs_add.sr_err != LDAP_ALREADY_EXISTS ) {
4857 				entry_free( e );
4858 				return rc;
4859 			}
4860 		}
4861 
4862 		/* Move to next child */
4863 		comma = ber_bvrchr( &ptr, ',' );
4864 		if ( comma == NULL ) {
4865 			break;
4866 		}
4867 		ptr.bv_len = comma - ptr.bv_val;
4868 
4869 		dn.bv_val = ++comma;
4870 		dn.bv_len = e->e_name.bv_len - (dn.bv_val - e->e_name.bv_val);
4871 
4872 		comma = ber_bvrchr( &nptr, ',' );
4873 		assert( comma != NULL );
4874 		nptr.bv_len = comma - nptr.bv_val;
4875 
4876 		ndn.bv_val = ++comma;
4877 		ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
4878 	}
4879 
4880 	return rc;
4881 }
4882 
4883 int
syncrepl_add_glue(Operation * op,Entry * e)4884 syncrepl_add_glue(
4885 	Operation* op,
4886 	Entry *e )
4887 {
4888 	slap_callback cb = { NULL };
4889 	int	rc;
4890 	Backend *be = op->o_bd;
4891 	SlapReply	rs_add = {REP_RESULT};
4892 
4893 	rc = syncrepl_add_glue_ancestors( op, e );
4894 	switch ( rc ) {
4895 	case LDAP_SUCCESS:
4896 	case LDAP_ALREADY_EXISTS:
4897 		break;
4898 
4899 	default:
4900 		return rc;
4901 	}
4902 
4903 	op->o_tag = LDAP_REQ_ADD;
4904 	op->o_callback = &cb;
4905 	cb.sc_response = syncrepl_null_callback;
4906 	cb.sc_private = NULL;
4907 
4908 	op->o_req_dn = e->e_name;
4909 	op->o_req_ndn = e->e_nname;
4910 	op->ora_e = e;
4911 	rc = be->be_add ( op, &rs_add );
4912 	if ( rs_add.sr_err == LDAP_SUCCESS ) {
4913 		if ( op->ora_e == e )
4914 			be_entry_release_w( op, e );
4915 	} else {
4916 		entry_free( e );
4917 	}
4918 
4919 	return rc;
4920 }
4921 
4922 static int
syncrepl_dsee_update(syncinfo_t * si,Operation * op)4923 syncrepl_dsee_update(
4924 	syncinfo_t *si,
4925 	Operation *op
4926 )
4927 {
4928 	Backend *be = op->o_bd;
4929 	Modifications mod;
4930 	struct berval first = BER_BVNULL;
4931 	slap_callback cb = { NULL };
4932 	SlapReply	rs_modify = {REP_RESULT};
4933 	char valbuf[sizeof("18446744073709551615")];
4934 	struct berval bvals[2];
4935 	int rc;
4936 
4937 	if ( si->si_lastchange == si->si_prevchange )
4938 		return 0;
4939 
4940 	mod.sml_op = LDAP_MOD_REPLACE;
4941 	mod.sml_desc = sy_ad_dseeLastChange;
4942 	mod.sml_type = mod.sml_desc->ad_cname;
4943 	mod.sml_flags = SLAP_MOD_INTERNAL;
4944 	mod.sml_nvalues = NULL;
4945 	mod.sml_values = bvals;
4946 	mod.sml_numvals = 1;
4947 	mod.sml_next = NULL;
4948 	bvals[0].bv_val = valbuf;
4949 	bvals[0].bv_len = sprintf( valbuf, "%lu", si->si_lastchange );
4950 	BER_BVZERO( &bvals[1] );
4951 
4952 	op->o_bd = si->si_wbe;
4953 
4954 	op->o_tag = LDAP_REQ_MODIFY;
4955 
4956 	cb.sc_response = syncrepl_null_callback;
4957 	cb.sc_private = si;
4958 
4959 	op->o_callback = &cb;
4960 	op->o_req_dn = si->si_contextdn;
4961 	op->o_req_ndn = si->si_contextdn;
4962 
4963 	/* update contextCSN */
4964 	op->o_dont_replicate = 1;
4965 
4966 	/* avoid timestamp collisions */
4967 	slap_op_time( &op->o_time, &op->o_tincr );
4968 
4969 	op->orm_modlist = &mod;
4970 	op->orm_no_opattrs = 1;
4971 	rc = op->o_bd->be_modify( op, &rs_modify );
4972 
4973 	op->o_bd = be;
4974 	si->si_prevchange = si->si_lastchange;
4975 
4976 	return rc;
4977 }
4978 
4979 static int
syncrepl_updateCookie(syncinfo_t * si,Operation * op,struct sync_cookie * syncCookie,int save)4980 syncrepl_updateCookie(
4981 	syncinfo_t *si,
4982 	Operation *op,
4983 	struct sync_cookie *syncCookie,
4984 	int save )
4985 {
4986 	Backend *be = op->o_bd;
4987 	Modifications mod;
4988 	struct berval first = BER_BVNULL;
4989 	struct sync_cookie sc;
4990 #ifdef CHECK_CSN
4991 	Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
4992 #endif
4993 
4994 	int rc, i, j, changed = 0;
4995 	ber_len_t len;
4996 
4997 	slap_callback cb = { NULL };
4998 	SlapReply	rs_modify = {REP_RESULT};
4999 
5000 	mod.sml_op = LDAP_MOD_REPLACE;
5001 	mod.sml_desc = slap_schema.si_ad_contextCSN;
5002 	mod.sml_type = mod.sml_desc->ad_cname;
5003 	mod.sml_flags = SLAP_MOD_INTERNAL;
5004 	mod.sml_nvalues = NULL;
5005 	mod.sml_next = NULL;
5006 
5007 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
5008 	while ( si->si_cookieState->cs_updating )
5009 		ldap_pvt_thread_cond_wait( &si->si_cookieState->cs_cond, &si->si_cookieState->cs_mutex );
5010 
5011 #ifdef CHECK_CSN
5012 	for ( i=0; i<syncCookie->numcsns; i++ ) {
5013 		assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i ));
5014 	}
5015 	for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
5016 		assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
5017 	}
5018 #endif
5019 
5020 	/* clone the cookieState CSNs so we can Replace the whole thing */
5021 	sc.numcsns = si->si_cookieState->cs_num;
5022 	if ( sc.numcsns ) {
5023 		ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
5024 		sc.sids = ch_malloc( sc.numcsns * sizeof(int));
5025 		for ( i=0; i<sc.numcsns; i++ )
5026 			sc.sids[i] = si->si_cookieState->cs_sids[i];
5027 	} else {
5028 		sc.ctxcsn = NULL;
5029 		sc.sids = NULL;
5030 	}
5031 
5032 	/* find any CSNs in the syncCookie that are newer than the cookieState */
5033 	for ( i=0; i<syncCookie->numcsns; i++ ) {
5034 		for ( j=0; j<sc.numcsns; j++ ) {
5035 			if ( syncCookie->sids[i] < sc.sids[j] )
5036 				break;
5037 			if ( syncCookie->sids[i] != sc.sids[j] )
5038 				continue;
5039 			len = syncCookie->ctxcsn[i].bv_len;
5040 			if ( len > sc.ctxcsn[j].bv_len )
5041 				len = sc.ctxcsn[j].bv_len;
5042 			if ( memcmp( syncCookie->ctxcsn[i].bv_val,
5043 				sc.ctxcsn[j].bv_val, len ) > 0 ) {
5044 				ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
5045 				changed = 1;
5046 				if ( BER_BVISNULL( &first ) ||
5047 					memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
5048 					first = syncCookie->ctxcsn[i];
5049 				}
5050 			}
5051 			break;
5052 		}
5053 		/* there was no match for this SID, it's a new CSN */
5054 		if ( j == sc.numcsns ||
5055 			syncCookie->sids[i] != sc.sids[j] ) {
5056 			slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
5057 				&syncCookie->ctxcsn[i] );
5058 			if ( BER_BVISNULL( &first ) ||
5059 				memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
5060 				first = syncCookie->ctxcsn[i];
5061 			}
5062 			changed = 1;
5063 		}
5064 	}
5065 	/* Should never happen, ITS#5065 */
5066 	if ( BER_BVISNULL( &first ) || !changed ) {
5067 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
5068 		ber_bvarray_free( sc.ctxcsn );
5069 		ch_free( sc.sids );
5070 		return 0;
5071 	}
5072 
5073 	si->si_cookieState->cs_updating = 1;
5074 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
5075 
5076 	op->o_bd = si->si_wbe;
5077 	slap_queue_csn( op, &first );
5078 
5079 	op->o_tag = LDAP_REQ_MODIFY;
5080 
5081 	cb.sc_response = syncrepl_null_callback;
5082 	cb.sc_private = si;
5083 
5084 	op->o_callback = &cb;
5085 	op->o_req_dn = si->si_contextdn;
5086 	op->o_req_ndn = si->si_contextdn;
5087 
5088 	/* update contextCSN */
5089 	op->o_dont_replicate = !save;
5090 
5091 	/* avoid timestamp collisions */
5092 	if ( save )
5093 		slap_op_time( &op->o_time, &op->o_tincr );
5094 
5095 	mod.sml_numvals = sc.numcsns;
5096 	mod.sml_values = sc.ctxcsn;
5097 
5098 	op->orm_modlist = &mod;
5099 	op->orm_no_opattrs = 1;
5100 	rc = op->o_bd->be_modify( op, &rs_modify );
5101 
5102 	if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
5103 		SLAP_SYNC_SUBENTRY( op->o_bd )) {
5104 		const char	*text;
5105 		char txtbuf[SLAP_TEXT_BUFLEN];
5106 		size_t textlen = sizeof txtbuf;
5107 		Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
5108 		rs_reinit( &rs_modify, REP_RESULT );
5109 		rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
5110 		slap_queue_csn( op, &first );
5111 		op->o_tag = LDAP_REQ_ADD;
5112 		op->ora_e = e;
5113 		rc = op->o_bd->be_add( op, &rs_modify );
5114 		if ( e == op->ora_e )
5115 			be_entry_release_w( op, op->ora_e );
5116 	}
5117 
5118 	op->orm_no_opattrs = 0;
5119 	op->o_dont_replicate = 0;
5120 	ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
5121 
5122 	if ( rs_modify.sr_err == LDAP_SUCCESS ) {
5123 		slap_sync_cookie_free( &si->si_syncCookie, 0 );
5124 		ber_bvarray_free( si->si_cookieState->cs_vals );
5125 		ch_free( si->si_cookieState->cs_sids );
5126 		si->si_cookieState->cs_vals = sc.ctxcsn;
5127 		si->si_cookieState->cs_sids = sc.sids;
5128 		si->si_cookieState->cs_num = sc.numcsns;
5129 
5130 		/* Don't just dup the provider's cookie, recreate it */
5131 		si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
5132 		ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL );
5133 		si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * sizeof(int) );
5134 		for ( i=0; i<si->si_cookieState->cs_num; i++ )
5135 			si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
5136 
5137 		si->si_cookieState->cs_age++;
5138 		si->si_cookieAge = si->si_cookieState->cs_age;
5139 	} else {
5140 		Debug( LDAP_DEBUG_ANY,
5141 			"syncrepl_updateCookie: %s be_modify failed (%d)\n",
5142 			si->si_ridtxt, rs_modify.sr_err );
5143 		ch_free( sc.sids );
5144 		ber_bvarray_free( sc.ctxcsn );
5145 	}
5146 
5147 #ifdef CHECK_CSN
5148 	for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
5149 		assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
5150 	}
5151 #endif
5152 
5153 	si->si_cookieState->cs_updating = 0;
5154 	ldap_pvt_thread_cond_broadcast( &si->si_cookieState->cs_cond );
5155 	ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
5156 
5157 	op->o_bd = be;
5158 	op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
5159 	BER_BVZERO( &op->o_csn );
5160 	if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
5161 
5162 	return rc;
5163 }
5164 
5165 /* Compare the attribute from the old entry to the one in the new
5166  * entry. The Modifications from the new entry will either be left
5167  * in place, or changed to an Add or Delete as needed.
5168  */
5169 static void
attr_cmp(Operation * op,Attribute * old,Attribute * new,Modifications *** mret,Modifications *** mcur)5170 attr_cmp( Operation *op, Attribute *old, Attribute *new,
5171 	Modifications ***mret, Modifications ***mcur )
5172 {
5173 	int i, j;
5174 	Modifications *mod, **modtail;
5175 
5176 	modtail = *mret;
5177 
5178 	if ( old ) {
5179 		int n, o, nn, no;
5180 		struct berval **adds, **dels;
5181 		/* count old and new */
5182 		for ( o=0; old->a_vals[o].bv_val; o++ ) ;
5183 		for ( n=0; new->a_vals[n].bv_val; n++ ) ;
5184 
5185 		/* there MUST be both old and new values */
5186 		assert( o != 0 );
5187 		assert( n != 0 );
5188 		j = 0;
5189 
5190 		adds = op->o_tmpalloc( sizeof(struct berval *) * n, op->o_tmpmemctx );
5191 		dels = op->o_tmpalloc( sizeof(struct berval *) * o, op->o_tmpmemctx );
5192 
5193 		for ( i=0; i<o; i++ ) dels[i] = &old->a_vals[i];
5194 		for ( i=0; i<n; i++ ) adds[i] = &new->a_vals[i];
5195 
5196 		nn = n; no = o;
5197 
5198 		for ( i=0; i<o; i++ ) {
5199 			for ( j=0; j<n; j++ ) {
5200 				if ( !adds[j] )
5201 					continue;
5202 				if ( bvmatch( dels[i], adds[j] ) ) {
5203 					no--;
5204 					nn--;
5205 					adds[j] = NULL;
5206 					dels[i] = NULL;
5207 					break;
5208 				}
5209 			}
5210 		}
5211 
5212 		/* Don't delete/add an objectClass, always use the replace op.
5213 		 * Modify would fail if provider has replaced entry with a new,
5214 		 * and the new explicitly includes a superior of a class that was
5215 		 * only included implicitly in the old entry.  Ref ITS#5517.
5216 		 *
5217 		 * Also use replace op if attr has no equality matching rule.
5218 		 * (ITS#5781)
5219 		 */
5220 		if ( ( nn || ( no > 0 && no < o ) ) &&
5221 			( old->a_desc == slap_schema.si_ad_objectClass ||
5222 			 !old->a_desc->ad_type->sat_equality ) )
5223 		{
5224 			no = o;
5225 		}
5226 
5227 		i = j;
5228 		/* all old values were deleted, just use the replace op */
5229 		if ( no == o ) {
5230 			i = j-1;
5231 		} else if ( no ) {
5232 		/* delete some values */
5233 			mod = ch_malloc( sizeof( Modifications ) );
5234 			mod->sml_op = LDAP_MOD_DELETE;
5235 			mod->sml_flags = 0;
5236 			mod->sml_desc = old->a_desc;
5237 			mod->sml_type = mod->sml_desc->ad_cname;
5238 			mod->sml_numvals = no;
5239 			mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
5240 			if ( old->a_vals != old->a_nvals ) {
5241 				mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
5242 			} else {
5243 				mod->sml_nvalues = NULL;
5244 			}
5245 			j = 0;
5246 			for ( i = 0; i < o; i++ ) {
5247 				if ( !dels[i] ) continue;
5248 				ber_dupbv( &mod->sml_values[j], &old->a_vals[i] );
5249 				if ( mod->sml_nvalues ) {
5250 					ber_dupbv( &mod->sml_nvalues[j], &old->a_nvals[i] );
5251 				}
5252 				j++;
5253 			}
5254 			BER_BVZERO( &mod->sml_values[j] );
5255 			if ( mod->sml_nvalues ) {
5256 				BER_BVZERO( &mod->sml_nvalues[j] );
5257 			}
5258 			*modtail = mod;
5259 			modtail = &mod->sml_next;
5260 			i = j;
5261 		}
5262 		op->o_tmpfree( dels, op->o_tmpmemctx );
5263 		/* some values were added */
5264 		if ( nn && no < o ) {
5265 			mod = ch_malloc( sizeof( Modifications ) );
5266 			if ( is_at_single_value( old->a_desc->ad_type ))
5267 				mod->sml_op = LDAP_MOD_REPLACE;
5268 			else
5269 				mod->sml_op = LDAP_MOD_ADD;
5270 			mod->sml_flags = 0;
5271 			mod->sml_desc = old->a_desc;
5272 			mod->sml_type = mod->sml_desc->ad_cname;
5273 			mod->sml_numvals = nn;
5274 			mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
5275 			if ( old->a_vals != old->a_nvals ) {
5276 				mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
5277 			} else {
5278 				mod->sml_nvalues = NULL;
5279 			}
5280 			j = 0;
5281 			for ( i = 0; i < n; i++ ) {
5282 				if ( !adds[i] ) continue;
5283 				ber_dupbv( &mod->sml_values[j], &new->a_vals[i] );
5284 				if ( mod->sml_nvalues ) {
5285 					ber_dupbv( &mod->sml_nvalues[j], &new->a_nvals[i] );
5286 				}
5287 				j++;
5288 			}
5289 			BER_BVZERO( &mod->sml_values[j] );
5290 			if ( mod->sml_nvalues ) {
5291 				BER_BVZERO( &mod->sml_nvalues[j] );
5292 			}
5293 			*modtail = mod;
5294 			modtail = &mod->sml_next;
5295 			i = j;
5296 		}
5297 		op->o_tmpfree( adds, op->o_tmpmemctx );
5298 	} else {
5299 		/* new attr, just use the new mod */
5300 		i = 0;
5301 		j = 1;
5302 	}
5303 	/* advance to next element */
5304 	mod = **mcur;
5305 	if ( mod ) {
5306 		if ( i != j ) {
5307 			**mcur = mod->sml_next;
5308 			*modtail = mod;
5309 			modtail = &mod->sml_next;
5310 		} else {
5311 			*mcur = &mod->sml_next;
5312 		}
5313 	}
5314 	*mret = modtail;
5315 }
5316 
5317 /* Generate a set of modifications to change the old entry into the
5318  * new one. On input ml is a list of modifications equivalent to
5319  * the new entry. It will be massaged and the result will be stored
5320  * in mods.
5321  */
syncrepl_diff_entry(Operation * op,Attribute * old,Attribute * new,Modifications ** mods,Modifications ** ml,int is_ctx)5322 void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
5323 	Modifications **mods, Modifications **ml, int is_ctx)
5324 {
5325 	Modifications **modtail = mods;
5326 
5327 	/* We assume that attributes are saved in the same order
5328 	 * in the remote and local databases. So if we walk through
5329 	 * the attributeDescriptions one by one they should match in
5330 	 * lock step. If not, look for an add or delete.
5331 	 */
5332 	while ( old && new )
5333 	{
5334 		/* If we've seen this before, use its mod now */
5335 		if ( new->a_flags & SLAP_ATTR_IXADD ) {
5336 			attr_cmp( op, NULL, new, &modtail, &ml );
5337 			new = new->a_next;
5338 			continue;
5339 		}
5340 		/* Skip contextCSN */
5341 		if ( is_ctx && old->a_desc ==
5342 			slap_schema.si_ad_contextCSN ) {
5343 			old = old->a_next;
5344 			continue;
5345 		}
5346 
5347 		if ( old->a_desc != new->a_desc ) {
5348 			Modifications *mod;
5349 			Attribute *tmp;
5350 
5351 			/* If it's just been re-added later,
5352 			 * remember that we've seen it.
5353 			 */
5354 			tmp = attr_find( new, old->a_desc );
5355 			if ( tmp ) {
5356 				tmp->a_flags |= SLAP_ATTR_IXADD;
5357 			} else {
5358 				/* If it's a new attribute, pull it in.
5359 				 */
5360 				tmp = attr_find( old, new->a_desc );
5361 				if ( !tmp ) {
5362 					attr_cmp( op, NULL, new, &modtail, &ml );
5363 					new = new->a_next;
5364 					continue;
5365 				}
5366 				/* Delete old attr */
5367 				mod = ch_malloc( sizeof( Modifications ) );
5368 				mod->sml_op = LDAP_MOD_DELETE;
5369 				mod->sml_flags = 0;
5370 				mod->sml_desc = old->a_desc;
5371 				mod->sml_type = mod->sml_desc->ad_cname;
5372 				mod->sml_numvals = 0;
5373 				mod->sml_values = NULL;
5374 				mod->sml_nvalues = NULL;
5375 				*modtail = mod;
5376 				modtail = &mod->sml_next;
5377 			}
5378 			old = old->a_next;
5379 			continue;
5380 		}
5381 		/* kludge - always update modifiersName so that it
5382 		 * stays co-located with the other mod opattrs. But only
5383 		 * if we know there are other valid mods.
5384 		 */
5385 		if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
5386 			old->a_desc == slap_schema.si_ad_modifyTimestamp ))
5387 			attr_cmp( op, NULL, new, &modtail, &ml );
5388 		else
5389 			attr_cmp( op, old, new, &modtail, &ml );
5390 		new = new->a_next;
5391 		old = old->a_next;
5392 	}
5393 
5394 	/* These are all missing from provider */
5395 	while ( old ) {
5396 		Modifications *mod = ch_malloc( sizeof( Modifications ) );
5397 
5398 		mod->sml_op = LDAP_MOD_DELETE;
5399 		mod->sml_flags = 0;
5400 		mod->sml_desc = old->a_desc;
5401 		mod->sml_type = mod->sml_desc->ad_cname;
5402 		mod->sml_numvals = 0;
5403 		mod->sml_values = NULL;
5404 		mod->sml_nvalues = NULL;
5405 
5406 		*modtail = mod;
5407 		modtail = &mod->sml_next;
5408 
5409 		old = old->a_next;
5410 	}
5411 
5412 	/* Newly added attributes */
5413 	while ( new ) {
5414 		attr_cmp( op, NULL, new, &modtail, &ml );
5415 
5416 		new = new->a_next;
5417 	}
5418 
5419 	*modtail = *ml;
5420 	*ml = NULL;
5421 }
5422 
5423 /* shallow copy attrs, excluding non-replicated attrs */
5424 static Attribute *
attrs_exdup(Operation * op,dninfo * dni,Attribute * attrs)5425 attrs_exdup( Operation *op, dninfo *dni, Attribute *attrs )
5426 {
5427 	int i;
5428 	Attribute *tmp, *anew;
5429 
5430 	if ( attrs == NULL ) return NULL;
5431 
5432 	/* count attrs */
5433 	for ( tmp = attrs,i=0; tmp; tmp=tmp->a_next ) i++;
5434 
5435 	anew = op->o_tmpalloc( i * sizeof(Attribute), op->o_tmpmemctx );
5436 	for ( tmp = anew; attrs; attrs=attrs->a_next ) {
5437 		int flag = is_at_operational( attrs->a_desc->ad_type ) ? dni->si->si_allopattrs :
5438 			dni->si->si_allattrs;
5439 		if ( !flag && !ad_inlist( attrs->a_desc, dni->si->si_anlist ))
5440 			continue;
5441 		if ( dni->si->si_exattrs && ad_inlist( attrs->a_desc, dni->si->si_exanlist ))
5442 			continue;
5443 		*tmp = *attrs;
5444 		tmp->a_next = tmp+1;
5445 		tmp++;
5446 	}
5447 	if ( tmp == anew ) {
5448 		/* excluded everything */
5449 		op->o_tmpfree( anew, op->o_tmpmemctx );
5450 		return NULL;
5451 	}
5452 	tmp[-1].a_next = NULL;
5453 	return anew;
5454 }
5455 
5456 static int
dn_callback(Operation * op,SlapReply * rs)5457 dn_callback(
5458 	Operation*	op,
5459 	SlapReply*	rs )
5460 {
5461 	dninfo *dni = op->o_callback->sc_private;
5462 
5463 	if ( rs->sr_type == REP_SEARCH ) {
5464 		if ( !BER_BVISNULL( &dni->dn ) ) {
5465 			Debug( LDAP_DEBUG_ANY,
5466 				"dn_callback : consistency error - "
5467 				"entryUUID is not unique\n" );
5468 		} else {
5469 			ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx );
5470 			ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
5471 			/* If there is a new entry, see if it differs from the old.
5472 			 * We compare the non-normalized values so that cosmetic changes
5473 			 * in the provider are always propagated.
5474 			 */
5475 			if ( dni->new_entry ) {
5476 				Attribute *old, *new;
5477 				struct berval old_rdn, new_rdn;
5478 				struct berval old_p, new_p;
5479 				int is_ctx, new_sup = 0;
5480 
5481 #ifdef LDAP_CONTROL_X_DIRSYNC
5482 				if ( dni->syncstate != MSAD_DIRSYNC_MODIFY )
5483 #endif
5484 				{
5485 					/* If old entry is not a glue entry, make sure new entry
5486 					 * is actually newer than old entry
5487 					 */
5488 					if ( !is_entry_glue( rs->sr_entry )) {
5489 						old = attr_find( rs->sr_entry->e_attrs,
5490 							slap_schema.si_ad_entryCSN );
5491 						new = attr_find( dni->new_entry->e_attrs,
5492 							slap_schema.si_ad_entryCSN );
5493 						if ( new && old ) {
5494 							int rc;
5495 							ber_len_t len = old->a_vals[0].bv_len;
5496 							if ( len > new->a_vals[0].bv_len )
5497 								len = new->a_vals[0].bv_len;
5498 							rc = memcmp( old->a_vals[0].bv_val,
5499 								new->a_vals[0].bv_val, len );
5500 							if ( rc > 0 ) {
5501 								Debug( LDAP_DEBUG_SYNC,
5502 									"dn_callback : new entry is older than ours "
5503 									"%s ours %s, new %s\n",
5504 									rs->sr_entry->e_name.bv_val,
5505 									old->a_vals[0].bv_val,
5506 									new->a_vals[0].bv_val );
5507 								return LDAP_SUCCESS;
5508 							} else if ( rc == 0 ) {
5509 								Debug( LDAP_DEBUG_SYNC,
5510 									"dn_callback : entries have identical CSN "
5511 									"%s %s\n",
5512 									rs->sr_entry->e_name.bv_val,
5513 									old->a_vals[0].bv_val );
5514 								return LDAP_SUCCESS;
5515 							}
5516 						}
5517 					}
5518 
5519 					is_ctx = dn_match( &rs->sr_entry->e_nname,
5520 						&op->o_bd->be_nsuffix[0] );
5521 				}
5522 
5523 				/* Did the DN change?
5524 				 * case changes in the parent are ignored,
5525 				 * we only want to know if the RDN was
5526 				 * actually changed.
5527 				 */
5528 				dnRdn( &rs->sr_entry->e_name, &old_rdn );
5529 				dnRdn( &dni->new_entry->e_name, &new_rdn );
5530 				dnParent( &rs->sr_entry->e_nname, &old_p );
5531 				dnParent( &dni->new_entry->e_nname, &new_p );
5532 
5533 				new_sup = !dn_match( &old_p, &new_p );
5534 				if ( !dn_match( &old_rdn, &new_rdn ) || new_sup )
5535 				{
5536 					struct berval oldRDN, oldVal;
5537 					AttributeDescription *ad = NULL;
5538 					int oldpos, newpos;
5539 					Attribute *a;
5540 
5541 					dni->renamed = 1;
5542 					if ( new_sup )
5543 						dni->nnewSup = new_p;
5544 
5545 					/* See if the oldRDN was deleted */
5546 					dnRdn( &rs->sr_entry->e_nname, &oldRDN );
5547 					oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
5548 					oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
5549 						oldRDN.bv_val );
5550 					oldRDN.bv_len -= oldVal.bv_len + 1;
5551 					slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
5552 					dni->oldDesc = ad;
5553 					for ( oldpos=0, a=rs->sr_entry->e_attrs;
5554 						a && a->a_desc != ad; oldpos++, a=a->a_next );
5555 					/* a should not be NULL but apparently it happens.
5556 					 * ITS#7144
5557 					 */
5558 					if ( a ) {
5559 						dni->oldNcount = a->a_numvals;
5560 						for ( newpos=0, a=dni->new_entry->e_attrs;
5561 							a && a->a_desc != ad; newpos++, a=a->a_next );
5562 						if ( !a || oldpos != newpos || attr_valfind( a,
5563 							SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
5564 							SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
5565 							SLAP_MR_VALUE_OF_SYNTAX,
5566 							&oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS )
5567 						{
5568 							dni->delOldRDN = 1;
5569 						}
5570 					}
5571 					/* Get the newRDN's desc */
5572 					dnRdn( &dni->new_entry->e_nname, &oldRDN );
5573 					oldVal.bv_val = strchr(oldRDN.bv_val, '=');
5574 					oldRDN.bv_len = oldVal.bv_val - oldRDN.bv_val;
5575 					ad = NULL;
5576 					slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
5577 					dni->newDesc = ad;
5578 
5579 					/* A ModDN has happened, but in Refresh mode other
5580 					 * changes may have occurred before we picked it up.
5581 					 * So fallthru to regular Modify processing.
5582 					 */
5583 				}
5584 
5585 #ifdef LDAP_CONTROL_X_DIRSYNC
5586 				if ( dni->syncstate == MSAD_DIRSYNC_MODIFY ) {
5587 					/* DirSync actually sends a diff already, mostly.
5588 					 * It has no way to indicate deletion of single-valued attrs.
5589 					 * FIXME: should do an auxiliary search to get the true
5590 					 * entry contents.
5591 					 */
5592 					dni->mods = *dni->modlist;
5593 					*dni->modlist = NULL;
5594 				} else
5595 #endif
5596 				{
5597 					Attribute *old = attrs_exdup( op, dni, rs->sr_entry->e_attrs );
5598 					syncrepl_diff_entry( op, old,
5599 						dni->new_entry->e_attrs, &dni->mods, dni->modlist,
5600 						is_ctx );
5601 					op->o_tmpfree( old, op->o_tmpmemctx );
5602 				}
5603 			}
5604 		}
5605 	} else if ( rs->sr_type == REP_RESULT ) {
5606 		if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
5607 			Debug( LDAP_DEBUG_ANY,
5608 				"dn_callback : consistency error - "
5609 				"entryUUID is not unique\n" );
5610 		}
5611 	}
5612 
5613 	return LDAP_SUCCESS;
5614 }
5615 
5616 static int
nonpresent_callback(Operation * op,SlapReply * rs)5617 nonpresent_callback(
5618 	Operation*	op,
5619 	SlapReply*	rs )
5620 {
5621 	syncinfo_t *si = op->o_callback->sc_private;
5622 	Attribute *a;
5623 	int count = 0;
5624 	char *present_uuid = NULL;
5625 	struct nonpresent_entry *np_entry;
5626 	struct sync_cookie *syncCookie = op->o_controls[slap_cids.sc_LDAPsync];
5627 
5628 	if ( rs->sr_type == REP_RESULT ) {
5629 		count = presentlist_free( si->si_presentlist );
5630 		si->si_presentlist = NULL;
5631 		Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s "
5632 			"had %d items left in the list\n", si->si_ridtxt, count );
5633 
5634 	} else if ( rs->sr_type == REP_SEARCH ) {
5635 		if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) {
5636 			a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
5637 
5638 			if ( a ) {
5639 				present_uuid = presentlist_find( si->si_presentlist, &a->a_nvals[0] );
5640 			}
5641 
5642 			Debug(LDAP_DEBUG_SYNC, "nonpresent_callback: "
5643 				"%s %spresent UUID %s, dn %s\n",
5644 				si->si_ridtxt,
5645 				present_uuid ? "" : "non",
5646 				a ? a->a_vals[0].bv_val : "<missing>",
5647 				rs->sr_entry->e_name.bv_val );
5648 
5649 			if ( a == NULL ) return 0;
5650 		}
5651 
5652 		if ( present_uuid == NULL ) {
5653 			int covered = 1; /* covered by our new contextCSN? */
5654 
5655 			if ( !syncCookie )
5656 				syncCookie = &si->si_syncCookie;
5657 
5658 			/* TODO: This can go once we can build a filter that takes care of
5659 			 * the check for us */
5660 			a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN );
5661 			if ( a ) {
5662 				int i, sid = slap_parse_csn_sid( &a->a_nvals[0] );
5663 				if ( sid != -1 ) {
5664 					covered = 0;
5665 					for ( i=0; i < syncCookie->numcsns && syncCookie->sids[i] <= sid; i++ ) {
5666 						if ( syncCookie->sids[i] == sid &&
5667 								ber_bvcmp( &a->a_nvals[0], &syncCookie->ctxcsn[i] ) <= 0 ) {
5668 							covered = 1;
5669 						}
5670 					}
5671 				}
5672 			}
5673 
5674 			if ( covered ) {
5675 				np_entry = (struct nonpresent_entry *)
5676 					ch_calloc( 1, sizeof( struct nonpresent_entry ) );
5677 				np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
5678 				np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
5679 				LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
5680 				Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s "
5681 					"adding entry %s to non-present list\n",
5682 					si->si_ridtxt, np_entry->npe_name->bv_val );
5683 			}
5684 
5685 		} else {
5686 			presentlist_delete( &si->si_presentlist, &a->a_nvals[0] );
5687 			ch_free( present_uuid );
5688 		}
5689 	}
5690 	return LDAP_SUCCESS;
5691 }
5692 
5693 static struct berval *
slap_uuidstr_from_normalized(struct berval * uuidstr,struct berval * normalized,void * ctx)5694 slap_uuidstr_from_normalized(
5695 	struct berval* uuidstr,
5696 	struct berval* normalized,
5697 	void *ctx )
5698 {
5699 #if 0
5700 	struct berval *new;
5701 	unsigned char nibble;
5702 	int i, d = 0;
5703 
5704 	if ( normalized == NULL ) return NULL;
5705 	if ( normalized->bv_len != 16 ) return NULL;
5706 
5707 	if ( uuidstr ) {
5708 		new = uuidstr;
5709 	} else {
5710 		new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
5711 		if ( new == NULL ) {
5712 			return NULL;
5713 		}
5714 	}
5715 
5716 	new->bv_len = 36;
5717 
5718 	if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
5719 		if ( new != uuidstr ) {
5720 			slap_sl_free( new, ctx );
5721 		}
5722 		return NULL;
5723 	}
5724 
5725 	for ( i = 0; i < 16; i++ ) {
5726 		if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
5727 			new->bv_val[(i<<1)+d] = '-';
5728 			d += 1;
5729 		}
5730 
5731 		nibble = (normalized->bv_val[i] >> 4) & 0xF;
5732 		if ( nibble < 10 ) {
5733 			new->bv_val[(i<<1)+d] = nibble + '0';
5734 		} else {
5735 			new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
5736 		}
5737 
5738 		nibble = (normalized->bv_val[i]) & 0xF;
5739 		if ( nibble < 10 ) {
5740 			new->bv_val[(i<<1)+d+1] = nibble + '0';
5741 		} else {
5742 			new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
5743 		}
5744 	}
5745 
5746 	new->bv_val[new->bv_len] = '\0';
5747 	return new;
5748 #endif
5749 
5750 	struct berval	*new;
5751 	int		rc = 0;
5752 
5753 	if ( normalized == NULL ) return NULL;
5754 	if ( normalized->bv_len != 16 ) return NULL;
5755 
5756 	if ( uuidstr ) {
5757 		new = uuidstr;
5758 
5759 	} else {
5760 		new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
5761 		if ( new == NULL ) {
5762 			return NULL;
5763 		}
5764 	}
5765 
5766 	new->bv_len = 36;
5767 
5768 	if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
5769 		rc = 1;
5770 		goto done;
5771 	}
5772 
5773 	rc = lutil_uuidstr_from_normalized( normalized->bv_val,
5774 		normalized->bv_len, new->bv_val, new->bv_len + 1 );
5775 
5776 done:;
5777 	if ( rc == -1 ) {
5778 		if ( new != NULL ) {
5779 			if ( new->bv_val != NULL ) {
5780 				slap_sl_free( new->bv_val, ctx );
5781 			}
5782 
5783 			if ( new != uuidstr ) {
5784 				slap_sl_free( new, ctx );
5785 			}
5786 		}
5787 		new = NULL;
5788 
5789 	} else {
5790 		new->bv_len = rc;
5791 	}
5792 
5793 	return new;
5794 }
5795 
5796 static int
syncuuid_cmp(const void * v_uuid1,const void * v_uuid2)5797 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
5798 {
5799 #ifdef HASHUUID
5800 	return ( memcmp( v_uuid1, v_uuid2, UUIDLEN-2 ));
5801 #else
5802 	return ( memcmp( v_uuid1, v_uuid2, UUIDLEN ));
5803 #endif
5804 }
5805 
5806 void
syncinfo_free(syncinfo_t * sie,int free_all)5807 syncinfo_free( syncinfo_t *sie, int free_all )
5808 {
5809 	syncinfo_t *si_next;
5810 
5811 	Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
5812 		sie->si_ridtxt );
5813 
5814 	do {
5815 		si_next = sie->si_next;
5816 
5817 		if ( !BER_BVISEMPTY( &sie->si_monitor_ndn )) {
5818 			syncrepl_monitor_del( sie );
5819 		}
5820 
5821 		if ( sie->si_ld ) {
5822 			if ( sie->si_conn ) {
5823 				connection_client_stop( sie->si_conn );
5824 				sie->si_conn = NULL;
5825 			}
5826 			ldap_unbind_ext( sie->si_ld, NULL, NULL );
5827 		}
5828 
5829 		if ( sie->si_re ) {
5830 			struct re_s		*re = sie->si_re;
5831 			sie->si_re = NULL;
5832 
5833 			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
5834 			if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
5835 				ldap_pvt_runqueue_stoptask( &slapd_rq, re );
5836 			ldap_pvt_runqueue_remove( &slapd_rq, re );
5837 			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
5838 		}
5839 
5840 		ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
5841 		ldap_pvt_thread_mutex_destroy( &sie->si_monitor_mutex );
5842 
5843 		bindconf_free( &sie->si_bindconf );
5844 
5845 		if ( sie->si_filterstr.bv_val ) {
5846 			ch_free( sie->si_filterstr.bv_val );
5847 		}
5848 		if ( sie->si_filter ) {
5849 			filter_free( sie->si_filter );
5850 		}
5851 		if ( sie->si_logfilterstr.bv_val ) {
5852 			ch_free( sie->si_logfilterstr.bv_val );
5853 		}
5854 		if ( sie->si_logfilter ) {
5855 			filter_free( sie->si_logfilter );
5856 		}
5857 		if ( sie->si_base.bv_val ) {
5858 			ch_free( sie->si_base.bv_val );
5859 		}
5860 		if ( sie->si_logbase.bv_val ) {
5861 			ch_free( sie->si_logbase.bv_val );
5862 		}
5863 		if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
5864 			ch_free( sie->si_contextdn.bv_val );
5865 		}
5866 		if ( sie->si_attrs ) {
5867 			int i = 0;
5868 			while ( sie->si_attrs[i] != NULL ) {
5869 				ch_free( sie->si_attrs[i] );
5870 				i++;
5871 			}
5872 			ch_free( sie->si_attrs );
5873 		}
5874 		if ( sie->si_exattrs ) {
5875 			int i = 0;
5876 			while ( sie->si_exattrs[i] != NULL ) {
5877 				ch_free( sie->si_exattrs[i] );
5878 				i++;
5879 			}
5880 			ch_free( sie->si_exattrs );
5881 		}
5882 		if ( sie->si_anlist ) {
5883 			int i = 0;
5884 			while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
5885 				ch_free( sie->si_anlist[i].an_name.bv_val );
5886 				i++;
5887 			}
5888 			ch_free( sie->si_anlist );
5889 		}
5890 		if ( sie->si_exanlist ) {
5891 			int i = 0;
5892 			while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
5893 				ch_free( sie->si_exanlist[i].an_name.bv_val );
5894 				i++;
5895 			}
5896 			ch_free( sie->si_exanlist );
5897 		}
5898 		if ( sie->si_retryinterval ) {
5899 			ch_free( sie->si_retryinterval );
5900 		}
5901 		if ( sie->si_retrynum ) {
5902 			ch_free( sie->si_retrynum );
5903 		}
5904 		if ( sie->si_retrynum_init ) {
5905 			ch_free( sie->si_retrynum_init );
5906 		}
5907 		slap_sync_cookie_free( &sie->si_syncCookie, 0 );
5908 #ifdef LDAP_CONTROL_X_DIRSYNC
5909 		if ( sie->si_dirSyncCookie.bv_val ) {
5910 			ch_free( sie->si_dirSyncCookie.bv_val );
5911 		}
5912 #endif
5913 		if ( sie->si_presentlist ) {
5914 		    presentlist_free( sie->si_presentlist );
5915 		}
5916 		while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
5917 			struct nonpresent_entry* npe;
5918 			npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
5919 			LDAP_LIST_REMOVE( npe, npe_link );
5920 			if ( npe->npe_name ) {
5921 				if ( npe->npe_name->bv_val ) {
5922 					ch_free( npe->npe_name->bv_val );
5923 				}
5924 				ch_free( npe->npe_name );
5925 			}
5926 			if ( npe->npe_nname ) {
5927 				if ( npe->npe_nname->bv_val ) {
5928 					ch_free( npe->npe_nname->bv_val );
5929 				}
5930 				ch_free( npe->npe_nname );
5931 			}
5932 			ch_free( npe );
5933 		}
5934 		if ( sie->si_cookieState ) {
5935 			sie->si_cookieState->cs_ref--;
5936 			if ( !sie->si_cookieState->cs_ref ) {
5937 				ch_free( sie->si_cookieState->cs_sids );
5938 				ber_bvarray_free( sie->si_cookieState->cs_vals );
5939 				ldap_pvt_thread_cond_destroy( &sie->si_cookieState->cs_cond );
5940 				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
5941 				ch_free( sie->si_cookieState->cs_psids );
5942 				ber_bvarray_free( sie->si_cookieState->cs_pvals );
5943 				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
5944 				ch_free( sie->si_cookieState );
5945 			}
5946 		}
5947 		if ( sie->si_rewrite )
5948 			rewrite_info_delete( &sie->si_rewrite );
5949 		if ( sie->si_suffixm.bv_val )
5950 			ch_free( sie->si_suffixm.bv_val );
5951 		ch_free( sie );
5952 		sie = si_next;
5953 	} while ( free_all && si_next );
5954 }
5955 
5956 static int
config_suffixm(ConfigArgs * c,syncinfo_t * si)5957 config_suffixm( ConfigArgs *c, syncinfo_t *si )
5958 {
5959 	char *argvEngine[] = { "rewriteEngine", "on", NULL };
5960 	char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
5961 	char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
5962 	char *vnc, *rnc;
5963 	int rc;
5964 
5965 	if ( si->si_rewrite )
5966 		rewrite_info_delete( &si->si_rewrite );
5967 	si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
5968 
5969 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
5970 	if ( rc != LDAP_SUCCESS )
5971 		return rc;
5972 
5973 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
5974 	if ( rc != LDAP_SUCCESS )
5975 		return rc;
5976 
5977 	vnc = ch_malloc( si->si_base.bv_len + 6 );
5978 	strcpy( vnc, "(.*)" );
5979 	lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
5980 	argvRule[1] = vnc;
5981 
5982 	rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
5983 	strcpy( rnc, "%1" );
5984 	strcpy( rnc+2, si->si_suffixm.bv_val );
5985 	argvRule[2] = rnc;
5986 
5987 	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
5988 	ch_free( vnc );
5989 	ch_free( rnc );
5990 	return rc;
5991 }
5992 
5993 /* NOTE: used & documented in slapd.conf(5) */
5994 #define IDSTR			"rid"
5995 #define PROVIDERSTR		"provider"
5996 #define SCHEMASTR		"schemachecking"
5997 #define FILTERSTR		"filter"
5998 #define SEARCHBASESTR		"searchbase"
5999 #define SCOPESTR		"scope"
6000 #define ATTRSONLYSTR		"attrsonly"
6001 #define ATTRSSTR		"attrs"
6002 #define TYPESTR			"type"
6003 #define INTERVALSTR		"interval"
6004 #define RETRYSTR		"retry"
6005 #define SLIMITSTR		"sizelimit"
6006 #define TLIMITSTR		"timelimit"
6007 #define SYNCDATASTR		"syncdata"
6008 #define LOGBASESTR		"logbase"
6009 #define LOGFILTERSTR	"logfilter"
6010 #define SUFFIXMSTR		"suffixmassage"
6011 #define	STRICT_REFRESH	"strictrefresh"
6012 #define LAZY_COMMIT		"lazycommit"
6013 
6014 /* FIXME: undocumented */
6015 #define EXATTRSSTR		"exattrs"
6016 #define MANAGEDSAITSTR		"manageDSAit"
6017 
6018 /* mandatory */
6019 enum {
6020 	GOT_RID			= 0x00000001U,
6021 	GOT_PROVIDER		= 0x00000002U,
6022 	GOT_SCHEMACHECKING	= 0x00000004U,
6023 	GOT_FILTER		= 0x00000008U,
6024 	GOT_SEARCHBASE		= 0x00000010U,
6025 	GOT_SCOPE		= 0x00000020U,
6026 	GOT_ATTRSONLY		= 0x00000040U,
6027 	GOT_ATTRS		= 0x00000080U,
6028 	GOT_TYPE		= 0x00000100U,
6029 	GOT_INTERVAL		= 0x00000200U,
6030 	GOT_RETRY		= 0x00000400U,
6031 	GOT_SLIMIT		= 0x00000800U,
6032 	GOT_TLIMIT		= 0x00001000U,
6033 	GOT_SYNCDATA		= 0x00002000U,
6034 	GOT_LOGBASE		= 0x00004000U,
6035 	GOT_LOGFILTER		= 0x00008000U,
6036 	GOT_EXATTRS		= 0x00010000U,
6037 	GOT_MANAGEDSAIT		= 0x00020000U,
6038 	GOT_BINDCONF		= 0x00040000U,
6039 	GOT_SUFFIXM		= 0x00080000U,
6040 
6041 /* check */
6042 	GOT_REQUIRED		= (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
6043 };
6044 
6045 static slap_verbmasks datamodes[] = {
6046 	{ BER_BVC("default"), SYNCDATA_DEFAULT },
6047 	{ BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
6048 	{ BER_BVC("changelog"), SYNCDATA_CHANGELOG },
6049 	{ BER_BVNULL, 0 }
6050 };
6051 
6052 static int
parse_syncrepl_retry(ConfigArgs * c,char * arg,syncinfo_t * si)6053 parse_syncrepl_retry(
6054 	ConfigArgs	*c,
6055 	char		*arg,
6056 	syncinfo_t	*si )
6057 {
6058 	char **retry_list;
6059 	int j, k, n;
6060 	int use_default = 0;
6061 
6062 	char *val = arg + STRLENOF( RETRYSTR "=" );
6063 	if ( strcasecmp( val, "undefined" ) == 0 ) {
6064 		val = "3600 +";
6065 		use_default = 1;
6066 	}
6067 
6068 	retry_list = (char **) ch_calloc( 1, sizeof( char * ) );
6069 	retry_list[0] = NULL;
6070 
6071 	slap_str2clist( &retry_list, val, " ,\t" );
6072 
6073 	for ( k = 0; retry_list && retry_list[k]; k++ ) ;
6074 	n = k / 2;
6075 	if ( k % 2 ) {
6076 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
6077 			"Error: incomplete syncrepl retry list" );
6078 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6079 		for ( k = 0; retry_list && retry_list[k]; k++ ) {
6080 			ch_free( retry_list[k] );
6081 		}
6082 		ch_free( retry_list );
6083 		return 1;
6084 	}
6085 	si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) );
6086 	si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) );
6087 	si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) );
6088 	for ( j = 0; j < n; j++ ) {
6089 		unsigned long	t;
6090 		if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
6091 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
6092 				"Error: invalid retry interval \"%s\" (#%d)",
6093 				retry_list[j*2], j );
6094 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6095 			/* do some cleanup */
6096 			return 1;
6097 		}
6098 		si->si_retryinterval[j] = (time_t)t;
6099 		if ( *retry_list[j*2+1] == '+' ) {
6100 			si->si_retrynum_init[j] = RETRYNUM_FOREVER;
6101 			si->si_retrynum[j] = RETRYNUM_FOREVER;
6102 			j++;
6103 			break;
6104 		} else {
6105 			if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
6106 					|| si->si_retrynum_init[j] <= 0 )
6107 			{
6108 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6109 					"Error: invalid initial retry number \"%s\" (#%d)",
6110 					retry_list[j*2+1], j );
6111 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6112 				/* do some cleanup */
6113 				return 1;
6114 			}
6115 			if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
6116 					|| si->si_retrynum[j] <= 0 )
6117 			{
6118 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6119 					"Error: invalid retry number \"%s\" (#%d)",
6120 					retry_list[j*2+1], j );
6121 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6122 				/* do some cleanup */
6123 				return 1;
6124 			}
6125 		}
6126 	}
6127 	if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) {
6128 		Debug( LDAP_DEBUG_CONFIG,
6129 			"%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n",
6130 			c->log );
6131 	}
6132 
6133 	si->si_retrynum_init[j] = RETRYNUM_TAIL;
6134 	si->si_retrynum[j] = RETRYNUM_TAIL;
6135 	si->si_retryinterval[j] = 0;
6136 
6137 	for ( k = 0; retry_list && retry_list[k]; k++ ) {
6138 		ch_free( retry_list[k] );
6139 	}
6140 	ch_free( retry_list );
6141 	if ( !use_default ) {
6142 		si->si_got |= GOT_RETRY;
6143 	}
6144 
6145 	return 0;
6146 }
6147 
6148 static int
parse_syncrepl_line(ConfigArgs * c,syncinfo_t * si)6149 parse_syncrepl_line(
6150 	ConfigArgs	*c,
6151 	syncinfo_t	*si )
6152 {
6153 	int	i;
6154 	char	*val;
6155 
6156 	for ( i = 1; i < c->argc; i++ ) {
6157 		if ( !strncasecmp( c->argv[ i ], IDSTR "=",
6158 					STRLENOF( IDSTR "=" ) ) )
6159 		{
6160 			int tmp;
6161 			/* '\0' string terminator accounts for '=' */
6162 			val = c->argv[ i ] + STRLENOF( IDSTR "=" );
6163 			if ( lutil_atoi( &tmp, val ) != 0 ) {
6164 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6165 					"Error: parse_syncrepl_line: "
6166 					"unable to parse syncrepl id \"%s\"", val );
6167 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6168 				return -1;
6169 			}
6170 			if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
6171 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6172 					"Error: parse_syncrepl_line: "
6173 					"syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
6174 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6175 				return -1;
6176 			}
6177 			si->si_rid = tmp;
6178 			sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid );
6179 			si->si_got |= GOT_RID;
6180 		} else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
6181 					STRLENOF( PROVIDERSTR "=" ) ) )
6182 		{
6183 			val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
6184 			ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
6185 #ifdef HAVE_TLS
6186 			if ( ldap_is_ldaps_url( val ))
6187 				si->si_bindconf.sb_tls_do_init = 1;
6188 #endif
6189 			si->si_got |= GOT_PROVIDER;
6190 		} else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
6191 					STRLENOF( SCHEMASTR "=" ) ) )
6192 		{
6193 			val = c->argv[ i ] + STRLENOF( SCHEMASTR "=" );
6194 			if ( !strncasecmp( val, "on", STRLENOF( "on" ) ) ) {
6195 				si->si_schemachecking = 1;
6196 			} else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
6197 				si->si_schemachecking = 0;
6198 			} else {
6199 				si->si_schemachecking = 1;
6200 			}
6201 			si->si_got |= GOT_SCHEMACHECKING;
6202 		} else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=",
6203 					STRLENOF( FILTERSTR "=" ) ) )
6204 		{
6205 			val = c->argv[ i ] + STRLENOF( FILTERSTR "=" );
6206 			if ( si->si_filterstr.bv_val )
6207 				ch_free( si->si_filterstr.bv_val );
6208 			ber_str2bv( val, 0, 1, &si->si_filterstr );
6209 			si->si_got |= GOT_FILTER;
6210 		} else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=",
6211 					STRLENOF( LOGFILTERSTR "=" ) ) )
6212 		{
6213 			val = c->argv[ i ] + STRLENOF( LOGFILTERSTR "=" );
6214 			if ( si->si_logfilterstr.bv_val )
6215 				ch_free( si->si_logfilterstr.bv_val );
6216 			ber_str2bv( val, 0, 1, &si->si_logfilterstr );
6217 			si->si_got |= GOT_LOGFILTER;
6218 		} else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=",
6219 					STRLENOF( SEARCHBASESTR "=" ) ) )
6220 		{
6221 			struct berval	bv;
6222 			int		rc;
6223 
6224 			val = c->argv[ i ] + STRLENOF( SEARCHBASESTR "=" );
6225 			if ( si->si_base.bv_val ) {
6226 				ch_free( si->si_base.bv_val );
6227 			}
6228 			ber_str2bv( val, 0, 0, &bv );
6229 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
6230 			if ( rc != LDAP_SUCCESS ) {
6231 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6232 					"Invalid base DN \"%s\": %d (%s)",
6233 					val, rc, ldap_err2string( rc ) );
6234 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6235 				return -1;
6236 			}
6237 			si->si_got |= GOT_SEARCHBASE;
6238 		} else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
6239 					STRLENOF( SUFFIXMSTR "=" ) ) )
6240 		{
6241 			struct berval	bv;
6242 			int		rc;
6243 
6244 			val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
6245 			if ( si->si_suffixm.bv_val ) {
6246 				ch_free( si->si_suffixm.bv_val );
6247 			}
6248 			ber_str2bv( val, 0, 0, &bv );
6249 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
6250 			if ( rc != LDAP_SUCCESS ) {
6251 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6252 					"Invalid massage DN \"%s\": %d (%s)",
6253 					val, rc, ldap_err2string( rc ) );
6254 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6255 				return -1;
6256 			}
6257 			if ( !be_issubordinate( c->be, &si->si_suffixm )) {
6258 				ch_free( si->si_suffixm.bv_val );
6259 				BER_BVZERO( &si->si_suffixm );
6260 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6261 					"Massage DN \"%s\" is not within the database naming context",
6262 					val );
6263 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6264 				return -1;
6265 			}
6266 			si->si_got |= GOT_SUFFIXM;
6267 		} else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
6268 					STRLENOF( LOGBASESTR "=" ) ) )
6269 		{
6270 			struct berval	bv;
6271 			int		rc;
6272 
6273 			val = c->argv[ i ] + STRLENOF( LOGBASESTR "=" );
6274 			if ( si->si_logbase.bv_val ) {
6275 				ch_free( si->si_logbase.bv_val );
6276 			}
6277 			ber_str2bv( val, 0, 0, &bv );
6278 			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_logbase, NULL );
6279 			if ( rc != LDAP_SUCCESS ) {
6280 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6281 					"Invalid logbase DN \"%s\": %d (%s)",
6282 					val, rc, ldap_err2string( rc ) );
6283 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6284 				return -1;
6285 			}
6286 			si->si_got |= GOT_LOGBASE;
6287 		} else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=",
6288 					STRLENOF( SCOPESTR "=" ) ) )
6289 		{
6290 			int j;
6291 			val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
6292 			j = ldap_pvt_str2scope( val );
6293 			if ( j < 0 ) {
6294 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6295 					"Error: parse_syncrepl_line: "
6296 					"unknown scope \"%s\"", val);
6297 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6298 				return -1;
6299 			}
6300 			si->si_scope = j;
6301 			si->si_got |= GOT_SCOPE;
6302 		} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
6303 					STRLENOF( ATTRSONLYSTR ) ) )
6304 		{
6305 			si->si_attrsonly = 1;
6306 			si->si_got |= GOT_ATTRSONLY;
6307 		} else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=",
6308 					STRLENOF( ATTRSSTR "=" ) ) )
6309 		{
6310 			val = c->argv[ i ] + STRLENOF( ATTRSSTR "=" );
6311 			if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
6312 				char *attr_fname;
6313 				attr_fname = ch_strdup( val + STRLENOF(":include:") );
6314 				si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
6315 				if ( si->si_anlist == NULL ) {
6316 					ch_free( attr_fname );
6317 					return -1;
6318 				}
6319 				si->si_anfile = attr_fname;
6320 			} else {
6321 				char *str, *s, *next;
6322 				const char *delimstr = " ,\t";
6323 				str = ch_strdup( val );
6324 				for ( s = ldap_pvt_strtok( str, delimstr, &next );
6325 						s != NULL;
6326 						s = ldap_pvt_strtok( NULL, delimstr, &next ) )
6327 				{
6328 					if ( strlen(s) == 1 && *s == '*' ) {
6329 						si->si_allattrs = 1;
6330 						val[ s - str ] = delimstr[0];
6331 					}
6332 					if ( strlen(s) == 1 && *s == '+' ) {
6333 						si->si_allopattrs = 1;
6334 						val [ s - str ] = delimstr[0];
6335 					}
6336 				}
6337 				ch_free( str );
6338 				si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
6339 				if ( si->si_anlist == NULL ) {
6340 					return -1;
6341 				}
6342 			}
6343 			si->si_got |= GOT_ATTRS;
6344 		} else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=",
6345 					STRLENOF( EXATTRSSTR "=" ) ) )
6346 		{
6347 			val = c->argv[ i ] + STRLENOF( EXATTRSSTR "=" );
6348 			if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
6349 				char *attr_fname;
6350 				attr_fname = ch_strdup( val + STRLENOF(":include:") );
6351 				si->si_exanlist = file2anlist(
6352 					si->si_exanlist, attr_fname, " ,\t" );
6353 				if ( si->si_exanlist == NULL ) {
6354 					ch_free( attr_fname );
6355 					return -1;
6356 				}
6357 				ch_free( attr_fname );
6358 			} else {
6359 				si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
6360 				if ( si->si_exanlist == NULL ) {
6361 					return -1;
6362 				}
6363 			}
6364 			si->si_got |= GOT_EXATTRS;
6365 		} else if ( !strncasecmp( c->argv[ i ], TYPESTR "=",
6366 					STRLENOF( TYPESTR "=" ) ) )
6367 		{
6368 			val = c->argv[ i ] + STRLENOF( TYPESTR "=" );
6369 			if ( !strncasecmp( val, "refreshOnly",
6370 						STRLENOF("refreshOnly") ) )
6371 			{
6372 				si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
6373 			} else if ( !strncasecmp( val, "refreshAndPersist",
6374 						STRLENOF("refreshAndPersist") ) )
6375 			{
6376 				si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_AND_PERSIST;
6377 				si->si_interval = 60;
6378 #ifdef LDAP_CONTROL_X_DIRSYNC
6379 			} else if ( !strncasecmp( val, "dirSync",
6380 						STRLENOF("dirSync") ) )
6381 			{
6382 				if ( sy_ad_objectGUID == NULL && syncrepl_dirsync_schema()) {
6383 					sprintf( c->cr_msg, "Error: dirSync schema is missing" );
6384 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6385 					return -1;
6386 				}
6387 				/* MS DirSync is refreshOnly, no persist */
6388 				si->si_type = si->si_ctype = MSAD_DIRSYNC;
6389 #endif
6390 			} else {
6391 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6392 					"Error: parse_syncrepl_line: "
6393 					"unknown sync type \"%s\"", val);
6394 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6395 				return -1;
6396 			}
6397 			si->si_got |= GOT_TYPE;
6398 		} else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=",
6399 					STRLENOF( INTERVALSTR "=" ) ) )
6400 		{
6401 			val = c->argv[ i ] + STRLENOF( INTERVALSTR "=" );
6402 			if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
6403 				si->si_interval = 0;
6404 			} else if ( strchr( val, ':' ) != NULL ) {
6405 				char *next, *ptr = val;
6406 				int dd, hh, mm, ss;
6407 
6408 				dd = strtol( ptr, &next, 10 );
6409 				if ( next == ptr || next[0] != ':' || dd < 0 ) {
6410 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
6411 						"Error: parse_syncrepl_line: "
6412 						"invalid interval \"%s\", unable to parse days", val );
6413 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6414 					return -1;
6415 				}
6416 				ptr = next + 1;
6417 				hh = strtol( ptr, &next, 10 );
6418 				if ( next == ptr || next[0] != ':' || hh < 0 || hh > 24 ) {
6419 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
6420 						"Error: parse_syncrepl_line: "
6421 						"invalid interval \"%s\", unable to parse hours", val );
6422 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6423 					return -1;
6424 				}
6425 				ptr = next + 1;
6426 				mm = strtol( ptr, &next, 10 );
6427 				if ( next == ptr || next[0] != ':' || mm < 0 || mm > 60 ) {
6428 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
6429 						"Error: parse_syncrepl_line: "
6430 						"invalid interval \"%s\", unable to parse minutes", val );
6431 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6432 					return -1;
6433 				}
6434 				ptr = next + 1;
6435 				ss = strtol( ptr, &next, 10 );
6436 				if ( next == ptr || next[0] != '\0' || ss < 0 || ss > 60 ) {
6437 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
6438 						"Error: parse_syncrepl_line: "
6439 						"invalid interval \"%s\", unable to parse seconds", val );
6440 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6441 					return -1;
6442 				}
6443 				si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
6444 			} else {
6445 				unsigned long	t;
6446 
6447 				if ( lutil_parse_time( val, &t ) != 0 ) {
6448 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
6449 						"Error: parse_syncrepl_line: "
6450 						"invalid interval \"%s\"", val );
6451 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6452 					return -1;
6453 				}
6454 				si->si_interval = (time_t)t;
6455 			}
6456 			if ( si->si_interval < 0 ) {
6457 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6458 					"Error: parse_syncrepl_line: "
6459 					"invalid interval \"%ld\"",
6460 					(long) si->si_interval);
6461 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6462 				return -1;
6463 			}
6464 			si->si_got |= GOT_INTERVAL;
6465 		} else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=",
6466 					STRLENOF( RETRYSTR "=" ) ) )
6467 		{
6468 			if ( parse_syncrepl_retry( c, c->argv[ i ], si ) ) {
6469 				return 1;
6470 			}
6471 		} else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=",
6472 					STRLENOF( MANAGEDSAITSTR "=" ) ) )
6473 		{
6474 			val = c->argv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
6475 			if ( lutil_atoi( &si->si_manageDSAit, val ) != 0
6476 				|| si->si_manageDSAit < 0 || si->si_manageDSAit > 1 )
6477 			{
6478 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6479 					"invalid manageDSAit value \"%s\".\n",
6480 					val );
6481 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6482 				return 1;
6483 			}
6484 			si->si_got |= GOT_MANAGEDSAIT;
6485 		} else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=",
6486 					STRLENOF( SLIMITSTR "=") ) )
6487 		{
6488 			val = c->argv[ i ] + STRLENOF( SLIMITSTR "=" );
6489 			if ( strcasecmp( val, "unlimited" ) == 0 ) {
6490 				si->si_slimit = 0;
6491 
6492 			} else if ( lutil_atoi( &si->si_slimit, val ) != 0 || si->si_slimit < 0 ) {
6493 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6494 					"invalid size limit value \"%s\".\n",
6495 					val );
6496 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6497 				return 1;
6498 			}
6499 			si->si_got |= GOT_SLIMIT;
6500 		} else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=",
6501 					STRLENOF( TLIMITSTR "=" ) ) )
6502 		{
6503 			val = c->argv[ i ] + STRLENOF( TLIMITSTR "=" );
6504 			if ( strcasecmp( val, "unlimited" ) == 0 ) {
6505 				si->si_tlimit = 0;
6506 
6507 			} else if ( lutil_atoi( &si->si_tlimit, val ) != 0 || si->si_tlimit < 0 ) {
6508 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
6509 					"invalid time limit value \"%s\".\n",
6510 					val );
6511 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6512 				return 1;
6513 			}
6514 			si->si_got |= GOT_TLIMIT;
6515 		} else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=",
6516 					STRLENOF( SYNCDATASTR "=" ) ) )
6517 		{
6518 			val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
6519 			si->si_syncdata = verb_to_mask( val, datamodes );
6520 			si->si_got |= GOT_SYNCDATA;
6521 			if ( si->si_syncdata == SYNCDATA_CHANGELOG ) {
6522 				if ( sy_ad_nsUniqueId == NULL ) {
6523 					int rc = syncrepl_dsee_schema();
6524 					if ( rc ) {
6525 						snprintf( c->cr_msg, sizeof( c->cr_msg ),
6526 							"changelog schema problem (%d)\n", rc );
6527 						Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6528 						return 1;
6529 					}
6530 				}
6531 			}
6532 		} else if ( !strncasecmp( c->argv[ i ], STRICT_REFRESH,
6533 					STRLENOF( STRICT_REFRESH ) ) )
6534 		{
6535 			si->si_strict_refresh = 1;
6536 		} else if ( !strncasecmp( c->argv[ i ], LAZY_COMMIT,
6537 					STRLENOF( LAZY_COMMIT ) ) )
6538 		{
6539 			si->si_lazyCommit = 1;
6540 		} else if ( !bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
6541 			si->si_got |= GOT_BINDCONF;
6542 		} else {
6543 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
6544 				"Error: parse_syncrepl_line: "
6545 				"unable to parse \"%s\"\n", c->argv[ i ] );
6546 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6547 			return -1;
6548 		}
6549 	}
6550 
6551 	if ( ( si->si_got & GOT_REQUIRED ) != GOT_REQUIRED ) {
6552 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
6553 			"Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s",
6554 			si->si_got & GOT_RID ? "" : " "IDSTR,
6555 			si->si_got & GOT_PROVIDER ? "" : " "PROVIDERSTR,
6556 			si->si_got & GOT_SEARCHBASE ? "" : " "SEARCHBASESTR );
6557 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6558 		return -1;
6559 	}
6560 
6561 	if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
6562 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
6563 			"Base DN \"%s\" is not within the database naming context",
6564 			si->si_base.bv_val );
6565 		ch_free( si->si_base.bv_val );
6566 		BER_BVZERO( &si->si_base );
6567 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6568 		return -1;
6569 	}
6570 
6571 	if ( si->si_got & GOT_SUFFIXM ) {
6572 		if (config_suffixm( c, si )) {
6573 			ch_free( si->si_suffixm.bv_val );
6574 			BER_BVZERO( &si->si_suffixm );
6575 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
6576 				"Error configuring rewrite engine" );
6577 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
6578 			return -1;
6579 		}
6580 	}
6581 
6582 	if ( !( si->si_got & GOT_RETRY ) ) {
6583 		Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n",
6584 			si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)" );
6585 		if ( si->si_retryinterval == NULL ) {
6586 			if ( parse_syncrepl_retry( c, "retry=undefined", si ) ) {
6587 				return 1;
6588 			}
6589 		}
6590 	}
6591 
6592 	si->si_filter = str2filter( si->si_filterstr.bv_val );
6593 	if ( si->si_filter == NULL ) {
6594 		Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n",
6595 			si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
6596 		return 1;
6597 	}
6598 
6599 	if ( si->si_got & GOT_LOGFILTER ) {
6600 		si->si_logfilter = str2filter( si->si_logfilterstr.bv_val );
6601 		if ( si->si_logfilter == NULL ) {
6602 			Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse logfilter=\"%s\"\n",
6603 				si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_logfilterstr.bv_val );
6604 			return 1;
6605 		}
6606 	}
6607 
6608 	return 0;
6609 }
6610 
6611 /* monitor entry contains:
6612 	provider URLs
6613 	timestamp of last contact
6614 	cookievals
6615 	*/
6616 
6617 static ObjectClass	*oc_olmSyncRepl;
6618 static AttributeDescription	*ad_olmProviderURIList,
6619 	*ad_olmConnection, *ad_olmSyncPhase,
6620 	*ad_olmNextConnect, *ad_olmLastConnect, *ad_olmLastContact,
6621 	*ad_olmLastCookieRcvd, *ad_olmLastCookieSent;
6622 
6623 static struct {
6624 	char *name;
6625 	char *oid;
6626 } s_oid[] = {
6627 	{ "olmSyncReplAttributes",	"olmOverlayAttributes:1" },
6628 	{ "olmSyncReplObjectClasses", "olmOverlayObjectClasses:1" },
6629 	{ NULL }
6630 };
6631 
6632 static struct {
6633 	char *desc;
6634 	AttributeDescription **ad;
6635 } s_at[] = {
6636 	{ "( olmSyncReplAttributes:1 "
6637 		"NAME ( 'olmSRProviderURIList' ) "
6638 		"DESC 'List of provider URIs for this consumer instance' "
6639 		"SUP monitoredInfo "
6640 		"NO-USER-MODIFICATION "
6641 		"USAGE dSAOperation )",
6642 		&ad_olmProviderURIList },
6643 	{ "( olmSyncReplAttributes:2 "
6644 		"NAME ( 'olmSRConnection' ) "
6645 		"DESC 'Local address:port of connection to provider' "
6646 		"SUP monitoredInfo "
6647 		"SINGLE-VALUE "
6648 		"NO-USER-MODIFICATION "
6649 		"USAGE dSAOperation )",
6650 		&ad_olmConnection },
6651 	{ "( olmSyncReplAttributes:3 "
6652 		"NAME ( 'olmSRSyncPhase' ) "
6653 		"DESC 'Current syncrepl mode' "
6654 		"SUP monitoredInfo "
6655 		"SINGLE-VALUE "
6656 		"NO-USER-MODIFICATION "
6657 		"USAGE dSAOperation )",
6658 		&ad_olmSyncPhase },
6659 	{ "( olmSyncReplAttributes:4 "
6660 		"NAME ( 'olmSRNextConnect' ) "
6661 		"DESC 'Scheduled time of next connection attempt' "
6662 		"SUP monitorTimestamp "
6663 		"SINGLE-VALUE "
6664 		"NO-USER-MODIFICATION "
6665 		"USAGE dSAOperation )",
6666 		&ad_olmNextConnect },
6667 	{ "( olmSyncReplAttributes:5 "
6668 		"NAME ( 'olmSRLastConnect' ) "
6669 		"DESC 'Time last connected to provider' "
6670 		"SUP monitorTimestamp "
6671 		"SINGLE-VALUE "
6672 		"NO-USER-MODIFICATION "
6673 		"USAGE dSAOperation )",
6674 		&ad_olmLastConnect },
6675 	{ "( olmSyncReplAttributes:6 "
6676 		"NAME ( 'olmSRLastContact' ) "
6677 		"DESC 'Time last message received from provider' "
6678 		"SUP monitorTimestamp "
6679 		"SINGLE-VALUE "
6680 		"NO-USER-MODIFICATION "
6681 		"USAGE dSAOperation )",
6682 		&ad_olmLastContact },
6683 	{ "( olmSyncReplAttributes:7 "
6684 		"NAME ( 'olmSRLastCookieRcvd' ) "
6685 		"DESC 'Last sync cookie received from provider' "
6686 		"SUP monitoredInfo "
6687 		"NO-USER-MODIFICATION "
6688 		"USAGE dSAOperation )",
6689 		&ad_olmLastCookieRcvd },
6690 	{ "( olmSyncReplAttributes:8 "
6691 		"NAME ( 'olmSRLastCookieSent' ) "
6692 		"DESC 'Last sync cookie sent to provider' "
6693 		"SUP monitoredInfo "
6694 		"NO-USER-MODIFICATION "
6695 		"USAGE dSAOperation )",
6696 		&ad_olmLastCookieSent },
6697 	{ NULL }
6698 };
6699 
6700 static struct {
6701 	char *desc;
6702 	ObjectClass **oc;
6703 } s_oc[] = {
6704 	{ "( olmSyncReplObjectClasses:1 "
6705 		"NAME ( 'olmSyncReplInstance' ) "
6706 		"SUP monitoredObject STRUCTURAL "
6707 		"MAY ( "
6708 			"olmSRProviderURIList "
6709 			"$ olmSRConnection "
6710 			"$ olmSRSyncPhase "
6711 			"$ olmSRNextConnect "
6712 			"$ olmSRLastConnect "
6713 			"$ olmSRLastContact "
6714 			"$ olmSRLastCookieRcvd "
6715 			"$ olmSRLastCookieSent "
6716 			") )",
6717 		&oc_olmSyncRepl },
6718 	{ NULL }
6719 };
6720 
6721 static int
6722 syncrepl_monitor_initialized;
6723 
6724 int
syncrepl_monitor_init(void)6725 syncrepl_monitor_init( void )
6726 {
6727 	int i, code;
6728 
6729 	if ( syncrepl_monitor_initialized )
6730 		return 0;
6731 
6732 	if ( backend_info( "monitor" ) == NULL )
6733 		return -1;
6734 
6735 	{
6736 		ConfigArgs c;
6737 		char *argv[3];
6738 
6739 		argv[ 0 ] = "syncrepl monitor";
6740 		c.argv = argv;
6741 		c.argc = 2;
6742 		c.fname = argv[0];
6743 		for ( i=0; s_oid[i].name; i++ ) {
6744 			argv[1] = s_oid[i].name;
6745 			argv[2] = s_oid[i].oid;
6746 			if ( parse_oidm( &c, 0, NULL )) {
6747 				Debug( LDAP_DEBUG_ANY,
6748 					"syncrepl_monitor_init: unable to add "
6749 					"objectIdentifier \"%s=%s\"\n",
6750 					s_oid[i].name, s_oid[i].oid );
6751 					return 2;
6752 			}
6753 		}
6754 	}
6755 
6756 	for ( i=0; s_at[i].desc != NULL; i++ ) {
6757 		code = register_at( s_at[i].desc, s_at[i].ad, 1 );
6758 		if ( code != LDAP_SUCCESS ) {
6759 			Debug( LDAP_DEBUG_ANY,
6760 				"syncrepl_monitor_init: register_at failed for attributeType (%s)\n",
6761 				s_at[i].desc );
6762 			return 3;
6763 		} else {
6764 			(*s_at[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
6765 		}
6766 	}
6767 
6768 	for ( i=0; s_oc[i].desc != NULL; i++ ) {
6769 		code = register_oc( s_oc[i].desc, s_oc[i].oc, 1 );
6770 		if ( code != LDAP_SUCCESS ) {
6771 			Debug( LDAP_DEBUG_ANY,
6772 				"syncrepl_monitor_init: register_oc failed for objectClass (%s)\n",
6773 				s_oc[i].desc );
6774 			return 4;
6775 		} else {
6776 			(*s_oc[i].oc)->soc_flags |= SLAP_OC_HIDE;
6777 		}
6778 	}
6779 	syncrepl_monitor_initialized = 1;
6780 
6781 	return 0;
6782 }
6783 
6784 static const struct berval zerotime = BER_BVC("00000101000000Z");
6785 
6786 static int
syncrepl_monitor_update(Operation * op,SlapReply * rs,Entry * e,void * priv)6787 syncrepl_monitor_update(
6788 	Operation *op,
6789 	SlapReply *rs,
6790 	Entry *e,
6791 	void *priv )
6792 {
6793 	syncinfo_t *si = (syncinfo_t *)priv;
6794 	Attribute *a;
6795 	int isConnected = 0;
6796 
6797 	a = attr_find( e->e_attrs, ad_olmConnection );
6798 	if ( !a )
6799 		return SLAP_CB_CONTINUE;
6800 	if ( si->si_ld ) {
6801 		if (!bvmatch( &a->a_vals[0], &si->si_connaddr )) {
6802 			AC_MEMCPY( a->a_vals[0].bv_val, si->si_connaddr.bv_val, si->si_connaddr.bv_len );
6803 			a->a_vals[0].bv_len = si->si_connaddr.bv_len;
6804 		}
6805 		isConnected = 1;
6806 	} else {
6807 		a->a_vals[0].bv_val[0] = '\0';
6808 		a->a_vals[0].bv_len = 0;
6809 	}
6810 
6811 	a = a->a_next;
6812 	if ( a->a_desc != ad_olmSyncPhase )
6813 		return SLAP_CB_CONTINUE;
6814 
6815 	if ( si->si_refreshDone ) {
6816 		struct berval bv = BER_BVC("Persist");
6817 		ber_bvreplace( &a->a_vals[0], &bv );
6818 	} else {
6819 		if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
6820 			struct berval bv = BER_BVC("Fallback Refresh");
6821 			ber_bvreplace( &a->a_vals[0], &bv );
6822 		} else {
6823 			struct berval bv = BER_BVC("Refresh");
6824 			ber_bvreplace( &a->a_vals[0], &bv );
6825 		}
6826 	}
6827 
6828 	{
6829 		struct tm tm;
6830 		char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
6831 		ber_len_t len;
6832 
6833 		a = a->a_next;
6834 		if ( a->a_desc != ad_olmNextConnect )
6835 			return SLAP_CB_CONTINUE;
6836 
6837 		if ( !isConnected && si->si_re && si->si_re->next_sched.tv_sec ) {
6838 			time_t next_sched = si->si_re->next_sched.tv_sec;
6839 			ldap_pvt_gmtime( &next_sched, &tm );
6840 			lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
6841 			len = strlen( tmbuf );
6842 			assert( len == a->a_vals[0].bv_len );
6843 			AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
6844 		} else {
6845 			AC_MEMCPY( a->a_vals[0].bv_val, zerotime.bv_val, zerotime.bv_len );
6846 		}
6847 
6848 		a = a->a_next;
6849 		if ( a->a_desc != ad_olmLastConnect )
6850 			return SLAP_CB_CONTINUE;
6851 
6852 		if ( si->si_lastconnect ) {
6853 			ldap_pvt_gmtime( &si->si_lastconnect, &tm );
6854 			lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
6855 			len = strlen( tmbuf );
6856 			assert( len == a->a_vals[0].bv_len );
6857 			AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
6858 		}
6859 
6860 		a = a->a_next;
6861 		if ( a->a_desc != ad_olmLastContact )
6862 			return SLAP_CB_CONTINUE;
6863 
6864 		if ( si->si_lastcontact ) {
6865 			ldap_pvt_gmtime( &si->si_lastcontact, &tm );
6866 			lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
6867 			len = strlen( tmbuf );
6868 			assert( len == a->a_vals[0].bv_len );
6869 			AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
6870 		}
6871 	}
6872 
6873 	a = a->a_next;
6874 	if ( a->a_desc != ad_olmLastCookieRcvd )
6875 		return SLAP_CB_CONTINUE;
6876 
6877 	ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
6878 	if ( !BER_BVISEMPTY( &si->si_lastCookieRcvd ) &&
6879 		!bvmatch( &a->a_vals[0], &si->si_lastCookieRcvd ))
6880 		ber_bvreplace( &a->a_vals[0], &si->si_lastCookieRcvd );
6881 
6882 	a = a->a_next;
6883 	if ( a->a_desc != ad_olmLastCookieSent ) {
6884 		ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
6885 		return SLAP_CB_CONTINUE;
6886 	}
6887 
6888 	if ( !BER_BVISEMPTY( &si->si_lastCookieSent ) &&
6889 		!bvmatch( &a->a_vals[0], &si->si_lastCookieSent ))
6890 		ber_bvreplace( &a->a_vals[0], &si->si_lastCookieSent );
6891 	ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
6892 
6893 	return SLAP_CB_CONTINUE;
6894 }
6895 
6896 static int
syncrepl_monitor_add(syncinfo_t * si)6897 syncrepl_monitor_add(
6898 	syncinfo_t *si
6899 )
6900 {
6901 	BackendInfo *mi;
6902 	monitor_extra_t *mbe;
6903 	struct berval pndn, pdn, rdn, bv;
6904 	char rdnbuf[sizeof("cn=Consumer 999")];
6905 	Entry *e, *p;
6906 	int rc;
6907 
6908 	if ( !syncrepl_monitor_initialized )
6909 		return -1;
6910 
6911 	mi = backend_info( "monitor" );
6912 	if ( !mi || !mi->bi_extra ) {
6913 		SLAP_DBFLAGS( si->si_be ) ^= SLAP_DBFLAG_MONITORING;
6914 		return 0;
6915 	}
6916 	mbe = mi->bi_extra;
6917 
6918 	if ( !mbe->is_configured() ) {
6919 		return 0;
6920 	}
6921 
6922 	rc = mbe->register_database( si->si_be, &pndn );
6923 	if ( rc ) {
6924 		Debug( LDAP_DEBUG_ANY, "syncrepl_monitor_add: "
6925 			"failed to register the database with back-monitor\n" );
6926 		return rc;
6927 	}
6928 	rdn.bv_len = sprintf(rdnbuf, "cn=Consumer %03d", si->si_rid );
6929 	rdn.bv_val = rdnbuf;
6930 	p = mbe->entry_get_unlocked( &pndn );
6931 	if ( p ) {
6932 		pdn = p->e_name;
6933 	} else {
6934 		pdn = pndn;
6935 	}
6936 
6937 	e = mbe->entry_stub( &pdn, &pndn, &rdn,
6938 		oc_olmSyncRepl, NULL, NULL );
6939 	if ( e == NULL ) {
6940 		Debug( LDAP_DEBUG_ANY,
6941 			"syncrepl_monitor_add: "
6942 			"unable to create entry \"%s,%s\"\n",
6943 			rdn.bv_val, pndn.bv_val );
6944 		return -1;
6945 	}
6946 
6947 	attr_merge_normalize_one( e, ad_olmProviderURIList,
6948 		&si->si_bindconf.sb_uri, NULL );
6949 
6950 	{
6951 		si->si_connaddr.bv_val = si->si_connaddrbuf;
6952 		si->si_connaddr.bv_len = sizeof( si->si_connaddrbuf );
6953 		si->si_connaddrbuf[0] = '\0';
6954 		attr_merge_normalize_one( e, ad_olmConnection, &si->si_connaddr, NULL );
6955 	}
6956 	{
6957 		struct berval bv = BER_BVC("Refresh");
6958 		attr_merge_normalize_one( e, ad_olmSyncPhase, &bv, NULL );
6959 	}
6960 	{
6961 		attr_merge_normalize_one( e, ad_olmNextConnect, (struct berval *)&zerotime, NULL );
6962 		attr_merge_normalize_one( e, ad_olmLastConnect, (struct berval *)&zerotime, NULL );
6963 		attr_merge_normalize_one( e, ad_olmLastContact, (struct berval *)&zerotime, NULL );
6964 	}
6965 	{
6966 		struct berval bv = BER_BVC("");
6967 		attr_merge_normalize_one( e, ad_olmLastCookieRcvd, &bv, NULL );
6968 		attr_merge_normalize_one( e, ad_olmLastCookieSent, &bv, NULL );
6969 	}
6970 	{
6971 		monitor_callback_t *cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
6972 		cb->mc_update = syncrepl_monitor_update;
6973 		cb->mc_private = si;
6974 		rc = mbe->register_entry( e, cb, NULL, 0 );
6975 	}
6976 
6977 	si->si_monitor_ndn = e->e_nname;
6978 	BER_BVZERO( &e->e_nname );
6979 	entry_free( e );
6980 
6981 	return rc;
6982 }
6983 
6984 static int
syncrepl_monitor_del(syncinfo_t * si)6985 syncrepl_monitor_del(
6986 	syncinfo_t *si
6987 )
6988 {
6989 	BackendInfo *mi;
6990 
6991 	mi = backend_info( "monitor" );
6992 	if ( mi && mi->bi_extra ) {
6993 		monitor_extra_t *mbe = mi->bi_extra;
6994 		mbe->unregister_entry( &si->si_monitor_ndn );
6995 	}
6996 	ch_free( si->si_lastCookieSent.bv_val );
6997 	ch_free( si->si_lastCookieRcvd.bv_val );
6998 	ch_free( si->si_monitor_ndn.bv_val );
6999 	return 0;
7000 }
7001 
7002 static int
add_syncrepl(ConfigArgs * c)7003 add_syncrepl(
7004 	ConfigArgs *c )
7005 {
7006 	syncinfo_t *si;
7007 	int	rc = 0;
7008 
7009 	if ( !( c->be->be_search && c->be->be_add && c->be->be_modify && c->be->be_delete ) ) {
7010 		snprintf( c->cr_msg, sizeof(c->cr_msg), "database %s does not support "
7011 			"operations required for syncrepl", c->be->be_type );
7012 		Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
7013 		return 1;
7014 	}
7015 	if ( BER_BVISEMPTY( &c->be->be_rootdn ) ) {
7016 		strcpy( c->cr_msg, "rootDN must be defined before syncrepl may be used" );
7017 		Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
7018 		return 1;
7019 	}
7020 	si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
7021 
7022 	if ( si == NULL ) {
7023 		Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n" );
7024 		return 1;
7025 	}
7026 
7027 	si->si_bindconf.sb_tls = SB_TLS_OFF;
7028 	si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
7029 	si->si_schemachecking = 0;
7030 	ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
7031 		&si->si_filterstr );
7032 	si->si_base.bv_val = NULL;
7033 	si->si_scope = LDAP_SCOPE_SUBTREE;
7034 	si->si_attrsonly = 0;
7035 	si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
7036 	si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
7037 	si->si_attrs = NULL;
7038 	si->si_allattrs = 0;
7039 	si->si_allopattrs = 0;
7040 	si->si_exattrs = NULL;
7041 	si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
7042 	si->si_interval = 86400;
7043 	si->si_retryinterval = NULL;
7044 	si->si_retrynum_init = NULL;
7045 	si->si_retrynum = NULL;
7046 	si->si_manageDSAit = 0;
7047 	si->si_tlimit = 0;
7048 	si->si_slimit = 0;
7049 
7050 	si->si_presentlist = NULL;
7051 	LDAP_LIST_INIT( &si->si_nonpresentlist );
7052 	ldap_pvt_thread_mutex_init( &si->si_monitor_mutex );
7053 	ldap_pvt_thread_mutex_init( &si->si_mutex );
7054 
7055 	si->si_is_configdb = strcmp( c->be->be_suffix[0].bv_val, "cn=config" ) == 0;
7056 
7057 	rc = parse_syncrepl_line( c, si );
7058 
7059 	if ( rc == 0 ) {
7060 		LDAPURLDesc *lud;
7061 
7062 		/* Must be LDAPv3 because we need controls */
7063 		switch ( si->si_bindconf.sb_version ) {
7064 		case 0:
7065 			/* not explicitly set */
7066 			si->si_bindconf.sb_version = LDAP_VERSION3;
7067 			break;
7068 		case 3:
7069 			/* explicitly set */
7070 			break;
7071 		default:
7072 			Debug( LDAP_DEBUG_ANY,
7073 				"version %d incompatible with syncrepl\n",
7074 				si->si_bindconf.sb_version );
7075 			syncinfo_free( si, 0 );
7076 			return 1;
7077 		}
7078 
7079 		if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
7080 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
7081 				"<%s> invalid URL", c->argv[0] );
7082 			Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
7083 				c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
7084 			return 1;
7085 		}
7086 
7087 		si->si_be = c->be;
7088 		if ( slapMode & SLAP_SERVER_MODE ) {
7089 			int isMe = 0;
7090 			/* check if consumer points to current server and database.
7091 			 * If so, ignore this configuration.
7092 			 */
7093 			if ( !SLAP_DBHIDDEN( c->be ) ) {
7094 				int i;
7095 				/* if searchbase doesn't match current DB suffix,
7096 				 * assume it's different
7097 				 */
7098 				for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
7099 					if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
7100 						isMe = 1;
7101 						break;
7102 					}
7103 				}
7104 				/* if searchbase matches, see if URLs match */
7105 				if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
7106 						lud ) == NULL )
7107 					isMe = 0;
7108 			}
7109 
7110 			if ( !isMe ) {
7111 				init_syncrepl( si );
7112 				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
7113 				si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
7114 					si->si_interval, do_syncrepl, si, "do_syncrepl",
7115 					si->si_ridtxt );
7116 				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
7117 				if ( si->si_re )
7118 					rc = config_sync_shadow( c ) ? -1 : 0;
7119 				else
7120 					rc = -1;
7121 			}
7122 		} else {
7123 			/* multiprovider still needs to see this flag in tool mode */
7124 			rc = config_sync_shadow( c ) ? -1 : 0;
7125 		}
7126 		ldap_free_urldesc( lud );
7127 	}
7128 
7129 #ifdef HAVE_TLS
7130 	/* Use main slapd defaults */
7131 	bindconf_tls_defaults( &si->si_bindconf );
7132 #endif
7133 	if ( rc != 0 ) {
7134 		Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n" );
7135 		syncinfo_free( si, 0 );
7136 		return 1;
7137 	} else {
7138 		Debug( LDAP_DEBUG_CONFIG,
7139 			"Config: ** successfully added syncrepl %s \"%s\"\n",
7140 			si->si_ridtxt,
7141 			BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
7142 			"(null)" : si->si_bindconf.sb_uri.bv_val );
7143 		if ( c->be->be_syncinfo ) {
7144 			syncinfo_t *sip;
7145 
7146 			si->si_cookieState = c->be->be_syncinfo->si_cookieState;
7147 
7148 			/* add new syncrepl to end of list (same order as when deleting) */
7149 			for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next );
7150 			sip->si_next = si;
7151 		} else {
7152 			si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
7153 			ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
7154 			ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
7155 			ldap_pvt_thread_cond_init( &si->si_cookieState->cs_cond );
7156 
7157 			c->be->be_syncinfo = si;
7158 		}
7159 		si->si_cookieState->cs_ref++;
7160 
7161 		si->si_next = NULL;
7162 		syncrepl_monitor_init();
7163 
7164 		return 0;
7165 	}
7166 }
7167 
7168 static void
syncrepl_unparse(syncinfo_t * si,struct berval * bv)7169 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
7170 {
7171 	struct berval bc, uri, bs;
7172 	char buf[BUFSIZ*2], *ptr;
7173 	ber_len_t len;
7174 	int i;
7175 #	define WHATSLEFT	((ber_len_t) (&buf[sizeof( buf )] - ptr))
7176 
7177 	BER_BVZERO( bv );
7178 
7179 	/* temporarily inhibit bindconf from printing URI */
7180 	uri = si->si_bindconf.sb_uri;
7181 	BER_BVZERO( &si->si_bindconf.sb_uri );
7182 	si->si_bindconf.sb_version = 0;
7183 	bindconf_unparse( &si->si_bindconf, &bc );
7184 	si->si_bindconf.sb_uri = uri;
7185 	si->si_bindconf.sb_version = LDAP_VERSION3;
7186 
7187 	ptr = buf;
7188 	assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
7189 	len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
7190 		si->si_rid, si->si_bindconf.sb_uri.bv_val );
7191 	if ( len >= sizeof( buf ) ) return;
7192 	ptr += len;
7193 	if ( !BER_BVISNULL( &bc ) ) {
7194 		if ( WHATSLEFT <= bc.bv_len ) {
7195 			free( bc.bv_val );
7196 			return;
7197 		}
7198 		ptr = lutil_strcopy( ptr, bc.bv_val );
7199 		free( bc.bv_val );
7200 	}
7201 	if ( !BER_BVISEMPTY( &si->si_filterstr ) ) {
7202 		if ( WHATSLEFT <= STRLENOF( " " FILTERSTR "=\"" "\"" ) + si->si_filterstr.bv_len ) return;
7203 		ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
7204 		ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
7205 		*ptr++ = '"';
7206 	}
7207 	if ( !BER_BVISNULL( &si->si_base ) ) {
7208 		if ( WHATSLEFT <= STRLENOF( " " SEARCHBASESTR "=\"" "\"" ) + si->si_base.bv_len ) return;
7209 		ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
7210 		ptr = lutil_strcopy( ptr, si->si_base.bv_val );
7211 		*ptr++ = '"';
7212 	}
7213 	if ( !BER_BVISNULL( &si->si_suffixm ) ) {
7214 		if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
7215 		ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
7216 		ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
7217 		*ptr++ = '"';
7218 	}
7219 	if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
7220 		if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
7221 		ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
7222 		ptr = lutil_strcopy( ptr, si->si_logfilterstr.bv_val );
7223 		*ptr++ = '"';
7224 	}
7225 	if ( !BER_BVISNULL( &si->si_logbase ) ) {
7226 		if ( WHATSLEFT <= STRLENOF( " " LOGBASESTR "=\"" "\"" ) + si->si_logbase.bv_len ) return;
7227 		ptr = lutil_strcopy( ptr, " " LOGBASESTR "=\"" );
7228 		ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
7229 		*ptr++ = '"';
7230 	}
7231 	if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
7232 		if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
7233 		ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
7234 		ptr = lutil_strcopy( ptr, bs.bv_val );
7235 	}
7236 	if ( si->si_attrsonly ) {
7237 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
7238 		ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR );
7239 	}
7240 	if ( si->si_anfile ) {
7241 		if ( WHATSLEFT <= STRLENOF( " " ATTRSSTR "=\":include:" "\"" ) + strlen( si->si_anfile ) ) return;
7242 		ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:\"" );
7243 		ptr = lutil_strcopy( ptr, si->si_anfile );
7244 		*ptr++ = '"';
7245 	} else if ( si->si_allattrs || si->si_allopattrs ||
7246 		( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) ) )
7247 	{
7248 		char *old;
7249 
7250 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
7251 		ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
7252 		old = ptr;
7253 		ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
7254 		if ( ptr == NULL ) return;
7255 		if ( si->si_allattrs ) {
7256 			if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
7257 			if ( old != ptr ) *ptr++ = ',';
7258 			*ptr++ = '*';
7259 		}
7260 		if ( si->si_allopattrs ) {
7261 			if ( WHATSLEFT <= STRLENOF( ",+\"" ) ) return;
7262 			if ( old != ptr ) *ptr++ = ',';
7263 			*ptr++ = '+';
7264 		}
7265 		*ptr++ = '"';
7266 	}
7267 	if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
7268 		if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
7269 		ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
7270 		ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
7271 		if ( ptr == NULL ) return;
7272 	}
7273 	if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
7274 	ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
7275 	ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
7276 
7277 	if ( WHATSLEFT <= STRLENOF( " " TYPESTR "=" ) + STRLENOF( "refreshAndPersist" ) ) return;
7278 	ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
7279 #ifdef LDAP_CONTROL_X_DIRSYNC
7280 	if ( si->si_type == MSAD_DIRSYNC )
7281 		ptr = lutil_strcopy( ptr, "dirSync" );
7282 	else
7283 #endif
7284 	ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
7285 		"refreshAndPersist" : "refreshOnly" );
7286 
7287 	if ( si->si_type == LDAP_SYNC_REFRESH_ONLY
7288 #ifdef LDAP_CONTROL_X_DIRSYNC
7289 		|| si->si_type == MSAD_DIRSYNC
7290 #endif
7291 	) {
7292 		int dd, hh, mm, ss;
7293 
7294 		dd = si->si_interval;
7295 		ss = dd % 60;
7296 		dd /= 60;
7297 		mm = dd % 60;
7298 		dd /= 60;
7299 		hh = dd % 24;
7300 		dd /= 24;
7301 		len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
7302 			INTERVALSTR, dd, hh, mm, ss );
7303 		if ( len >= WHATSLEFT ) return;
7304 		ptr += len;
7305 	}
7306 
7307 	if ( si->si_got & GOT_RETRY ) {
7308 		const char *space = "";
7309 		if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
7310 		ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
7311 		for (i=0; si->si_retryinterval[i]; i++) {
7312 			len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
7313 				(long) si->si_retryinterval[i] );
7314 			space = " ";
7315 			if ( WHATSLEFT - 1 <= len ) return;
7316 			ptr += len;
7317 			if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
7318 				*ptr++ = '+';
7319 			else {
7320 				len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
7321 				if ( WHATSLEFT <= len ) return;
7322 				ptr += len;
7323 			}
7324 		}
7325 		if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
7326 		*ptr++ = '"';
7327 	} else {
7328 		ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" );
7329 	}
7330 
7331 	if ( si->si_slimit ) {
7332 		len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
7333 		if ( WHATSLEFT <= len ) return;
7334 		ptr += len;
7335 	}
7336 
7337 	if ( si->si_tlimit ) {
7338 		len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
7339 		if ( WHATSLEFT <= len ) return;
7340 		ptr += len;
7341 	}
7342 
7343 	if ( si->si_syncdata ) {
7344 		if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) {
7345 			if ( WHATSLEFT <= STRLENOF( " " SYNCDATASTR "=" ) + bc.bv_len ) return;
7346 			ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" );
7347 			ptr = lutil_strcopy( ptr, bc.bv_val );
7348 		}
7349 	}
7350 
7351 	if ( si->si_lazyCommit ) {
7352 		ptr = lutil_strcopy( ptr, " " LAZY_COMMIT );
7353 	}
7354 
7355 	bc.bv_len = ptr - buf;
7356 	bc.bv_val = buf;
7357 	ber_dupbv( bv, &bc );
7358 }
7359 
7360 int
syncrepl_config(ConfigArgs * c)7361 syncrepl_config( ConfigArgs *c )
7362 {
7363 	if (c->op == SLAP_CONFIG_EMIT) {
7364 		if ( c->be->be_syncinfo ) {
7365 			struct berval bv;
7366 			syncinfo_t *si;
7367 
7368 			for ( si = c->be->be_syncinfo; si; si=si->si_next ) {
7369 				syncrepl_unparse( si, &bv );
7370 				ber_bvarray_add( &c->rvalue_vals, &bv );
7371 			}
7372 			return 0;
7373 		}
7374 		return 1;
7375 	} else if ( c->op == LDAP_MOD_DELETE ) {
7376 		int isrunning = 0;
7377 		if ( c->be->be_syncinfo ) {
7378 			syncinfo_t *si, **sip;
7379 			int i;
7380 
7381 			for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
7382 				si = *sip;
7383 				if ( c->valx == -1 || i == c->valx ) {
7384 					*sip = si->si_next;
7385 					si->si_ctype = -1;
7386 					si->si_next = NULL;
7387 					/* If the task is currently active, we have to leave
7388 					 * it running. It will exit on its own. This will only
7389 					 * happen when running on the cn=config DB.
7390 					 */
7391 					if ( si->si_re ) {
7392 						if ( si->si_be == c->be || ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
7393 							isrunning = 1;
7394 						} else {
7395 							/* There is no active thread, but we must still
7396 							 * ensure that no thread is (or will be) queued
7397 							 * while we removes the task.
7398 							 */
7399 							struct re_s *re = si->si_re;
7400 							si->si_re = NULL;
7401 
7402 							if ( si->si_conn ) {
7403 								connection_client_stop( si->si_conn );
7404 								si->si_conn = NULL;
7405 							}
7406 
7407 							ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
7408 							if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) {
7409 								ldap_pvt_runqueue_stoptask( &slapd_rq, re );
7410 								isrunning = 1;
7411 							}
7412 							if ( ldap_pvt_thread_pool_retract( re->pool_cookie ) > 0 )
7413 								isrunning = 0;
7414 
7415 							ldap_pvt_runqueue_remove( &slapd_rq, re );
7416 							ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
7417 
7418 							ldap_pvt_thread_mutex_unlock( &si->si_mutex );
7419 						}
7420 					}
7421 					if ( !isrunning ) {
7422 						syncinfo_free( si, 0 );
7423 					}
7424 					if ( i == c->valx )
7425 						break;
7426 				} else {
7427 					sip = &si->si_next;
7428 				}
7429 			}
7430 		}
7431 		if ( !c->be->be_syncinfo ) {
7432 			SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
7433 		}
7434 		return 0;
7435 	}
7436 	if ( SLAP_SLURP_SHADOW( c->be ) ) {
7437 		Debug(LDAP_DEBUG_ANY, "%s: "
7438 			"syncrepl: database already shadowed.\n",
7439 			c->log );
7440 		return(1);
7441 	} else {
7442 		return add_syncrepl( c );
7443 	}
7444 }
7445