From 69cd0731a6f5756e065d12dfb666c3b1825da367 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Wed, 26 Aug 2009 01:12:02 +0000
Subject: [PATCH] add pedantic checks

---
 servers/slapd/syncrepl.c | 451 ++++++++++++++++-----------------------
 1 file changed, 181 insertions(+), 270 deletions(-)

diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c
index b95397f472..f10c36b600 100644
--- a/servers/slapd/syncrepl.c
+++ b/servers/slapd/syncrepl.c
@@ -41,7 +41,6 @@ typedef struct cookie_state {
 	ldap_pvt_thread_mutex_t	cs_mutex;
 	int	cs_num;
 	int cs_age;
-	int cs_ref;
 	struct berval *cs_vals;
 	int *cs_sids;
 } cookie_state;
@@ -864,7 +863,6 @@ do_syncrep2(
 							}
 						}
 					}
-					op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
 				}
 			}
 			rc = 0;
@@ -971,7 +969,6 @@ do_syncrep2(
 					if ( !BER_BVISNULL( &syncCookie.octet_str ) )
 					{
 						slap_parse_sync_cookie( &syncCookie, NULL );
-						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
 					}
 				}
 				if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
@@ -1050,7 +1047,6 @@ do_syncrep2(
 					}
 					if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
 						slap_parse_sync_cookie( &syncCookie, NULL );
-						op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
 					}
 					break;
 				case LDAP_TAG_SYNC_REFRESH_DELETE:
@@ -1081,7 +1077,6 @@ do_syncrep2(
 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
 						{
 							slap_parse_sync_cookie( &syncCookie, NULL );
-							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
 						}
 					}
 					/* Defaults to TRUE */
@@ -1117,7 +1112,6 @@ do_syncrep2(
 						if ( !BER_BVISNULL( &syncCookie.octet_str ) )
 						{
 							slap_parse_sync_cookie( &syncCookie, NULL );
-							op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
 							compare_csns( &syncCookie_req, &syncCookie, &m );
 						}
 					}
@@ -1256,27 +1250,16 @@ do_syncrepl(
 	int rc = LDAP_SUCCESS;
 	int dostop = 0;
 	ber_socket_t s;
-	int i, defer = 1, fail = 0, freeinfo = 0;
+	int i, defer = 1, fail = 0;
 	Backend *be;
 
-	if ( si == NULL )
-		return NULL;
-	if ( slapd_shutdown )
-		return NULL;
-
 	Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
 
-	/* Don't get stuck here while a pause is initiated */
-	while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
-		if ( slapd_shutdown )
-			return NULL;
-		if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
-			ldap_pvt_thread_yield();
-	}
+	if ( si == NULL )
+		return NULL;
 
