CVE-2016-4992 (published 2017-06-08T19:29Z)

389 Directory Server in Red Hat Enterprise Linux Desktop 6 through 7, Red Hat Enterprise Linux HPC Node 6 through 7, Red Hat Enterprise Linux Server 6 through 7, and Red Hat Enterprise Linux Workstation 6 through 7 allows remote attackers to infer the existence of RDN component objects.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:P/I:N/A:N)
CVSS v3 base score: 7.5, HIGH (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-200
cwe_name: Exposure of Sensitive Information to an Unauthorized Actor
description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
extended_description: 
	   There are many different kinds of mistakes that introduce information exposures. The severity of the error can range widely, depending on the context in which the product operates, the type of sensitive information that is revealed, and the benefits it may provide to an attacker.  Some kinds of sensitive information include:
       
         private, personal information, such as personal messages, financial data, health records, geographic location, or contact details
         system status and environment, such as the operating system and installed packages
		 business secrets and intellectual property
		 network status and configuration
		 the product's own code or internal state
         metadata, e.g. logging of connections or message headers
		 indirect information, such as a discrepancy between two internal operations that can be observed by an outsider
       
	    Information might be sensitive to different parties, each of which may have their own expectations for whether the information should be protected.  These parties include:
               
                  the product's own users
                  people or organizations whose information is created or used by the product, even if they are not direct product users
		  the product's administrators, including the admins of the system(s) and/or networks on which the product operates
                  the developer
               
	    Information exposures can occur in different ways:
               
                  the code explicitly inserts sensitive information into resources or messages that are intentionally made accessible to unauthorized actors, but should not contain the information - i.e., the information should have been "scrubbed" or "sanitized"
                  a different weakness or mistake indirectly inserts the sensitive information into resources, such as a web script error revealing the full system path of the program.
                  the code manages resources that intentionally contain sensitive information, but the resources are unintentionally made accessible to unauthorized actors. In this case, the information exposure is resultant - i.e., a different weakness enabled the access to the information in the first place.
               
	    It is common practice to describe any loss of confidentiality as an "information exposure," but this can lead to overuse of CWE-200 in CWE mapping. From the CWE perspective, loss of confidentiality is a technical impact that can arise from dozens of different weaknesses, such as insecure file permissions or out-of-bounds read.  CWE-200 and its lower-level descendants are intended to cover the mistakes that occur in behaviors that explicitly manage, store, transfer, or cleanse sensitive information.
         
         

Fix information:
repo_url: https://github.com/389ds/389-ds-base
commit_details: repo_url: https://github.com/389ds/389-ds-base
author: Noriko Hosoi
author_date: 2016-07-13 14:49:18-07:00
msg: Bug 1347760 - CVE-2016-4992 389-ds-base: Information disclosure via repeated use of LDAP ADD operation, etc.

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

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

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

Reviewed by lkrispen@redhat.com, mreynolds@redhat.com, and tbordaz@redhat.com.
Thank you!!!
repository: repo_url: https://github.com/389ds/389-ds-base
repo_name: 389ds/389-ds-base
description: The enterprise-class Open Source LDAP server for Linux
repo_language: C
owner: 389ds
file_changes: filename: dn2entry.c
change_type: ModificationType.MODIFY
diff: @@ -151,14 +151,15 @@ struct backentry *
 dn2ancestor(
     Slapi_Backend *be,
     const Slapi_DN	*sdn,
-	Slapi_DN *ancestordn,
+    Slapi_DN *ancestordn,
     back_txn		*txn,
-    int			*err
+    int			*err,
+    int allow_suffix
 )
 {
-	struct backentry *e = NULL;
+    struct backentry *e = NULL;
 
-	LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
+    LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
 
     /* first, check to see if the given sdn is empty or a root suffix of the
        given backend - if so, it has no parent */
@@ -190,7 +191,13 @@ dn2ancestor(
         */
 
         /* stop when we get to "", or a backend suffix point */
-        while (!e && !slapi_sdn_isempty(&ancestorndn) && !slapi_be_issuffix( be, &ancestorndn )) {
+        while (!e && !slapi_sdn_isempty(&ancestorndn)) {
+            if (!allow_suffix) {
+                /* Original behavior. */
+                if (slapi_be_issuffix(be, &ancestorndn)) {
+                    break;
+                }
+            }
             /* find the entry - it uses the ndn, so no further conversion is necessary */
             e= dn2entry(be,&ancestorndn,txn,err);
             if (!e) {

programming_language: C
filename: findentry.c
change_type: ModificationType.MODIFY
diff: @@ -16,8 +16,8 @@
 #include "back-ldbm.h"
 
 
-static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags);
-static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags);
+static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags, int *rc);
+static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags, int *rc);
 /* The flags take these values */
 #define FE_TOMBSTONE_INCLUDED TOMBSTONE_INCLUDED /* :1 defined in back-ldbm.h */
 #define FE_REALLY_INTERNAL 0x2
@@ -27,7 +27,7 @@ check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, co
 {
 	int rc=0, i=0, numValues=0;
 	Slapi_Attr *attr;
-	Slapi_Value *val=NULL;	
+	Slapi_Value *val=NULL;
 	struct berval **refscopy=NULL;
 	struct berval **url=NULL;
 
@@ -80,12 +80,13 @@ out:
 
 static struct backentry *
 find_entry_internal_dn(
-	Slapi_PBlock	*pb,
+    Slapi_PBlock	*pb,
     backend			*be,
     const Slapi_DN *sdn,
     int				lock,
-	back_txn		*txn,
-	int				flags
+    back_txn		*txn,
+    int				flags,
+    int				*rc /* return code */
 )
 { 
 	struct backentry *e;
@@ -93,9 +94,14 @@ find_entry_internal_dn(
 	int	err;
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
 	size_t tries = 0;
+	int isroot = 0;
+	int op_type;
+	char *errbuf = NULL;
 
 	/* get the managedsait ldap message control */
-	slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
+	slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+	slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
 
 	while ( (tries < LDBM_CACHE_RETRY_COUNT) && 
 	        (e = dn2entry_ext( be, sdn, txn, flags & TOMBSTONE_INCLUDED, &err ))
@@ -113,6 +119,9 @@ find_entry_internal_dn(
 			if(check_entry_for_referral(pb, e->ep_entry, NULL, "find_entry_internal_dn"))
 			{
 				CACHE_RETURN( &inst->inst_cache, &e );
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
+					*rc = FE_RC_SENT_RESULT;
+				}
 				return( NULL );
 			}
 		}
@@ -151,27 +160,89 @@ find_entry_internal_dn(
 		struct backentry *me;
 		Slapi_DN ancestorsdn;
 		slapi_sdn_init(&ancestorsdn);
-		me= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,txn,&err);
+		me = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, txn, &err, 1 /* allow_suffix */);
 		if ( !managedsait && me != NULL ) {
 			/* if the entry is a referral send the referral */
 			if(check_entry_for_referral(pb, me->ep_entry, (char*)slapi_sdn_get_dn(&ancestorsdn), "find_entry_internal_dn"))
 			{
 				CACHE_RETURN( &inst->inst_cache, &me );
 				slapi_sdn_done(&ancestorsdn);
+				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
+					*rc = FE_RC_SENT_RESULT;
+				}
 				return( NULL );
 			}
 			/* else fall through to no such object */
 		}
 
 		/* entry not found */
-		slapi_send_ldap_result( pb, ( 0 == err || DB_NOTFOUND == err ) ?
-			LDAP_NO_SUCH_OBJECT : ( LDAP_INVALID_DN_SYNTAX == err ) ?
-			LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
-			(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
+		if ((0 == err) || (DB_NOTFOUND == err)) {
+			if (me && !isroot) {
+				/* If not root, you may not want to reveal it. */
+				int acl_type = -1;
+				int return_err = LDAP_NO_SUCH_OBJECT;
+				err = LDAP_SUCCESS;
+				switch (op_type) {
+				case SLAPI_OPERATION_ADD:
+					acl_type = SLAPI_ACL_ADD;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_DELETE:
+					acl_type = SLAPI_ACL_DELETE;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_MODDN:
+					acl_type = SLAPI_ACL_MODDN;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_MODIFY:
+					acl_type = SLAPI_ACL_WRITE;
+					return_err = LDAP_INSUFFICIENT_ACCESS;
+					break;
+				case SLAPI_OPERATION_SEARCH:
+				case SLAPI_OPERATION_COMPARE:
+					return_err = LDAP_SUCCESS;
+					acl_type = SLAPI_ACL_READ;
+					break;
+				case SLAPI_OPERATION_BIND:
+					acl_type = -1; /* skip acl check. acl is not set up for bind. */
+					return_err = LDAP_INVALID_CREDENTIALS;
+					slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
+					break;
+				}
+				if (acl_type > 0) {
+					err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
+					                             ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
+				}
+				if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
+					/*
+					 * Operations to be checked && ACL returns disallow.
+					 * Not to disclose the info about the entry's existence,
+					 * do not return the "matched" DN.
+					 * Plus, the bind case returns LDAP_INAPPROPRIATE_AUTH.
+					 */
+					slapi_send_ldap_result(pb, return_err, NULL, NULL, 0, NULL);
+				} else {
+					slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT,
+						(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
+				}
+			} else {
+				slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT,
+					(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
+			}
+		} else {
+			slapi_send_ldap_result( pb, ( LDAP_INVALID_DN_SYNTAX == err ) ?
+				LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
+				(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
+		}
+		if (rc) {
+			*rc = FE_RC_SENT_RESULT;
+		}
 		slapi_sdn_done(&ancestorsdn);
 		CACHE_RETURN( &inst->inst_cache, &me );
 	}
 
+	slapi_ch_free_string(&errbuf);
 	LDAPDebug( LDAP_DEBUG_TRACE, "<= find_entry_internal_dn not found (%s)\n",
 	    slapi_sdn_get_dn(sdn), 0, 0 );
 	return( NULL );
@@ -183,11 +254,11 @@ find_entry_internal_dn(
  */
 static struct backentry *
 find_entry_internal_uniqueid(
-	Slapi_PBlock	*pb,
+    Slapi_PBlock	*pb,
     backend *be,
-	const char 			*uniqueid,
+    const char 			*uniqueid,
     int				lock,
-	back_txn		*txn
+    back_txn		*txn
 )
 {
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
@@ -243,8 +314,9 @@ find_entry_internal(
     Slapi_Backend *be,
     const entry_address *addr,
     int			lock,
-	back_txn *txn,
-	int flags
+    back_txn *txn,
+    int flags,
+    int *rc
 )
 {
 	/* check if we should search based on uniqueid or dn */
@@ -261,11 +333,9 @@ find_entry_internal(
 		LDAPDebug( LDAP_DEBUG_TRACE, "=> find_entry_internal (dn=%s) lock %d\n",
 		           slapi_sdn_get_dn(addr->sdn), lock, 0 );
 		if (addr->sdn) {
-			entry = find_entry_internal_dn (pb, be, addr->sdn, 
-			                                lock, txn, flags);
+			entry = find_entry_internal_dn (pb, be, addr->sdn, lock, txn, flags, rc);
 		} else {
-			LDAPDebug0Args( LDAP_DEBUG_ANY,
-			                "find_entry_internal: Null target dn\n" );
+			LDAPDebug0Args( LDAP_DEBUG_ANY, "find_entry_internal: Null target dn\n" );
 		}
 
 		LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= find_entry_internal\n" );
@@ -278,10 +348,11 @@ find_entry(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-	back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, 0/*flags*/ ) );
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, 0/*flags*/, rc));
 }
 
 struct backentry *
@@ -289,10 +360,11 @@ find_entry2modify(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-	back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 0/*flags*/ ) );
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0/*flags*/, rc));
 }
 
 /* New routines which do not do any referral stuff.
@@ -304,10 +376,11 @@ find_entry_only(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-	back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL ) );
+	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL, rc));
 }
 
 struct backentry *
@@ -315,10 +388,11 @@ find_entry2modify_only(
     Slapi_PBlock		*pb,
     Slapi_Backend *be,
     const entry_address *addr,
-    back_txn *txn
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL ) );
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0 /* to check aci, disable INTERNAL */, rc));
 }
 
 struct backentry *
