Blame SOURCES/0010-Bug-1347760-CVE-2016-4992-389-ds-base-Information-di.patch

7c7f29
From ef8228ad564f31992386bfc61553df8387d9e306 Mon Sep 17 00:00:00 2001
7c7f29
From: Noriko Hosoi <nhosoi@redhat.com>
7c7f29
Date: Wed, 13 Jul 2016 14:49:18 -0700
7c7f29
Subject: [PATCH 10/15] Bug 1347760 - CVE-2016-4992 389-ds-base: Information
7c7f29
 disclosure via repeated use of LDAP ADD operation, etc.
7c7f29
7c7f29
Description: If a bind user has no rights, it should not disclose
7c7f29
any information including the existence of the entry.
7c7f29
7c7f29
Fix description:
7c7f29
1) ALREADY_EXISTS in add -- If to be added entry is found existing
7c7f29
   in ldbm_back_add, it checks the ACI and if there is no rights,
7c7f29
   it returns INSUFFICIENT_ACCESS instead of ALREADY_EXISTS.
7c7f29
2) NO_SUCH_OBJECT in other update operations -- If the target entry
7c7f29
   is found not existing, it checks the ancestor entry's access
7c7f29
   rights in find_entry.  If it is not allowed to access the subtree,
7c7f29
   it returns INSUFFICIENT_ACCESS instead of NO_SUC_OBJECT.  Plus,
7c7f29
   it supresses the "Matched" ancestor message.
7c7f29
3) NO_SUCH_OBJECT in search -- If a bind entry has no rights to read
7c7f29
   a subtree, it returns no search results with SUCCESS.  It should
7c7f29
   be applied to the no existing subtree if the bind entry has no
7c7f29
   rights to the super tree.
7c7f29
4) If bind fails because of the non-existence of the bind user or
7c7f29
   the parent nodes, the bind returns LDAP_INVALID_CREDENTIALS to
7c7f29
   the client with no other information.
7c7f29
   The detailed cause is logged in the access log as follows:
7c7f29
	 RESULT err=49 .. etime=0 - No such suffix (<given suffix="">)
7c7f29
	 RESULT err=49 .. etime=0 - Invalid credentials
7c7f29
	 RESULT err=49 .. etime=0 - No such entry
7c7f29
7c7f29
https://bugzilla.redhat.com/show_bug.cgi?id=1347760
7c7f29
7c7f29
Reviewed by lkrispen@redhat.com, mreynolds@redhat.com, and tbordaz@redhat.com.
7c7f29
Thank you!!!
7c7f29
7c7f29
(cherry picked from commit 0b932d4b926d46ac5060f02617330dc444e06da1)
7c7f29
---
7c7f29
 ldap/servers/slapd/back-ldbm/dn2entry.c        |  17 ++-
7c7f29
 ldap/servers/slapd/back-ldbm/findentry.c       | 139 +++++++++++++++++++------
7c7f29
 ldap/servers/slapd/back-ldbm/ldbm_add.c        |  21 +++-
7c7f29
 ldap/servers/slapd/back-ldbm/ldbm_bind.c       |  11 +-
7c7f29
 ldap/servers/slapd/back-ldbm/ldbm_compare.c    |   2 +-
7c7f29
 ldap/servers/slapd/back-ldbm/ldbm_delete.c     |   9 +-
7c7f29
 ldap/servers/slapd/back-ldbm/ldbm_modify.c     |  18 ++--
7c7f29
 ldap/servers/slapd/back-ldbm/ldbm_modrdn.c     |  15 +--
7c7f29
 ldap/servers/slapd/back-ldbm/ldbm_search.c     |   2 +-
7c7f29
 ldap/servers/slapd/back-ldbm/misc.c            |   2 +-
7c7f29
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h |  14 +--
7c7f29
 ldap/servers/slapd/back-ldbm/vlv_srch.c        |   2 +-
7c7f29
 ldap/servers/slapd/bind.c                      |  75 ++++++-------
7c7f29
 ldap/servers/slapd/defbackend.c                |  82 ++++++++++++++-
7c7f29
 ldap/servers/slapd/result.c                    |  16 ++-
7c7f29
 15 files changed, 311 insertions(+), 114 deletions(-)
7c7f29
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/dn2entry.c b/ldap/servers/slapd/back-ldbm/dn2entry.c
7c7f29
index 6d1d92f..7656688 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/dn2entry.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/dn2entry.c
7c7f29
@@ -151,14 +151,15 @@ struct backentry *
7c7f29
 dn2ancestor(
7c7f29
     Slapi_Backend *be,
7c7f29
     const Slapi_DN	*sdn,
7c7f29
-	Slapi_DN *ancestordn,
7c7f29
+    Slapi_DN *ancestordn,
7c7f29
     back_txn		*txn,
7c7f29
-    int			*err
7c7f29
+    int			*err,
7c7f29
+    int allow_suffix
7c7f29
 )