-	if ( si->si_ctype < 1 ) {
-		goto deleted;
-	}
+	/* There will never be more than one instance active */
+	ldap_pvt_thread_mutex_lock( &si->si_mutex );
 
 	switch( abs( si->si_type ) ) {
 	case LDAP_SYNC_REFRESH_ONLY:
@@ -1303,6 +1286,10 @@ do_syncrepl(
 	connection_fake_init( &conn, &opbuf, ctx );
 	op = &opbuf.ob_op;
 
+	/* use global malloc for now */
+	op->o_tmpmemctx = NULL;
+	op->o_tmpmfuncs = &ch_mfuncs;
+
 	op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
 	be = si->si_be;
 
@@ -1361,13 +1348,8 @@ reload:
 			goto reload;
 		}
 
-deleted:
 		/* We got deleted while running on cn=config */
-		if ( si->si_ctype < 1 ) {
-			if ( si->si_ctype == -1 ) {
-				si->si_ctype = 0;
-				freeinfo = 1;
-			}
+		if ( !si->si_ctype ) {
 			if ( si->si_conn )
 				dostop = 1;
 			rc = -1;
@@ -1434,7 +1416,7 @@ deleted:
 				break;
 		}
 
-		if ( si->si_ctype < 1
+		if ( !si->si_ctype
 			|| !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
 			if ( si->si_re ) {
 				ldap_pvt_runqueue_remove( &slapd_rq, rtask );
@@ -1457,22 +1439,24 @@ deleted:
 	if ( rc ) {
 		if ( fail == RETRYNUM_TAIL ) {
 			Debug( LDAP_DEBUG_ANY,
-				"do_syncrepl: %s rc %d quitting\n",
-				si->si_ridtxt, rc, 0 );
+				"do_syncrepl: %s quitting\n",
+				si->si_ridtxt, 0, 0 );
 		} else if ( fail > 0 ) {
 			Debug( LDAP_DEBUG_ANY,
-				"do_syncrepl: %s rc %d retrying (%d retries left)\n",
-				si->si_ridtxt, rc, fail );
+				"do_syncrepl: %s retrying (%d retries left)\n",
+				si->si_ridtxt, fail, 0 );
 		} else {
 			Debug( LDAP_DEBUG_ANY,
-				"do_syncrepl: %s rc %d retrying\n",
-				si->si_ridtxt, rc, 0 );
+				"do_syncrepl: %s retrying\n",
+				si->si_ridtxt, 0, 0 );
 		}
 	}
 
 	/* Do final delete cleanup */
-	if ( freeinfo ) {
-		syncinfo_free( si, 0 );
+	if ( !si->si_ctype ) {
+		cookie_state *cs = si->si_cookieState;
+		syncinfo_free( si, ( !be->be_syncinfo ||
+			be->be_syncinfo->si_cookieState != cs ));
 	}
 	return NULL;
 }
@@ -1594,7 +1578,6 @@ syncrepl_message_to_op(
 		prdn = BER_BVNULL, nrdn = BER_BVNULL,
 		psup = BER_BVNULL, nsup = BER_BVNULL;
 	int		rc, deleteOldRdn = 0, freeReqDn = 0;
-	int		do_graduate = 0;
 
 	if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
 		Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
@@ -1627,16 +1610,7 @@ syncrepl_message_to_op(
 
 		if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
 			bdn = bvals[0];
-			rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
-			if ( rc != LDAP_SUCCESS ) {
-				Debug( LDAP_DEBUG_ANY,
-					"syncrepl_message_to_op: %s "
-					"dn \"%s\" normalization failed (%d)",
-					si->si_ridtxt, bdn.bv_val, rc );
-				rc = -1;
-				ch_free( bvals );
-				goto done;
-			}
+			dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
 			ber_dupbv( &op->o_req_dn, &dn );
 			ber_dupbv( &op->o_req_ndn, &ndn );
 			slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
@@ -1672,7 +1646,6 @@ syncrepl_message_to_op(
 			&slap_schema.si_ad_entryCSN->ad_cname ) )
 		{
 			slap_queue_csn( op, bvals );
-			do_graduate = 1;
 		}
 		ch_free( bvals );
 	}
@@ -1717,7 +1690,6 @@ syncrepl_message_to_op(
 				Debug( LDAP_DEBUG_SYNC,
 					"syncrepl_message_to_op: %s be_add %s (%d)\n", 
 					si->si_ridtxt, op->o_req_dn.bv_val, rc );
-				do_graduate = 0;
 			}
 			if ( e == op->ora_e )
 				be_entry_release_w( op, op->ora_e );
@@ -1730,7 +1702,6 @@ syncrepl_message_to_op(
 				"syncrepl_message_to_op: %s be_modify %s (%d)\n", 
 				si->si_ridtxt, op->o_req_dn.bv_val, rc );
 			op->o_bd = si->si_be;
-			do_graduate = 0;
 		}
 		break;
 	case LDAP_REQ_MODRDN:
@@ -1774,19 +1745,16 @@ syncrepl_message_to_op(
 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
 			"syncrepl_message_to_op: %s be_modrdn %s (%d)\n", 
 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
-		do_graduate = 0;
 		break;
 	case LDAP_REQ_DELETE:
 		rc = op->o_bd->be_delete( op, &rs );
 		Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
 			"syncrepl_message_to_op: %s be_delete %s (%d)\n", 
 			si->si_ridtxt, op->o_req_dn.bv_val, rc );
-		do_graduate = 0;
 		break;
 	}
 done:
