CVE-2016-4992: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: 389 Directory Server in Red Hat Enterprise Linux Desktop 6 through 7, Red Hat Enterprise Linux HPC Node 6 through 7, Red Hat Enterprise Linux Server 6 through 7, and Red Hat Enterprise Linux Workstation 6 through 7 allows remote attackers to infer the existence of RDN component objects.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
CVSS v3 base score: 7.5
Published: 2017-06-08T19:29Z
Repository: https://github.com/389ds/389-ds-base
Language: C
Files changed: ldap/servers/slapd/back-ldbm/dn2entry.c, ldap/servers/slapd/back-ldbm/findentry.c, ldap/servers/slapd/back-ldbm/ldbm_add.c, ldap/servers/slapd/back-ldbm/ldbm_bind.c, ldap/servers/slapd/back-ldbm/ldbm_compare.c, ldap/servers/slapd/back-ldbm/ldbm_delete.c, ldap/servers/slapd/back-ldbm/ldbm_modify.c, ldap/servers/slapd/back-ldbm/ldbm_modrdn.c, ldap/servers/slapd/back-ldbm/ldbm_search.c, ldap/servers/slapd/back-ldbm/misc.c, ldap/servers/slapd/back-ldbm/proto-back-ldbm.h, ldap/servers/slapd/back-ldbm/vlv_srch.c, ldap/servers/slapd/bind.c, ldap/servers/slapd/defbackend.c, ldap/servers/slapd/result.c
Commit date: 2016-07-14 10:10:35 -0700
Commit message: Bug 1347760 - CVE-2016-4992 389-ds-base: Information disclosure via repeated use of LDAP ADD operation, etc.

Description: If a bind user has no rights, it should not disclose
any information including the existence of the entry.

Fix description:
1) ALREADY_EXISTS in add -- If to be added entry is found existing
   in ldbm_back_add, it checks the ACI and if there is no rights,
   it returns INSUFFICIENT_ACCESS instead of ALREADY_EXISTS.
2) NO_SUCH_OBJECT in other update operations -- If the target entry
   is found not existing, it checks the ancestor entry's access
   rights in find_entry.  If it is not allowed to access the subtree,
   it returns INSUFFICIENT_ACCESS instead of NO_SUC_OBJECT.  Plus,
   it supresses the "Matched" ancestor message.
3) NO_SUCH_OBJECT in search -- If a bind entry has no rights to read
   a subtree, it returns no search results with SUCCESS.  It should
   be applied to the no existing subtree if the bind entry has no
   rights to the super tree.
4) If bind fails because of the non-existence of the bind user or
   the parent nodes, the bind returns LDAP_INVALID_CREDENTIALS to
   the client with no other information.
   The detailed cause is logged in the access log as follows:
	 RESULT err=49 .. etime=0 - No such suffix (<given suffix>)
	 RESULT err=49 .. etime=0 - Invalid credentials
	 RESULT err=49 .. etime=0 - No such entry

https://bugzilla.redhat.com/show_bug.cgi?id=1347760

Reviewed by lkrispen@redhat.com, mreynolds@redhat.com, and tbordaz@redhat.com.
Thank you!!!