7c7f29
 {
7c7f29
-	struct backentry *e = NULL;
7c7f29
+    struct backentry *e = NULL;
7c7f29
 
7c7f29
-	LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
7c7f29
+    LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
7c7f29
 
7c7f29
     /* first, check to see if the given sdn is empty or a root suffix of the
7c7f29
        given backend - if so, it has no parent */
7c7f29
@@ -190,7 +191,13 @@ dn2ancestor(
7c7f29
         */
7c7f29
 
7c7f29
         /* stop when we get to "", or a backend suffix point */
7c7f29
-        while (!e && !slapi_sdn_isempty(&ancestorndn) && !slapi_be_issuffix( be, &ancestorndn )) {
7c7f29
+        while (!e && !slapi_sdn_isempty(&ancestorndn)) {
7c7f29
+            if (!allow_suffix) {
7c7f29
+                /* Original behavior. */
7c7f29
+                if (slapi_be_issuffix(be, &ancestorndn)) {
7c7f29
+                    break;
7c7f29
+                }
7c7f29
+            }
7c7f29
             /* find the entry - it uses the ndn, so no further conversion is necessary */
7c7f29
             e= dn2entry(be,&ancestorndn,txn,err);
7c7f29
             if (!e) {
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c
7c7f29
index 4a574bf..8b842e3 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/findentry.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/findentry.c
7c7f29
@@ -16,8 +16,8 @@
7c7f29
 #include "back-ldbm.h"
7c7f29
 
7c7f29
 
7c7f29
-static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags);
7c7f29
-static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags);
7c7f29
+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);
7c7f29
+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);
7c7f29
 /* The flags take these values */
7c7f29
 #define FE_TOMBSTONE_INCLUDED TOMBSTONE_INCLUDED /* :1 defined in back-ldbm.h */
7c7f29
 #define FE_REALLY_INTERNAL 0x2
7c7f29
@@ -27,7 +27,7 @@ check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, co
7c7f29
 {
7c7f29
 	int rc=0, i=0, numValues=0;
7c7f29
 	Slapi_Attr *attr;
7c7f29
-	Slapi_Value *val=NULL;	
7c7f29
+	Slapi_Value *val=NULL;
7c7f29
 	struct berval **refscopy=NULL;
7c7f29
 	struct berval **url=NULL;
7c7f29
 
7c7f29
@@ -80,12 +80,13 @@ out:
7c7f29
 
7c7f29
 static struct backentry *
7c7f29
 find_entry_internal_dn(
7c7f29
-	Slapi_PBlock	*pb,
7c7f29
+    Slapi_PBlock	*pb,
7c7f29
     backend			*be,
7c7f29
     const Slapi_DN *sdn,
7c7f29
     int				lock,
7c7f29
-	back_txn		*txn,
7c7f29
-	int				flags
7c7f29
+    back_txn		*txn,
7c7f29
+    int				flags,
7c7f29
+    int				*rc /* return code */
7c7f29
 )
7c7f29
 { 
7c7f29
 	struct backentry *e;
7c7f29
@@ -93,9 +94,14 @@ find_entry_internal_dn(
7c7f29
 	int	err;
7c7f29
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
7c7f29
 	size_t tries = 0;
7c7f29
+	int isroot = 0;
7c7f29
+	int op_type;
7c7f29
+	char *errbuf = NULL;
7c7f29
 
7c7f29
 	/* get the managedsait ldap message control */
7c7f29
-	slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
7c7f29
+	slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
7c7f29
+	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
7c7f29
+	slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
7c7f29
 
7c7f29
 	while ( (tries < LDBM_CACHE_RETRY_COUNT) && 
7c7f29
 	        (e = dn2entry_ext( be, sdn, txn, flags & TOMBSTONE_INCLUDED, &err ))
7c7f29
@@ -113,6 +119,9 @@ find_entry_internal_dn(
7c7f29
 			if(check_entry_for_referral(pb, e->ep_entry, NULL, "find_entry_internal_dn"))
7c7f29
 			{
7c7f29
 				CACHE_RETURN( &inst->inst_cache, &e );
7c7f29
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
7c7f29
+					*rc = FE_RC_SENT_RESULT;
7c7f29
+				}
7c7f29
 				return( NULL );
7c7f29
 			}
7c7f29
 		}
7c7f29
@@ -151,27 +160,89 @@ find_entry_internal_dn(
7c7f29
 		struct backentry *me;
7c7f29
 		Slapi_DN ancestorsdn;
7c7f29
 		slapi_sdn_init(&ancestorsdn);
7c7f29
-		me= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,txn,&err);
7c7f29
+		me = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, txn, &err, 1 /* allow_suffix */);
7c7f29
 		if ( !managedsait && me != NULL ) {
7c7f29
 			/* if the entry is a referral send the referral */
7c7f29
 			if(check_entry_for_referral(pb, me->ep_entry, (char*)slapi_sdn_get_dn(&ancestorsdn), "find_entry_internal_dn"))
7c7f29
 			{
7c7f29
 				CACHE_RETURN( &inst->inst_cache, &me );
7c7f29
 				slapi_sdn_done(&ancestorsdn);
7c7f29
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
7c7f29
+					*rc = FE_RC_SENT_RESULT;
7c7f29
+				}
7c7f29
 				return( NULL );
7c7f29
 			}
7c7f29
 			/* else fall through to no such object */
7c7f29
 		}
7c7f29
 
7c7f29
 		/* entry not found */
7c7f29
-		slapi_send_ldap_result( pb, ( 0 == err || DB_NOTFOUND == err ) ?
7c7f29
-			LDAP_NO_SUCH_OBJECT : ( LDAP_INVALID_DN_SYNTAX == err ) ?
7c7f29
-			LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
7c7f29
-			(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
7c7f29
+		if ((0 == err) || (DB_NOTFOUND == err)) {
7c7f29
+			if (me && !isroot) {
7c7f29
+				/* If not root, you may not want to reveal it. */
7c7f29
+				int acl_type = -1;
7c7f29
+				int return_err = LDAP_NO_SUCH_OBJECT;
7c7f29
+				err = LDAP_SUCCESS;
7c7f29
+				switch (op_type) {
7c7f29
+				case SLAPI_OPERATION_ADD:
7c7f29
+					acl_type = SLAPI_ACL_ADD;
7c7f29
+					return_err = LDAP_INSUFFICIENT_ACCESS;
7c7f29
+					break;
7c7f29
+				case SLAPI_OPERATION_DELETE:
7c7f29
+					acl_type = SLAPI_ACL_DELETE;
7c7f29
+					return_err = LDAP_INSUFFICIENT_ACCESS;
7c7f29
+					break;
7c7f29
+				case SLAPI_OPERATION_MODDN:
7c7f29
+					acl_type = SLAPI_ACL_MODDN;
7c7f29
+					return_err = LDAP_INSUFFICIENT_ACCESS;
7c7f29
+					break;
7c7f29
+				case SLAPI_OPERATION_MODIFY:
7c7f29
+					acl_type = SLAPI_ACL_WRITE;
7c7f29
+					return_err = LDAP_INSUFFICIENT_ACCESS;
7c7f29
+					break;
7c7f29
+				case SLAPI_OPERATION_SEARCH:
7c7f29
+				case SLAPI_OPERATION_COMPARE:
7c7f29
+					return_err = LDAP_SUCCESS;
7c7f29
+					acl_type = SLAPI_ACL_READ;
7c7f29
+					break;
7c7f29
+				case SLAPI_OPERATION_BIND:
7c7f29
+					acl_type = -1; /* skip acl check. acl is not set up for bind. */
7c7f29
+					return_err = LDAP_INVALID_CREDENTIALS;
7c7f29
+					slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
7c7f29
+					break;
7c7f29
+				}
7c7f29
+				if (acl_type > 0) {
7c7f29
+					err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
7c7f29
+					                             ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
7c7f29
+				}
7c7f29
+				if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
7c7f29
+					/*
7c7f29
+					 * Operations to be checked && ACL returns disallow.
7c7f29
+					 * Not to disclose the info about the entry's existence,
7c7f29
+					 * do not return the "matched" DN.
7c7f29
+					 * Plus, the bind case returns LDAP_INAPPROPRIATE_AUTH.
7c7f29
+					 */
7c7f29
+					slapi_send_ldap_result(pb, return_err, NULL, NULL, 0, NULL);
7c7f29
+				} else {
7c7f29
+					slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT,
7c7f29
+						(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
7c7f29
+				}
7c7f29
+			} else {
7c7f29
+				slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT,
7c7f29
+					(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
7c7f29
+			}
7c7f29
+		} else {
7c7f29
+			slapi_send_ldap_result( pb, ( LDAP_INVALID_DN_SYNTAX == err ) ?
7c7f29
+				LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
7c7f29
+				(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
7c7f29
+		}
7c7f29
+		if (rc) {
7c7f29
+			*rc = FE_RC_SENT_RESULT;
7c7f29
+		}
7c7f29
 		slapi_sdn_done(&ancestorsdn);
7c7f29
 		CACHE_RETURN( &inst->inst_cache, &me );
7c7f29
 	}
7c7f29
 
7c7f29
+	slapi_ch_free_string(&errbuf);
7c7f29
 	LDAPDebug( LDAP_DEBUG_TRACE, "<= find_entry_internal_dn not found (%s)\n",
7c7f29
 	    slapi_sdn_get_dn(sdn), 0, 0 );
7c7f29
 	return( NULL );
7c7f29
@@ -183,11 +254,11 @@ find_entry_internal_dn(
7c7f29
  */
7c7f29
 static struct backentry *
7c7f29
 find_entry_internal_uniqueid(
7c7f29
-	Slapi_PBlock	*pb,
7c7f29
+    Slapi_PBlock	*pb,
7c7f29
     backend *be,
7c7f29
-	const char 			*uniqueid,
7c7f29
+    const char 			*uniqueid,
7c7f29
     int				lock,
7c7f29
-	back_txn		*txn
7c7f29
+    back_txn		*txn
7c7f29
 )
7c7f29
 {
7c7f29
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
7c7f29
@@ -243,8 +314,9 @@ find_entry_internal(
7c7f29
     Slapi_Backend *be,
7c7f29
     const entry_address *addr,
7c7f29
     int			lock,
7c7f29
-	back_txn *txn,
7c7f29
-	int flags
7c7f29
+    back_txn *txn,
7c7f29
+    int flags,
7c7f29
+    int *rc
7c7f29
 )
7c7f29
 {
7c7f29
 	/* check if we should search based on uniqueid or dn */
7c7f29
@@ -261,11 +333,9 @@ find_entry_internal(
7c7f29
 		LDAPDebug( LDAP_DEBUG_TRACE, "=> find_entry_internal (dn=%s) lock %d\n",
7c7f29
 		           slapi_sdn_get_dn(addr->sdn), lock, 0 );
7c7f29
 		if (addr->sdn) {
7c7f29
-			entry = find_entry_internal_dn (pb, be, addr->sdn, 
7c7f29
-			                                lock, txn, flags);
7c7f29
+			entry = find_entry_internal_dn (pb, be, addr->sdn, lock, txn, flags, rc);
7c7f29
 		} else {
7c7f29
-			LDAPDebug0Args( LDAP_DEBUG_ANY,
7c7f29
-			                "find_entry_internal: Null target dn\n" );
7c7f29
+			LDAPDebug0Args( LDAP_DEBUG_ANY, "find_entry_internal: Null target dn\n" );
7c7f29
 		}
7c7f29
 
7c7f29
 		LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= find_entry_internal\n" );
7c7f29
@@ -278,10 +348,11 @@ find_entry(
7c7f29
     Slapi_PBlock		*pb,
7c7f29
     Slapi_Backend *be,
7c7f29
     const entry_address *addr,
7c7f29
-	back_txn *txn
7c7f29
+    back_txn *txn,
7c7f29
+    int *rc
7c7f29
 )
7c7f29
 {
7c7f29
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, 0/*flags*/ ) );
7c7f29
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, 0/*flags*/, rc));
7c7f29
 }
7c7f29
 
7c7f29
 struct backentry *
7c7f29
@@ -289,10 +360,11 @@ find_entry2modify(
7c7f29
     Slapi_PBlock		*pb,
7c7f29
     Slapi_Backend *be,
7c7f29
     const entry_address *addr,
7c7f29
-	back_txn *txn
7c7f29
+    back_txn *txn,
7c7f29
+    int *rc
7c7f29
 )
7c7f29
 {
7c7f29
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 0/*flags*/ ) );
7c7f29
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0/*flags*/, rc));
7c7f29
 }
7c7f29
 
7c7f29
 /* New routines which do not do any referral stuff.
7c7f29
@@ -304,10 +376,11 @@ find_entry_only(
7c7f29
     Slapi_PBlock		*pb,
7c7f29
     Slapi_Backend *be,
7c7f29
     const entry_address *addr,
7c7f29
-	back_txn *txn
7c7f29
+    back_txn *txn,
7c7f29
+    int *rc
7c7f29
 )
7c7f29
 {
7c7f29
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL ) );
7c7f29
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL, rc));
7c7f29
 }
7c7f29
 
7c7f29
 struct backentry *
7c7f29
@@ -315,10 +388,11 @@ find_entry2modify_only(
7c7f29
     Slapi_PBlock		*pb,
7c7f29
     Slapi_Backend *be,
7c7f29
     const entry_address *addr,
7c7f29
-    back_txn *txn
7c7f29
+    back_txn *txn,
7c7f29
+    int *rc
7c7f29
 )
7c7f29
 {
7c7f29
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL ) );
7c7f29
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0 /* to check aci, disable INTERNAL */, rc));
7c7f29
 }