-	if ( do_graduate )
-		slap_graduate_commit_csn( op );
+	slap_graduate_commit_csn( op );
 	op->o_bd = si->si_be;
 	op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
 	BER_BVZERO( &op->o_csn );
@@ -1868,21 +1836,7 @@ syncrepl_message_to_entry(
 		return -1;
 	}
 
-	rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
-	if ( rc != LDAP_SUCCESS ) {
-		/* One of the things that could happen is that the schema
-		 * is not lined-up; this could result in unknown attributes.
-		 * A value non conformant to the syntax should be unlikely,
-		 * except when replicating between different versions
-		 * of the software, or when syntax validation bugs are fixed
-		 */
-		Debug( LDAP_DEBUG_ANY,
-			"syncrepl_message_to_entry: "
-			"%s dn \"%s\" normalization failed (%d)",
-			si->si_ridtxt, bdn.bv_val, rc );
-		return rc;
-	}
-
+	dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
 	ber_dupbv( &op->o_req_dn, &dn );
 	ber_dupbv( &op->o_req_ndn, &ndn );
 	slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
@@ -2210,8 +2164,8 @@ retry_add:;
 
 			rc = op->o_bd->be_add( op, &rs_add );
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_add %s (%d)\n", 
-					si->si_ridtxt, op->o_req_dn.bv_val, rc );
+					"syncrepl_entry: %s be_add (%d)\n", 
+					si->si_ridtxt, rc, 0 );
 			switch ( rs_add.sr_err ) {
 			case LDAP_SUCCESS:
 				if ( op->ora_e == entry ) {
@@ -2273,11 +2227,10 @@ retry_add:;
 
 			default:
 				Debug( LDAP_DEBUG_ANY,
-					"syncrepl_entry: %s be_add %s failed (%d)\n",
-					si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
+					"syncrepl_entry: %s be_add failed (%d)\n",
+					si->si_ridtxt, rs_add.sr_err, 0 );
 				break;
 			}
-			syncCSN = NULL;
 			op->o_bd = be;
 			goto done;
 		}
@@ -2368,12 +2321,6 @@ retry_add:;
 								break;
 							}
 						}
-						if ( !mod->sml_numvals ) {
-							/* Drop this op */
-							*ml = mod->sml_next;
-							mod->sml_next = NULL;
-							slap_mods_free( mod, 1 );
-						}
 						break;
 					}
 				}
@@ -2413,7 +2360,7 @@ retry_add:;
 					}
 				}
 			}
-
+					
 			/* RDNs must be NUL-terminated for back-ldap */
 			noldp = op->orr_newrdn;
 			ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
@@ -2470,16 +2417,14 @@ retry_add:;
 
 			slap_mods_free( op->orr_modlist, 1 );
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_modrdn %s (%d)\n", 
-					si->si_ridtxt, op->o_req_dn.bv_val, rc );
+					"syncrepl_entry: %s be_modrdn (%d)\n", 
+					si->si_ridtxt, rc, 0 );
 			op->o_bd = be;
 			/* Renamed entries may still have other mods so just fallthru */
 			op->o_req_dn = entry->e_name;
 			op->o_req_ndn = entry->e_nname;
 			/* Use CSN on the modify */
