andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone

Blame 0391-Subject-PATCH-Bug-1358559-CVE-2016-4992-389-ds-base-.patch

dc8c34
From 9cbd265f317febe4811a47db6efb2b5e3c0ed8ca Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Thu, 1 Sep 2016 16:02:53 -0700
dc8c34
Subject: [PATCH 391/394] Subject: [PATCH] Bug 1358559 - CVE-2016-4992
dc8c34
 389-ds-base: Information disclosure via repeated use of LDAP ADD operation,
dc8c34
 etc.
dc8c34
dc8c34
0. Backported the Bug-1347760 patches from the master branch to 1.2.11.
dc8c34
dc8c34
1. Description: If a bind user has no rights, it should not disclose
dc8c34
any information including the existence of the entry.
dc8c34
dc8c34
   Fix description:
dc8c34
   1) ALREADY_EXISTS in add -- If to be added entry is found existing
dc8c34
      in ldbm_back_add, it checks the ACI and if there is no rights,
dc8c34
      it returns INSUFFICIENT_ACCESS instead of ALREADY_EXISTS.
dc8c34
   2) NO_SUCH_OBJECT in other update operations -- If the target entry
dc8c34
      is found not existing, it checks the ancestor entry's access
dc8c34
      rights in find_entry.  If it is not allowed to access the subtree,
dc8c34
      it returns INSUFFICIENT_ACCESS instead of NO_SUC_OBJECT.  Plus,
dc8c34
      it supresses the "Matched" ancestor message.
dc8c34
   3) NO_SUCH_OBJECT in search -- If a bind entry has no rights to read
dc8c34
      a subtree, it returns no search results with SUCCESS.  It should
dc8c34
      be applied to the no existing subtree if the bind entry has no
dc8c34
      rights to the super tree.
dc8c34
   4) If bind fails because of the non-existence of the bind user or
dc8c34
      the parent nodes, the bind returns LDAP_INVALID_CREDENTIALS to
dc8c34
      the client with no other information.
dc8c34
      The detailed cause is logged in the access log as follows:
dc8c34
        RESULT err=49 .. etime=0 - No such suffix (<given suffix>)
dc8c34
        RESULT err=49 .. etime=0 - Invalid credentials
dc8c34
        RESULT err=49 .. etime=0 - No such entry
dc8c34
dc8c34
   Reviewed by lkrispen@redhat.com, mreynolds@redhat.com, and tbordaz@redhat.com.
dc8c34
dc8c34
2. Description:
dc8c34
   1. When an account is inactivated, the error UNWILLING_TO_PERFORM with
dc8c34
      the inactivated message should be returned only when the bind is
dc8c34
      successful.
dc8c34
   2. When SASL bind fails, instead of returning the cause of the failure
dc8c34
      directly to the client, but logging it in the access log.
dc8c34
dc8c34
   Reviewed by wibrown@redhat.com (Thank you, William!)
dc8c34
dc8c34
3. Description: do not overwrite rc used to decide if bind was successful.
dc8c34
   When the bind is through ldapi/autobind, an entry does not exist to be
dc8c34
   checked with slapi_check_account_lock.  In that case, a variable rc is
dc8c34
   not supposed to be modified which confuses the following code path.
dc8c34
dc8c34
   Reviewed by nhosoi@redhat.com.
dc8c34
dc8c34
https://bugzilla.redhat.com/show_bug.cgi?id=1358559
dc8c34
(cherry picked from commit 8078a9e5d067e85dbf1817f5620ecd50cde3f5c2)
dc8c34
(cherry picked from commit 3927f4f8c331c33eeeb773ebf762a51d5e303484)
dc8c34
---
dc8c34
 ldap/servers/slapd/back-ldbm/dn2entry.c        |  17 ++-
dc8c34
 ldap/servers/slapd/back-ldbm/findentry.c       | 139 +++++++++++++++++++------
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_add.c        |  21 +++-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_bind.c       |  11 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_compare.c    |   2 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_delete.c     |   9 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_modify.c     |   5 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_modrdn.c     |  17 +--
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_search.c     |   2 +-
dc8c34
 ldap/servers/slapd/back-ldbm/misc.c            |   2 +-
dc8c34
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h |  14 +--
dc8c34
 ldap/servers/slapd/back-ldbm/vlv_srch.c        |   2 +-
dc8c34
 ldap/servers/slapd/bind.c                      | 120 +++++++++++----------
dc8c34
 ldap/servers/slapd/defbackend.c                |  82 ++++++++++++++-
dc8c34
 ldap/servers/slapd/result.c                    |  16 ++-
dc8c34
 ldap/servers/slapd/saslbind.c                  |   4 +-
dc8c34
 16 files changed, 324 insertions(+), 139 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/dn2entry.c b/ldap/servers/slapd/back-ldbm/dn2entry.c
dc8c34
index 3cf37b6..c7c3ec2 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/dn2entry.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/dn2entry.c
dc8c34
@@ -180,14 +180,15 @@ struct backentry *
dc8c34
 dn2ancestor(
dc8c34
     Slapi_Backend *be,
dc8c34
     const Slapi_DN	*sdn,
dc8c34
-	Slapi_DN *ancestordn,
dc8c34
+    Slapi_DN *ancestordn,
dc8c34
     back_txn		*txn,
dc8c34
-    int			*err
dc8c34
+    int			*err,
dc8c34
+    int allow_suffix
dc8c34
 )