7c7f29
 
7c7f29
 struct backentry *
7c7f29
@@ -327,10 +401,9 @@ find_entry2modify_only_ext(
7c7f29
     Slapi_Backend *be,
7c7f29
     const entry_address *addr,
7c7f29
     int flags,
7c7f29
-    back_txn *txn
7c7f29
-
7c7f29
+    back_txn *txn,
7c7f29
+    int *rc
7c7f29
 )
7c7f29
 {
7c7f29
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 
7c7f29
-		                         FE_REALLY_INTERNAL | flags ));
7c7f29
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL | flags, rc));
7c7f29
 }
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
7c7f29
index 7eb8fe9..f462376 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
7c7f29
@@ -93,6 +93,7 @@ ldbm_back_add( Slapi_PBlock *pb )
7c7f29
 	int myrc = 0;
7c7f29
 	PRUint64 conn_id;
7c7f29
 	int op_id;
7c7f29
+	int result_sent = 0;
7c7f29
 	if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
7c7f29
 		conn_id = 0; /* connection is NULL */
7c7f29
 	}
7c7f29
@@ -379,7 +380,7 @@ ldbm_back_add( Slapi_PBlock *pb )
7c7f29
 				addr.sdn = &parentsdn;
7c7f29
 				addr.udn = NULL;