Diff: diff --git a/ldap/servers/slapd/back-ldbm/dn2entry.c b/ldap/servers/slapd/back-ldbm/dn2entry.c
index 6d1d92ff..76566882 100644
--- a/ldap/servers/slapd/back-ldbm/dn2entry.c
+++ b/ldap/servers/slapd/back-ldbm/dn2entry.c
@@ -149,18 +149,19 @@ bail:
  */
 struct backentry *
 dn2ancestor(
     Slapi_Backend *be,
     const Slapi_DN	*sdn,
-	Slapi_DN *ancestordn,
+    Slapi_DN *ancestordn,
     back_txn		*txn,
-    int			*err
+    int			*err,
+    int allow_suffix
 )
 {
-	struct backentry *e = NULL;
+    struct backentry *e = NULL;
 
-	LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
+    LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
 
     /* first, check to see if the given sdn is empty or a root suffix of the
        given backend - if so, it has no parent */
     if (!slapi_sdn_isempty(sdn) && !slapi_be_issuffix( be, sdn )) {
         Slapi_DN ancestorndn;
@@ -188,11 +189,17 @@ dn2ancestor(
           So, why not just use a char* for the ancestorndn?  Because dn2entry requires
           a Slapi_DN with the normalized dn.
         */
 
         /* stop when we get to "", or a backend suffix point */
-        while (!e && !slapi_sdn_isempty(&ancestorndn) && !slapi_be_issuffix( be, &ancestorndn )) {
+        while (!e && !slapi_sdn_isempty(&ancestorndn)) {
+            if (!allow_suffix) {
+                /* Original behavior. */
+                if (slapi_be_issuffix(be, &ancestorndn)) {
+                    break;
+                }
+            }
             /* find the entry - it uses the ndn, so no further conversion is necessary */
             e= dn2entry(be,&ancestorndn,txn,err);
             if (!e) {
                 /* not found, so set ancestordn to its parent and try again */
                 ptr = slapi_dn_find_parent(slapi_sdn_get_ndn(&ancestorndn));
diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c
index 4a574bf8..8b842e3e 100644
--- a/ldap/servers/slapd/back-ldbm/findentry.c
+++ b/ldap/servers/slapd/back-ldbm/findentry.c
@@ -14,22 +14,22 @@
 /* findentry.c - find a database entry, obeying referrals (& aliases?) */
 
 #include "back-ldbm.h"
 
 
-static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags);
-static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags);
+static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags, int *rc);
+static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags, int *rc);
 /* The flags take these values */
 #define FE_TOMBSTONE_INCLUDED TOMBSTONE_INCLUDED /* :1 defined in back-ldbm.h */
 #define FE_REALLY_INTERNAL 0x2
 
 int
 check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, const char *callingfn) /* JCM - Move somewhere more appropriate */
 {
 	int rc=0, i=0, numValues=0;
 	Slapi_Attr *attr;
-	Slapi_Value *val=NULL;	
+	Slapi_Value *val=NULL;
 	struct berval **refscopy=NULL;
 	struct berval **url=NULL;
 
 	/* if the entry is a referral send the referral */
 	if ( slapi_entry_attr_find( entry, "ref", &attr ) )
@@ -78,26 +78,32 @@ out:
 	return rc;
 }
 
 static struct backentry *
 find_entry_internal_dn(
-	Slapi_PBlock	*pb,
+    Slapi_PBlock	*pb,
     backend			*be,
     const Slapi_DN *sdn,
     int				lock,
-	back_txn		*txn,
-	int				flags
+    back_txn		*txn,
+    int				flags,
+    int				*rc /* return code */
 )
 { 
 	struct backentry *e;
 	int	managedsait = 0;
 	int	err;
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
 	size_t tries = 0;
+	int isroot = 0;
+	int op_type;
+	char *errbuf = NULL;
 
 	/* get the managedsait ldap message control */
-	slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
+	slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+	slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
 
 	while ( (tries < LDBM_CACHE_RETRY_COUNT) && 
 	        (e = dn2entry_ext( be, sdn, txn, flags & TOMBSTONE_INCLUDED, &err ))
 	        != NULL )
 	{
@@ -111,10 +117,13 @@ find_entry_internal_dn(
 		if ( !managedsait && !(flags & FE_REALLY_INTERNAL)) {
 			/* see if the entry is a referral */
 			if(check_entry_for_referral(pb, e->ep_entry, NULL, "find_entry_internal_dn"))
 			{
 				CACHE_RETURN( &inst->inst_cache, &e );
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
+					*rc = FE_RC_SENT_RESULT;
+				}
 				return( NULL );
 			}
 		}
 
 		/*
@@ -149,31 +158,93 @@ find_entry_internal_dn(
 	 */
 	if (!(flags & FE_REALLY_INTERNAL)) {
 		struct backentry *me;
 		Slapi_DN ancestorsdn;
 		slapi_sdn_init(&ancestorsdn);
-		me= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,txn,&err);
+		me = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, txn, &err, 1 /* allow_suffix */);
 		if ( !managedsait && me != NULL ) {
 			/* if the entry is a referral send the referral */
 			if(check_entry_for_referral(pb, me->ep_entry, (char*)slapi_sdn_get_dn(&ancestorsdn), "find_entry_internal_dn"))
 			{
 				CACHE_RETURN( &inst->inst_cache, &me );
 				slapi_sdn_done(&ancestorsdn);
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
+					*rc = FE_RC_SENT_RESULT;
+				}
 				return( NULL );
 			}
 			/* else fall through to no such object */
 		}
 
 		/* entry not found */
-		slapi_send_ldap_result( pb, ( 0 == err || DB_NOTFOUND == err ) ?
-			LDAP_NO_SUCH_OBJECT : ( LDAP_INVALID_DN_SYNTAX == err ) ?
-			LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
-			(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
+		if ((0 == err) || (DB_NOTFOUND == err)) {
+			if (me && !isroot) {
+				/* If not root, you may not want to reveal it. */
+				int acl_type = -1;
+				int return_err = LDAP_NO_SUCH_OBJECT;
+				err = LDAP_SUCCESS;
+				switch (op_type) {
+				case SLAPI_OPERATION_ADD:
+					acl_type = SLAPI_ACL_ADD;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_DELETE:
+					acl_type = SLAPI_ACL_DELETE;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_MODDN:
+					acl_type = SLAPI_ACL_MODDN;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_MODIFY:
+					acl_type = SLAPI_ACL_WRITE;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_SEARCH:
+				case SLAPI_OPERATION_COMPARE:
+					return_err = LDAP_SUCCESS;
+					acl_type = SLAPI_ACL_READ;
+					break;
+				case SLAPI_OPERATION_BIND:
+					acl_type = -1; /* skip acl check. acl is not set up for bind. */
+					return_err = LDAP_INVALID_CREDENTIALS;
+					slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
+					break;
+				}
+				if (acl_type > 0) {
+					err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
+					                             ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
+				}
+				if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
+					/*
+					 * Operations to be checked && ACL returns disallow.
+					 * Not to disclose the info about the entry's existence,
+					 * do not return the "matched" DN.
+					 * Plus, the bind case returns LDAP_INAPPROPRIATE_AUTH.
+					 */
+					slapi_send_ldap_result(pb, return_err, NULL, NULL, 0, NULL);
+				} else {
+					slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT,
+						(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
+				}
+			} else {
+				slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT,
+					(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
+			}
+		} else {
+			slapi_send_ldap_result( pb, ( LDAP_INVALID_DN_SYNTAX == err ) ?
+				LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
+				(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
+		}
+		if (rc) {
+			*rc = FE_RC_SENT_RESULT;
+		}
 		slapi_sdn_done(&ancestorsdn);
 		CACHE_RETURN( &inst->inst_cache, &me );
 	}
 
+	slapi_ch_free_string(&errbuf);
 	LDAPDebug( LDAP_DEBUG_TRACE, "<= find_entry_internal_dn not found (%s)\n",
 	    slapi_sdn_get_dn(sdn), 0, 0 );
 	return( NULL );
 }
 
@@ -181,15 +252,15 @@ find_entry_internal_dn(
    It should only be called in case of 5.0 replicated operation
    which should not be referred.
  */
 static struct backentry *
 find_entry_internal_uniqueid(
-	Slapi_PBlock	*pb,
+    Slapi_PBlock	*pb,
     backend *be,
-	const char 			*uniqueid,
+    const char 			*uniqueid,
     int				lock,
-	back_txn		*txn
+    back_txn		*txn
 )
 {
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
 	struct backentry	*e;
 	int			err;
@@ -241,12 +312,13 @@ static struct backentry *
 find_entry_internal(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
     int			lock,
-	back_txn *txn,
-	int flags
+    back_txn *txn,
+    int flags,
+    int *rc
 )
 {
 	/* check if we should search based on uniqueid or dn */
 	if (addr->uniqueid!=NULL)
 	{
@@ -259,15 +331,13 @@ find_entry_internal(
 		struct backentry *entry = NULL;
 
 		LDAPDebug( LDAP_DEBUG_TRACE, "=> find_entry_internal (dn=%s) lock %d\n",
 		           slapi_sdn_get_dn(addr->sdn), lock, 0 );
 		if (addr->sdn) {
-			entry = find_entry_internal_dn (pb, be, addr->sdn, 
-			                                lock, txn, flags);
+			entry = find_entry_internal_dn (pb, be, addr->sdn, lock, txn, flags, rc);
 		} else {
-			LDAPDebug0Args( LDAP_DEBUG_ANY,
-			                "find_entry_internal: Null target dn\n" );
+			LDAPDebug0Args( LDAP_DEBUG_ANY, "find_entry_internal: Null target dn\n" );
 		}
 
 		LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= find_entry_internal\n" );
 		return entry;
 	}
@@ -276,25 +346,27 @@ find_entry_internal(
 struct backentry *
 find_entry(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-	back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, 0/*flags*/ ) );
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, 0/*flags*/, rc));
 }
 
 struct backentry *
 find_entry2modify(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-	back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 0/*flags*/ ) );
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0/*flags*/, rc));
 }
 
 /* New routines which do not do any referral stuff.
    Call these if all you want to do is get pointer to an entry
    and certainly do not want any side-effects relating to client ! */
@@ -302,35 +374,36 @@ find_entry2modify(
 struct backentry *
 find_entry_only(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-	back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL ) );
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL, rc));
 }
 
 struct backentry *
 find_entry2modify_only(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-    back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL ) );
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0 /* to check aci, disable INTERNAL */, rc));
 }
 
 struct backentry *
 find_entry2modify_only_ext(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
     int flags,
-    back_txn *txn
-
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 
-		                         FE_REALLY_INTERNAL | flags ));
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL | flags, rc));
 }
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index 7eb8fe96..f462376d 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -91,10 +91,11 @@ ldbm_back_add( Slapi_PBlock *pb )
 	int parent_switched = 0;
 	int noabort = 1;
 	int myrc = 0;
 	PRUint64 conn_id;
 	int op_id;