-			if ( just_rename )
-				syncCSN = NULL;
-			else if ( syncCSN )
+			if ( syncCSN && !just_rename )
 				slap_queue_csn( op, syncCSN );
 		}
 		if ( dni.mods ) {
@@ -2492,23 +2437,18 @@ retry_add:;
 			slap_mods_free( op->orm_modlist, 1 );
 			op->orm_no_opattrs = 0;
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_modify %s (%d)\n", 
-					si->si_ridtxt, op->o_req_dn.bv_val, rc );
+					"syncrepl_entry: %s be_modify (%d)\n", 
+					si->si_ridtxt, rc, 0 );
 			if ( rs_modify.sr_err != LDAP_SUCCESS ) {
 				Debug( LDAP_DEBUG_ANY,
 					"syncrepl_entry: %s be_modify failed (%d)\n",
 					si->si_ridtxt, rs_modify.sr_err, 0 );
 			}
-			syncCSN = NULL;
 			op->o_bd = be;
 		} else if ( !dni.renamed ) {
 			Debug( LDAP_DEBUG_SYNC,
 					"syncrepl_entry: %s entry unchanged, ignored (%s)\n", 
 					si->si_ridtxt, op->o_req_dn.bv_val, 0 );
-			if ( syncCSN ) {
-				slap_graduate_commit_csn( op );
-				syncCSN = NULL;
-			}
 		}
 		goto done;
 	case LDAP_SYNC_DELETE :
@@ -2519,8 +2459,8 @@ retry_add:;
 			op->o_bd = si->si_wbe;
 			rc = op->o_bd->be_delete( op, &rs_delete );
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_delete %s (%d)\n", 
-					si->si_ridtxt, op->o_req_dn.bv_val, rc );
+					"syncrepl_entry: %s be_delete (%d)\n", 
+					si->si_ridtxt, rc, 0 );
 
 			while ( rs_delete.sr_err == LDAP_SUCCESS
 				&& op->o_delete_glue_parent ) {
@@ -2537,7 +2477,6 @@ retry_add:;
 					break;
 				}
 			}
-			syncCSN = NULL;
 			op->o_bd = be;
 		}
 		goto done;