7c7f29
 				addr.uniqueid = operation->o_params.p.p_add.parentuniqueid;
7c7f29
-				parententry = find_entry2modify_only(pb,be,&addr,&txn);
7c7f29
+				parententry = find_entry2modify_only(pb, be, &addr, &txn, &result_sent);
7c7f29
 				if (parententry && parententry->ep_entry) {
7c7f29
 					if (!operation->o_params.p.p_add.parentuniqueid){
7c7f29
 						/* Set the parentuniqueid now */
7c7f29
@@ -431,6 +432,14 @@ ldbm_back_add( Slapi_PBlock *pb )
7c7f29
 						/* The entry already exists */ 
7c7f29
 						ldap_result_code = LDAP_ALREADY_EXISTS;
7c7f29
 					}
7c7f29
+					if ((LDAP_ALREADY_EXISTS == ldap_result_code) && !isroot && !is_replicated_operation) {
7c7f29
+						myrc = plugin_call_acl_plugin(pb, e, NULL, NULL, SLAPI_ACL_ADD,
7c7f29
+						                              ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
7c7f29
+						if (myrc) {
7c7f29
+							ldap_result_code = myrc;
7c7f29
+							ldap_result_message = errbuf;
7c7f29
+						}
7c7f29
+					}
7c7f29
 					goto error_return;
7c7f29
 				} 
7c7f29
 				else 
7c7f29
@@ -447,7 +456,7 @@ ldbm_back_add( Slapi_PBlock *pb )
7c7f29
 						Slapi_DN ancestorsdn;
7c7f29
 						struct backentry *ancestorentry;
7c7f29
 						slapi_sdn_init(&ancestorsdn);
7c7f29
-						ancestorentry= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,&txn,&err);
7c7f29
+						ancestorentry = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, &txn, &err, 0);
7c7f29
 						slapi_sdn_done(&ancestorsdn);
7c7f29
 						if ( ancestorentry != NULL )
7c7f29
 						{
7c7f29
@@ -495,7 +504,7 @@ ldbm_back_add( Slapi_PBlock *pb )
7c7f29
 				addr.udn = NULL;
7c7f29
 				addr.sdn = NULL;
7c7f29
 				addr.uniqueid = (char *)slapi_entry_get_uniqueid(e); /* jcm - cast away const */
7c7f29
-				tombstoneentry = find_entry2modify( pb, be, &addr, &txn );
7c7f29
+				tombstoneentry = find_entry2modify(pb, be, &addr, &txn, &result_sent);
7c7f29
 				if ( tombstoneentry==NULL )
7c7f29
 				{
7c7f29
 					ldap_result_code= -1;
7c7f29
@@ -712,7 +721,7 @@ ldbm_back_add( Slapi_PBlock *pb )
7c7f29
 					LDAPDebug1Arg(LDAP_DEBUG_BACKLDBM, "ldbm_add: Parent \"%s\" does not exist. "
7c7f29
 					              "It might be a conflict entry.\n", slapi_sdn_get_dn(&parentsdn));
7c7f29
 					slapi_sdn_init(&ancestorsdn);
7c7f29
-					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err );
7c7f29
+					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err, 1);
7c7f29
 					CACHE_RETURN( &inst->inst_cache, &ancestorentry );
7c7f29
 
7c7f29
 					ldap_result_code= LDAP_NO_SUCH_OBJECT;
7c7f29
@@ -1349,7 +1358,9 @@ common_return:
7c7f29
 			 * And we don't want the supplier to halt sending the updates. */
7c7f29
 			ldap_result_code = LDAP_SUCCESS;
7c7f29
 		}
7c7f29
-		slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
7c7f29
+		if (!result_sent) {
7c7f29
+			slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL);
7c7f29
+		}
7c7f29
 	}
7c7f29
 	backentry_free(&originalentry);
7c7f29
 	backentry_free(&tmpentry);
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_bind.c b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
7c7f29
index ea0df33..99a0818 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/ldbm_bind.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
7c7f29
@@ -29,6 +29,7 @@ ldbm_back_bind( Slapi_PBlock *pb )
7c7f29
 	entry_address *addr;
7c7f29
 	back_txn txn = {NULL};
7c7f29
 	int rc = SLAPI_BIND_SUCCESS;
7c7f29
+	int result_sent = 0;
7c7f29
 
7c7f29
 	/* get parameters */
7c7f29
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be );
7c7f29
@@ -63,8 +64,12 @@ ldbm_back_bind( Slapi_PBlock *pb )
7c7f29
 	 * find the target entry.  find_entry() takes care of referrals
7c7f29
 	 *   and sending errors if the entry does not exist.
7c7f29
 	 */
7c7f29
-	if (( e = find_entry( pb, be, addr, &txn )) == NULL ) {
7c7f29
+	if ((e = find_entry( pb, be, addr, &txn, &result_sent)) == NULL) {
7c7f29
 		rc = SLAPI_BIND_FAIL;
7c7f29
+		/* In the failure case, the result is supposed to be sent in the backend. */
7c7f29
+		if (!result_sent) {
7c7f29
+			slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
7c7f29
+		}
7c7f29
 		goto bail;
7c7f29
 	}
7c7f29
 
7c7f29
@@ -82,8 +87,8 @@ ldbm_back_bind( Slapi_PBlock *pb )
7c7f29
 		bvals= attr_get_present_values(attr);
7c7f29
 		slapi_value_init_berval(&cv,cred);
7c7f29
 		if ( slapi_pw_find_sv( bvals, &cv ) != 0 ) {
7c7f29
-			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
7c7f29
-			    NULL, 0, NULL );
7c7f29
+			slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
7c7f29
+			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
7c7f29
 			CACHE_RETURN( &inst->inst_cache, &e );
7c7f29
 			value_done(&cv);
7c7f29
 			rc = SLAPI_BIND_FAIL;
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_compare.c b/ldap/servers/slapd/back-ldbm/ldbm_compare.c
7c7f29
index e52cd6c..e9973a9 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/ldbm_compare.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/ldbm_compare.c
7c7f29
@@ -56,7 +56,7 @@ ldbm_back_compare( Slapi_PBlock *pb )
7c7f29
 	/* get the namespace dn */
7c7f29
 	namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
7c7f29
 
7c7f29
-	if ( (e = find_entry( pb, be, addr, &txn )) == NULL ) {
7c7f29
+	if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL) {
7c7f29
 		ret = -1;	/* error result sent by find_entry() */
7c7f29
 		goto bail;
7c7f29
 	}
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
7c7f29
index 5b24af2..f801e01 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
7c7f29
@@ -77,6 +77,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
7c7f29
 	int op_id;
7c7f29
 	ID ep_id = 0;
7c7f29
 	ID tomb_ep_id = 0;
7c7f29
+	int result_sent = 0;
7c7f29
 
7c7f29
 	if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
7c7f29
 		conn_id = 0; /* connection is NULL */
7c7f29
@@ -266,7 +267,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
7c7f29
 			 * deleted.  That is, the entry 'e' found with "addr" is a tomb-
7c7f29
 			 * stone.  If it is the case, we need to back off.
7c7f29
 			 */
7c7f29
-			if ( (e = find_entry2modify( pb, be, addr, &txn )) == NULL )
7c7f29
+			if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL)
7c7f29
 			{
7c7f29
 				ldap_result_code= LDAP_NO_SUCH_OBJECT; 
7c7f29
 				retval = -1;
7c7f29
@@ -507,7 +508,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
7c7f29
 						parent_addr.uniqueid = NULL;
7c7f29
 					}