+	int result_sent = 0;
 	if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
 		conn_id = 0; /* connection is NULL */
 	}
 	slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id);
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
@@ -377,11 +378,11 @@ ldbm_back_add( Slapi_PBlock *pb )
 			if(have_parent_address(&parentsdn, operation->o_params.p.p_add.parentuniqueid))
 			{
 				addr.sdn = &parentsdn;
 				addr.udn = NULL;
 				addr.uniqueid = operation->o_params.p.p_add.parentuniqueid;
-				parententry = find_entry2modify_only(pb,be,&addr,&txn);
+				parententry = find_entry2modify_only(pb, be, &addr, &txn, &result_sent);
 				if (parententry && parententry->ep_entry) {
 					if (!operation->o_params.p.p_add.parentuniqueid){
 						/* Set the parentuniqueid now */
 						operation->o_params.p.p_add.parentuniqueid = 
 						    slapi_ch_strdup(slapi_entry_get_uniqueid(parententry->ep_entry));
@@ -429,10 +430,18 @@ ldbm_back_add( Slapi_PBlock *pb )
 						}
 					} else {
 						/* The entry already exists */ 
 						ldap_result_code = LDAP_ALREADY_EXISTS;
 					}
+					if ((LDAP_ALREADY_EXISTS == ldap_result_code) && !isroot && !is_replicated_operation) {
+						myrc = plugin_call_acl_plugin(pb, e, NULL, NULL, SLAPI_ACL_ADD,
+						                              ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
+						if (myrc) {
+							ldap_result_code = myrc;
+							ldap_result_message = errbuf;
+						}
+					}
 					goto error_return;
 				} 
 				else 
 				{
 					/*
@@ -445,11 +454,11 @@ ldbm_back_add( Slapi_PBlock *pb )
 					{
 						int err= 0;
 						Slapi_DN ancestorsdn;
 						struct backentry *ancestorentry;
 						slapi_sdn_init(&ancestorsdn);
-						ancestorentry= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,&txn,&err);
+						ancestorentry = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, &txn, &err, 0);
 						slapi_sdn_done(&ancestorsdn);
 						if ( ancestorentry != NULL )
 						{
 							int sentreferral= check_entry_for_referral(pb, ancestorentry->ep_entry, backentry_get_ndn(ancestorentry), "ldbm_back_add");
 							CACHE_RETURN( &inst->inst_cache, &ancestorentry );
@@ -493,11 +502,11 @@ ldbm_back_add( Slapi_PBlock *pb )
 				 * to find the tombstone entry and lock it down in the cache.
 				 */
 				addr.udn = NULL;
 				addr.sdn = NULL;
 				addr.uniqueid = (char *)slapi_entry_get_uniqueid(e); /* jcm - cast away const */
-				tombstoneentry = find_entry2modify( pb, be, &addr, &txn );
+				tombstoneentry = find_entry2modify(pb, be, &addr, &txn, &result_sent);
 				if ( tombstoneentry==NULL )
 				{
 					ldap_result_code= -1;
 					goto error_return;  /* error result sent by find_entry2modify() */
 				}
@@ -710,11 +719,11 @@ ldbm_back_add( Slapi_PBlock *pb )
 					struct backentry *ancestorentry;
 
 					LDAPDebug1Arg(LDAP_DEBUG_BACKLDBM, "ldbm_add: Parent \"%s\" does not exist. "
 					              "It might be a conflict entry.\n", slapi_sdn_get_dn(&parentsdn));
 					slapi_sdn_init(&ancestorsdn);
-					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err );
+					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err, 1);
 					CACHE_RETURN( &inst->inst_cache, &ancestorentry );
 
 					ldap_result_code= LDAP_NO_SUCH_OBJECT;
 					ldap_result_matcheddn= 
 					    slapi_ch_strdup((char *)slapi_sdn_get_dn(&ancestorsdn)); /* jcm - cast away const. */
@@ -1347,11 +1356,13 @@ common_return:
 		if (not_an_error) {
 			/* This is mainly used by urp.  Solved conflict is not an error.
 			 * And we don't want the supplier to halt sending the updates. */
 			ldap_result_code = LDAP_SUCCESS;
 		}
-		slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
+		if (!result_sent) {
+			slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL);
+		}
 	}
 	backentry_free(&originalentry);
 	backentry_free(&tmpentry);
 	slapi_sdn_done(&parentsdn);
 	slapi_ch_free( (void**)&ldap_result_matcheddn );
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_bind.c b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
index ea0df330..99a08181 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_bind.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
@@ -27,10 +27,11 @@ ldbm_back_bind( Slapi_PBlock *pb )
 	Slapi_Attr		*attr;
 	Slapi_Value **bvals;
 	entry_address *addr;
 	back_txn txn = {NULL};
 	int rc = SLAPI_BIND_SUCCESS;
+	int result_sent = 0;
 
 	/* get parameters */
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be );
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
 	slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr );
@@ -61,12 +62,16 @@ ldbm_back_bind( Slapi_PBlock *pb )
 
 	/*
 	 * find the target entry.  find_entry() takes care of referrals
 	 *   and sending errors if the entry does not exist.
 	 */
-	if (( e = find_entry( pb, be, addr, &txn )) == NULL ) {
+	if ((e = find_entry( pb, be, addr, &txn, &result_sent)) == NULL) {
 		rc = SLAPI_BIND_FAIL;
+		/* In the failure case, the result is supposed to be sent in the backend. */
+		if (!result_sent) {
+			slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
+		}
 		goto bail;
 	}
 
 	switch ( method ) {
 	case LDAP_AUTH_SIMPLE:
@@ -80,12 +85,12 @@ ldbm_back_bind( Slapi_PBlock *pb )
 			goto bail;
 		}
 		bvals= attr_get_present_values(attr);
 		slapi_value_init_berval(&cv,cred);
 		if ( slapi_pw_find_sv( bvals, &cv ) != 0 ) {
-			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
-			    NULL, 0, NULL );
+			slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
+			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
 			CACHE_RETURN( &inst->inst_cache, &e );
 			value_done(&cv);
 			rc = SLAPI_BIND_FAIL;
 			goto bail;
 		}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_compare.c b/ldap/servers/slapd/back-ldbm/ldbm_compare.c
index e52cd6c8..e9973a9c 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_compare.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_compare.c
@@ -54,11 +54,11 @@ ldbm_back_compare( Slapi_PBlock *pb )
 		return -1;
 	}
 	/* get the namespace dn */
 	namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
 
-	if ( (e = find_entry( pb, be, addr, &txn )) == NULL ) {
+	if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL) {
 		ret = -1;	/* error result sent by find_entry() */
 		goto bail;
 	}
 
 	err = slapi_access_allowed (pb, e->ep_entry, type, bval, SLAPI_ACL_COMPARE);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index 5b24af2a..f801e01e 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -75,10 +75,11 @@ ldbm_back_delete( Slapi_PBlock *pb )
 	const CSN *tombstone_csn = NULL;
 	char deletion_csn_str[CSN_STRSIZE];
 	int op_id;
 	ID ep_id = 0;
 	ID tomb_ep_id = 0;
+	int result_sent = 0;
 
 	if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
 		conn_id = 0; /* connection is NULL */
 	}
 	slapi_pblock_get( pb, SLAPI_OPERATION_ID, &op_id);
@@ -264,11 +265,11 @@ ldbm_back_delete( Slapi_PBlock *pb )
 			 * op from another master could target a conflict entry; while the
 			 * corresponding entry on this server could have been already 
 			 * deleted.  That is, the entry 'e' found with "addr" is a tomb-
 			 * stone.  If it is the case, we need to back off.
 			 */