@@ -327,10 +401,9 @@ find_entry2modify_only_ext(
     Slapi_Backend *be,
     const entry_address *addr,
     int flags,
-    back_txn *txn
-
+    back_txn *txn,
+    int *rc
 )
 {
-	return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 
-		                         FE_REALLY_INTERNAL | flags ));
+	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL | flags, rc));
 }

programming_language: C
filename: ldbm_add.c
change_type: ModificationType.MODIFY
diff: @@ -93,6 +93,7 @@ ldbm_back_add( Slapi_PBlock *pb )
 	int myrc = 0;
 	PRUint64 conn_id;
 	int op_id;
+	int result_sent = 0;
 	if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
 		conn_id = 0; /* connection is NULL */
 	}
@@ -379,7 +380,7 @@ ldbm_back_add( Slapi_PBlock *pb )
 				addr.sdn = &parentsdn;
 				addr.udn = NULL;
 				addr.uniqueid = operation->o_params.p.p_add.parentuniqueid;
-				parententry = find_entry2modify_only(pb,be,&addr,&txn);
+				parententry = find_entry2modify_only(pb, be, &addr, &txn, &result_sent);
 				if (parententry && parententry->ep_entry) {
 					if (!operation->o_params.p.p_add.parentuniqueid){
 						/* Set the parentuniqueid now */
@@ -431,6 +432,14 @@ ldbm_back_add( Slapi_PBlock *pb )
 						/* The entry already exists */ 
 						ldap_result_code = LDAP_ALREADY_EXISTS;
 					}
+					if ((LDAP_ALREADY_EXISTS == ldap_result_code) && !isroot && !is_replicated_operation) {
+						myrc = plugin_call_acl_plugin(pb, e, NULL, NULL, SLAPI_ACL_ADD,
+						                              ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
+						if (myrc) {
+							ldap_result_code = myrc;
+							ldap_result_message = errbuf;
+						}
+					}
 					goto error_return;
 				} 
 				else 
@@ -447,7 +456,7 @@ ldbm_back_add( Slapi_PBlock *pb )
 						Slapi_DN ancestorsdn;
 						struct backentry *ancestorentry;
 						slapi_sdn_init(&ancestorsdn);
-						ancestorentry= dn2ancestor(pb->pb_backend,sdn,&ancestorsdn,&txn,&err);
+						ancestorentry = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, &txn, &err, 0);
 						slapi_sdn_done(&ancestorsdn);
 						if ( ancestorentry != NULL )
 						{
@@ -495,7 +504,7 @@ ldbm_back_add( Slapi_PBlock *pb )
 				addr.udn = NULL;
 				addr.sdn = NULL;
 				addr.uniqueid = (char *)slapi_entry_get_uniqueid(e); /* jcm - cast away const */
-				tombstoneentry = find_entry2modify( pb, be, &addr, &txn );
+				tombstoneentry = find_entry2modify(pb, be, &addr, &txn, &result_sent);
 				if ( tombstoneentry==NULL )
 				{
 					ldap_result_code= -1;
@@ -712,7 +721,7 @@ ldbm_back_add( Slapi_PBlock *pb )
 					LDAPDebug1Arg(LDAP_DEBUG_BACKLDBM, "ldbm_add: Parent \"%s\" does not exist. "
 					              "It might be a conflict entry.\n", slapi_sdn_get_dn(&parentsdn));
 					slapi_sdn_init(&ancestorsdn);
-					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err );
+					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err, 1);
 					CACHE_RETURN( &inst->inst_cache, &ancestorentry );
 
 					ldap_result_code= LDAP_NO_SUCH_OBJECT;