7c7f29
 					parent_addr.sdn = &parentsdn;
7c7f29
-					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn);
7c7f29
+					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn, &result_sent);
7c7f29
 				}
7c7f29
 				if (parent) {
7c7f29
 					int isglue;
7c7f29
@@ -1466,7 +1467,9 @@ diskfull_return:
7c7f29
 			 * And we don't want the supplier to halt sending the updates. */
7c7f29
 			ldap_result_code = LDAP_SUCCESS;
7c7f29
 		}
7c7f29
-		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
7c7f29
+		if (!result_sent) {
7c7f29
+			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
7c7f29
+		}
7c7f29
 	}
7c7f29
 	slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
7c7f29
 	                "conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p, in_cache=%d\n",
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
7c7f29
index 9b3062c..34d9861 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
7c7f29
@@ -392,6 +392,7 @@ ldbm_back_modify( Slapi_PBlock *pb )
7c7f29
 	int not_an_error = 0;
7c7f29
 	int fixup_tombstone = 0;
7c7f29
 	int ec_locked = 0;
7c7f29
+	int result_sent = 0;
7c7f29
 
7c7f29
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be);
7c7f29
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
7c7f29
@@ -466,12 +467,12 @@ ldbm_back_modify( Slapi_PBlock *pb )
7c7f29
 	if ( MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
7c7f29
 		/* find and lock the entry we are about to modify */
7c7f29
 		if (fixup_tombstone) {
7c7f29
-			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
7c7f29
+			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
7c7f29
 		} else {
7c7f29
-			e = find_entry2modify( pb, be, addr, &txn );
7c7f29
+			e = find_entry2modify( pb, be, addr, &txn, &result_sent );
7c7f29
 		}
7c7f29
 		if (e == NULL) {
7c7f29
-			ldap_result_code= -1;
7c7f29
+			ldap_result_code = -1;
7c7f29
 			goto error_return; /* error result sent by find_entry2modify() */
7c7f29
 		}
7c7f29
 	}
7c7f29
@@ -551,12 +552,12 @@ ldbm_back_modify( Slapi_PBlock *pb )
7c7f29
 			if ( !MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
7c7f29
 				/* find and lock the entry we are about to modify */
7c7f29
 				if (fixup_tombstone) {
7c7f29
-					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
7c7f29
+					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
7c7f29
 				} else {
7c7f29
-					e = find_entry2modify( pb, be, addr, &txn );
7c7f29
+					e = find_entry2modify( pb, be, addr, &txn, &result_sent );
7c7f29
 				}
7c7f29
 				if (e == NULL) {
7c7f29
-					ldap_result_code= -1;
7c7f29
+					ldap_result_code = -1;
7c7f29
 					goto error_return; /* error result sent by find_entry2modify() */
7c7f29
 				}
7c7f29
 			}
7c7f29
@@ -966,7 +967,10 @@ common_return:
7c7f29
 			 * And we don't want the supplier to halt sending the updates. */
7c7f29
 			ldap_result_code = LDAP_SUCCESS;
7c7f29
 		}
7c7f29
-		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
7c7f29
+		if (!result_sent) {
7c7f29
+			/* result is already sent in find_entry. */
7c7f29
+			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
7c7f29
+		}
7c7f29
 	}
7c7f29
 
7c7f29
 	/* free our backups */
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
7c7f29
index c0cd2ab..f934305 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
7c7f29
@@ -95,6 +95,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
7c7f29
     int myrc = 0;
7c7f29
     PRUint64 conn_id;
7c7f29
     int op_id;
7c7f29
+    int result_sent = 0;
7c7f29
     if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
7c7f29
         conn_id = 0; /* connection is NULL */
7c7f29
     }
7c7f29
@@ -474,7 +475,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
7c7f29
             /* find and lock the entry we are about to modify */
7c7f29
             /* JCMREPL - Argh, what happens about the stinking referrals? */
7c7f29
             slapi_pblock_get (pb, SLAPI_TARGET_ADDRESS, &old_addr);
7c7f29
-            e = find_entry2modify( pb, be, old_addr, &txn );
7c7f29
+            e = find_entry2modify(pb, be, old_addr, &txn, &result_sent);
7c7f29
             if ( e == NULL )
7c7f29
             {
7c7f29
                 ldap_result_code= -1;
7c7f29
@@ -510,7 +511,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
7c7f29
             } else {
7c7f29
                 oldparent_addr.uniqueid = NULL;            
7c7f29
             }
7c7f29
-            parententry = find_entry2modify_only( pb, be, &oldparent_addr, &txn );
7c7f29
+            parententry = find_entry2modify_only(pb, be, &oldparent_addr, &txn, &result_sent);
7c7f29
             modify_init(&parent_modify_context,parententry);
7c7f29
         
7c7f29
             /* Fetch and lock the new parent of the entry that is moving */            
7c7f29
@@ -520,7 +521,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
7c7f29
                 if (is_resurect_operation) {
7c7f29
                     newsuperior_addr->uniqueid = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
7c7f29
                 }
7c7f29
-                newparententry = find_entry2modify_only( pb, be, newsuperior_addr, &txn );
7c7f29
+                newparententry = find_entry2modify_only(pb, be, newsuperior_addr, &txn, &result_sent);
7c7f29
                 slapi_ch_free_string(&newsuperior_addr->uniqueid);