dc8c34
 {
dc8c34
-	struct backentry *e = NULL;
dc8c34
+    struct backentry *e = NULL;
dc8c34
 
dc8c34
-	LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
dc8c34
+    LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
dc8c34
 
dc8c34
     /* first, check to see if the given sdn is empty or a root suffix of the
dc8c34
        given backend - if so, it has no parent */
dc8c34
@@ -219,7 +220,13 @@ dn2ancestor(
dc8c34
         */
dc8c34
 
dc8c34
         /* stop when we get to "", or a backend suffix point */
dc8c34
-        while (!e && !slapi_sdn_isempty(&ancestorndn) && !slapi_be_issuffix( be, &ancestorndn )) {
dc8c34
+        while (!e && !slapi_sdn_isempty(&ancestorndn)) {
dc8c34
+            if (!allow_suffix) {
dc8c34
+                /* Original behavior. */
dc8c34
+                if (slapi_be_issuffix(be, &ancestorndn)) {
dc8c34
+                    break;
dc8c34
+                }
dc8c34
+            }
dc8c34
             /* find the entry - it uses the ndn, so no further conversion is necessary */
dc8c34
             e= dn2entry(be,&ancestorndn,txn,err);
dc8c34
             if (!e) {
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c
dc8c34
index 7174c08..a667ff8 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/findentry.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/findentry.c
dc8c34
@@ -45,8 +45,8 @@
dc8c34
 #include "back-ldbm.h"
dc8c34
 
dc8c34
 
dc8c34
-static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags);
dc8c34
-static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags);
dc8c34
+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);
dc8c34
+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);
dc8c34
 /* The flags take these values */
dc8c34
 #define FE_TOMBSTONE_INCLUDED TOMBSTONE_INCLUDED /* :1 defined in back-ldbm.h */
dc8c34
 #define FE_REALLY_INTERNAL 0x2
dc8c34
@@ -56,7 +56,7 @@ check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, co
dc8c34
 {
dc8c34
 	int rc=0, i=0, numValues=0;
dc8c34
 	Slapi_Attr *attr;
dc8c34
-	Slapi_Value *val=NULL;	
dc8c34
+	Slapi_Value *val=NULL;
dc8c34
 	struct berval **refscopy=NULL;
dc8c34
 	struct berval **url=NULL;
dc8c34
 
dc8c34
@@ -109,12 +109,13 @@ out:
dc8c34
 
dc8c34
 static struct backentry *
dc8c34
 find_entry_internal_dn(
dc8c34
-	Slapi_PBlock	*pb,
dc8c34
+    Slapi_PBlock	*pb,
dc8c34
     backend			*be,
dc8c34
     const Slapi_DN *sdn,
dc8c34
     int				lock,
dc8c34
-	back_txn		*txn,
dc8c34
-	int				flags
dc8c34
+    back_txn		*txn,
dc8c34
+    int				flags,
dc8c34
+    int				*rc /* return code */
dc8c34
 )
dc8c34
 { 
dc8c34
 	struct backentry *e;
dc8c34
@@ -122,9 +123,14 @@ find_entry_internal_dn(
dc8c34
 	int	err;
dc8c34
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
dc8c34
 	size_t tries = 0;
dc8c34
+	int isroot = 0;
dc8c34
+	int op_type;
dc8c34
+	char *errbuf = NULL;
dc8c34
 
dc8c34
 	/* get the managedsait ldap message control */
dc8c34
-	slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
dc8c34
+	slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
dc8c34
+	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
dc8c34
+	slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
dc8c34
 
dc8c34
 	while ( (tries < LDBM_CACHE_RETRY_COUNT) && 
dc8c34
 	        (e = dn2entry_ext( be, sdn, txn, flags & TOMBSTONE_INCLUDED, &err ))
dc8c34
@@ -142,6 +148,9 @@ find_entry_internal_dn(
dc8c34
 			if(check_entry_for_referral(pb, e->ep_entry, NULL, "find_entry_internal_dn"))
dc8c34
 			{
dc8c34
 				CACHE_RETURN( &inst->inst_cache, &e );
dc8c34
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
dc8c34
+					*rc = FE_RC_SENT_RESULT;
dc8c34
+				}
dc8c34
 				return( NULL );
dc8c34
 			}
dc8c34
 		}
dc8c34
@@ -180,27 +189,89 @@ find_entry_internal_dn(
dc8c34
 		struct backentry *me;
dc8c34
 		Slapi_DN ancestorsdn;
dc8c34
 		slapi_sdn_init(&ancestorsdn);
dc8c34
-		me= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,txn,&err;;
dc8c34
+		me = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, txn, &err, 1 /* allow_suffix */);
dc8c34
 		if ( !managedsait && me != NULL ) {
dc8c34
 			/* if the entry is a referral send the referral */
dc8c34
 			if(check_entry_for_referral(pb, me->ep_entry, (char*)slapi_sdn_get_dn(&ancestorsdn), "find_entry_internal_dn"))
dc8c34
 			{
dc8c34
 				CACHE_RETURN( &inst->inst_cache, &me );
dc8c34
 				slapi_sdn_done(&ancestorsdn);
dc8c34
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
dc8c34
+					*rc = FE_RC_SENT_RESULT;
dc8c34
+				}
dc8c34
 				return( NULL );
dc8c34
 			}
dc8c34
 			/* else fall through to no such object */
dc8c34
 		}
dc8c34
 
dc8c34
 		/* entry not found */
dc8c34
-		slapi_send_ldap_result( pb, ( 0 == err || DB_NOTFOUND == err ) ?
dc8c34
-			LDAP_NO_SUCH_OBJECT : ( LDAP_INVALID_DN_SYNTAX == err ) ?
dc8c34
-			LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
dc8c34
-			(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
dc8c34
+		if ((0 == err) || (DB_NOTFOUND == err)) {
dc8c34
+			if (me && !isroot) {
dc8c34
+				/* If not root, you may not want to reveal it. */
dc8c34
+				int acl_type = -1;
dc8c34
+				int return_err = LDAP_NO_SUCH_OBJECT;
dc8c34
+				err = LDAP_SUCCESS;
dc8c34
+				switch (op_type) {
dc8c34
+				case SLAPI_OPERATION_ADD:
dc8c34
+					acl_type = SLAPI_ACL_ADD;
dc8c34
+					return_err = LDAP_INSUFFICIENT_ACCESS;
dc8c34
+					break;
dc8c34
+				case SLAPI_OPERATION_DELETE:
dc8c34
+					acl_type = SLAPI_ACL_DELETE;
dc8c34
+					return_err = LDAP_INSUFFICIENT_ACCESS;
dc8c34
+					break;
dc8c34
+				case SLAPI_OPERATION_MODDN:
dc8c34
+					acl_type = SLAPI_ACL_WRITE;
dc8c34
+					return_err = LDAP_INSUFFICIENT_ACCESS;
dc8c34
+					break;
dc8c34
+				case SLAPI_OPERATION_MODIFY:
dc8c34
+					acl_type = SLAPI_ACL_WRITE;
dc8c34
+					return_err = LDAP_INSUFFICIENT_ACCESS;
dc8c34
+					break;
dc8c34
+				case SLAPI_OPERATION_SEARCH:
dc8c34
+				case SLAPI_OPERATION_COMPARE:
dc8c34
+					return_err = LDAP_SUCCESS;
dc8c34
+					acl_type = SLAPI_ACL_READ;
dc8c34
+					break;
dc8c34
+				case SLAPI_OPERATION_BIND:
dc8c34
+					acl_type = -1; /* skip acl check. acl is not set up for bind. */
dc8c34
+					return_err = LDAP_INVALID_CREDENTIALS;
dc8c34
+					slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
dc8c34
+					break;
dc8c34
+				}
dc8c34
+				if (acl_type > 0) {
dc8c34
+					err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
dc8c34
+					                             ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
dc8c34
+				}
dc8c34
+				if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
dc8c34
+					/*
dc8c34
+					 * Operations to be checked && ACL returns disallow.
dc8c34
+					 * Not to disclose the info about the entry's existence,
dc8c34
+					 * do not return the "matched" DN.
dc8c34
+					 * Plus, the bind case returns LDAP_INAPPROPRIATE_AUTH.
dc8c34
+					 */
dc8c34
+					slapi_send_ldap_result(pb, return_err, NULL, NULL, 0, NULL);
dc8c34
+				} else {
dc8c34
+					slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT,
dc8c34
+						(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
dc8c34
+				}
dc8c34
+			} else {
dc8c34
+				slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT,
dc8c34
+					(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
dc8c34
+			}
dc8c34
+		} else {
dc8c34
+			slapi_send_ldap_result( pb, ( LDAP_INVALID_DN_SYNTAX == err ) ?
dc8c34
+				LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
dc8c34
+				(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
dc8c34
+		}
dc8c34
+		if (rc) {
dc8c34
+			*rc = FE_RC_SENT_RESULT;
dc8c34
+		}
dc8c34
 		slapi_sdn_done(&ancestorsdn);
dc8c34
 		CACHE_RETURN( &inst->inst_cache, &me );
dc8c34
 	}
dc8c34
 
dc8c34
+	slapi_ch_free_string(&errbuf);
dc8c34
 	LDAPDebug( LDAP_DEBUG_TRACE, "<= find_entry_internal_dn not found (%s)\n",
dc8c34
 	    slapi_sdn_get_dn(sdn), 0, 0 );
dc8c34
 	return( NULL );
dc8c34
@@ -212,11 +283,11 @@ find_entry_internal_dn(
dc8c34
  */
dc8c34
 static struct backentry *
dc8c34
 find_entry_internal_uniqueid(
dc8c34
-	Slapi_PBlock	*pb,
dc8c34
+    Slapi_PBlock	*pb,
dc8c34
     backend *be,
dc8c34
-	const char 			*uniqueid,
dc8c34
+    const char 			*uniqueid,
dc8c34
     int				lock,
dc8c34
-	back_txn		*txn
dc8c34
+    back_txn		*txn
dc8c34
 )
dc8c34
 {
dc8c34
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
dc8c34
@@ -272,8 +343,9 @@ find_entry_internal(
dc8c34
     Slapi_Backend *be,
dc8c34
     const entry_address *addr,
dc8c34
     int			lock,
dc8c34
-	back_txn *txn,
dc8c34
-	int flags
dc8c34
+    back_txn *txn,
dc8c34
+    int flags,
dc8c34
+    int *rc
dc8c34
 )
dc8c34
 {
dc8c34
 	/* check if we should search based on uniqueid or dn */
dc8c34
@@ -290,11 +362,9 @@ find_entry_internal(
dc8c34
 		LDAPDebug( LDAP_DEBUG_TRACE, "=> find_entry_internal (dn=%s) lock %d\n",
dc8c34
 		           slapi_sdn_get_dn(addr->sdn), lock, 0 );
dc8c34
 		if (addr->sdn) {
dc8c34
-			entry = find_entry_internal_dn (pb, be, addr->sdn, 
dc8c34
-			                                lock, txn, flags);
dc8c34
+			entry = find_entry_internal_dn (pb, be, addr->sdn, lock, txn, flags, rc);
dc8c34
 		} else {
dc8c34
-			LDAPDebug0Args( LDAP_DEBUG_ANY,
dc8c34
-			                "find_entry_internal: Null target dn\n" );
dc8c34
+			LDAPDebug0Args( LDAP_DEBUG_ANY, "find_entry_internal: Null target dn\n" );
dc8c34
 		}
dc8c34
 
dc8c34
 		LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= find_entry_internal\n" );
dc8c34
@@ -307,10 +377,11 @@ find_entry(
dc8c34
     Slapi_PBlock		*pb,
dc8c34
     Slapi_Backend *be,
dc8c34
     const entry_address *addr,
dc8c34
-	back_txn *txn
dc8c34
+    back_txn *txn,
dc8c34
+    int *rc
dc8c34
 )
dc8c34
 {
dc8c34
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, 0/*flags*/ ) );
dc8c34
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, 0/*flags*/, rc));
dc8c34
 }
dc8c34
 
dc8c34
 struct backentry *
dc8c34
@@ -318,10 +389,11 @@ find_entry2modify(
dc8c34
     Slapi_PBlock		*pb,
dc8c34
     Slapi_Backend *be,
dc8c34
     const entry_address *addr,
dc8c34
-	back_txn *txn
dc8c34
+    back_txn *txn,
dc8c34
+    int *rc
dc8c34
 )
dc8c34
 {
dc8c34
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 0/*flags*/ ) );
dc8c34
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0/*flags*/, rc));
dc8c34
 }
dc8c34
 
dc8c34
 /* New routines which do not do any referral stuff.
dc8c34
@@ -333,10 +405,11 @@ find_entry_only(
dc8c34
     Slapi_PBlock		*pb,
dc8c34
     Slapi_Backend *be,
dc8c34
     const entry_address *addr,
dc8c34
-	back_txn *txn
dc8c34
+    back_txn *txn,
dc8c34
+    int *rc
dc8c34
 )
dc8c34
 {
dc8c34
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL ) );
dc8c34
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL, rc));
dc8c34
 }
dc8c34
 
dc8c34
 struct backentry *
dc8c34
@@ -344,10 +417,11 @@ find_entry2modify_only(
dc8c34
     Slapi_PBlock		*pb,
dc8c34
     Slapi_Backend *be,
dc8c34
     const entry_address *addr,
dc8c34
-    back_txn *txn
dc8c34
+    back_txn *txn,
dc8c34
+    int *rc
dc8c34
 )
dc8c34
 {
dc8c34
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL ) );
dc8c34
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0 /* to check aci, disable INTERNAL */, rc));
dc8c34
 }