@@ -1349,7 +1358,9 @@ common_return:
 			 * And we don't want the supplier to halt sending the updates. */
 			ldap_result_code = LDAP_SUCCESS;
 		}
-		slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
+		if (!result_sent) {
+			slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL);
+		}
 	}
 	backentry_free(&originalentry);
 	backentry_free(&tmpentry);

programming_language: C
filename: ldbm_bind.c
change_type: ModificationType.MODIFY
diff: @@ -29,6 +29,7 @@ ldbm_back_bind( Slapi_PBlock *pb )
 	entry_address *addr;
 	back_txn txn = {NULL};
 	int rc = SLAPI_BIND_SUCCESS;
+	int result_sent = 0;
 
 	/* get parameters */
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be );
@@ -63,8 +64,12 @@ ldbm_back_bind( Slapi_PBlock *pb )
 	 * find the target entry.  find_entry() takes care of referrals
 	 *   and sending errors if the entry does not exist.
 	 */
-	if (( e = find_entry( pb, be, addr, &txn )) == NULL ) {
+	if ((e = find_entry( pb, be, addr, &txn, &result_sent)) == NULL) {
 		rc = SLAPI_BIND_FAIL;
+		/* In the failure case, the result is supposed to be sent in the backend. */
+		if (!result_sent) {
+			slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
+		}
 		goto bail;
 	}
 
@@ -82,8 +87,8 @@ ldbm_back_bind( Slapi_PBlock *pb )
 		bvals= attr_get_present_values(attr);
 		slapi_value_init_berval(&cv,cred);
 		if ( slapi_pw_find_sv( bvals, &cv ) != 0 ) {
-			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
-			    NULL, 0, NULL );
+			slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
+			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
 			CACHE_RETURN( &inst->inst_cache, &e );
 			value_done(&cv);
 			rc = SLAPI_BIND_FAIL;

programming_language: C
filename: ldbm_compare.c
change_type: ModificationType.MODIFY
diff: @@ -56,7 +56,7 @@ ldbm_back_compare( Slapi_PBlock *pb )
 	/* get the namespace dn */
 	namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
 
-	if ( (e = find_entry( pb, be, addr, &txn )) == NULL ) {
+	if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL) {
 		ret = -1;	/* error result sent by find_entry() */
 		goto bail;
 	}

programming_language: C
filename: ldbm_delete.c
change_type: ModificationType.MODIFY
diff: @@ -77,6 +77,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
 	int op_id;
 	ID ep_id = 0;
 	ID tomb_ep_id = 0;
+	int result_sent = 0;
 
 	if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
 		conn_id = 0; /* connection is NULL */
@@ -266,7 +267,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
 			 * deleted.  That is, the entry 'e' found with "addr" is a tomb-
 			 * stone.  If it is the case, we need to back off.
 			 */
-			if ( (e = find_entry2modify( pb, be, addr, &txn )) == NULL )
+			if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL)
 			{
 				ldap_result_code= LDAP_NO_SUCH_OBJECT; 
 				retval = -1;
@@ -507,7 +508,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
 						parent_addr.uniqueid = NULL;
 					}
 					parent_addr.sdn = &parentsdn;