7c7f29
                 modify_init(&newparent_modify_context,newparententry);
7c7f29
             }
7c7f29
@@ -581,7 +582,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
7c7f29
                         Slapi_DN ancestorsdn;
7c7f29
                         struct backentry *ancestorentry;
7c7f29
                         slapi_sdn_init(&ancestorsdn);
7c7f29
-                        ancestorentry= dn2ancestor(be,&dn_newdn,&ancestorsdn,&txn,&err);
7c7f29
+                        ancestorentry = dn2ancestor(be, &dn_newdn, &ancestorsdn, &txn, &err, 0);
7c7f29
                         CACHE_RETURN( &inst->inst_cache, &ancestorentry );
7c7f29
                         ldap_result_matcheddn= slapi_ch_strdup((char *) slapi_sdn_get_dn(&ancestorsdn));
7c7f29
                         ldap_result_code= LDAP_NO_SUCH_OBJECT;
7c7f29
@@ -1486,8 +1487,10 @@ common_return:
7c7f29
              * And we don't want the supplier to halt sending the updates. */
7c7f29
             ldap_result_code = LDAP_SUCCESS;
7c7f29
         }
7c7f29
-        slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn,
7c7f29
-                    ldap_result_message, 0,NULL );
7c7f29
+        if (!result_sent) {
7c7f29
+            slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn,
7c7f29
+                                   ldap_result_message, 0, NULL);
7c7f29
+        }
7c7f29
     }
7c7f29
     slapi_mods_done(&smods_operation_wsi);
7c7f29
     slapi_mods_done(&smods_generated);
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
7c7f29
index 535529c..cda1714 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
7c7f29
@@ -584,7 +584,7 @@ ldbm_back_search( Slapi_PBlock *pb )
7c7f29
     }
7c7f29
     else
7c7f29
     {
7c7f29
-        if ( ( e = find_entry( pb, be, addr, &txn )) == NULL )
7c7f29
+        if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL)
7c7f29
         {
7c7f29
             /* error or referral sent by find_entry */
7c7f29
             return ldbm_back_search_cleanup(pb, li, sort_control, 
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
7c7f29
index 77c1e70..516b32d 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/misc.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/misc.c
7c7f29
@@ -412,7 +412,7 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
7c7f29
 
7c7f29
     /* Note: if we find the bentry, it will stay locked until someone calls
7c7f29
      * modify_term on the mc we'll be associating the bentry with */
7c7f29
-    bentry = find_entry2modify_only( pb, be, &bentry_addr, &txn );
7c7f29
+    bentry = find_entry2modify_only(pb, be, &bentry_addr, &txn, NULL);
7c7f29
 
7c7f29
     if (NULL == bentry) {
7c7f29
         /* Uh oh, we couldn't find and lock the RUV entry! */
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
7c7f29
index 86e2237..8c813dd 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
7c7f29
@@ -174,7 +174,7 @@ int ldbm_back_ctrl_info(Slapi_Backend *be, int cmd, void *info);
7c7f29
 struct backentry *dn2entry(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int    *err);
7c7f29
 struct backentry *dn2entry_ext(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int flags, int *err);
7c7f29
 struct backentry *dn2entry_or_ancestor(Slapi_Backend *be, const Slapi_DN *sdn, Slapi_DN *ancestor, back_txn *txn, int *err);
7c7f29
-struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err);
7c7f29
+struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err, int allow_suffix);
7c7f29
 int get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
7c7f29
 int get_copy_of_entry_ext(Slapi_PBlock *pb, ID id, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
7c7f29
 void done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter);
7c7f29
@@ -194,11 +194,13 @@ IDList * filter_candidates_ext( Slapi_PBlock *pb, backend *be, const char *base,
7c7f29
 /*
7c7f29
  * findentry.c
7c7f29
  */
7c7f29
-struct backentry * find_entry2modify( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
7c7f29
-struct backentry * find_entry( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
7c7f29
-struct backentry * find_entry2modify_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
7c7f29
-struct backentry * find_entry2modify_only_ext( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn);
7c7f29
-struct backentry * find_entry_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
7c7f29
+/* Return code */
7c7f29
+#define FE_RC_SENT_RESULT 1
7c7f29
+struct backentry *find_entry2modify(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
7c7f29
+struct backentry *find_entry(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
7c7f29
+struct backentry *find_entry2modify_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
7c7f29
+struct backentry *find_entry2modify_only_ext(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn, int *rc);
7c7f29
+struct backentry *find_entry_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
7c7f29
 int check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, const char *callingfn);
7c7f29
 
7c7f29
 /*
7c7f29
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.c b/ldap/servers/slapd/back-ldbm/vlv_srch.c
7c7f29
index fcd0c2d..df378211 100644
7c7f29
--- a/ldap/servers/slapd/back-ldbm/vlv_srch.c
7c7f29
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.c
7c7f29
@@ -162,7 +162,7 @@ vlvSearch_init(struct vlvSearch* p, Slapi_PBlock *pb, const Slapi_Entry *e, ldbm
7c7f29
 
7c7f29
             addr.sdn = p->vlv_base;
7c7f29
             addr.uniqueid = NULL;
7c7f29
-            e = find_entry( pb, inst->inst_be, &addr, &txn );
7c7f29
+            e = find_entry(pb, inst->inst_be, &addr, &txn, NULL);
7c7f29
             /* Check to see if the entry is absent. If it is, mark this search
7c7f29
              * as not initialized */
7c7f29
             if (NULL == e) {
7c7f29
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
7c7f29
index 1ffec4e..b441615 100644
7c7f29
--- a/ldap/servers/slapd/bind.c
7c7f29
+++ b/ldap/servers/slapd/bind.c
7c7f29
@@ -438,8 +438,8 @@ do_bind( Slapi_PBlock *pb )
7c7f29
              * to an LDAP DN, fail and return an invalidCredentials error.
7c7f29
              */
7c7f29
             if ( NULL == pb->pb_conn->c_external_dn ) {
7c7f29
-                send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
7c7f29
-                                  "client certificate mapping failed", 0, NULL );
7c7f29
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Client certificate mapping failed");
7c7f29
+                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
7c7f29
                 /* call postop plugins */
7c7f29
                 plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
7c7f29
                 goto free_and_return;
7c7f29
@@ -556,33 +556,32 @@ do_bind( Slapi_PBlock *pb )
7c7f29
         /* Check if simple binds are allowed over an insecure channel.  We only check
7c7f29
          * this for authenticated binds. */
7c7f29
         } else if (config_get_require_secure_binds() == 1) {
7c7f29
-                Connection *conn = NULL;
7c7f29
-                int sasl_ssf = 0;
7c7f29
-                int local_ssf = 0;
7c7f29
-
7c7f29
-                /* Allow simple binds only for SSL/TLS established connections
7c7f29
-                 * or connections using SASL privacy layers */
7c7f29
-                conn = pb->pb_conn;
7c7f29
-                if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
7c7f29
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
7c7f29
-                                     "Could not get SASL SSF from connection\n" );
7c7f29
-                    sasl_ssf = 0;
7c7f29
-                }
7c7f29
+            Connection *conn = NULL;
7c7f29
+            int sasl_ssf = 0;
7c7f29
+            int local_ssf = 0;
7c7f29
+
7c7f29
+            /* Allow simple binds only for SSL/TLS established connections
7c7f29
+             * or connections using SASL privacy layers */
7c7f29
+            conn = pb->pb_conn;
7c7f29
+            if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
7c7f29
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
7c7f29
+                                 "Could not get SASL SSF from connection\n" );
7c7f29
+                sasl_ssf = 0;
7c7f29
+            }
7c7f29
 
7c7f29
-                if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
7c7f29
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
7c7f29
-                                     "Could not get local SSF from connection\n" );
7c7f29
-                    local_ssf = 0;
7c7f29
-                }
7c7f29
+            if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
7c7f29
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
7c7f29
+                                 "Could not get local SSF from connection\n" );
7c7f29
+                local_ssf = 0;
7c7f29
+            }
7c7f29
 