dc8c34
 
dc8c34
 struct backentry *
dc8c34
@@ -356,10 +430,9 @@ find_entry2modify_only_ext(
dc8c34
     Slapi_Backend *be,
dc8c34
     const entry_address *addr,
dc8c34
     int flags,
dc8c34
-    back_txn *txn
dc8c34
-
dc8c34
+    back_txn *txn,
dc8c34
+    int *rc
dc8c34
 )
dc8c34
 {
dc8c34
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 
dc8c34
-		                         FE_REALLY_INTERNAL | flags ));
dc8c34
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL | flags, rc));
dc8c34
 }
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
index b915bfe..30fb8f2 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
@@ -118,6 +118,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	int parent_switched = 0;
dc8c34
 	int noabort = 1;
dc8c34
 	const char *dn = NULL;
dc8c34
+	int result_sent = 0;
dc8c34
 
dc8c34
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
dc8c34
 	slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e );
dc8c34
@@ -302,7 +303,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		addr.sdn = &parentsdn;
dc8c34
 		addr.udn = NULL;
dc8c34
 		addr.uniqueid = operation->o_params.p.p_add.parentuniqueid;
dc8c34
-		parententry = find_entry2modify_only(pb,be,&addr,&txn);
dc8c34
+		parententry = find_entry2modify_only(pb, be, &addr, &txn, &result_sent);
dc8c34
 		if (parententry && parententry->ep_entry) {
dc8c34
 			if (!operation->o_params.p.p_add.parentuniqueid){
dc8c34
 				/* Set the parentuniqueid now */
dc8c34
@@ -356,6 +357,14 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 				/* The entry already exists */ 
dc8c34
 				ldap_result_code = LDAP_ALREADY_EXISTS;
dc8c34
 			}
dc8c34
+			if ((LDAP_ALREADY_EXISTS == ldap_result_code) && !isroot && !is_replicated_operation) {
dc8c34
+				int myrc = plugin_call_acl_plugin(pb, e, NULL, NULL, SLAPI_ACL_ADD,
dc8c34
+				                                  ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
dc8c34
+				if (myrc) {
dc8c34
+					ldap_result_code = myrc;
dc8c34
+					ldap_result_message = errbuf;
dc8c34
+				}
dc8c34
+			}
dc8c34
 			goto error_return;
dc8c34
 		} 
dc8c34
 		else 
dc8c34
@@ -372,7 +381,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 				Slapi_DN ancestorsdn;
dc8c34
 				struct backentry *ancestorentry;
dc8c34
 				slapi_sdn_init(&ancestorsdn);
dc8c34
-				ancestorentry= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,&txn,&err;;
dc8c34
+				ancestorentry = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, &txn, &err, 0);
dc8c34
 				slapi_sdn_done(&ancestorsdn);