-					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn);
+					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn, &result_sent);
 				}
 				if (parent) {
 					int isglue;
@@ -1466,7 +1467,9 @@ diskfull_return:
 			 * And we don't want the supplier to halt sending the updates. */
 			ldap_result_code = LDAP_SUCCESS;
 		}
-		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		if (!result_sent) {
+			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		}
 	}
 	slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
 	                "conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p, in_cache=%d\n",

programming_language: C
filename: ldbm_modify.c
change_type: ModificationType.MODIFY
diff: @@ -392,6 +392,7 @@ ldbm_back_modify( Slapi_PBlock *pb )
 	int not_an_error = 0;
 	int fixup_tombstone = 0;
 	int ec_locked = 0;
+	int result_sent = 0;
 
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be);
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
@@ -466,12 +467,12 @@ ldbm_back_modify( Slapi_PBlock *pb )
 	if ( MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
 		/* find and lock the entry we are about to modify */
 		if (fixup_tombstone) {
-			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
+			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
 		} else {
-			e = find_entry2modify( pb, be, addr, &txn );
+			e = find_entry2modify( pb, be, addr, &txn, &result_sent );
 		}
 		if (e == NULL) {
-			ldap_result_code= -1;
+			ldap_result_code = -1;
 			goto error_return; /* error result sent by find_entry2modify() */
 		}
 	}