7c7f29
-                if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
7c7f29
-                    (sasl_ssf <= 1) && (local_ssf <= 1)) {
7c7f29
-                        send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
7c7f29
-                                         "Operation requires a secure connection",
7c7f29
-                                         0, NULL);
7c7f29
-                        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
7c7f29
-                        goto free_and_return;
7c7f29
-                }
7c7f29
+            if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
7c7f29
+                (sasl_ssf <= 1) && (local_ssf <= 1)) {
7c7f29
+                send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
7c7f29
+                                 "Operation requires a secure connection", 0, NULL);
7c7f29
+                slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
7c7f29
+                goto free_and_return;
7c7f29
+            }
7c7f29
         }
7c7f29
         break;
7c7f29
     default:
7c7f29
@@ -627,6 +626,7 @@ do_bind( Slapi_PBlock *pb )
7c7f29
                 /*
7c7f29
                  *  right dn, wrong passwd - reject with invalid credentials
7c7f29
                  */
7c7f29
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
7c7f29
                 send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
7c7f29
                 /* increment BindSecurityErrorcount */
7c7f29
                 slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
7c7f29
@@ -686,7 +686,8 @@ do_bind( Slapi_PBlock *pb )
7c7f29
             slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &pb_sdn);
7c7f29
             if (!pb_sdn) {
7c7f29
                 slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set NULL dn\n");
7c7f29
-                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
7c7f29
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
7c7f29
+                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
7c7f29
                 goto free_and_return;
7c7f29
             } else if ((pb_sdn != sdn) || (sdn_updated = slapi_sdn_compare(original_sdn, pb_sdn))) {
7c7f29
                 /*
7c7f29
@@ -696,8 +697,10 @@ do_bind( Slapi_PBlock *pb )
7c7f29
                 sdn = pb_sdn;
7c7f29
                 dn = slapi_sdn_get_dn(sdn);
7c7f29
                 if (!dn) {
7c7f29
-                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn\n");
7c7f29
-                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
7c7f29
+                    char *udn = slapi_sdn_get_udn(sdn);
7c7f29
+                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn %s\n", udn?udn:"");
7c7f29
+                    slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
7c7f29
+                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
7c7f29
                     goto free_and_return;
7c7f29
                 }
7c7f29
                 if (!sdn_updated) { /* pb_sdn != sdn; need to compare the dn's. */
7c7f29
@@ -711,7 +714,8 @@ do_bind( Slapi_PBlock *pb )
7c7f29
                         slapi_pblock_set( pb, SLAPI_BACKEND, be );
7c7f29
                     } else {
7c7f29
                         slapi_create_errormsg(errorbuf, sizeof(errorbuf), "No matching backend for %s\n", dn);
7c7f29
-                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
7c7f29
+                        slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
7c7f29
+                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
7c7f29
                         goto free_and_return;
7c7f29
                     }
7c7f29
                 }
7c7f29
@@ -790,7 +794,8 @@ do_bind( Slapi_PBlock *pb )
7c7f29
                                     goto account_locked;
7c7f29
                                 }
7c7f29
                             } else {
7c7f29
-                                send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, "", 0, NULL);
7c7f29
+                                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
7c7f29
+                                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
7c7f29
                                 goto free_and_return;
7c7f29
                             }
7c7f29
                         }
7c7f29
@@ -850,8 +855,7 @@ account_locked:
7c7f29
              * the front end.
7c7f29
              */
7c7f29
             if ( rc == SLAPI_BIND_SUCCESS || rc == SLAPI_BIND_ANONYMOUS) {
7c7f29
-                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL,
7c7f29
-                                  0, NULL );
7c7f29
+                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
7c7f29
             }
7c7f29
 
7c7f29
             slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
7c7f29
@@ -876,8 +880,7 @@ free_and_return:;
7c7f29
     slapi_sdn_free(&sdn);
7c7f29
     slapi_ch_free_string( &saslmech );
7c7f29
     slapi_ch_free( (void **)&cred.bv_val );
7c7f29
-    if ( bind_target_entry != NULL )
7c7f29
-        slapi_entry_free(bind_target_entry);
7c7f29
+    slapi_entry_free(bind_target_entry);
7c7f29
 }
7c7f29
 
7c7f29
 
7c7f29
diff --git a/ldap/servers/slapd/defbackend.c b/ldap/servers/slapd/defbackend.c
7c7f29
index 7d73501..da4a701 100644
7c7f29
--- a/ldap/servers/slapd/defbackend.c
7c7f29
+++ b/ldap/servers/slapd/defbackend.c
7c7f29
@@ -171,6 +171,51 @@ defbackend_abandon( Slapi_PBlock *pb )
7c7f29
 }
7c7f29
 
7c7f29
 