dc8c34
 				if ( ancestorentry != NULL )
dc8c34
 				{
dc8c34
@@ -419,7 +428,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		addr.udn = NULL;
dc8c34
 		addr.sdn = NULL;
dc8c34
 		addr.uniqueid = (char *)slapi_entry_get_uniqueid(e); /* jcm - cast away const */
dc8c34
-		tombstoneentry = find_entry2modify( pb, be, &addr, &txn );
dc8c34
+		tombstoneentry = find_entry2modify(pb, be, &addr, &txn, &result_sent);
dc8c34
 		if ( tombstoneentry==NULL )
dc8c34
 		{
dc8c34
 			ldap_result_code= -1;
dc8c34
@@ -617,7 +626,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			              "It might be a conflict entry.\n", slapi_sdn_get_dn(&parentsdn));
dc8c34
 
dc8c34
 			slapi_sdn_init(&ancestorsdn);
dc8c34
-			ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err );
dc8c34
+			ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err, 1);
dc8c34
 			CACHE_RETURN( &inst->inst_cache, &ancestorentry );
dc8c34
 
dc8c34
 			ldap_result_code= LDAP_NO_SUCH_OBJECT;
dc8c34
@@ -1257,7 +1266,9 @@ common_return:
dc8c34
 	}
dc8c34
 	if(ldap_result_code!=-1)
dc8c34
 	{
dc8c34
-		slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
dc8c34
+		if (!result_sent) {
dc8c34
+			slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
dc8c34
+		}
dc8c34
 	}
dc8c34
 	backentry_free(&originalentry);
dc8c34
 	backentry_free(&tmpentry);
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_bind.c b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
dc8c34
index 24c0b4f..00a2021 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_bind.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
dc8c34
@@ -211,6 +211,7 @@ ldbm_back_bind( Slapi_PBlock *pb )
dc8c34
 	Slapi_Value **bvals;
dc8c34
 	entry_address *addr;
dc8c34
 	back_txn txn = {NULL};
dc8c34
+	int result_sent = 0;
dc8c34
 
dc8c34
 	/* get parameters */
dc8c34
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be );
dc8c34
@@ -236,7 +237,11 @@ ldbm_back_bind( Slapi_PBlock *pb )
dc8c34
 	 * find the target entry.  find_entry() takes care of referrals
dc8c34
 	 *   and sending errors if the entry does not exist.
dc8c34
 	 */
dc8c34
-	if (( e = find_entry( pb, be, addr, &txn )) == NULL ) {
dc8c34
+	if ((e = find_entry( pb, be, addr, &txn, &result_sent)) == NULL) {
dc8c34
+		/* In the failure case, the result is supposed to be sent in the backend. */
dc8c34
+		if (!result_sent) {
dc8c34
+			slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
dc8c34
+		}
dc8c34
 		return( SLAPI_BIND_FAIL );
dc8c34
 	}
dc8c34
 
dc8c34
@@ -265,8 +270,8 @@ ldbm_back_bind( Slapi_PBlock *pb )
dc8c34
 				break;
dc8c34
 			}
dc8c34
 #endif
dc8c34
-			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
dc8c34
-			    NULL, 0, NULL );
dc8c34
+			slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
dc8c34
+			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
dc8c34
 			CACHE_RETURN( &inst->inst_cache, &e );
dc8c34
 			value_done(&cv;;
dc8c34
 			return( SLAPI_BIND_FAIL );
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_compare.c b/ldap/servers/slapd/back-ldbm/ldbm_compare.c
dc8c34
index e9761ec..1849fc4 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_compare.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_compare.c
dc8c34
@@ -78,7 +78,7 @@ ldbm_back_compare( Slapi_PBlock *pb )
dc8c34
 	/* get the namespace dn */
dc8c34
 	namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
dc8c34
 
dc8c34
-	if ( (e = find_entry( pb, be, addr, &txn )) == NULL ) {
dc8c34
+	if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL) {
dc8c34
 		return( -1 );	/* error result sent by find_entry() */
dc8c34
 	}
dc8c34
 
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
index f30e2a6..4113da2 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
@@ -100,6 +100,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 	int free_delete_existing_entry = 0;
dc8c34
 	ID ep_id = 0;
dc8c34
 	ID tomb_ep_id = 0;
dc8c34
+	int result_sent = 0;
dc8c34
 
dc8c34
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be);
dc8c34
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
dc8c34
@@ -188,7 +189,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 	 * deleted.  That is, the entry 'e' found with "addr" is a tomb-
dc8c34
 	 * stone.  If it is the case, we need to back off.
dc8c34
 	 */
dc8c34
-	if ( (e = find_entry2modify( pb, be, addr, &txn )) == NULL )
dc8c34
+	if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL)
dc8c34
 	{
dc8c34
 		ldap_result_code= LDAP_NO_SUCH_OBJECT; 
dc8c34
 		/* retval is -1 */
dc8c34
@@ -398,7 +399,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 				parent_addr.uniqueid = NULL;
dc8c34
 			}
dc8c34
 			parent_addr.sdn = &parentsdn;
dc8c34
-			parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn);
dc8c34
+			parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn, &result_sent);
dc8c34
 		}