@@ -551,12 +552,12 @@ ldbm_back_modify( Slapi_PBlock *pb )
 			if ( !MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
 				/* find and lock the entry we are about to modify */
 				if (fixup_tombstone) {
-					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn );
+					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
 				} else {
-					e = find_entry2modify( pb, be, addr, &txn );
+					e = find_entry2modify( pb, be, addr, &txn, &result_sent );
 				}
 				if (e == NULL) {
-					ldap_result_code= -1;
+					ldap_result_code = -1;
 					goto error_return; /* error result sent by find_entry2modify() */
 				}
 			}
@@ -966,7 +967,10 @@ common_return:
 			 * And we don't want the supplier to halt sending the updates. */
 			ldap_result_code = LDAP_SUCCESS;
 		}
-		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		if (!result_sent) {
+			/* result is already sent in find_entry. */
+			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+		}
 	}
 
 	/* free our backups */

programming_language: C
filename: ldbm_modrdn.c
change_type: ModificationType.MODIFY
diff: @@ -95,6 +95,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
     int myrc = 0;
     PRUint64 conn_id;
     int op_id;
+    int result_sent = 0;
     if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
         conn_id = 0; /* connection is NULL */
     }
@@ -474,7 +475,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
             /* find and lock the entry we are about to modify */
             /* JCMREPL - Argh, what happens about the stinking referrals? */
             slapi_pblock_get (pb, SLAPI_TARGET_ADDRESS, &old_addr);
-            e = find_entry2modify( pb, be, old_addr, &txn );
+            e = find_entry2modify(pb, be, old_addr, &txn, &result_sent);
             if ( e == NULL )
             {
                 ldap_result_code= -1;
@@ -510,7 +511,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
             } else {
                 oldparent_addr.uniqueid = NULL;            
             }
-            parententry = find_entry2modify_only( pb, be, &oldparent_addr, &txn );
+            parententry = find_entry2modify_only(pb, be, &oldparent_addr, &txn, &result_sent);
             modify_init(&parent_modify_context,parententry);
         
             /* Fetch and lock the new parent of the entry that is moving */            
@@ -520,7 +521,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
                 if (is_resurect_operation) {
                     newsuperior_addr->uniqueid = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
                 }
-                newparententry = find_entry2modify_only( pb, be, newsuperior_addr, &txn );
+                newparententry = find_entry2modify_only(pb, be, newsuperior_addr, &txn, &result_sent);
                 slapi_ch_free_string(&newsuperior_addr->uniqueid);
                 modify_init(&newparent_modify_context,newparententry);
             }
