X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldap%2Fsearch.c;h=41b397a9da22dd2cdef2c9535414219f59671768;hb=71e35141e151b7ca602c7a4638c35260f65d946d;hp=1b0e3a20ee28a785f69dd546ce1b850fbcf560cb;hpb=74fa239a201cd2d785fe34bdbaf6804161bdb231;p=openldap diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 1b0e3a20ee..41b397a9da 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -1,7 +1,7 @@ /* search.c - ldap backend search function */ /* $OpenLDAP$ */ /* - * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ /* This is an altered version */ @@ -45,24 +45,26 @@ #include "slap.h" #include "back-ldap.h" +#undef ldap_debug /* silence a warning in ldap-int.h */ +#include "../../../libraries/libldap/ldap-int.h" -static void ldap_send_entry( Backend *be, Operation *op, struct ldapconn *lc, - LDAPMessage *e, char **attrs, int attrsonly ); +static int ldap_send_entry( Backend *be, Operation *op, struct ldapconn *lc, + LDAPMessage *e, AttributeName *attrs, int attrsonly ); int ldap_back_search( Backend *be, Connection *conn, Operation *op, - const char *base, - const char *nbase, + struct berval *base, + struct berval *nbase, int scope, int deref, - int size, - int time, + int slimit, + int tlimit, Filter *filter, - const char *filterstr, - char **attrs, + struct berval *filterstr, + AttributeName *attrs, int attrsonly ) { @@ -72,46 +74,115 @@ ldap_back_search( LDAPMessage *res, *e; int count, rc = 0, msgid, sres = LDAP_SUCCESS; char *match = NULL, *err = NULL; - char *mbase = NULL, *mapped_filter = NULL, **mapped_attrs = NULL; + char *mapped_filter = NULL, **mapped_attrs = NULL; + struct berval mbase; #ifdef ENABLE_REWRITE - char *mfilter = NULL, *mmatch = NULL; + char *mmatch = NULL; + struct berval mfilter = { 0, NULL }; #endif /* ENABLE_REWRITE */ + struct slap_limits_set *limit = NULL; + int isroot = 0; + BerVarray v2refs = NULL; lc = ldap_back_getconn(li, conn, op); if ( !lc ) { return( -1 ); } - if (deref != -1) - ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&deref); - if (time != -1) - ldap_set_option( lc->ld, LDAP_OPT_TIMELIMIT, (void *)&time); - if (size != -1) - ldap_set_option( lc->ld, LDAP_OPT_SIZELIMIT, (void *)&size); - + /* + * controls are set in ldap_back_dobind() + * + * FIXME: in case of values return filter, we might want + * to map attrs and maybe rewrite value + */ if ( !ldap_back_dobind( lc, op ) ) { return( -1 ); } + /* if not root, get appropriate limits */ + if ( be_isroot( be, &op->o_ndn ) ) { + isroot = 1; + } else { + ( void ) get_limits( be, &op->o_ndn, &limit ); + } + + /* if no time limit requested, rely on remote server limits */ + /* if requested limit higher than hard limit, abort */ + if ( !isroot && tlimit > limit->lms_t_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_t_hard == 0 + && limit->lms_t_soft > -1 + && tlimit > limit->lms_t_soft ) { + tlimit = limit->lms_t_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_t_hard > 0 ) { + send_ldap_result( conn, op, LDAP_ADMINLIMIT_EXCEEDED, + NULL, NULL, NULL, NULL ); + rc = 0; + goto finish; + } + + /* negative hard limit means no limit */ + } + + /* if no size limit requested, rely on remote server limits */ + /* if requested limit higher than hard limit, abort */ + if ( !isroot && slimit > limit->lms_s_hard ) { + /* no hard limit means use soft instead */ + if ( limit->lms_s_hard == 0 + && limit->lms_s_soft > -1 + && slimit > limit->lms_s_soft ) { + slimit = limit->lms_s_soft; + + /* positive hard limit means abort */ + } else if ( limit->lms_s_hard > 0 ) { + send_ldap_result( conn, op, LDAP_ADMINLIMIT_EXCEEDED, + NULL, NULL, NULL, NULL ); + rc = 0; + goto finish; + } + + /* negative hard limit means no limit */ + } + + /* should we check return values? */ + if (deref != -1) + ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&deref); + if (tlimit != -1) + ldap_set_option( lc->ld, LDAP_OPT_TIMELIMIT, (void *)&tlimit); + if (slimit != -1) + ldap_set_option( lc->ld, LDAP_OPT_SIZELIMIT, (void *)&slimit); + /* * Rewrite the search base, if required */ #ifdef ENABLE_REWRITE switch ( rewrite_session( li->rwinfo, "searchBase", - base, conn, &mbase ) ) { + base->bv_val, conn, &mbase.bv_val ) ) { case REWRITE_REGEXEC_OK: - if ( mbase == NULL ) { - mbase = ( char * )base; + if ( mbase.bv_val == NULL ) { + mbase = *base; } +#ifdef NEW_LOGGING + LDAP_LOG( BACK_LDAP, DETAIL1, + "[rw] searchBase: \"%s\" -> \"%s\"\n", + base->bv_val, mbase.bv_val, 0 ); +#else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s", - base, mbase, "" ); + base->bv_val, mbase.bv_val, "" ); +#endif /* !NEW_LOGGING */ break; case REWRITE_REGEXEC_UNWILLING: send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, - NULL, "Unwilling to perform", NULL, NULL ); + NULL, "Operation not allowed", NULL, NULL ); + rc = -1; + goto finish; case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "Rewrite error", NULL, NULL ); rc = -1; goto finish; } @@ -120,54 +191,79 @@ ldap_back_search( * Rewrite the search filter, if required */ switch ( rewrite_session( li->rwinfo, "searchFilter", - filterstr, conn, &mfilter ) ) { + filterstr->bv_val, conn, &mfilter.bv_val ) ) { case REWRITE_REGEXEC_OK: - if ( mfilter == NULL || mfilter[0] == '\0') { - if ( mfilter != NULL ) { - free( mfilter ); + if ( mfilter.bv_val == NULL || mfilter.bv_val[0] == '\0') { + if ( mfilter.bv_val != NULL ) { + free( mfilter.bv_val ); } - mfilter = ( char * )filterstr; + mfilter = *filterstr; + } else { + mfilter.bv_len = strlen( mfilter.bv_val ); } + +#ifdef NEW_LOGGING + LDAP_LOG( BACK_LDAP, DETAIL1, + "[rw] searchFilter: \"%s\" -> \"%s\"\n", + filterstr->bv_val, mfilter.bv_val, 0 ); +#else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> searchFilter: \"%s\" -> \"%s\"\n%s", - filterstr, mfilter, "" ); + filterstr->bv_val, mfilter.bv_val, "" ); +#endif /* !NEW_LOGGING */ break; case REWRITE_REGEXEC_UNWILLING: send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, - NULL, "Unwilling to perform", NULL, NULL ); + NULL, "Operation not allowed", NULL, NULL ); + rc = -1; + goto finish; + case REWRITE_REGEXEC_ERR: + send_ldap_result( conn, op, LDAP_OTHER, + NULL, "Rewrite error", NULL, NULL ); rc = -1; goto finish; } #else /* !ENABLE_REWRITE */ - mbase = ldap_back_dn_massage( li, ch_strdup( base ), 0 ); + ldap_back_dn_massage( li, base, &mbase, 0, 1 ); #endif /* !ENABLE_REWRITE */ mapped_filter = ldap_back_map_filter(&li->at_map, &li->oc_map, #ifdef ENABLE_REWRITE - (char *)mfilter, + &mfilter, #else /* !ENABLE_REWRITE */ - (char *)filterstr, + filterstr, #endif /* !ENABLE_REWRITE */ - 0); + BACKLDAP_MAP); if ( mapped_filter == NULL ) { #ifdef ENABLE_REWRITE - mapped_filter = (char *)mfilter; + mapped_filter = mfilter.bv_val; #else /* !ENABLE_REWRITE */ - mapped_filter = (char *)filterstr; + mapped_filter = filterstr->bv_val; #endif /* !ENABLE_REWRITE */ } - mapped_attrs = ldap_back_map_attrs(&li->at_map, attrs, 0); - if ( mapped_attrs == NULL ) { - mapped_attrs = attrs; +#ifdef ENABLE_REWRITE + if ( mfilter.bv_val != filterstr->bv_val ) { + free( mfilter.bv_val ); } +#endif /* ENABLE_REWRITE */ - if ((msgid = ldap_search(lc->ld, mbase, scope, mapped_filter, mapped_attrs, - attrsonly)) == -1) - { -fail: + mapped_attrs = ldap_back_map_attrs(&li->at_map, attrs, BACKLDAP_MAP); + if ( mapped_attrs == NULL && attrs) { + for (count=0; attrs[count].an_name.bv_val; count++); + mapped_attrs = ch_malloc( (count+1) * sizeof(char *)); + for (count=0; attrs[count].an_name.bv_val; count++) { + mapped_attrs[count] = attrs[count].an_name.bv_val; + } + mapped_attrs[count] = NULL; + } + + msgid = ldap_search(lc->ld, mbase.bv_val, scope, mapped_filter, + mapped_attrs, attrsonly); + if ( msgid == -1 ) { +fail:; rc = ldap_back_op_result(lc, op); goto finish; } @@ -179,29 +275,69 @@ fail: for ( count=0, rc=0; rc != -1; - rc = ldap_result(lc->ld, LDAP_RES_ANY, 0, &tv, &res)) + rc = ldap_result(lc->ld, msgid, 0, &tv, &res)) { - int ab; - /* check for abandon */ - ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); - ab = op->o_abandon; - ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - - if (ab) { + if (op->o_abandon) { ldap_abandon(lc->ld, msgid); rc = 0; goto finish; } + if (rc == 0) { tv.tv_sec = 0; tv.tv_usec = 100000; ldap_pvt_thread_yield(); + } else if (rc == LDAP_RES_SEARCH_ENTRY) { e = ldap_first_entry(lc->ld,res); - ldap_send_entry(be, op, lc, e, attrs, attrsonly); - count++; + if ( ldap_send_entry(be, op, lc, e, attrs, attrsonly) + == LDAP_SUCCESS ) { + count++; + } ldap_msgfree(res); + + } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) { + char **references = NULL; + LDAPControl **ctrls = NULL; + BerVarray refs; + int cnt; + + rc = ldap_parse_reference( lc->ld, res, + &references, &ctrls, 1 ); + + if ( rc != LDAP_SUCCESS ) { + continue; + } + + if ( references == NULL ) { + continue; + } + + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; + + refs = ch_calloc( cnt + 1, sizeof( struct berval ) ); + + for ( cnt = 0; references[ cnt ]; cnt++ ) { + refs[ cnt ].bv_val = references[ cnt ]; + refs[ cnt ].bv_len = strlen( references[ cnt ] ); + } + + /* ignore return value by now */ + ( void )send_search_reference( be, conn, op, + NULL, refs, ctrls, &v2refs ); + + /* cleanup */ + if ( references ) { + ldap_value_free( references ); + ch_free( refs ); + } + + if ( ctrls ) { + ldap_controls_free( ctrls ); + } + } else { sres = ldap_result2error(lc->ld, res, 1); sres = ldap_back_map_result(sres); @@ -226,173 +362,206 @@ fail: if ( mmatch == NULL ) { mmatch = ( char * )match; } +#ifdef NEW_LOGGING + LDAP_LOG( BACK_LDAP, DETAIL1, + "[rw] matchedDn:" " \"%s\" -> \"%s\"\n", match, mmatch, 0 ); +#else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:" - " \"%s\" -> \"%s\"\n%s", - match, mmatch, "" ); + " \"%s\" -> \"%s\"\n%s", + match, mmatch, "" ); +#endif /* !NEW_LOGGING */ break; case REWRITE_REGEXEC_UNWILLING: - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, - NULL, "Unwilling to perform", - NULL, NULL ); case REWRITE_REGEXEC_ERR: - rc = -1; - goto finish; + /* FIXME: no error, but no matched ... */ + mmatch = NULL; + break; } } + if ( v2refs ) { + sres = LDAP_REFERRAL; + } + send_search_result( conn, op, sres, - mmatch, err, NULL, NULL, count ); + mmatch, err, v2refs, NULL, count ); #else /* !ENABLE_REWRITE */ + if ( v2refs ) { + sres = LDAP_REFERRAL; + } send_search_result( conn, op, sres, - match, err, NULL, NULL, count ); + match, err, v2refs, NULL, count ); #endif /* !ENABLE_REWRITE */ -finish: +finish:; if ( match ) { #ifdef ENABLE_REWRITE if ( mmatch != match ) { free( mmatch ); } #endif /* ENABLE_REWRITE */ - free(match); + LDAP_FREE(match); } if ( err ) { - free( err ); - } - if ( mapped_attrs != attrs ) { - charray_free( mapped_attrs ); - } -#ifdef ENABLE_REWRITE - if ( mapped_filter != mfilter ) { - free( mapped_filter ); + LDAP_FREE( err ); } - if ( mfilter != filterstr ) { - free( mfilter ); + if ( mapped_attrs ) { + ch_free( mapped_attrs ); } -#else /* !ENABLE_REWRITE */ - if ( mapped_filter != filterstr ) { - free( mapped_filter ); + if ( mapped_filter != filterstr->bv_val ) { + ch_free( mapped_filter ); } -#endif /* !ENABLE_REWRITE */ - -#ifdef ENABLE_REWRITE - if ( mbase != base ) { -#endif /* ENABLE_REWRITE */ - free( mbase ); -#ifdef ENABLE_REWRITE + if ( mbase.bv_val != base->bv_val ) { + free( mbase.bv_val ); } -#endif /* ENABLE_REWRITE */ return rc; } -static void +static int ldap_send_entry( Backend *be, Operation *op, struct ldapconn *lc, LDAPMessage *e, - char **attrs, + AttributeName *attrs, int attrsonly ) { struct ldapinfo *li = (struct ldapinfo *) be->be_private; - char *a, *mapped; + struct berval a, mapped; Entry ent; - BerElement *ber = NULL; + BerElement ber = *e->lm_ber; Attribute *attr, **attrp; - struct berval *dummy = NULL; - struct berval *bv; + struct berval dummy = { 0, NULL }; + struct berval *bv, bdn; const char *text; -#ifdef ENABLE_REWRITE - char *dn; - - dn = ldap_get_dn(lc->ld, e); - if ( dn == NULL ) { - return; + if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) { + return LDAP_DECODING_ERROR; } +#ifdef ENABLE_REWRITE /* * Rewrite the dn of the result, if needed */ switch ( rewrite_session( li->rwinfo, "searchResult", - dn, lc->conn, &ent.e_dn ) ) { + bdn.bv_val, lc->conn, &ent.e_name.bv_val ) ) { case REWRITE_REGEXEC_OK: - if ( ent.e_dn == NULL ) { - ent.e_dn = dn; + if ( ent.e_name.bv_val == NULL ) { + ent.e_name = bdn; } else { +#ifdef NEW_LOGGING + LDAP_LOG( BACK_LDAP, DETAIL1, + "[rw] searchResult: \"%s\"" " -> \"%s\"\n", + bdn.bv_val, ent.e_dn, 0 ); +#else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> searchResult: \"%s\"" - " -> \"%s\"\n%s", dn, ent.e_dn, "" ); - free( dn ); - dn = NULL; + " -> \"%s\"\n%s", bdn.bv_val, ent.e_dn, "" ); +#endif /* !NEW_LOGGING */ + ent.e_name.bv_len = strlen( ent.e_name.bv_val ); } break; case REWRITE_REGEXEC_ERR: case REWRITE_REGEXEC_UNWILLING: - free( dn ); - return; + return LDAP_OTHER; } #else /* !ENABLE_REWRITE */ - ent.e_dn = ldap_back_dn_restore( li, ldap_get_dn(lc->ld, e), 0 ); + ldap_back_dn_massage( li, &bdn, &ent.e_name, 0, 0 ); #endif /* !ENABLE_REWRITE */ - ent.e_ndn = ch_strdup( ent.e_dn ); - (void) dn_normalize( ent.e_ndn ); + /* + * Note: this may fail if the target host(s) schema differs + * from the one known to the meta, and a DN with unknown + * attributes is returned. + * + * FIXME: should we log anything, or delegate to dnNormalize2? + */ + if ( dnNormalize2( NULL, &ent.e_name, &ent.e_nname ) != LDAP_SUCCESS ) { + return LDAP_INVALID_DN_SYNTAX; + } + ent.e_id = 0; ent.e_attrs = 0; ent.e_private = 0; attrp = &ent.e_attrs; - for ( a = ldap_first_attribute(lc->ld, e, &ber); - a != NULL; - a = ldap_next_attribute(lc->ld, e, ber)) - { - mapped = ldap_back_map(&li->at_map, a, 1); - if (mapped == NULL) + while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { + ldap_back_map(&li->at_map, &a, &mapped, BACKLDAP_REMAP); + if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') continue; attr = (Attribute *)ch_malloc( sizeof(Attribute) ); if (attr == NULL) continue; + attr->a_flags = 0; attr->a_next = 0; attr->a_desc = NULL; - if (slap_str2ad(mapped, &attr->a_desc, &text) != LDAP_SUCCESS) { + if (slap_bv2ad(&mapped, &attr->a_desc, &text) != LDAP_SUCCESS) { + if (slap_bv2undef_ad(&mapped, &attr->a_desc, &text) + != LDAP_SUCCESS) { +#ifdef NEW_LOGGING + LDAP_LOG( BACK_LDAP, DETAIL1, + "slap_bv2undef_ad(%s): %s\n", mapped.bv_val, text, 0 ); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ANY, + "slap_bv2undef_ad(%s): " + "%s\n%s", mapped.bv_val, text, "" ); +#endif /* !NEW_LOGGING */ + ch_free(attr); + continue; + } + } + + /* no subschemaSubentry */ + if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) { ch_free(attr); continue; } - attr->a_vals = ldap_get_values_len(lc->ld, e, a); - if (!attr->a_vals) { + + if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR + || attr->a_vals == NULL ) { + /* + * Note: attr->a_vals can be null when using + * values result filter + */ attr->a_vals = &dummy; - } else if ( strcasecmp( mapped, "objectclass" ) == 0 ) { + + } else if ( attr->a_desc == slap_schema.si_ad_objectClass + || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { int i, last; - for ( last = 0; attr->a_vals[last]; last++ ) ; - for ( i = 0; ( bv = attr->a_vals[i] ); i++ ) { - mapped = ldap_back_map(&li->oc_map, bv->bv_val, 1); - if (mapped == NULL) { - ber_bvfree(attr->a_vals[i]); - attr->a_vals[i] = NULL; + + for ( last = 0; attr->a_vals[last].bv_val; last++ ) ; + for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { + ldap_back_map(&li->oc_map, bv, &mapped, + BACKLDAP_REMAP); + if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') { + LBER_FREE(bv->bv_val); + bv->bv_val = NULL; if (--last < 0) break; - attr->a_vals[i] = attr->a_vals[last]; - attr->a_vals[last] = NULL; + *bv = attr->a_vals[last]; + attr->a_vals[last].bv_val = NULL; i--; - } else if ( mapped != bv->bv_val ) { - ch_free(bv->bv_val); - bv->bv_val = ch_strdup( mapped ); - bv->bv_len = strlen( mapped ); + } else if ( mapped.bv_val != bv->bv_val ) { + /* + * FIXME: after LBER_FREEing + * the value is replaced by + * ch_alloc'ed memory + */ + LBER_FREE(bv->bv_val); + ber_dupbv( bv, &mapped ); } } -#ifdef ENABLE_REWRITE /* * It is necessary to try to rewrite attributes with * dn syntax because they might be used in ACLs as * members of groups; since ACLs are applied to the - * rewritten stuff, no dn-based subecj clause could + * rewritten stuff, no dn-based subject clause could * be used at the ldap backend side (see * http://www.OpenLDAP.org/faq/data/cache/452.html) * The problem can be overcome by moving the dn-based @@ -402,27 +571,34 @@ ldap_send_entry( } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid, SLAPD_DN_SYNTAX ) == 0 ) { int i; - for ( i = 0; ( bv = attr->a_vals[ i ] ); i++ ) { - char *newval; + for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { + struct berval newval; +#ifdef ENABLE_REWRITE switch ( rewrite_session( li->rwinfo, "searchResult", bv->bv_val, - lc->conn, &newval )) { + lc->conn, + &newval.bv_val )) { case REWRITE_REGEXEC_OK: /* left as is */ - if ( newval == NULL ) { + if ( newval.bv_val == NULL ) { break; } + newval.bv_len = strlen( newval.bv_val ); +#ifdef NEW_LOGGING + LDAP_LOG( BACK_LDAP, DETAIL1, + "[rw] searchResult on attr=%s: \"%s\" -> \"%s\"\n", + attr->a_desc->ad_type->sat_cname.bv_val, + bv->bv_val, newval.bv_val ); +#else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> searchResult on attr=%s: \"%s\" -> \"%s\"\n", - attr->a_desc->ad_type->sat_cname, - bv->bv_val, newval ); - + attr->a_desc->ad_type->sat_cname.bv_val, + bv->bv_val, newval.bv_val ); +#endif /* !NEW_LOGGING */ free( bv->bv_val ); - bv->bv_val = newval; - bv->bv_len = strlen( newval ); - + *bv = newval; break; case REWRITE_REGEXEC_UNWILLING: @@ -435,8 +611,11 @@ ldap_send_entry( */ break; } +#else /* !ENABLE_REWRITE */ + ldap_back_dn_massage( li, bv, &newval, 0, 0 ); + *bv = newval; +#endif /* !ENABLE_REWRITE */ } -#endif /* ENABLE_REWRITE */ } *attrp = attr; @@ -446,17 +625,15 @@ ldap_send_entry( while (ent.e_attrs) { attr = ent.e_attrs; ent.e_attrs = attr->a_next; - ad_free(attr->a_desc, 1); if (attr->a_vals != &dummy) - ber_bvecfree(attr->a_vals); - free(attr); + ber_bvarray_free(attr->a_vals); + ch_free(attr); } - if (ber) - ber_free(ber,0); - if ( ent.e_dn ) + if ( ent.e_dn && ( ent.e_dn != bdn.bv_val ) ) free( ent.e_dn ); if ( ent.e_ndn ) free( ent.e_ndn ); -} + return LDAP_SUCCESS; +}