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

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

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

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

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


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

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

                /* Allow simple binds only for SSL/TLS established connections
                 * or connections using SASL privacy layers */
                conn = pb->pb_conn;
                if ( slapi_pblock_get(pb, SLAPI_CONN_SASL_SSF, &sasl_ssf) != 0) {
                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
                                     "Could not get SASL SSF from connection\n" );
                    sasl_ssf = 0;
                }
                if ( slapi_pblock_get(pb, SLAPI_CONN_LOCAL_SSF, &local_ssf) != 0) {
                    slapi_log_error( SLAPI_LOG_PLUGIN, "do_bind",
                                     "Could not get local SSF from connection\n" );
                    local_ssf = 0;
                }
                if (((conn->c_flags & CONN_FLAG_SSL) != CONN_FLAG_SSL) &&
                    (sasl_ssf <= 1) && (local_ssf <= 1)) {
                        send_ldap_result(pb, LDAP_CONFIDENTIALITY_REQUIRED, NULL,
                                         "Operation requires a secure connection",
                                         0, NULL);
                        slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
                        goto free_and_return;
                }
                send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
                    slapi_create_errormsg(errorbuf, sizeof(errorbuf), "Pre-bind plug-in set corrupted dn\n");
                    send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
                        send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, errorbuf, 0, NULL);
                                send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, "", 0, NULL);
                send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL,
                                  0, NULL );
    if ( bind_target_entry != NULL )
        slapi_entry_free(bind_target_entry);
	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
	rc = SLAPI_BIND_ANONYMOUS;
	send_nobackend_ldap_result( pb );
	rc = SLAPI_BIND_FAIL;
							  " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n",
							  notes_str, csn_str );