@@ -581,7 +582,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
                         Slapi_DN ancestorsdn;
                         struct backentry *ancestorentry;
                         slapi_sdn_init(&ancestorsdn);
-                        ancestorentry= dn2ancestor(be,&dn_newdn,&ancestorsdn,&txn,&err);
+                        ancestorentry = dn2ancestor(be, &dn_newdn, &ancestorsdn, &txn, &err, 0);
                         CACHE_RETURN( &inst->inst_cache, &ancestorentry );
                         ldap_result_matcheddn= slapi_ch_strdup((char *) slapi_sdn_get_dn(&ancestorsdn));
                         ldap_result_code= LDAP_NO_SUCH_OBJECT;
@@ -1486,8 +1487,10 @@ common_return:
              * And we don't want the supplier to halt sending the updates. */
             ldap_result_code = LDAP_SUCCESS;
         }
-        slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn,
-                    ldap_result_message, 0,NULL );
+        if (!result_sent) {
+            slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn,
+                                   ldap_result_message, 0, NULL);
+        }
     }
     slapi_mods_done(&smods_operation_wsi);
     slapi_mods_done(&smods_generated);

programming_language: C
filename: ldbm_search.c
change_type: ModificationType.MODIFY
diff: @@ -584,7 +584,7 @@ ldbm_back_search( Slapi_PBlock *pb )
     }
     else
     {
-        if ( ( e = find_entry( pb, be, addr, &txn )) == NULL )
+        if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL)
         {
             /* error or referral sent by find_entry */
             return ldbm_back_search_cleanup(pb, li, sort_control, 

programming_language: C
filename: misc.c
change_type: ModificationType.MODIFY
diff: @@ -412,7 +412,7 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
 
     /* Note: if we find the bentry, it will stay locked until someone calls
      * modify_term on the mc we'll be associating the bentry with */
-    bentry = find_entry2modify_only( pb, be, &bentry_addr, &txn );
+    bentry = find_entry2modify_only(pb, be, &bentry_addr, &txn, NULL);
 
     if (NULL == bentry) {
         /* Uh oh, we couldn't find and lock the RUV entry! */

programming_language: C
filename: proto-back-ldbm.h
change_type: ModificationType.MODIFY
diff: @@ -174,7 +174,7 @@ int ldbm_back_ctrl_info(Slapi_Backend *be, int cmd, void *info);
 struct backentry *dn2entry(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int    *err);
 struct backentry *dn2entry_ext(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int flags, int *err);
 struct backentry *dn2entry_or_ancestor(Slapi_Backend *be, const Slapi_DN *sdn, Slapi_DN *ancestor, back_txn *txn, int *err);
-struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err);
+struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err, int allow_suffix);
 int get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
 int get_copy_of_entry_ext(Slapi_PBlock *pb, ID id, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
 void done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter);
@@ -194,11 +194,13 @@ IDList * filter_candidates_ext( Slapi_PBlock *pb, backend *be, const char *base,
 /*
  * findentry.c
  */
-struct backentry * find_entry2modify( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
-struct backentry * find_entry( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
-struct backentry * find_entry2modify_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
-struct backentry * find_entry2modify_only_ext( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn);
-struct backentry * find_entry_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
+/* Return code */
+#define FE_RC_SENT_RESULT 1
+struct backentry *find_entry2modify(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
+struct backentry *find_entry(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
+struct backentry *find_entry2modify_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
+struct backentry *find_entry2modify_only_ext(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn, int *rc);
+struct backentry *find_entry_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
 int check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, const char *callingfn);
 
 /*

programming_language: C
filename: vlv_srch.c
change_type: ModificationType.MODIFY
diff: @@ -162,7 +162,7 @@ vlvSearch_init(struct vlvSearch* p, Slapi_PBlock *pb, const Slapi_Entry *e, ldbm
 
             addr.sdn = p->vlv_base;
             addr.uniqueid = NULL;
-            e = find_entry( pb, inst->inst_be, &addr, &txn );
+            e = find_entry(pb, inst->inst_be, &addr, &txn, NULL);
             /* Check to see if the entry is absent. If it is, mark this search
              * as not initialized */
             if (NULL == e) {

programming_language: C
filename: bind.c
change_type: ModificationType.MODIFY
diff: @@ -438,8 +438,8 @@ do_bind( Slapi_PBlock *pb )
              * to an LDAP DN, fail and return an invalidCredentials error.
              */
             if ( NULL == pb->pb_conn->c_external_dn ) {
-                send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
-                                  "client certificate mapping failed", 0, NULL );
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Client certificate mapping failed");
+                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
                 /* call postop plugins */
                 plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
                 goto free_and_return;
@@ -556,33 +556,32 @@ do_bind( Slapi_PBlock *pb )
         /* Check if simple binds are allowed over an insecure channel.  We only check
          * this for authenticated binds. */
         } else if (config_get_require_secure_binds() == 1) {
-                Connection *conn = NULL;
-                int sasl_ssf = 0;
-                int local_ssf = 0;
-
-                /* Allow simple binds only for SSL/TLS established connections
-                 * or connections using SASL privacy layers */
-                conn = pb->pb_conn;
-                if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
-                                     "Could not get SASL SSF from connection\n" );
-                    sasl_ssf = 0;
-                }
+            Connection *conn = NULL;
+            int sasl_ssf = 0;
+            int local_ssf = 0;
+
+            /* Allow simple binds only for SSL/TLS established connections
+             * or connections using SASL privacy layers */
+            conn = pb->pb_conn;
+            if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
+                                 "Could not get SASL SSF from connection\n" );
+                sasl_ssf = 0;
+            }
 
-                if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
-                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
-                                     "Could not get local SSF from connection\n" );
-                    local_ssf = 0;
-                }
+            if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
+                slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
+                                 "Could not get local SSF from connection\n" );
+                local_ssf = 0;
+            }
 