-			if ( (e = find_entry2modify( pb, be, addr, &txn )) == NULL )
+			if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL)
 			{
 				ldap_result_code= LDAP_NO_SUCH_OBJECT; 
 				retval = -1;
 				LDAPDebug0Args(LDAP_DEBUG_BACKLDBM, "ldbm_back_delete: Deleting entry is already deleted.\n");
 				goto error_return; /* error result sent by find_entry2modify() */
@@ -505,11 +506,11 @@ ldbm_back_delete( Slapi_PBlock *pb )
 						parent_addr.uniqueid = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
 					} else {
 						parent_addr.uniqueid = NULL;
 					}
 					parent_addr.sdn = &parentsdn;
-					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn);
+					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn, &result_sent);
 				}
 				if (parent) {
 					int isglue;
 					size_t haschildren = 0;
 					int op = PARENTUPDATE_DEL;
@@ -1464,11 +1465,13 @@ diskfull_return:
 		if (not_an_error) {
 			/* This is mainly used by urp.  Solved conflict is not an error.
 			 * And we don't want the supplier to halt sending the updates. */
 			ldap_result_code = LDAP_SUCCESS;
 		}
-		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		if (!result_sent) {
+			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		}
 	}
 	slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
 	                "conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p, in_cache=%d\n",
 	                conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry,
 	                cache_is_in_cache(&inst->inst_cache, parent_modify_c.new_entry));
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index 9b3062c0..34d9861d 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -390,10 +390,11 @@ ldbm_back_modify( Slapi_PBlock *pb )
 	int opreturn = 0;
 	int mod_count = 0;
 	int not_an_error = 0;
 	int fixup_tombstone = 0;
 	int ec_locked = 0;
+	int result_sent = 0;
 
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be);
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
 	slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr );
 	slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
@@ -464,16 +465,16 @@ ldbm_back_modify( Slapi_PBlock *pb )
 	}
 	 */
 	if ( MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
 		/* find and lock the entry we are about to modify */
 		if (fixup_tombstone) {
-			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
+			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
 		} else {
-			e = find_entry2modify( pb, be, addr, &txn );
+			e = find_entry2modify( pb, be, addr, &txn, &result_sent );
 		}
 		if (e == NULL) {
-			ldap_result_code= -1;
+			ldap_result_code = -1;
 			goto error_return; /* error result sent by find_entry2modify() */
 		}
 	}
 
 	txn.back_txn_txn = NULL; /* ready to create the child transaction */
@@ -549,16 +550,16 @@ ldbm_back_modify( Slapi_PBlock *pb )
 
 		if (0 == retry_count) { /* just once */
 			if ( !MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
 				/* find and lock the entry we are about to modify */
 				if (fixup_tombstone) {
-					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
+					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
 				} else {
-					e = find_entry2modify( pb, be, addr, &txn );
+					e = find_entry2modify( pb, be, addr, &txn, &result_sent );
 				}
 				if (e == NULL) {
-					ldap_result_code= -1;
+					ldap_result_code = -1;
 					goto error_return; /* error result sent by find_entry2modify() */
 				}
 			}
 		
 			if ( !is_fixup_operation && !fixup_tombstone)
@@ -964,11 +965,14 @@ common_return:
 		if (not_an_error) {
 			/* This is mainly used by urp.  Solved conflict is not an error.
 			 * And we don't want the supplier to halt sending the updates. */
 			ldap_result_code = LDAP_SUCCESS;
 		}
-		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		if (!result_sent) {
+			/* result is already sent in find_entry. */
+			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		}
 	}
 
 	/* free our backups */
 	ldap_mods_free(mods_original, 1);
 	backentry_free(&original_entry);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index c0cd2ab5..f9343052 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -93,10 +93,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
     int not_an_error = 0;
     int support_moddn_aci;
     int myrc = 0;
     PRUint64 conn_id;
     int op_id;
+    int result_sent = 0;
     if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
         conn_id = 0; /* connection is NULL */
     }
     slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id);
 
@@ -472,11 +473,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
             }
         
             /* find and lock the entry we are about to modify */
             /* JCMREPL - Argh, what happens about the stinking referrals? */
             slapi_pblock_get (pb, SLAPI_TARGET_ADDRESS, &old_addr);
-            e = find_entry2modify( pb, be, old_addr, &txn );
+            e = find_entry2modify(pb, be, old_addr, &txn, &result_sent);
             if ( e == NULL )
             {
                 ldap_result_code= -1;
                 goto error_return; /* error result sent by find_entry2modify() */
             }
@@ -508,21 +509,21 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
             if (is_resurect_operation) {
                 oldparent_addr.uniqueid = operation->o_params.p.p_modrdn.modrdn_newsuperior_address.uniqueid;
             } else {
                 oldparent_addr.uniqueid = NULL;            
             }
-            parententry = find_entry2modify_only( pb, be, &oldparent_addr, &txn );
+            parententry = find_entry2modify_only(pb, be, &oldparent_addr, &txn, &result_sent);
             modify_init(&parent_modify_context,parententry);
         
             /* Fetch and lock the new parent of the entry that is moving */            
             if(slapi_sdn_get_ndn(dn_newsuperiordn) != NULL)
             {
                 slapi_pblock_get (pb, SLAPI_MODRDN_NEWSUPERIOR_ADDRESS, &newsuperior_addr);
                 if (is_resurect_operation) {
                     newsuperior_addr->uniqueid = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
                 }
-                newparententry = find_entry2modify_only( pb, be, newsuperior_addr, &txn );
+                newparententry = find_entry2modify_only(pb, be, newsuperior_addr, &txn, &result_sent);
                 slapi_ch_free_string(&newsuperior_addr->uniqueid);
                 modify_init(&newparent_modify_context,newparententry);
             }
         
             opcsn = operation_get_csn (operation);
@@ -579,11 +580,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
                         /* Here means that we didn't find the parent */
                         int err = 0;
                         Slapi_DN ancestorsdn;
                         struct backentry *ancestorentry;
                         slapi_sdn_init(&ancestorsdn);
-                        ancestorentry= dn2ancestor(be,&dn_newdn,&ancestorsdn,&txn,&err);
+                        ancestorentry = dn2ancestor(be, &dn_newdn, &ancestorsdn, &txn, &err, 0);
                         CACHE_RETURN( &inst->inst_cache, &ancestorentry );
                         ldap_result_matcheddn= slapi_ch_strdup((char *) slapi_sdn_get_dn(&ancestorsdn));
                         ldap_result_code= LDAP_NO_SUCH_OBJECT;
                         LDAPDebug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: New superior "
                                     "does not exist matched %s, newsuperior = %s\n", 
@@ -1484,12 +1485,14 @@ common_return:
         if (not_an_error) {
             /* This is mainly used by urp.  Solved conflict is not an error.
              * And we don't want the supplier to halt sending the updates. */
             ldap_result_code = LDAP_SUCCESS;
         }