@@ -2948,12 +2887,11 @@ syncrepl_updateCookie(
 {
 	Backend *be = op->o_bd;
 	Modifications mod;
-	struct berval first = BER_BVNULL;
 #ifdef CHECK_CSN
 	Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
 #endif
 
-	int rc, i, j;
+	int rc, i, j, csn_changed = 0;
 	ber_len_t len;
 
 	slap_callback cb = { NULL };
@@ -2995,13 +2933,7 @@ syncrepl_updateCookie(
 			if ( memcmp( syncCookie->ctxcsn[i].bv_val,
 				si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
 				mod.sml_values[j] = syncCookie->ctxcsn[i];
-				if ( BER_BVISNULL( &first ) ) {
-					first = syncCookie->ctxcsn[i];
-
-				} else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
-				{
-					first = syncCookie->ctxcsn[i];
-				}
+				csn_changed = 1;
 			}
 			break;
 		}
@@ -3011,23 +2943,16 @@ syncrepl_updateCookie(
 				( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx );
 			mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i];
 			BER_BVZERO( &mod.sml_values[mod.sml_numvals] );
-			if ( BER_BVISNULL( &first ) ) {
-				first = syncCookie->ctxcsn[i];
-			} else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
-			{
-				first = syncCookie->ctxcsn[i];
-			}
+			csn_changed = 1;
 		}
 	}
 	/* Should never happen, ITS#5065 */
-	if ( BER_BVISNULL( &first )) {
+	if ( !csn_changed ) {
 		ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
 		op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
 		return 0;
 	}
 	op->o_bd = si->si_wbe;
-	slap_queue_csn( op, &first );
-
 	op->o_tag = LDAP_REQ_MODIFY;
 
 	cb.sc_response = null_callback;
@@ -3088,10 +3013,6 @@ syncrepl_updateCookie(
 	return rc;
 }
 
-/* Compare the attribute from the old entry to the one in the new
- * entry. The Modifications from the new entry will either be left
- * in place, or changed to an Add or Delete as needed.
- */
 static void
 attr_cmp( Operation *op, Attribute *old, Attribute *new,
 	Modifications ***mret, Modifications ***mcur )
@@ -3235,86 +3156,6 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
 	*mret = modtail;
 }
 
-/* Generate a set of modifications to change the old entry into the
- * new one. On input ml is a list of modifications equivalent to
- * the new entry. It will be massaged and the result will be stored
- * in mods.
- */
-void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
-	Modifications **mods, Modifications **ml, int is_ctx)
-{
-	Modifications **modtail = mods;
-
-	/* We assume that attributes are saved in the same order
-	 * in the remote and local databases. So if we walk through
-	 * the attributeDescriptions one by one they should match in
-	 * lock step. If not, look for an add or delete.
-	 */
-	while ( old && new )
-	{
-		/* If we've seen this before, use its mod now */
-		if ( new->a_flags & SLAP_ATTR_IXADD ) {
-			attr_cmp( op, NULL, new, &modtail, &ml );
-			new = new->a_next;
-			continue;
-		}
-		/* Skip contextCSN */
-		if ( is_ctx && old->a_desc ==
-			slap_schema.si_ad_contextCSN ) {
-			old = old->a_next;
-			continue;
-		}
-
-		if ( old->a_desc != new->a_desc ) {
-			Modifications *mod;
-			Attribute *tmp;
-
-			/* If it's just been re-added later,
-			 * remember that we've seen it.
-			 */
-			tmp = attr_find( new, old->a_desc );
-			if ( tmp ) {
-				tmp->a_flags |= SLAP_ATTR_IXADD;
-			} else {
-				/* If it's a new attribute, pull it in.
-				 */
-				tmp = attr_find( old, new->a_desc );
-				if ( !tmp ) {
-					attr_cmp( op, NULL, new, &modtail, &ml );
-					new = new->a_next;
-					continue;
-				}
-				/* Delete old attr */
-				mod = ch_malloc( sizeof( Modifications ) );
-				mod->sml_op = LDAP_MOD_DELETE;
-				mod->sml_flags = 0;
-				mod->sml_desc = old->a_desc;
-				mod->sml_type = mod->sml_desc->ad_cname;
-				mod->sml_numvals = 0;
-				mod->sml_values = NULL;
-				mod->sml_nvalues = NULL;
-				*modtail = mod;
-				modtail = &mod->sml_next;
-			}
-			old = old->a_next;
-			continue;
-		}
-		/* kludge - always update modifiersName so that it
-		 * stays co-located with the other mod opattrs. But only
-		 * if we know there are other valid mods.
-		 */
-		if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
-			old->a_desc == slap_schema.si_ad_modifyTimestamp ))
-			attr_cmp( op, NULL, new, &modtail, &ml );
-		else
-			attr_cmp( op, old, new, &modtail, &ml );
-		new = new->a_next;
-		old = old->a_next;
-	}
-	*modtail = *ml;
-	*ml = NULL;
-}
-
 static int
 dn_callback(
 	Operation*	op,
@@ -3345,6 +3186,8 @@ dn_callback(
 				 * is actually newer than old entry
 				 */
 				if ( !is_entry_glue( rs->sr_entry )) {
+					old = attr_find( rs->sr_entry->e_attrs,
+						slap_schema.si_ad_objectClass );
 					old = attr_find( rs->sr_entry->e_attrs,
 						slap_schema.si_ad_entryCSN );
 					new = attr_find( dni->new_entry->e_attrs,
@@ -3435,9 +3278,78 @@ dn_callback(
 					 */
 				}
 
-				syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
-					dni->new_entry->e_attrs, &dni->mods, dni->modlist,
-					is_ctx );
+				modtail = &dni->mods;
+				ml = dni->modlist;
+
+				/* We assume that attributes are saved in the same order
+				 * in the remote and local databases. So if we walk through
+				 * the attributeDescriptions one by one they should match in
+				 * lock step. If not, look for an add or delete.
+				 */
+				for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs;
+						old && new; )
+				{
+					/* If we've seen this before, use its mod now */
+					if ( new->a_flags & SLAP_ATTR_IXADD ) {
+						attr_cmp( op, NULL, new, &modtail, &ml );
+						new = new->a_next;
+						continue;
+					}
+					/* Skip contextCSN */
+					if ( is_ctx && old->a_desc ==
+						slap_schema.si_ad_contextCSN ) {
+						old = old->a_next;
+						continue;
+					}
+
+					if ( old->a_desc != new->a_desc ) {
+						Modifications *mod;
+						Attribute *tmp;
+
+						/* If it's just been re-added later,
+						 * remember that we've seen it.
+						 */
+						tmp = attr_find( new, old->a_desc );
+						if ( tmp ) {
+							tmp->a_flags |= SLAP_ATTR_IXADD;
+						} else {
+							/* If it's a new attribute, pull it in.
+							 */
+							tmp = attr_find( old, new->a_desc );
+							if ( !tmp ) {
+								attr_cmp( op, NULL, new, &modtail, &ml );
+								new = new->a_next;
+								continue;
+							}
+							/* Delete old attr */
+							mod = ch_malloc( sizeof( Modifications ) );
+							mod->sml_op = LDAP_MOD_DELETE;
+							mod->sml_flags = 0;
+							mod->sml_desc = old->a_desc;
+							mod->sml_type = mod->sml_desc->ad_cname;
+							mod->sml_numvals = 0;
+							mod->sml_values = NULL;
+							mod->sml_nvalues = NULL;
+							*modtail = mod;
+							modtail = &mod->sml_next;
+						}
+						old = old->a_next;
+						continue;
+					}
+					/* kludge - always update modifiersName so that it
+					 * stays co-located with the other mod opattrs. But only
+					 * if we know there are other valid mods.
+					 */
+					if ( dni->mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
+						old->a_desc == slap_schema.si_ad_modifyTimestamp ))
+						attr_cmp( op, NULL, new, &modtail, &ml );
+					else
+						attr_cmp( op, old, new, &modtail, &ml );
+					new = new->a_next;
+					old = old->a_next;
+				}
+				*modtail = *ml;
+				*ml = NULL;
 			}
 		}
 	} else if ( rs->sr_type == REP_RESULT ) {
@@ -3640,9 +3552,12 @@ syncinfo_free( syncinfo_t *sie, int free_all )
 {
 	syncinfo_t *si_next;
 
-	Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
-		sie->si_ridtxt, 0, 0 );
-
+	if ( free_all && sie->si_cookieState ) {
+		ch_free( sie->si_cookieState->cs_sids );
+		ber_bvarray_free( sie->si_cookieState->cs_vals );
+		ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
+		ch_free( sie->si_cookieState );
+	}
 	do {
 		si_next = sie->si_next;
 
@@ -3654,21 +3569,20 @@ syncinfo_free( syncinfo_t *sie, int free_all )
 			ldap_unbind_ext( sie->si_ld, NULL, NULL );
 		}
 	
+		/* re-fetch it, in case it was already removed */
+		ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+		sie->si_re = ldap_pvt_runqueue_find( &slapd_rq, do_syncrepl, sie );
 		if ( sie->si_re ) {
-			struct re_s		*re = sie->si_re;
-			sie->si_re = NULL;
-
-			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
-			if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
-				ldap_pvt_runqueue_stoptask( &slapd_rq, re );
-			ldap_pvt_runqueue_remove( &slapd_rq, re );
-			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+			if ( ldap_pvt_runqueue_isrunning( &slapd_rq, sie->si_re ) )
+				ldap_pvt_runqueue_stoptask( &slapd_rq, sie->si_re );
+			ldap_pvt_runqueue_remove( &slapd_rq, sie->si_re );
 		}
-
-		ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
-
+	
+		ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+	 	ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
+	
 		bindconf_free( &sie->si_bindconf );
-
+	
 		if ( sie->si_filterstr.bv_val ) {
 			ch_free( sie->si_filterstr.bv_val );
 		}
@@ -3744,15 +3658,6 @@ syncinfo_free( syncinfo_t *sie, int free_all )
 			}
 			ch_free( npe );
 		}