dc8c34
 		if (parent) {
dc8c34
 			int isglue;
dc8c34
@@ -1323,7 +1324,9 @@ common_return:
dc8c34
 diskfull_return:
dc8c34
 	if(ldap_result_code!=-1)
dc8c34
 	{
dc8c34
-		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
dc8c34
+		if (!result_sent) {
dc8c34
+			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
dc8c34
+		}
dc8c34
 	}
dc8c34
 	modify_term(&parent_modify_c, be);
dc8c34
 	if(dblock_acquired)
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
index 15cfe2c..e5b3cf2 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
@@ -388,6 +388,7 @@ ldbm_back_modify( Slapi_PBlock *pb )
dc8c34
 	int opreturn = 0;
dc8c34
 	int mod_count = 0;
dc8c34
 	int ec_locked = 0;
dc8c34
+	int result_sent = 0;
dc8c34
 
dc8c34
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be);
dc8c34
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
dc8c34
@@ -447,7 +448,7 @@ ldbm_back_modify( Slapi_PBlock *pb )
dc8c34
 	}
dc8c34
 
dc8c34
 	/* find and lock the entry we are about to modify */
dc8c34
-	if ( (e = find_entry2modify( pb, be, addr, &txn )) == NULL ) {
dc8c34
+	if ( (e = find_entry2modify( pb, be, addr, &txn, &result_sent )) == NULL ) {
dc8c34
 		ldap_result_code= -1;
dc8c34
 		goto error_return;	  /* error result sent by find_entry2modify() */
dc8c34
 	}
dc8c34
@@ -890,7 +891,7 @@ common_return:
dc8c34
 	{
dc8c34
 		dblayer_unlock_backend(be);
dc8c34
 	}
dc8c34
-	if(ldap_result_code!=-1)
dc8c34
+	if ((ldap_result_code!=-1) && !result_sent)
dc8c34
 	{
dc8c34
 		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
dc8c34
 	}
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
index d8379ab..0fa72bf 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
@@ -120,6 +120,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
     char *newrdn = NULL;
dc8c34
     int opreturn = 0;
dc8c34
     int free_modrdn_existing_entry = 0;
dc8c34
+    int result_sent = 0;
dc8c34
 
dc8c34
     /* sdn & parentsdn need to be initialized before "goto *_return" */
dc8c34
     slapi_sdn_init(&dn_newdn);
dc8c34
@@ -352,7 +353,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
     /* find and lock the entry we are about to modify */
dc8c34
     /* JCMREPL - Argh, what happens about the stinking referrals? */
dc8c34
     slapi_pblock_get (pb, SLAPI_TARGET_ADDRESS, &old_addr);
dc8c34
-    e = find_entry2modify( pb, be, old_addr, &txn );
dc8c34
+    e = find_entry2modify( pb, be, old_addr, &txn, &result_sent );
dc8c34
     if ( e == NULL )
dc8c34
     {
dc8c34
         ldap_result_code= -1;
dc8c34
@@ -389,7 +390,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
     } else {
dc8c34
         oldparent_addr.uniqueid = NULL;            
dc8c34
     }
dc8c34
-    parententry = find_entry2modify_only( pb, be, &oldparent_addr, &txn );
dc8c34
+    parententry = find_entry2modify_only( pb, be, &oldparent_addr, &txn, &result_sent );
dc8c34
     modify_init(&parent_modify_context,parententry);
dc8c34
 
dc8c34
     /* Fetch and lock the new parent of the entry that is moving */            
dc8c34
@@ -399,7 +400,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
         if (is_resurect_operation) {
dc8c34
             newsuperior_addr->uniqueid = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
dc8c34
         }
dc8c34
-        newparententry = find_entry2modify_only( pb, be, newsuperior_addr, &txn );
dc8c34
+        newparententry = find_entry2modify_only( pb, be, newsuperior_addr, &txn, &result_sent );
dc8c34
         slapi_ch_free_string(&newsuperior_addr->uniqueid);
dc8c34
         modify_init(&newparent_modify_context,newparententry);
dc8c34
     }
dc8c34
@@ -460,7 +461,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
                 Slapi_DN ancestorsdn;
dc8c34
                 struct backentry *ancestorentry;
dc8c34
                 slapi_sdn_init(&ancestorsdn);
dc8c34
-                ancestorentry= dn2ancestor(be,&dn_newdn,&ancestorsdn,&txn,&err;;
dc8c34
+                ancestorentry = dn2ancestor(be, &dn_newdn, &ancestorsdn, &txn, &err, 0);
dc8c34
                 CACHE_RETURN( &inst->inst_cache, &ancestorentry );
dc8c34
                 ldap_result_matcheddn= slapi_ch_strdup((char *) slapi_sdn_get_dn(&ancestorsdn));
dc8c34
                 ldap_result_code= LDAP_NO_SUCH_OBJECT;
dc8c34
@@ -1418,10 +1419,10 @@ common_return:
dc8c34
         modify_term(&ruv_c, be);
dc8c34
     }
dc8c34
 
dc8c34
-    if (ldap_result_code!=-1)
dc8c34
-    {
dc8c34
-        slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn,
dc8c34
-                    ldap_result_message, 0,NULL );
dc8c34
+    if ((ldap_result_code!=-1) && !result_sent)
dc8c34
+    { 
dc8c34
+        slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn,
dc8c34
+                               ldap_result_message, 0, NULL);
dc8c34
     }
dc8c34
     slapi_mods_done(&smods_operation_wsi);
dc8c34
     slapi_mods_done(&smods_generated);
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
index bbcbe0e..d468481 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
@@ -603,7 +603,7 @@ ldbm_back_search( Slapi_PBlock *pb )
dc8c34
     }
dc8c34
     else