-                if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
-                    (sasl_ssf <= 1) && (local_ssf <= 1)) {
-                        send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
-                                         "Operation requires a secure connection",
-                                         0, NULL);
-                        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
-                        goto free_and_return;
-                }
+            if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
+                (sasl_ssf <= 1) && (local_ssf <= 1)) {
+                send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
+                                 "Operation requires a secure connection", 0, NULL);
+                slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
+                goto free_and_return;
+            }
         }
         break;
     default:
@@ -627,6 +626,7 @@ do_bind( Slapi_PBlock *pb )
                 /*
                  *  right dn, wrong passwd - reject with invalid credentials
                  */
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
                 send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
                 /* increment BindSecurityErrorcount */
                 slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
@@ -686,7 +686,8 @@ do_bind( Slapi_PBlock *pb )
             slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &pb_sdn);
             if (!pb_sdn) {
                 slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set NULL dn\n");
-                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
+                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
+                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                 goto free_and_return;
             } else if ((pb_sdn != sdn) || (sdn_updated = slapi_sdn_compare(original_sdn, pb_sdn))) {
                 /*
@@ -696,8 +697,10 @@ do_bind( Slapi_PBlock *pb )
                 sdn = pb_sdn;
                 dn = slapi_sdn_get_dn(sdn);
                 if (!dn) {
-                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn\n");
-                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
+                    char *udn = slapi_sdn_get_udn(sdn);
+                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn %s\n", udn?udn:"");
+                    slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
+                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                     goto free_and_return;
                 }
                 if (!sdn_updated) { /* pb_sdn != sdn; need to compare the dn's. */
@@ -711,7 +714,8 @@ do_bind( Slapi_PBlock *pb )
                         slapi_pblock_set( pb, SLAPI_BACKEND, be );
                     } else {
                         slapi_create_errormsg(errorbuf, sizeof(errorbuf), "No matching backend for %s\n", dn);
-                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
+                        slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errorbuf);
+                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "", 0, NULL);
                         goto free_and_return;
                     }
                 }
@@ -790,7 +794,8 @@ do_bind( Slapi_PBlock *pb )
                                     goto account_locked;
                                 }
                             } else {
-                                send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, "", 0, NULL);
+                                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
+                                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
                                 goto free_and_return;
                             }
                         }
@@ -850,8 +855,7 @@ account_locked:
              * the front end.
              */
             if ( rc == SLAPI_BIND_SUCCESS || rc == SLAPI_BIND_ANONYMOUS) {
-                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL,
-                                  0, NULL );
+                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
             }
 
             slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
@@ -876,8 +880,7 @@ free_and_return:;
     slapi_sdn_free(&sdn);
     slapi_ch_free_string( &saslmech );
     slapi_ch_free( (void **)&cred.bv_val );
-    if ( bind_target_entry != NULL )
-        slapi_entry_free(bind_target_entry);
+    slapi_entry_free(bind_target_entry);
 }
 
 

programming_language: C
filename: defbackend.c
change_type: ModificationType.MODIFY
diff: @@ -171,6 +171,51 @@ defbackend_abandon( Slapi_PBlock *pb )
 }
 
 