Fixed code:
    Slapi_DN *ancestordn,
    int			*err,
    int allow_suffix
    struct backentry *e = NULL;
    LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
        while (!e && !slapi_sdn_isempty(&ancestorndn)) {
            if (!allow_suffix) {
                /* Original behavior. */
                if (slapi_be_issuffix(be, &ancestorndn)) {
                    break;
                }
            }
static struct backentry *find_entry_internal_dn(Slapi_PBlock *pb, backend *be, const Slapi_DN *sdn, int lock, back_txn *txn, int flags, int *rc);
static struct backentry * find_entry_internal(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int lock, back_txn *txn, int flags, int *rc);
	Slapi_Value *val=NULL;
    Slapi_PBlock	*pb,
    back_txn		*txn,
    int				flags,
    int				*rc /* return code */
	int isroot = 0;
	int op_type;
	char *errbuf = NULL;
	slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
	slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
					*rc = FE_RC_SENT_RESULT;
				}
		me = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, txn, &err, 1 /* allow_suffix */);
				if (rc) { /* if check_entry_for_referral returns non-zero, result is sent. */
					*rc = FE_RC_SENT_RESULT;
				}
		if ((0 == err) || (DB_NOTFOUND == err)) {
			if (me && !isroot) {
				/* If not root, you may not want to reveal it. */
				int acl_type = -1;
				int return_err = LDAP_NO_SUCH_OBJECT;
				err = LDAP_SUCCESS;
				switch (op_type) {
				case SLAPI_OPERATION_ADD:
					acl_type = SLAPI_ACL_ADD;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_DELETE:
					acl_type = SLAPI_ACL_DELETE;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_MODDN:
					acl_type = SLAPI_ACL_MODDN;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_MODIFY:
					acl_type = SLAPI_ACL_WRITE;
					return_err = LDAP_INSUFFICIENT_ACCESS;
					break;
				case SLAPI_OPERATION_SEARCH:
				case SLAPI_OPERATION_COMPARE:
					return_err = LDAP_SUCCESS;
					acl_type = SLAPI_ACL_READ;
					break;
				case SLAPI_OPERATION_BIND:
					acl_type = -1; /* skip acl check. acl is not set up for bind. */
					return_err = LDAP_INVALID_CREDENTIALS;
					slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "No such entry");
					break;
				}
				if (acl_type > 0) {
					err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
					                             ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
				}
				if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
					/*
					 * Operations to be checked && ACL returns disallow.
					 * Not to disclose the info about the entry's existence,
					 * do not return the "matched" DN.
					 * Plus, the bind case returns LDAP_INAPPROPRIATE_AUTH.
					 */
					slapi_send_ldap_result(pb, return_err, NULL, NULL, 0, NULL);
				} else {
					slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT,
						(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
				}
			} else {
				slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT,
					(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL);
			}
		} else {
			slapi_send_ldap_result( pb, ( LDAP_INVALID_DN_SYNTAX == err ) ?
				LDAP_INVALID_DN_SYNTAX : LDAP_OPERATIONS_ERROR,
				(char*)slapi_sdn_get_dn(&ancestorsdn), NULL, 0, NULL );
		}
		if (rc) {
			*rc = FE_RC_SENT_RESULT;
		}
	slapi_ch_free_string(&errbuf);
    Slapi_PBlock	*pb,
    const char 			*uniqueid,
    back_txn		*txn
    back_txn *txn,
    int flags,
    int *rc
			entry = find_entry_internal_dn (pb, be, addr->sdn, lock, txn, flags, rc);
			LDAPDebug0Args( LDAP_DEBUG_ANY, "find_entry_internal: Null target dn\n" );
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, 0/*flags*/, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0/*flags*/, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 0/*!lock*/, txn, FE_REALLY_INTERNAL, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, 0 /* to check aci, disable INTERNAL */, rc));
    back_txn *txn,
    int *rc
	return(find_entry_internal(pb, be, addr, 1/*lock*/, txn, FE_REALLY_INTERNAL | flags, rc));
	int result_sent = 0;
				parententry = find_entry2modify_only(pb, be, &addr, &txn, &result_sent);
					if ((LDAP_ALREADY_EXISTS == ldap_result_code) && !isroot && !is_replicated_operation) {
						myrc = plugin_call_acl_plugin(pb, e, NULL, NULL, SLAPI_ACL_ADD,
						                              ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
						if (myrc) {
							ldap_result_code = myrc;
							ldap_result_message = errbuf;
						}
					}
						ancestorentry = dn2ancestor(pb->pb_backend, sdn, &ancestorsdn, &txn, &err, 0);
				tombstoneentry = find_entry2modify(pb, be, &addr, &txn, &result_sent);
					ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err, 1);
		if (!result_sent) {
			slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL);
		}
	int result_sent = 0;
	if ((e = find_entry( pb, be, addr, &txn, &result_sent)) == NULL) {
		/* In the failure case, the result is supposed to be sent in the backend. */
		if (!result_sent) {
			slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
		}
			slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
			slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
	if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL) {
	int result_sent = 0;
			if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL)
					parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn, &result_sent);
		if (!result_sent) {
			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
		}
	int result_sent = 0;
			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
			e = find_entry2modify( pb, be, addr, &txn, &result_sent );
			ldap_result_code = -1;
					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
					e = find_entry2modify( pb, be, addr, &txn, &result_sent );
					ldap_result_code = -1;
		if (!result_sent) {
			/* result is already sent in find_entry. */
			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
		}
    int result_sent = 0;
            e = find_entry2modify(pb, be, old_addr, &txn, &result_sent);
            parententry = find_entry2modify_only(pb, be, &oldparent_addr, &txn, &result_sent);
                newparententry = find_entry2modify_only(pb, be, newsuperior_addr, &txn, &result_sent);
                        ancestorentry = dn2ancestor(be, &dn_newdn, &ancestorsdn, &txn, &err, 0);
        if (!result_sent) {
            slapi_send_ldap_result(pb, ldap_result_code, ldap_result_matcheddn,
                                   ldap_result_message, 0, NULL);
        }
        if ((e = find_entry(pb, be, addr, &txn, NULL)) == NULL)
    bentry = find_entry2modify_only(pb, be, &bentry_addr, &txn, NULL);
struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err, int allow_suffix);
/* Return code */
#define FE_RC_SENT_RESULT 1
struct backentry *find_entry2modify(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
struct backentry *find_entry(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
struct backentry *find_entry2modify_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
struct backentry *find_entry2modify_only_ext(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, int flags, back_txn *txn, int *rc);
struct backentry *find_entry_only(Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn, int *rc);
            e = find_entry(pb, inst->inst_be, &addr, &txn, NULL);
                slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Client certificate mapping failed");
                send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, "", 0, NULL);
            Connection *conn = NULL;
            int sasl_ssf = 0;
            int local_ssf = 0;

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

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