7c7f29
+#define DEFBE_NO_SUCH_SUFFIX "No such suffix"
7c7f29
+/*
7c7f29
+ * Generate a "No such suffix" return text
7c7f29
+ * Example:
7c7f29
+ *   cn=X,dc=bogus,dc=com ==> "No such suffix (dc=bogus,dc=com)" 
7c7f29
+ *     if the last rdn starts with "dc=", print all last dc= rdn's.
7c7f29
+ *   cn=X,cn=bogus ==> "No such suffix (cn=bogus)"
7c7f29
+ *     otherwise, print the very last rdn.
7c7f29
+ *   cn=X,z=bogus ==> "No such suffix (x=bogus)"
7c7f29
+ *     it is true even if it is an invalid rdn.
7c7f29
+ *   cn=X,bogus ==> "No such suffix (bogus)"
7c7f29
+ *     another example of invalid rdn.
7c7f29
+ */
7c7f29
+static void
7c7f29
+_defbackend_gen_returntext(char *buffer, size_t buflen, char **dns)
7c7f29
+{
7c7f29
+    int dnidx;
7c7f29
+    int sidx;
7c7f29
+    struct suffix_repeat {
7c7f29
+        char *suffix;
7c7f29
+        int size;
7c7f29
+    } candidates[] = {
7c7f29
+        {"dc=", 3}, /* dc could be repeated.  otherwise the last rdn is used. */
7c7f29
+        {NULL, 0}
7c7f29
+    };
7c7f29
+    PR_snprintf(buffer, buflen, "%s (", DEFBE_NO_SUCH_SUFFIX);
7c7f29
+    for (dnidx = 0; dns[dnidx]; dnidx++) ; /* finding the last */
7c7f29
+    dnidx--; /* last rdn */
7c7f29
+    for (sidx = 0; candidates[sidx].suffix; sidx++) {
7c7f29
+        if (!PL_strncasecmp(dns[dnidx], candidates[sidx].suffix, candidates[sidx].size)) {
7c7f29
+            while (!PL_strncasecmp(dns[--dnidx], candidates[sidx].suffix, candidates[sidx].size)) ;
7c7f29
+            PL_strcat(buffer, dns[++dnidx]); /* the first "dn=", e.g. */
7c7f29
+            for (++dnidx; dns[dnidx]; dnidx++) {
7c7f29
+                PL_strcat(buffer, ",");
7c7f29
+                PL_strcat(buffer, dns[dnidx]);
7c7f29
+            }
7c7f29
+            PL_strcat(buffer, ")");
7c7f29
+            return; /* finished the task */
7c7f29
+        }
7c7f29
+    }
7c7f29
+    PL_strcat(buffer, dns[dnidx]);
7c7f29
+    PL_strcat(buffer, ")");
7c7f29
+    return;
7c7f29
+}
7c7f29
+
7c7f29
 static int
7c7f29
 defbackend_bind( Slapi_PBlock *pb )
7c7f29
 {
7c7f29
@@ -188,11 +233,40 @@ defbackend_bind( Slapi_PBlock *pb )
7c7f29
     slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method );
7c7f29
     slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred );
7c7f29
     if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
7c7f29
-	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
7c7f29
-	rc = SLAPI_BIND_ANONYMOUS;
7c7f29
+        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
7c7f29
+        rc = SLAPI_BIND_ANONYMOUS;
7c7f29
     } else {
7c7f29
-	send_nobackend_ldap_result( pb );
7c7f29
-	rc = SLAPI_BIND_FAIL;
7c7f29
+        Slapi_DN *sdn = NULL;
7c7f29
+        char *suffix = NULL;
7c7f29
+        char **dns = NULL;
7c7f29
+        
7c7f29
+        if (pb->pb_op) {
7c7f29
+            sdn = operation_get_target_spec(pb->pb_op);
7c7f29
+            if (sdn) {
7c7f29
+                dns = slapi_ldap_explode_dn(slapi_sdn_get_dn(sdn), 0);
7c7f29
+                if (dns) {
7c7f29
+                    size_t dnlen = slapi_sdn_get_ndn_len(sdn);
7c7f29
+                    size_t len = dnlen + sizeof(DEFBE_NO_SUCH_SUFFIX) + 4;
7c7f29
+                    suffix = slapi_ch_malloc(len);
7c7f29
+                    if (dnlen) {
7c7f29
+                        _defbackend_gen_returntext(suffix, len, dns);
7c7f29
+                    } else {
7c7f29
+                        PR_snprintf(suffix, len, "%s", DEFBE_NO_SUCH_SUFFIX);
7c7f29
+                    }
7c7f29
+                }
7c7f29
+            }
7c7f29
+        }
7c7f29
+        if (suffix) {
7c7f29
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, suffix);
7c7f29
+        } else {
7c7f29
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, DEFBE_NO_SUCH_SUFFIX);
7c7f29
+        }
7c7f29
+        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
7c7f29
+        if (dns) {
7c7f29
+            slapi_ldap_value_free(dns);
7c7f29
+        }
7c7f29
+        slapi_ch_free_string(&suffix);
7c7f29
+        rc = SLAPI_BIND_FAIL;
7c7f29
     }
7c7f29
 
7c7f29
     return( rc );
7c7f29
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
7c7f29
index 506da92..c2a0206 100644
7c7f29
--- a/ldap/servers/slapd/result.c
7c7f29
+++ b/ldap/servers/slapd/result.c
7c7f29
@@ -2067,14 +2067,26 @@ log_result( Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentrie
7c7f29
 		}
7c7f29
 		else if ( !internal_op )
7c7f29
 		{
7c7f29
+			char *pbtxt = NULL;
7c7f29
+			char *ext_str = NULL;
7c7f29
+			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &pbtxt);
7c7f29
+			if (pbtxt) {
7c7f29
+				ext_str = slapi_ch_smprintf(" - %s", pbtxt);
7c7f29
+			} else {
7c7f29
+				ext_str = "";
7c7f29
+			}
7c7f29
 			slapi_log_access( LDAP_DEBUG_STATS,
7c7f29
 							  "conn=%" NSPRIu64 " op=%d RESULT err=%d"
7c7f29
-							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n",
7c7f29
+							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s%s\n",
7c7f29
 							  op->o_connid,
7c7f29
 							  op->o_opid,
7c7f29
 							  err, tag, nentries,
7c7f29
 							  etime,
7c7f29
-							  notes_str, csn_str );
7c7f29
+							  notes_str, csn_str, ext_str);
7c7f29
+			if (pbtxt) {
7c7f29
+				/* if !pbtxt ==> ext_str == "".  Don't free ext_str. */
7c7f29
+				slapi_ch_free_string(&ext_str);
7c7f29
+			}
7c7f29
 		}
7c7f29
 		else
7c7f29
 		{
7c7f29
-- 
7c7f29
2.4.11
7c7f29