dc8c34
     {
dc8c34
-        if ( ( e = find_entry( pb, be, addr, &txn )) == NULL )
dc8c34
+        if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL)
dc8c34
         {
dc8c34
             /* error or referral sent by find_entry */
dc8c34
             return ldbm_back_search_cleanup(pb, li, sort_control, 
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
index 7a90742..11e97bc 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
@@ -433,7 +433,7 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
dc8c34
 
dc8c34
     /* Note: if we find the bentry, it will stay locked until someone calls
dc8c34
      * modify_term on the mc we'll be associating the bentry with */
dc8c34
-    bentry = find_entry2modify_only( pb, be, &bentry_addr, &txn );
dc8c34
+    bentry = find_entry2modify_only(pb, be, &bentry_addr, &txn, NULL);
dc8c34
 
dc8c34
     if (NULL == bentry) {
dc8c34
 	/* Uh oh, we couldn't find and lock the RUV entry! */
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
index 688f293..eeeb7eb 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
@@ -190,7 +190,7 @@ int ldbm_back_ctrl_info(Slapi_Backend *be, int cmd, void *info);
dc8c34
 struct backentry *dn2entry(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int    *err);
dc8c34
 struct backentry *dn2entry_ext(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int flags, int *err);
dc8c34
 struct backentry *dn2entry_or_ancestor(Slapi_Backend *be, const Slapi_DN *sdn, Slapi_DN *ancestor, back_txn *txn, int *err);
dc8c34
-struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err);
dc8c34
+struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err, int allow_suffix);
dc8c34
 int get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
dc8c34
 int get_copy_of_entry_ext(Slapi_PBlock *pb, ID id, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
dc8c34
 void done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter);
dc8c34
@@ -210,11 +210,13 @@ IDList * filter_candidates_ext( Slapi_PBlock *pb, backend *be, const char *base,
dc8c34
 /*
dc8c34
  * findentry.c
dc8c34
  */
dc8c34
-struct backentry * find_entry2modify( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
dc8c34
-struct backentry * find_entry( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
dc8c34
-struct backentry * find_entry2modify_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
dc8c34
-struct backentry * find_entry2modify_only_ext( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn);
dc8c34
-struct backentry * find_entry_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
dc8c34
+/* Return code */
dc8c34
+#define FE_RC_SENT_RESULT 1
dc8c34
+struct backentry *find_entry2modify(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
dc8c34
+struct backentry *find_entry(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
dc8c34
+struct backentry *find_entry2modify_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
dc8c34
+struct backentry *find_entry2modify_only_ext(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn, int *rc);
dc8c34
+struct backentry *find_entry_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
dc8c34
 int check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, const char *callingfn);
dc8c34
 
dc8c34
 /*
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.c b/ldap/servers/slapd/back-ldbm/vlv_srch.c
dc8c34
index d7e28c1..8edf295 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/vlv_srch.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.c
dc8c34
@@ -191,7 +191,7 @@ vlvSearch_init(struct vlvSearch* p, Slapi_PBlock *pb, const Slapi_Entry *e, ldbm
dc8c34
 
dc8c34
             addr.sdn = p->vlv_base;
dc8c34
             addr.uniqueid = NULL;
dc8c34
-            e = find_entry( pb, inst->inst_be, &addr, &txn );
dc8c34
+            e = find_entry(pb, inst->inst_be, &addr, &txn, NULL);
dc8c34
             /* Check to see if the entry is absent. If it is, mark this search
dc8c34
              * as not initialized */
dc8c34
             if (NULL == e) {
dc8c34
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
dc8c34
index bc8040f..eb6ee83 100644
dc8c34
--- a/ldap/servers/slapd/bind.c
dc8c34
+++ b/ldap/servers/slapd/bind.c
dc8c34
@@ -470,8 +470,8 @@ do_bind( Slapi_PBlock *pb )
dc8c34
              * to an LDAP DN, fail and return an invalidCredentials error.
dc8c34
              */
dc8c34
             if ( NULL == pb->pb_conn->c_external_dn ) {
dc8c34
-                send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
dc8c34
-                                  "client certificate mapping failed", 0, NULL );
dc8c34
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Client certificate mapping failed");
dc8c34
+                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
dc8c34
                 /* call postop plugins */
dc8c34
                 plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
dc8c34
                 goto free_and_return;
dc8c34
@@ -588,33 +588,32 @@ do_bind( Slapi_PBlock *pb )
dc8c34
         /* Check if simple binds are allowed over an insecure channel.  We only check
dc8c34
          * this for authenticated binds. */
dc8c34
         } else if (config_get_require_secure_binds() == 1) {
dc8c34
-                Connection *conn = NULL;
dc8c34
-                int sasl_ssf = 0;
dc8c34
-                int local_ssf = 0;
dc8c34
-
dc8c34
-                /* Allow simple binds only for SSL/TLS established connections
dc8c34
-                 * or connections using SASL privacy layers */
dc8c34
-                conn = pb->pb_conn;
dc8c34
-                if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
dc8c34
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
dc8c34
-                                     "Could not get SASL SSF from connection\n" );
dc8c34
-                    sasl_ssf = 0;
dc8c34
-                }
dc8c34
+            Connection *conn = NULL;
dc8c34
+            int sasl_ssf = 0;
dc8c34
+            int local_ssf = 0;
dc8c34
+
dc8c34
+            /* Allow simple binds only for SSL/TLS established connections
dc8c34
+             * or connections using SASL privacy layers */
dc8c34
+            conn = pb->pb_conn;
dc8c34
+            if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
dc8c34
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
dc8c34
+                                 "Could not get SASL SSF from connection\n" );
dc8c34
+                sasl_ssf = 0;
dc8c34
+            }
dc8c34
 
dc8c34
-                if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
dc8c34
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
dc8c34
-                                     "Could not get local SSF from connection\n" );
dc8c34
-                    local_ssf = 0;
dc8c34
-                }
dc8c34
+            if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
dc8c34
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
dc8c34
+                                 "Could not get local SSF from connection\n" );
dc8c34
+                local_ssf = 0;
dc8c34
+            }
dc8c34
 
dc8c34
-                if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
dc8c34
-                    (sasl_ssf <= 1) && (local_ssf <= 1)) {
dc8c34
-                        send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
dc8c34
-                                         "Operation requires a secure connection",
dc8c34
-                                         0, NULL);
dc8c34
-                        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
dc8c34
-                        goto free_and_return;
dc8c34
-                }
dc8c34
+            if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
dc8c34
+                (sasl_ssf <= 1) && (local_ssf <= 1)) {
dc8c34
+                send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
dc8c34
+                                 "Operation requires a secure connection", 0, NULL);
dc8c34
+                slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
dc8c34
+                goto free_and_return;
dc8c34
+            }
dc8c34
         }
dc8c34
         break;
dc8c34
     default:
dc8c34
@@ -659,6 +658,7 @@ do_bind( Slapi_PBlock *pb )
dc8c34
                 /*
dc8c34
                  *  right dn, wrong passwd - reject with invalid credentials
dc8c34
                  */
dc8c34
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
dc8c34
                 send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
dc8c34
                 /* increment BindSecurityErrorcount */
dc8c34
                 slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
dc8c34
@@ -681,6 +681,7 @@ do_bind( Slapi_PBlock *pb )
dc8c34
             /* call postop plugins */
dc8c34
             plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
dc8c34
         } else {
dc8c34
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Pre-bind plug-in failed");
dc8c34
             send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
dc8c34
         }
dc8c34
         goto free_and_return;
dc8c34
@@ -713,31 +714,11 @@ do_bind( Slapi_PBlock *pb )
dc8c34
         if ( plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN )
dc8c34
              == 0 )  {
dc8c34
             rc = 0;
dc8c34
-
dc8c34
-            /*
dc8c34
-             * Is this account locked ?
dc8c34
-             *	could be locked through the account inactivation
dc8c34
-             *	or by the password policy
dc8c34
-             *
dc8c34
-             * rc=0: account not locked
dc8c34
-             * rc=1: account locked, can not bind, result has been sent
dc8c34
-             * rc!=0 and rc!=1: error. Result was not sent, lets be_bind
dc8c34
-             * 		deal with it.
dc8c34
-             *
dc8c34
-             */
dc8c34
-
dc8c34
-            /* get the entry now, so that we can give it to slapi_check_account_lock and reslimit_update_from_dn */
dc8c34
-            if (! slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
dc8c34
-                bind_target_entry = get_entry(pb,  slapi_sdn_get_ndn(sdn));
dc8c34
-                rc = slapi_check_account_lock ( pb, bind_target_entry, pw_response_requested, 1, 1);
dc8c34
-            }
dc8c34
-
dc8c34
             slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );
dc8c34
             set_db_default_result_handlers(pb);
dc8c34
-            if ( (rc != 1) && 
dc8c34
-                 (auto_bind || 
dc8c34
-                  (((rc = (*be->be_bind)( pb )) == SLAPI_BIND_SUCCESS) ||
dc8c34
-                   (rc == SLAPI_BIND_ANONYMOUS))) ) {
dc8c34
+            if (auto_bind || 
dc8c34
+                (((rc = (*be->be_bind)( pb )) == SLAPI_BIND_SUCCESS) ||
dc8c34
+                 (rc == SLAPI_BIND_ANONYMOUS))) {
dc8c34
                 long t;
dc8c34
                 char* authtype = NULL;
dc8c34
                 /* rc is SLAPI_BIND_SUCCESS or SLAPI_BIND_ANONYMOUS */
dc8c34
@@ -770,6 +751,28 @@ do_bind( Slapi_PBlock *pb )
dc8c34
 
dc8c34
                 if ( rc == SLAPI_BIND_SUCCESS ) {
dc8c34
                     int myrc = 0;
dc8c34
+                    /*
dc8c34
+                     * Is this account locked ?
dc8c34
+                     *	could be locked through the account inactivation
dc8c34
+                     *	or by the password policy
dc8c34
+                     *
dc8c34
+                     * rc=0: account not locked
dc8c34
+                     * rc=1: account locked, can not bind, result has been sent
dc8c34
+                     * rc!=0 and rc!=1: error. Result was not sent, lets be_bind
dc8c34
+                     * 		deal with it.
dc8c34
+                     *
dc8c34
+                     */
dc8c34
+
dc8c34
+                    /* get the entry now, so that we can give it to slapi_check_account_lock and reslimit_update_from_dn */
dc8c34
+                    if (! slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
dc8c34
+                        bind_target_entry = get_entry(pb,  slapi_sdn_get_ndn(sdn));
dc8c34
+                        myrc = slapi_check_account_lock ( pb, bind_target_entry, pw_response_requested, 1, 1);
dc8c34
+                        if (1 == myrc) { /* account is locked */
dc8c34
+                            rc = myrc;
dc8c34
+                            goto account_locked;
dc8c34
+                        }
dc8c34
+                        myrc = 0;                        
dc8c34
+                    }
dc8c34
                     if (!auto_bind) {
dc8c34
                         /* 
dc8c34
                          * There could be a race that bind_target_entry was not added 
dc8c34
@@ -780,14 +783,9 @@ do_bind( Slapi_PBlock *pb )
dc8c34
                         if (!slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA) && 
dc8c34
                             !bind_target_entry) {
dc8c34
                             bind_target_entry = get_entry(pb, slapi_sdn_get_ndn(sdn));
dc8c34
-                            if (bind_target_entry) {
dc8c34
-                                myrc = slapi_check_account_lock(pb, bind_target_entry,
dc8c34
-                                                              pw_response_requested, 1, 1);
dc8c34
-                                if (1 == myrc) { /* account is locked */
dc8c34
-                                    goto account_locked;
dc8c34
-                                }
dc8c34
-                            } else {
dc8c34
-                                send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, "", 0, NULL);
dc8c34
+                            if (!bind_target_entry) {
dc8c34
+                                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
dc8c34
+                                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
dc8c34
                                 goto free_and_return;
dc8c34
                             }
dc8c34
                         }
dc8c34
@@ -847,8 +845,7 @@ account_locked:
dc8c34
              * the front end.
dc8c34
              */
dc8c34
             if ( rc == SLAPI_BIND_SUCCESS || rc == SLAPI_BIND_ANONYMOUS) {
dc8c34
-                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL,
dc8c34
-                                  0, NULL );
dc8c34
+                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
dc8c34
             }
dc8c34
 
dc8c34
             slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
dc8c34
@@ -871,8 +868,7 @@ free_and_return:;
dc8c34
     slapi_sdn_free(&sdn;;
dc8c34
     slapi_ch_free_string( &saslmech );
dc8c34
     slapi_ch_free( (void **)&cred.bv_val );
dc8c34
-    if ( bind_target_entry != NULL )
dc8c34
-        slapi_entry_free(bind_target_entry);
dc8c34
+    slapi_entry_free(bind_target_entry);
dc8c34
 }
dc8c34
 
dc8c34
 
dc8c34
diff --git a/ldap/servers/slapd/defbackend.c b/ldap/servers/slapd/defbackend.c
dc8c34
index dd948d0..13d5919 100644
dc8c34
--- a/ldap/servers/slapd/defbackend.c
dc8c34
+++ b/ldap/servers/slapd/defbackend.c
dc8c34
@@ -200,6 +200,51 @@ defbackend_abandon( Slapi_PBlock *pb )
dc8c34
 }
dc8c34
 
dc8c34
 