-        slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn,
-                    ldap_result_message, 0,NULL );
+        if (!result_sent) {
+            slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn,
+                                   ldap_result_message, 0, NULL);
+        }
     }
     slapi_mods_done(&smods_operation_wsi);
     slapi_mods_done(&smods_generated);
     slapi_mods_done(&smods_generated_wsi);
     slapi_ch_free((void**)&child_entries);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index 535529c4..cda1714d 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -582,11 +582,11 @@ ldbm_back_search( Slapi_PBlock *pb )
     {
         e = NULL;
     }
     else
     {
-        if ( ( e = find_entry( pb, be, addr, &txn )) == NULL )
+        if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL)
         {
             /* error or referral sent by find_entry */
             return ldbm_back_search_cleanup(pb, li, sort_control, 
                             LDBM_SRCH_DEFAULT_RESULT, NULL, 1, &vlv_request_control, NULL, candidates);
         }
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
index 77c1e70f..516b32d5 100644
--- a/ldap/servers/slapd/back-ldbm/misc.c
+++ b/ldap/servers/slapd/back-ldbm/misc.c
@@ -410,11 +410,11 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
     bentry_addr.udn = NULL;
     bentry_addr.uniqueid = uniqueid;
 
     /* Note: if we find the bentry, it will stay locked until someone calls
      * modify_term on the mc we'll be associating the bentry with */
-    bentry = find_entry2modify_only( pb, be, &bentry_addr, &txn );
+    bentry = find_entry2modify_only(pb, be, &bentry_addr, &txn, NULL);
 
     if (NULL == bentry) {
         /* Uh oh, we couldn't find and lock the RUV entry! */
         LDAPDebug( LDAP_DEBUG_ANY, "Error: ldbm_txn_ruv_modify_context failed to retrieve and lock RUV entry\n",
             0, 0, 0 );
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 86e2237f..8c813dd8 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -172,11 +172,11 @@ int ldbm_back_ctrl_info(Slapi_Backend *be, int cmd, void *info);
  * dn2entry.c
  */
 struct backentry *dn2entry(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int    *err);
 struct backentry *dn2entry_ext(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int flags, int *err);
 struct backentry *dn2entry_or_ancestor(Slapi_Backend *be, const Slapi_DN *sdn, Slapi_DN *ancestor, back_txn *txn, int *err);
-struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err);
+struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err, int allow_suffix);
 int get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
 int get_copy_of_entry_ext(Slapi_PBlock *pb, ID id, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
 void done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter);
 
 /*
@@ -192,15 +192,17 @@ IDList * filter_candidates( Slapi_PBlock *pb, backend *be, const char *base, Sla
 IDList * filter_candidates_ext( Slapi_PBlock *pb, backend *be, const char *base, Slapi_Filter *f, Slapi_Filter *nextf, int range, int *err, int allidslimit );
 
 /*
  * findentry.c
  */
-struct backentry * find_entry2modify( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
-struct backentry * find_entry( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
-struct backentry * find_entry2modify_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
-struct backentry * find_entry2modify_only_ext( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn);
-struct backentry * find_entry_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
+/* Return code */
+#define FE_RC_SENT_RESULT 1
+struct backentry *find_entry2modify(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
+struct backentry *find_entry(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
+struct backentry *find_entry2modify_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
+struct backentry *find_entry2modify_only_ext(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn, int *rc);
+struct backentry *find_entry_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
 int check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, const char *callingfn);
 
 /*
  * haschildren.c
  */
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.c b/ldap/servers/slapd/back-ldbm/vlv_srch.c
index fcd0c2d8..df378211 100644
--- a/ldap/servers/slapd/back-ldbm/vlv_srch.c
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.c
@@ -160,11 +160,11 @@ vlvSearch_init(struct vlvSearch* p, Slapi_PBlock *pb, const Slapi_Entry *e, ldbm
             slapi_pblock_set(pb, SLAPI_PLUGIN, inst->inst_be->be_database);
             slapi_pblock_get(pb, SLAPI_TXN, &txn.back_txn_txn);
 
             addr.sdn = p->vlv_base;
             addr.uniqueid = NULL;
-            e = find_entry( pb, inst->inst_be, &addr, &txn );
+            e = find_entry(pb, inst->inst_be, &addr, &txn, NULL);
             /* Check to see if the entry is absent. If it is, mark this search
              * as not initialized */
             if (NULL == e) {
                 p->vlv_initialized = 0;
 		/* We crash on anyhow, and rely on the fact that the filter
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
index 1ffec4e2..b4416151 100644
--- a/ldap/servers/slapd/bind.c
+++ b/ldap/servers/slapd/bind.c
@@ -436,12 +436,12 @@ do_bind( Slapi_PBlock *pb )
             /*
              * if the client sent us a certificate but we could not map it
              * to an LDAP DN, fail and return an invalidCredentials error.
              */
             if ( NULL == pb->pb_conn->c_external_dn ) {
-                send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
-                                  "client certificate mapping failed", 0, NULL );
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Client certificate mapping failed");
+                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
                 /* call postop plugins */
                 plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
                 goto free_and_return;
             }
 
@@ -554,37 +554,36 @@ do_bind( Slapi_PBlock *pb )
                 goto free_and_return;
             }
         /* Check if simple binds are allowed over an insecure channel.  We only check
          * this for authenticated binds. */
         } else if (config_get_require_secure_binds() == 1) {
-                Connection *conn = NULL;
-                int sasl_ssf = 0;
-                int local_ssf = 0;
-
-                /* Allow simple binds only for SSL/TLS established connections
-                 * or connections using SASL privacy layers */
-                conn = pb->pb_conn;
-                if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
-                                     "Could not get SASL SSF from connection\n" );
-                    sasl_ssf = 0;
-                }
+            Connection *conn = NULL;
+            int sasl_ssf = 0;
+            int local_ssf = 0;
+
+            /* Allow simple binds only for SSL/TLS established connections
+             * or connections using SASL privacy layers */
+            conn = pb->pb_conn;
+            if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
+                                 "Could not get SASL SSF from connection\n" );
+                sasl_ssf = 0;
+            }
 
-                if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
-                                     "Could not get local SSF from connection\n" );
-                    local_ssf = 0;
-                }
+            if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
+                                 "Could not get local SSF from connection\n" );
+                local_ssf = 0;
+            }
 
-                if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
-                    (sasl_ssf <= 1) && (local_ssf <= 1)) {
-                        send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
-                                         "Operation requires a secure connection",
-                                         0, NULL);
-                        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
-                        goto free_and_return;
-                }
+            if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
+                (sasl_ssf <= 1) && (local_ssf <= 1)) {
+                send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
+                                 "Operation requires a secure connection", 0, NULL);
+                slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
+                goto free_and_return;
+            }
         }
         break;
     default:
         break;
     }
@@ -625,10 +624,11 @@ do_bind( Slapi_PBlock *pb )
                                       NULL, NULL, NULL , NULL);
             } else {
                 /*
                  *  right dn, wrong passwd - reject with invalid credentials
                  */
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
                 send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
                 /* increment BindSecurityErrorcount */
                 slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
                 value_done(&cv);
                 goto free_and_return;
@@ -684,22 +684,25 @@ do_bind( Slapi_PBlock *pb )
             /* Check if a pre_bind plugin mapped the DN to another backend */
             Slapi_DN *pb_sdn;
             slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &pb_sdn);
             if (!pb_sdn) {
                 slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set NULL dn\n");
-                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
+                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                 goto free_and_return;
             } else if ((pb_sdn != sdn) || (sdn_updated = slapi_sdn_compare(original_sdn, pb_sdn))) {
                 /*
                  * Slapi_DN set in pblock was changed by a pre bind plug-in.
                  * It is a plug-in's responsibility to free the original Slapi_DN.
                  */
                 sdn = pb_sdn;
                 dn = slapi_sdn_get_dn(sdn);
                 if (!dn) {
-                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn\n");
-                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
+                    char *udn = slapi_sdn_get_udn(sdn);
+                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn %s\n", udn?udn:"");
+                    slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
+                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                     goto free_and_return;
                 }
                 if (!sdn_updated) { /* pb_sdn != sdn; need to compare the dn's. */
                     sdn_updated = slapi_sdn_compare(original_sdn, sdn);
                 }
@@ -709,11 +712,12 @@ do_bind( Slapi_PBlock *pb )
                     if (be) {
                         slapi_be_Rlock(be);
                         slapi_pblock_set( pb, SLAPI_BACKEND, be );
                     } else {
                         slapi_create_errormsg(errorbuf, sizeof(errorbuf), "No matching backend for %s\n", dn);
-                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
+                        slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
+                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                         goto free_and_return;
                     }
                 }
             }
 