-		if ( sie->si_cookieState ) {
-			sie->si_cookieState->cs_ref--;
-			if ( !sie->si_cookieState->cs_ref ) {
-				ch_free( sie->si_cookieState->cs_sids );
-				ber_bvarray_free( sie->si_cookieState->cs_vals );
-				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
-				ch_free( sie->si_cookieState );
-			}
-		}
 		ch_free( sie );
 		sie = si_next;
 	} while ( free_all && si_next );
@@ -3808,6 +3713,21 @@ enum {
 	GOT_REQUIRED		= (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
 };
 
+static struct {
+	struct berval key;
+	int val;
+} scopes[] = {
+	{ BER_BVC("base"), LDAP_SCOPE_BASE },
+	{ BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
+	{ BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL },	/* OpenLDAP extension */
+	{ BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
+	{ BER_BVC("subord"), LDAP_SCOPE_SUBORDINATE },
+	{ BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE },
+	{ BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
+	{ BER_BVC("subtree"), LDAP_SCOPE_SUBTREE },	/* OpenLDAP extension */
+	{ BER_BVNULL, 0 }
+};
+
 static slap_verbmasks datamodes[] = {
 	{ BER_BVC("default"), SYNCDATA_DEFAULT },
 	{ BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
@@ -4025,15 +3945,19 @@ parse_syncrepl_line(
 		{
 			int j;
 			val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
-			j = ldap_pvt_str2scope( val );
-			if ( j < 0 ) {
+			for ( j = 0; !BER_BVISNULL(&scopes[j].key); j++ ) {
+				if (!strcasecmp( val, scopes[j].key.bv_val ) ) {
+					si->si_scope = scopes[j].val;
+					break;
+				}
+			}
+			if ( BER_BVISNULL(&scopes[j].key) ) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
 					"Error: parse_syncrepl_line: "
 					"unknown scope \"%s\"", val);
 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
 				return -1;
 			}
-			si->si_scope = j;
 			si->si_got |= GOT_SCOPE;
 		} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
 					STRLENOF( ATTRSONLYSTR ) ) )
@@ -4330,8 +4254,6 @@ add_syncrepl(
 	rc = parse_syncrepl_line( c, si );
 
 	if ( rc == 0 ) {
-		LDAPURLDesc *lud;
-
 		/* Must be LDAPv3 because we need controls */
 		switch ( si->si_bindconf.sb_version ) {
 		case 0:
@@ -4349,35 +4271,24 @@ add_syncrepl(
 			return 1;
 		}
 
-		if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"<%s> invalid URL", c->argv[0] );
-			Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
-				c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
-			return 1;
-		}
-
 		si->si_be = c->be;
 		if ( slapMode & SLAP_SERVER_MODE ) {
+			Listener **l = slapd_get_listeners();
 			int isMe = 0;
-			/* check if consumer points to current server and database.
-			 * If so, ignore this configuration.
+
+			/* check if URL points to current server. If so, ignore
+			 * this configuration. We require an exact match. Just
+			 * in case they really want to do this, they can vary
+			 * the case of the URL to allow it.
 			 */
-			if ( !SLAP_DBHIDDEN( c->be ) ) {
+			if ( l && !SLAP_DBHIDDEN( c->be ) ) {
 				int i;
-				/* if searchbase doesn't match current DB suffix,
-				 * assume it's different
-				 */
-				for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
-					if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
+				for ( i=0; l[i]; i++ ) {
+					if ( bvmatch( &l[i]->sl_url, &si->si_bindconf.sb_uri ) ) {
 						isMe = 1;
 						break;
 					}
 				}
-				/* if searchbase matches, see if URLs match */
-				if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
-						lud ) == NULL )
-					isMe = 0;
 			}
 
 			if ( !isMe ) {
@@ -4396,7 +4307,6 @@ add_syncrepl(
 			/* mirrormode still needs to see this flag in tool mode */
 			rc = config_sync_shadow( c ) ? -1 : 0;
 		}
-		ldap_free_urldesc( lud );
 	}
 
 #ifdef HAVE_TLS
@@ -4417,7 +4327,7 @@ add_syncrepl(
 
 			si->si_cookieState = c->be->be_syncinfo->si_cookieState;
 
-			/* add new syncrepl to end of list (same order as when deleting) */
+			// add new syncrepl to end of list (same order as when deleting)
 			for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next );
 			sip->si_next = si;
 		} else {
@@ -4426,7 +4336,6 @@ add_syncrepl(
 
 			c->be->be_syncinfo = si;
 		}
-		si->si_cookieState->cs_ref++;
 
 		si->si_next = NULL;
 
@@ -4437,7 +4346,7 @@ add_syncrepl(
 static void
 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 {
-	struct berval bc, uri, bs;
+	struct berval bc, uri;
 	char buf[BUFSIZ*2], *ptr;
 	ber_len_t len;
 	int i;
@@ -4491,10 +4400,13 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 		ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
 		*ptr++ = '"';
 	}
-	if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
-		if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
-		ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
-		ptr = lutil_strcopy( ptr, bs.bv_val );
+	for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
+		if ( si->si_scope == scopes[i].val ) {
+			if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + scopes[i].key.bv_len ) return;
+			ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
+			ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
+			break;
+		}
 	}
 	if ( si->si_attrsonly ) {
 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
@@ -4622,11 +4534,13 @@ syncrepl_config( ConfigArgs *c )
 		}
 		return 1;
 	} else if ( c->op == LDAP_MOD_DELETE ) {
+		cookie_state *cs = NULL;
 		int isrunning = 0;
 		if ( c->be->be_syncinfo ) {
 			syncinfo_t *si, **sip;
 			int i;
 
+			cs = c->be->be_syncinfo->si_cookieState;
 			for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
 				si = *sip;
 				if ( c->valx == -1 || i == c->valx ) {
@@ -4639,20 +4553,11 @@ syncrepl_config( ConfigArgs *c )
 						if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
 							isrunning = 1;
 						} else {
-							if ( si->si_conn ) {
-								/* If there's a persistent connection, it may
-								 * already have a thread queued. We know it's
-								 * not active, so it must be pending and we
-								 * can simply cancel it now.
-								 */
-								ldap_pvt_thread_pool_retract( &connection_pool,
-									si->si_re->routine, si->si_re );
-							}
 							ldap_pvt_thread_mutex_unlock( &si->si_mutex );
 						}
 					}
-					if ( isrunning ) {
-						si->si_ctype = -1;
+					if ( si->si_re && isrunning ) {
+						si->si_ctype = 0;
 						si->si_next = NULL;
 					} else {
 						syncinfo_free( si, 0 );
@@ -4666,6 +4571,12 @@ syncrepl_config( ConfigArgs *c )
 		}
 		if ( !c->be->be_syncinfo ) {
 			SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
+			if ( cs && !isrunning ) {
+				ch_free( cs->cs_sids );
+				ber_bvarray_free( cs->cs_vals );
+				ldap_pvt_thread_mutex_destroy( &cs->cs_mutex );
+				ch_free( cs );
+			}
 		}
 		return 0;
 	}
-- 
GitLab