dc8c34
+#define DEFBE_NO_SUCH_SUFFIX "No such suffix"
dc8c34
+/*
dc8c34
+ * Generate a "No such suffix" return text
dc8c34
+ * Example:
dc8c34
+ *   cn=X,dc=bogus,dc=com ==> "No such suffix (dc=bogus,dc=com)" 
dc8c34
+ *     if the last rdn starts with "dc=", print all last dc= rdn's.
dc8c34
+ *   cn=X,cn=bogus ==> "No such suffix (cn=bogus)"
dc8c34
+ *     otherwise, print the very last rdn.
dc8c34
+ *   cn=X,z=bogus ==> "No such suffix (x=bogus)"
dc8c34
+ *     it is true even if it is an invalid rdn.
dc8c34
+ *   cn=X,bogus ==> "No such suffix (bogus)"
dc8c34
+ *     another example of invalid rdn.
dc8c34
+ */
dc8c34
+static void
dc8c34
+_defbackend_gen_returntext(char *buffer, size_t buflen, char **dns)
dc8c34
+{
dc8c34
+    int dnidx;
dc8c34
+    int sidx;
dc8c34
+    struct suffix_repeat {
dc8c34
+        char *suffix;
dc8c34
+        int size;
dc8c34
+    } candidates[] = {
dc8c34
+        {"dc=", 3}, /* dc could be repeated.  otherwise the last rdn is used. */
dc8c34
+        {NULL, 0}
dc8c34
+    };
dc8c34
+    PR_snprintf(buffer, buflen, "%s (", DEFBE_NO_SUCH_SUFFIX);
dc8c34
+    for (dnidx = 0; dns[dnidx]; dnidx++) ; /* finding the last */
dc8c34
+    dnidx--; /* last rdn */
dc8c34
+    for (sidx = 0; candidates[sidx].suffix; sidx++) {
dc8c34
+        if (!PL_strncasecmp(dns[dnidx], candidates[sidx].suffix, candidates[sidx].size)) {
dc8c34
+            while (!PL_strncasecmp(dns[--dnidx], candidates[sidx].suffix, candidates[sidx].size)) ;
dc8c34
+            PL_strcat(buffer, dns[++dnidx]); /* the first "dn=", e.g. */
dc8c34
+            for (++dnidx; dns[dnidx]; dnidx++) {
dc8c34
+                PL_strcat(buffer, ",");
dc8c34
+                PL_strcat(buffer, dns[dnidx]);
dc8c34
+            }
dc8c34
+            PL_strcat(buffer, ")");
dc8c34
+            return; /* finished the task */
dc8c34
+        }
dc8c34
+    }
dc8c34
+    PL_strcat(buffer, dns[dnidx]);
dc8c34
+    PL_strcat(buffer, ")");
dc8c34
+    return;
dc8c34
+}
dc8c34
+
dc8c34
 static int
dc8c34
 defbackend_bind( Slapi_PBlock *pb )
dc8c34
 {
dc8c34
@@ -216,11 +261,40 @@ defbackend_bind( Slapi_PBlock *pb )
dc8c34
     slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method );
dc8c34
     slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred );
dc8c34
     if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
dc8c34
-	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
dc8c34
-	rc = SLAPI_BIND_ANONYMOUS;
dc8c34
+        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
dc8c34
+        rc = SLAPI_BIND_ANONYMOUS;
dc8c34
     } else {
dc8c34
-	send_nobackend_ldap_result( pb );
dc8c34
-	rc = SLAPI_BIND_FAIL;
dc8c34
+        Slapi_DN *sdn = NULL;
dc8c34
+        char *suffix = NULL;
dc8c34
+        char **dns = NULL;
dc8c34
+        
dc8c34
+        if (pb->pb_op) {
dc8c34
+            sdn = operation_get_target_spec(pb->pb_op);
dc8c34
+            if (sdn) {
dc8c34
+                dns = slapi_ldap_explode_dn(slapi_sdn_get_dn(sdn), 0);
dc8c34
+                if (dns) {
dc8c34
+                    size_t dnlen = slapi_sdn_get_ndn_len(sdn);
dc8c34
+                    size_t len = dnlen + sizeof(DEFBE_NO_SUCH_SUFFIX) + 4;
dc8c34
+                    suffix = slapi_ch_malloc(len);
dc8c34
+                    if (dnlen) {
dc8c34
+                        _defbackend_gen_returntext(suffix, len, dns);
dc8c34
+                    } else {
dc8c34
+                        PR_snprintf(suffix, len, "%s", DEFBE_NO_SUCH_SUFFIX);
dc8c34
+                    }
dc8c34
+                }
dc8c34
+            }
dc8c34
+        }
dc8c34
+        if (suffix) {
dc8c34
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, suffix);
dc8c34
+        } else {
dc8c34
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, DEFBE_NO_SUCH_SUFFIX);
dc8c34
+        }
dc8c34
+        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
dc8c34
+        if (dns) {
dc8c34
+            slapi_ldap_value_free(dns);
dc8c34
+        }
dc8c34
+        slapi_ch_free_string(&suffix);
dc8c34
+        rc = SLAPI_BIND_FAIL;
dc8c34
     }
dc8c34
 
dc8c34
     return( rc );
dc8c34
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
dc8c34
index 6ed6c55..c385368 100644
dc8c34
--- a/ldap/servers/slapd/result.c
dc8c34
+++ b/ldap/servers/slapd/result.c
dc8c34
@@ -1815,14 +1815,26 @@ log_result( Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag,
dc8c34
 		} else {
dc8c34
 			if ( !internal_op )
dc8c34
 			{
dc8c34
+				char *pbtxt = NULL;
dc8c34
+				char *ext_str = NULL;
dc8c34
+				slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &pbtxt);
dc8c34
+				if (pbtxt) {
dc8c34
+					ext_str = slapi_ch_smprintf(" - %s", pbtxt);
dc8c34
+				} else {
dc8c34
+					ext_str = "";
dc8c34
+				}
dc8c34
 				slapi_log_access( LDAP_DEBUG_STATS,
dc8c34
 								  "conn=%" NSPRIu64 " op=%d RESULT err=%d"
dc8c34
-								  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n",
dc8c34
+								  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s%s\n",
dc8c34
 								  op->o_connid, 
dc8c34
 								  op->o_opid,
dc8c34
 								  err, tag, nentries, 
dc8c34
 								  etime, 
dc8c34
-								  notes_str, csn_str );
dc8c34
+								  notes_str, csn_str, ext_str );
dc8c34
+				if (pbtxt) {
dc8c34
+					/* if !pbtxt ==> ext_str == "".  Don't free ext_str. */
dc8c34
+					slapi_ch_free_string(&ext_str);
dc8c34
+				}
dc8c34
 			}
dc8c34
 			else
dc8c34
 			{
dc8c34
diff --git a/ldap/servers/slapd/saslbind.c b/ldap/servers/slapd/saslbind.c
dc8c34
index c1e5f2b..5ef098e 100644
dc8c34
--- a/ldap/servers/slapd/saslbind.c
dc8c34
+++ b/ldap/servers/slapd/saslbind.c
dc8c34
@@ -1049,8 +1049,8 @@ void ids_sasl_check_bind(Slapi_PBlock *pb)
dc8c34
         errstr = sasl_errdetail(sasl_conn);
dc8c34
 
dc8c34
         PR_ExitMonitor(pb->pb_conn->c_mutex); /* BIG LOCK */
dc8c34
-        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL,
dc8c34
-                         (char*)errstr, 0, NULL);
dc8c34
+        slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, (void *)errstr);
dc8c34
+        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
dc8c34
         break;
dc8c34
     }
dc8c34
 
dc8c34
-- 
dc8c34
2.4.11
dc8c34