@@ -788,11 +792,12 @@ do_bind( Slapi_PBlock *pb )
                                                               pw_response_requested, 1, 1);
                                 if (1 == myrc) { /* account is locked */
                                     goto account_locked;
                                 }
                             } else {
-                                send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, "", 0, NULL);
+                                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
+                                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
                                 goto free_and_return;
                             }
                         }
                         bind_credentials_set(pb->pb_conn, authtype,
                                              slapi_ch_strdup(slapi_sdn_get_ndn(sdn)),
@@ -848,12 +853,11 @@ account_locked:
              * backend that the bind succeeded before we set the
              * c_dn field in the connection structure here in
              * the front end.
              */
             if ( rc == SLAPI_BIND_SUCCESS || rc == SLAPI_BIND_ANONYMOUS) {
-                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL,
-                                  0, NULL );
+                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
             }
 
             slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
             plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
         } else {
@@ -874,12 +878,11 @@ free_and_return:;
         slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &sdn);
     }
     slapi_sdn_free(&sdn);
     slapi_ch_free_string( &saslmech );
     slapi_ch_free( (void **)&cred.bv_val );
-    if ( bind_target_entry != NULL )
-        slapi_entry_free(bind_target_entry);
+    slapi_entry_free(bind_target_entry);
 }
 
 
 /*
  * register all of the LDAPv3 SASL mechanisms we know about.
diff --git a/ldap/servers/slapd/defbackend.c b/ldap/servers/slapd/defbackend.c
index 7d73501a..da4a7019 100644
--- a/ldap/servers/slapd/defbackend.c
+++ b/ldap/servers/slapd/defbackend.c
@@ -169,10 +169,55 @@ defbackend_abandon( Slapi_PBlock *pb )
     /* nothing to do */
     return( DEFBACKEND_OP_HANDLED );
 }
 
 
+#define DEFBE_NO_SUCH_SUFFIX "No such suffix"
+/*
+ * Generate a "No such suffix" return text
+ * Example:
+ *   cn=X,dc=bogus,dc=com ==> "No such suffix (dc=bogus,dc=com)" 
+ *     if the last rdn starts with "dc=", print all last dc= rdn's.
+ *   cn=X,cn=bogus ==> "No such suffix (cn=bogus)"
+ *     otherwise, print the very last rdn.
+ *   cn=X,z=bogus ==> "No such suffix (x=bogus)"
+ *     it is true even if it is an invalid rdn.
+ *   cn=X,bogus ==> "No such suffix (bogus)"
+ *     another example of invalid rdn.
+ */
+static void
+_defbackend_gen_returntext(char *buffer, size_t buflen, char **dns)
+{
+    int dnidx;
+    int sidx;
+    struct suffix_repeat {
+        char *suffix;
+        int size;
+    } candidates[] = {
+        {"dc=", 3}, /* dc could be repeated.  otherwise the last rdn is used. */
+        {NULL, 0}
+    };
+    PR_snprintf(buffer, buflen, "%s (", DEFBE_NO_SUCH_SUFFIX);
+    for (dnidx = 0; dns[dnidx]; dnidx++) ; /* finding the last */
+    dnidx--; /* last rdn */
+    for (sidx = 0; candidates[sidx].suffix; sidx++) {
+        if (!PL_strncasecmp(dns[dnidx], candidates[sidx].suffix, candidates[sidx].size)) {
+            while (!PL_strncasecmp(dns[--dnidx], candidates[sidx].suffix, candidates[sidx].size)) ;
+            PL_strcat(buffer, dns[++dnidx]); /* the first "dn=", e.g. */
+            for (++dnidx; dns[dnidx]; dnidx++) {
+                PL_strcat(buffer, ",");
+                PL_strcat(buffer, dns[dnidx]);
+            }
+            PL_strcat(buffer, ")");
+            return; /* finished the task */
+        }
+    }
+    PL_strcat(buffer, dns[dnidx]);
+    PL_strcat(buffer, ")");
+    return;
+}
+
 static int
 defbackend_bind( Slapi_PBlock *pb )
 {
     int			rc;
     ber_tag_t		method;
@@ -186,15 +231,44 @@ defbackend_bind( Slapi_PBlock *pb )
      * grant access based on these "NULL binds")
      */
     slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method );
     slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred );
     if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