+#define DEFBE_NO_SUCH_SUFFIX "No such suffix"
+/*
+ * Generate a "No such suffix" return text
+ * Example:
+ *   cn=X,dc=bogus,dc=com ==> "No such suffix (dc=bogus,dc=com)" 
+ *     if the last rdn starts with "dc=", print all last dc= rdn's.
+ *   cn=X,cn=bogus ==> "No such suffix (cn=bogus)"
+ *     otherwise, print the very last rdn.
+ *   cn=X,z=bogus ==> "No such suffix (x=bogus)"
+ *     it is true even if it is an invalid rdn.
+ *   cn=X,bogus ==> "No such suffix (bogus)"
+ *     another example of invalid rdn.
+ */
+static void
+_defbackend_gen_returntext(char *buffer, size_t buflen, char **dns)
+{
+    int dnidx;
+    int sidx;
+    struct suffix_repeat {
+        char *suffix;
+        int size;
+    } candidates[] = {
+        {"dc=", 3}, /* dc could be repeated.  otherwise the last rdn is used. */
+        {NULL, 0}
+    };
+    PR_snprintf(buffer, buflen, "%s (", DEFBE_NO_SUCH_SUFFIX);
+    for (dnidx = 0; dns[dnidx]; dnidx++) ; /* finding the last */
+    dnidx--; /* last rdn */
+    for (sidx = 0; candidates[sidx].suffix; sidx++) {
+        if (!PL_strncasecmp(dns[dnidx], candidates[sidx].suffix, candidates[sidx].size)) {
+            while (!PL_strncasecmp(dns[--dnidx], candidates[sidx].suffix, candidates[sidx].size)) ;
+            PL_strcat(buffer, dns[++dnidx]); /* the first "dn=", e.g. */
+            for (++dnidx; dns[dnidx]; dnidx++) {
+                PL_strcat(buffer, ",");
+                PL_strcat(buffer, dns[dnidx]);
+            }
+            PL_strcat(buffer, ")");
+            return; /* finished the task */
+        }
+    }
+    PL_strcat(buffer, dns[dnidx]);
+    PL_strcat(buffer, ")");
+    return;
+}
+
 static int
 defbackend_bind( Slapi_PBlock *pb )
 {
@@ -188,11 +233,40 @@ defbackend_bind( Slapi_PBlock *pb )
     slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method );
     slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred );
     if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
-	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
-	rc = SLAPI_BIND_ANONYMOUS;
+        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
+        rc = SLAPI_BIND_ANONYMOUS;
     } else {
-	send_nobackend_ldap_result( pb );
-	rc = SLAPI_BIND_FAIL;
+        Slapi_DN *sdn = NULL;
+        char *suffix = NULL;
+        char **dns = NULL;
+        
+        if (pb->pb_op) {
+            sdn = operation_get_target_spec(pb->pb_op);
+            if (sdn) {
+                dns = slapi_ldap_explode_dn(slapi_sdn_get_dn(sdn), 0);
+                if (dns) {
+                    size_t dnlen = slapi_sdn_get_ndn_len(sdn);
+                    size_t len = dnlen + sizeof(DEFBE_NO_SUCH_SUFFIX) + 4;
+                    suffix = slapi_ch_malloc(len);
+                    if (dnlen) {
+                        _defbackend_gen_returntext(suffix, len, dns);
+                    } else {
+                        PR_snprintf(suffix, len, "%s", DEFBE_NO_SUCH_SUFFIX);
+                    }
+                }
+            }
+        }
+        if (suffix) {
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, suffix);
+        } else {
+            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, DEFBE_NO_SUCH_SUFFIX);
+        }
+        send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
+        if (dns) {
+            slapi_ldap_value_free(dns);
+        }
+        slapi_ch_free_string(&suffix);
+        rc = SLAPI_BIND_FAIL;
     }
 
     return( rc );

programming_language: C
filename: result.c
change_type: ModificationType.MODIFY
diff: @@ -2067,14 +2067,26 @@ log_result( Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentrie
 		}
 		else if ( !internal_op )
 		{
+			char *pbtxt = NULL;
+			char *ext_str = NULL;
+			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &pbtxt);
+			if (pbtxt) {
+				ext_str = slapi_ch_smprintf(" - %s", pbtxt);
+			} else {
+				ext_str = "";
+			}
 			slapi_log_access( LDAP_DEBUG_STATS,
 							  "conn=%" NSPRIu64 " op=%d RESULT err=%d"
-							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n",
+							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s%s\n",
 							  op->o_connid,
 							  op->o_opid,
 							  err, tag, nentries,
 							  etime,
-							  notes_str, csn_str );
+							  notes_str, csn_str, ext_str);
+			if (pbtxt) {
+				/* if !pbtxt ==> ext_str == "".  Don't free ext_str. */
+				slapi_ch_free_string(&ext_str);
+			}
 		}
 		else
 		{

programming_language: C