-	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
-	rc = SLAPI_BIND_ANONYMOUS;
+        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
+        rc = SLAPI_BIND_ANONYMOUS;
     } else {
-	send_nobackend_ldap_result( pb );
-	rc = SLAPI_BIND_FAIL;
+        Slapi_DN *sdn = NULL;
+        char *suffix = NULL;
+        char **dns = NULL;
+        
+        if (pb->pb_op) {
+            sdn = operation_get_target_spec(pb->pb_op);
+            if (sdn) {
+                dns = slapi_ldap_explode_dn(slapi_sdn_get_dn(sdn), 0);
+                if (dns) {
+                    size_t dnlen = slapi_sdn_get_ndn_len(sdn);
+                    size_t len = dnlen + sizeof(DEFBE_NO_SUCH_SUFFIX) + 4;
+                    suffix = slapi_ch_malloc(len);
+                    if (dnlen) {
+                        _defbackend_gen_returntext(suffix, len, dns);
+                    } else {
+                        PR_snprintf(suffix, len, "%s", DEFBE_NO_SUCH_SUFFIX);
+                    }
+                }
+            }
+        }
+        if (suffix) {
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, suffix);
+        } else {
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, DEFBE_NO_SUCH_SUFFIX);
+        }
+        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
+        if (dns) {
+            slapi_ldap_value_free(dns);
+        }
+        slapi_ch_free_string(&suffix);
+        rc = SLAPI_BIND_FAIL;
     }
 
     return( rc );
 }
 
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
index 506da920..c2a02060 100644
--- a/ldap/servers/slapd/result.c
+++ b/ldap/servers/slapd/result.c
@@ -2065,18 +2065,30 @@ log_result( Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentrie
 								  notes_str, csn_str, pr_idx, pr_cookie );
 			}
 		}
 		else if ( !internal_op )
 		{
+			char *pbtxt = NULL;
+			char *ext_str = NULL;
+			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &pbtxt);
+			if (pbtxt) {
+				ext_str = slapi_ch_smprintf(" - %s", pbtxt);
+			} else {
+				ext_str = "";
+			}
 			slapi_log_access( LDAP_DEBUG_STATS,
 							  "conn=%" NSPRIu64 " op=%d RESULT err=%d"
-							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n",
+							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s%s\n",
 							  op->o_connid,
 							  op->o_opid,
 							  err, tag, nentries,
 							  etime,
-							  notes_str, csn_str );
+							  notes_str, csn_str, ext_str);
+			if (pbtxt) {
+				/* if !pbtxt ==> ext_str == "".  Don't free ext_str. */
+				slapi_ch_free_string(&ext_str);
+			}
 		}
 		else
 		{
 			int optype;
 			slapi_log_access( LDAP_DEBUG_ARGS,

Vulnerable code: 	Slapi_DN *ancestordn,
    int			*err
	struct backentry *e = NULL;
	LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
        while (!e && !slapi_sdn_isempty(&ancestorndn) && !slapi_be_issuffix( be, &ancestorndn )) {
static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags);
static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags);
	Slapi_Value *val=NULL;	
	Slapi_PBlock	*pb,
	back_txn		*txn,
	int				flags
	slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
		me= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,txn,&err);
		slapi_send_ldap_result( pb, ( 0 == err || DB_NOTFOUND == err ) ?
			LDAP_NO_SUCH_OBJECT : ( LDAP_INVALID_DN_SYNTAX == err ) ?
			LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
			(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
	Slapi_PBlock	*pb,
	const char 			*uniqueid,
	back_txn		*txn
	back_txn *txn,
	int flags
			entry = find_entry_internal_dn (pb, be, addr->sdn, 
			                                lock, txn, flags);
			LDAPDebug0Args( LDAP_DEBUG_ANY,
			                "find_entry_internal: Null target dn\n" );
	back_txn *txn
	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, 0/*flags*/ ) );
	back_txn *txn
	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 0/*flags*/ ) );
	back_txn *txn
	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL ) );
    back_txn *txn
	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL ) );
    back_txn *txn

	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 
		                         FE_REALLY_INTERNAL | flags ));
				parententry = find_entry2modify_only(pb,be,&addr,&txn);
						ancestorentry= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,&txn,&err);
				tombstoneentry = find_entry2modify( pb, be, &addr, &txn );
					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err );
		slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
	if (( e = find_entry( pb, be, addr, &txn )) == NULL ) {
			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
			    NULL, 0, NULL );
	if ( (e = find_entry( pb, be, addr, &txn )) == NULL ) {
			if ( (e = find_entry2modify( pb, be, addr, &txn )) == NULL )
					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn);
		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
			e = find_entry2modify( pb, be, addr, &txn );
			ldap_result_code= -1;
					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
					e = find_entry2modify( pb, be, addr, &txn );
					ldap_result_code= -1;
		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
            e = find_entry2modify( pb, be, old_addr, &txn );
            parententry = find_entry2modify_only( pb, be, &oldparent_addr, &txn );
                newparententry = find_entry2modify_only( pb, be, newsuperior_addr, &txn );
                        ancestorentry= dn2ancestor(be,&dn_newdn,&ancestorsdn,&txn,&err);
        slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn,
                    ldap_result_message, 0,NULL );
        if ( ( e = find_entry( pb, be, addr, &txn )) == NULL )
    bentry = find_entry2modify_only( pb, be, &bentry_addr, &txn );
struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err);
struct backentry * find_entry2modify( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
struct backentry * find_entry( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
struct backentry * find_entry2modify_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
struct backentry * find_entry2modify_only_ext( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn);
struct backentry * find_entry_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
            e = find_entry( pb, inst->inst_be, &addr, &txn );
                send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
                                  "client certificate mapping failed", 0, NULL );
                Connection *conn = NULL;
                int sasl_ssf = 0;
                int local_ssf = 0;

                /* Allow simple binds only for SSL/TLS established connections
                 * or connections using SASL privacy layers */
                conn = pb->pb_conn;
                if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
                                     "Could not get SASL SSF from connection\n" );
                    sasl_ssf = 0;
                }
                if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
                                     "Could not get local SSF from connection\n" );
                    local_ssf = 0;
                }
                if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
                    (sasl_ssf <= 1) && (local_ssf <= 1)) {
                        send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
                                         "Operation requires a secure connection",
                                         0, NULL);
                        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
                        goto free_and_return;
                }
                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn\n");
                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
                                send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, "", 0, NULL);
                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL,
                                  0, NULL );
    if ( bind_target_entry != NULL )
        slapi_entry_free(bind_target_entry);
	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
	rc = SLAPI_BIND_ANONYMOUS;
	send_nobackend_ldap_result( pb );
	rc = SLAPI_BIND_FAIL;
							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n",
							  notes_str, csn_str );
Fixed code:     Slapi_DN *ancestordn,
    int			*err,
    int allow_suffix
    struct backentry *e = NULL;
    LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
        while (!e && !slapi_sdn_isempty(&ancestorndn)) {
            if (!allow_suffix) {
                /* Original behavior. */
                if (slapi_be_issuffix(be, &ancestorndn)) {
                    break;
                }
            }
static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags, int *rc);
static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags, int *rc);
	Slapi_Value *val=NULL;
    Slapi_PBlock	*pb,
    back_txn		*txn,
    int				flags,
    int				*rc /* return code */
	int isroot = 0;
	int op_type;
	char *errbuf = NULL;
	slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
	slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
					*rc = FE_RC_SENT_RESULT;
				}
		me = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, txn, &err, 1 /* allow_suffix */);
				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
					*rc = FE_RC_SENT_RESULT;
				}
		if ((0 == err) || (DB_NOTFOUND == err)) {
			if (me && !isroot) {
				/* If not root, you may not want to reveal it. */
				int acl_type = -1;
				int return_err = LDAP_NO_SUCH_OBJECT;
				err = LDAP_SUCCESS;
				switch (op_type) {
				case SLAPI_OPERATION_ADD:
					acl_type = SLAPI_ACL_ADD;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_DELETE:
					acl_type = SLAPI_ACL_DELETE;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_MODDN:
					acl_type = SLAPI_ACL_MODDN;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_MODIFY:
					acl_type = SLAPI_ACL_WRITE;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_SEARCH:
				case SLAPI_OPERATION_COMPARE:
					return_err = LDAP_SUCCESS;
					acl_type = SLAPI_ACL_READ;
					break;
				case SLAPI_OPERATION_BIND:
					acl_type = -1; /* skip acl check. acl is not set up for bind. */
					return_err = LDAP_INVALID_CREDENTIALS;
					slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
					break;
				}
				if (acl_type > 0) {
					err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
					                             ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
				}
				if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
					/*
					 * Operations to be checked && ACL returns disallow.
					 * Not to disclose the info about the entry's existence,
					 * do not return the "matched" DN.
					 * Plus, the bind case returns LDAP_INAPPROPRIATE_AUTH.
					 */
					slapi_send_ldap_result(pb, return_err, NULL, NULL, 0, NULL);
				} else {
					slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT,
						(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
				}
			} else {
				slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT,
					(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
			}
		} else {
			slapi_send_ldap_result( pb, ( LDAP_INVALID_DN_SYNTAX == err ) ?
				LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
				(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
		}
		if (rc) {
			*rc = FE_RC_SENT_RESULT;
		}
	slapi_ch_free_string(&errbuf);
    Slapi_PBlock	*pb,
    const char 			*uniqueid,
    back_txn		*txn
    back_txn *txn,
    int flags,
    int *rc
			entry = find_entry_internal_dn (pb, be, addr->sdn, lock, txn, flags, rc);
			LDAPDebug0Args( LDAP_DEBUG_ANY, "find_entry_internal: Null target dn\n" );
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, 0/*flags*/, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0/*flags*/, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0 /* to check aci, disable INTERNAL */, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL | flags, rc));
	int result_sent = 0;
				parententry = find_entry2modify_only(pb, be, &addr, &txn, &result_sent);
					if ((LDAP_ALREADY_EXISTS == ldap_result_code) && !isroot && !is_replicated_operation) {
						myrc = plugin_call_acl_plugin(pb, e, NULL, NULL, SLAPI_ACL_ADD,
						                              ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
						if (myrc) {
							ldap_result_code = myrc;
							ldap_result_message = errbuf;
						}
					}
						ancestorentry = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, &txn, &err, 0);
				tombstoneentry = find_entry2modify(pb, be, &addr, &txn, &result_sent);
					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err, 1);
		if (!result_sent) {
			slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL);
		}
	int result_sent = 0;
	if ((e = find_entry( pb, be, addr, &txn, &result_sent)) == NULL) {
		/* In the failure case, the result is supposed to be sent in the backend. */
		if (!result_sent) {
			slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
		}
			slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
	if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL) {
	int result_sent = 0;
			if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL)
					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn, &result_sent);
		if (!result_sent) {
			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
		}
	int result_sent = 0;
			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
			e = find_entry2modify( pb, be, addr, &txn, &result_sent );
			ldap_result_code = -1;
					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
					e = find_entry2modify( pb, be, addr, &txn, &result_sent );
					ldap_result_code = -1;
		if (!result_sent) {
			/* result is already sent in find_entry. */
			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
		}
    int result_sent = 0;
            e = find_entry2modify(pb, be, old_addr, &txn, &result_sent);
            parententry = find_entry2modify_only(pb, be, &oldparent_addr, &txn, &result_sent);
                newparententry = find_entry2modify_only(pb, be, newsuperior_addr, &txn, &result_sent);
                        ancestorentry = dn2ancestor(be, &dn_newdn, &ancestorsdn, &txn, &err, 0);
        if (!result_sent) {
            slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn,
                                   ldap_result_message, 0, NULL);
        }
        if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL)
    bentry = find_entry2modify_only(pb, be, &bentry_addr, &txn, NULL);
struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err, int allow_suffix);
/* Return code */
#define FE_RC_SENT_RESULT 1
struct backentry *find_entry2modify(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
struct backentry *find_entry(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
struct backentry *find_entry2modify_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
struct backentry *find_entry2modify_only_ext(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn, int *rc);
struct backentry *find_entry_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
            e = find_entry(pb, inst->inst_be, &addr, &txn, NULL);
                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Client certificate mapping failed");
                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
            Connection *conn = NULL;
            int sasl_ssf = 0;
            int local_ssf = 0;

            /* Allow simple binds only for SSL/TLS established connections
             * or connections using SASL privacy layers */
            conn = pb->pb_conn;
            if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
                                 "Could not get SASL SSF from connection\n" );
                sasl_ssf = 0;
            }
            if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
                                 "Could not get local SSF from connection\n" );
                local_ssf = 0;
            }
            if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
                (sasl_ssf <= 1) && (local_ssf <= 1)) {
                send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
                                 "Operation requires a secure connection", 0, NULL);
                slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
                goto free_and_return;
            }
                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                    char *udn = slapi_sdn_get_udn(sdn);
                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn %s\n", udn?udn:"");
                    slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                        slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
                                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
    slapi_entry_free(bind_target_entry);
#define DEFBE_NO_SUCH_SUFFIX "No such suffix"
/*
 * Generate a "No such suffix" return text
 * Example:
 *   cn=X,dc=bogus,dc=com ==> "No such suffix (dc=bogus,dc=com)" 
 *     if the last rdn starts with "dc=", print all last dc= rdn's.
 *   cn=X,cn=bogus ==> "No such suffix (cn=bogus)"
 *     otherwise, print the very last rdn.
 *   cn=X,z=bogus ==> "No such suffix (x=bogus)"
 *     it is true even if it is an invalid rdn.
 *   cn=X,bogus ==> "No such suffix (bogus)"
 *     another example of invalid rdn.
 */
static void
_defbackend_gen_returntext(char *buffer, size_t buflen, char **dns)
{
    int dnidx;
    int sidx;
    struct suffix_repeat {
        char *suffix;
        int size;
    } candidates[] = {
        {"dc=", 3}, /* dc could be repeated.  otherwise the last rdn is used. */
        {NULL, 0}
    };
    PR_snprintf(buffer, buflen, "%s (", DEFBE_NO_SUCH_SUFFIX);
    for (dnidx = 0; dns[dnidx]; dnidx++) ; /* finding the last */
    dnidx--; /* last rdn */
    for (sidx = 0; candidates[sidx].suffix; sidx++) {
        if (!PL_strncasecmp(dns[dnidx], candidates[sidx].suffix, candidates[sidx].size)) {
            while (!PL_strncasecmp(dns[--dnidx], candidates[sidx].suffix, candidates[sidx].size)) ;
            PL_strcat(buffer, dns[++dnidx]); /* the first "dn=", e.g. */
            for (++dnidx; dns[dnidx]; dnidx++) {
                PL_strcat(buffer, ",");
                PL_strcat(buffer, dns[dnidx]);
            }
            PL_strcat(buffer, ")");
            return; /* finished the task */
        }
    }
    PL_strcat(buffer, dns[dnidx]);
    PL_strcat(buffer, ")");
    return;
}

        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
        rc = SLAPI_BIND_ANONYMOUS;
        Slapi_DN *sdn = NULL;
        char *suffix = NULL;
        char **dns = NULL;
        
        if (pb->pb_op) {
            sdn = operation_get_target_spec(pb->pb_op);
            if (sdn) {
                dns = slapi_ldap_explode_dn(slapi_sdn_get_dn(sdn), 0);
                if (dns) {
                    size_t dnlen = slapi_sdn_get_ndn_len(sdn);
                    size_t len = dnlen + sizeof(DEFBE_NO_SUCH_SUFFIX) + 4;
                    suffix = slapi_ch_malloc(len);
                    if (dnlen) {
                        _defbackend_gen_returntext(suffix, len, dns);
                    } else {
                        PR_snprintf(suffix, len, "%s", DEFBE_NO_SUCH_SUFFIX);
                    }
                }
            }
        }
        if (suffix) {
            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, suffix);
        } else {
            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, DEFBE_NO_SUCH_SUFFIX);
        }
        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
        if (dns) {
            slapi_ldap_value_free(dns);
        }
        slapi_ch_free_string(&suffix);
        rc = SLAPI_BIND_FAIL;
			char *pbtxt = NULL;
			char *ext_str = NULL;
			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &pbtxt);
			if (pbtxt) {
				ext_str = slapi_ch_smprintf(" - %s", pbtxt);
			} else {
				ext_str = "";
			}
							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s%s\n",
							  notes_str, csn_str, ext_str);
			if (pbtxt) {
				/* if !pbtxt ==> ext_str == "".  Don't free ext_str. */
				slapi_ch_free_string(&ext_str);
			}