]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldap/search.c
reset SlapReply flags
[openldap] / servers / slapd / back-ldap / search.c
index 3fafc9dcc849bf620c175ff157d1a3461b4d5d1a..6cf7697fdafc54bb1bcfbcfc0c8376e0797f407a 100644 (file)
@@ -1,38 +1,24 @@
 /* search.c - ldap backend search function */
 /* $OpenLDAP$ */
-/*
- * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/* This is an altered version */
-/*
- * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
- * 
- * Permission is granted to anyone to use this software for any purpose
- * on any computer system, and to alter it and redistribute it, subject
- * to the following restrictions:
- * 
- * 1. The author is not responsible for the consequences of use of this
- *    software, no matter how awful, even if they arise from flaws in it.
- * 
- * 2. The origin of this software must not be misrepresented, either by
- *    explicit claim or by omission.  Since few users ever read sources,
- *    credits should appear in the documentation.
- * 
- * 3. Altered versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.  Since few users
- *    ever read sources, credits should appear in the documentation.
- * 
- * 4. This notice may not be removed or altered.
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
+ * Copyright 1999-2004 The OpenLDAP Foundation.
+ * Portions Copyright 1999-2003 Howard Chu.
+ * Portions Copyright 2000-2003 Pierangelo Masarati.
+ * All rights reserved.
  *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
  *
- * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
- * 
- * This software is being modified by Pierangelo Masarati.
- * The previously reported conditions apply to the modified code as well.
- * Changes in the original code are highlighted where required.
- * Credits for the original code go to the author, Howard Chu.
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by the Howard Chu for inclusion
+ * in OpenLDAP Software and subsequently enhanced by Pierangelo
+ * Masarati.
  */
 
 #include "portable.h"
 
 #include "lutil.h"
 
+static int
+ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent,
+        struct berval *bdn, int flags );
+#define LDAP_BUILD_ENTRY_PRIVATE       0x01
+#define LDAP_BUILD_ENTRY_NORMALIZE     0x02
+
 static struct berval dummy = { 0, NULL };
 
 int
@@ -61,15 +53,18 @@ ldap_back_search(
        struct ldapconn *lc;
        struct timeval  tv;
        LDAPMessage             *res, *e;
-       int     count, rc = 0, msgid; 
-       char *match = NULL;
+       int     rc = 0, msgid; 
+       struct berval match = { 0, NULL };
        char **mapped_attrs = NULL;
        struct berval mbase;
        struct berval mfilter = { 0, NULL };
-       struct slap_limits_set *limit = NULL;
-       int isroot = 0;
+       int dontfreetext = 0;
+       dncookie dc;
+#ifdef LDAP_BACK_PROXY_AUTHZ
+       LDAPControl **ctrls = NULL;
+#endif /* LDAP_BACK_PROXY_AUTHZ */
 
-       lc = ldap_back_getconn(li, op, rs);
+       lc = ldap_back_getconn(op, rs);
        if ( !lc ) {
                return( -1 );
        }
@@ -78,62 +73,15 @@ ldap_back_search(
         * FIXME: in case of values return filter, we might want
         * to map attrs and maybe rewrite value
         */
-       if ( !ldap_back_dobind( li, lc, op, rs ) ) {
+       if ( !ldap_back_dobind( lc, op, rs ) ) {
                return( -1 );
        }
 
-       /* if not root, get appropriate limits */
-       if ( be_isroot( op->o_bd, &op->o_ndn ) ) {
-               isroot = 1;
-       } else {
-               ( void ) get_limits( op->o_bd, &op->o_ndn, &limit );
-       }
-       
-       /* if no time limit requested, rely on remote server limits */
-       /* if requested limit higher than hard limit, abort */
-       if ( !isroot && op->oq_search.rs_tlimit > limit->lms_t_hard ) {
-               /* no hard limit means use soft instead */
-               if ( limit->lms_t_hard == 0
-                               && limit->lms_t_soft > -1
-                               && op->oq_search.rs_tlimit > limit->lms_t_soft ) {
-                       op->oq_search.rs_tlimit = limit->lms_t_soft;
-                       
-               /* positive hard limit means abort */
-               } else if ( limit->lms_t_hard > 0 ) {
-                       rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
-                       send_ldap_result( op, rs );
-                       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 && op->oq_search.rs_slimit > limit->lms_s_hard ) {
-               /* no hard limit means use soft instead */
-               if ( limit->lms_s_hard == 0
-                               && limit->lms_s_soft > -1
-                               && op->oq_search.rs_slimit > limit->lms_s_soft ) {
-                       op->oq_search.rs_slimit = limit->lms_s_soft;
-                       
-               /* positive hard limit means abort */
-               } else if ( limit->lms_s_hard > 0 ) {
-                       rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
-                       send_ldap_result( op, rs );
-                       rc = 0;
-                       goto finish;
-               }
-               
-               /* negative hard limit means no limit */
-       }
-
        /* should we check return values? */
-       if (op->oq_search.rs_deref != -1)
-               ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&op->oq_search.rs_deref);
-       if (op->oq_search.rs_tlimit != -1) {
-               tv.tv_sec = op->oq_search.rs_tlimit;
+       if (op->ors_deref != -1)
+               ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&op->ors_deref);
+       if (op->ors_tlimit != -1) {
+               tv.tv_sec = op->ors_tlimit;
                tv.tv_usec = 0;
        } else {
                tv.tv_sec = 0;
@@ -142,70 +90,72 @@ ldap_back_search(
        /*
         * Rewrite the search base, if required
         */
+       dc.rwmap = &li->rwmap;
 #ifdef ENABLE_REWRITE
-       switch ( rewrite_session( li->rwinfo, "searchBase",
-                               op->o_req_dn.bv_val, op->o_conn, &mbase.bv_val ) ) {
-       case REWRITE_REGEXEC_OK:
-               if ( mbase.bv_val == NULL ) {
-                       mbase = op->o_req_dn;
-               }
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_LDAP, DETAIL1, 
-                       "[rw] searchBase: \"%s\" -> \"%s\"\n", 
-                       op->o_req_dn.bv_val, mbase.bv_val, 0 );
-#else /* !NEW_LOGGING */
-               Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s",
-                               op->o_req_dn.bv_val, mbase.bv_val, "" );
-#endif /* !NEW_LOGGING */
+       dc.conn = op->o_conn;
+       dc.rs = rs;
+       dc.ctx = "searchBase";
+#else
+       dc.tofrom = 1;
+       dc.normalized = 0;
+#endif
+       if ( ldap_back_dn_massage( &dc, &op->o_req_ndn, &mbase ) ) {
+               send_ldap_result( op, rs );
+               return -1;
+       }
+
+       rc = ldap_back_filter_map_rewrite( &dc, op->ors_filter,
+                       &mfilter, BACKLDAP_MAP );
+
+       switch ( rc ) {
+       case LDAP_SUCCESS:
                break;
-               
-       case REWRITE_REGEXEC_UNWILLING:
-               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
-                               "Operation not allowed" );
-               rc = -1;
+
+       case LDAP_COMPARE_FALSE:
+               rs->sr_err = LDAP_SUCCESS;
+               rs->sr_text = NULL;
+               rc = 0;
                goto finish;
 
-       case REWRITE_REGEXEC_ERR:
-               send_ldap_error( op, rs, LDAP_OTHER,
-                               "Rewrite error" );
+       default:
+               rs->sr_err = LDAP_OTHER;
+               rs->sr_text = "Rewrite error";
+               dontfreetext = 1;
                rc = -1;
                goto finish;
        }
 
-#else /* !ENABLE_REWRITE */
-       ldap_back_dn_massage( li, &op->o_req_dn, &mbase, 0, 1 );
-#endif /* !ENABLE_REWRITE */
-
-#ifdef ENABLE_REWRITE
-       rc = ldap_back_filter_map_rewrite_( li->rwinfo, op->o_conn,
-                       &li->at_map, &li->oc_map, op->oq_search.rs_filter, &mfilter, 
-                       BACKLDAP_MAP );
-#else /* ! ENABLE_REWRITE */
-       rc = ldap_back_filter_map_rewrite_( &li->at_map, &li->oc_map, 
-                       op->oq_search.rs_filter, &mfilter, BACKLDAP_MAP );
-#endif /* ! ENABLE_REWRITE */
-
-       if ( rc ) {
+       rs->sr_err = ldap_back_map_attrs( &li->rwmap.rwm_at,
+                       op->ors_attrs,
+                       BACKLDAP_MAP, &mapped_attrs );
+       if ( rs->sr_err ) {
                rc = -1;
                goto finish;
        }
 
-       mapped_attrs = ldap_back_map_attrs(&li->at_map, op->oq_search.rs_attrs, BACKLDAP_MAP);
-       if ( mapped_attrs == NULL && op->oq_search.rs_attrs) {
-               for (count=0; op->oq_search.rs_attrs[count].an_name.bv_val; count++);
-               mapped_attrs = ch_malloc( (count+1) * sizeof(char *));
-               for (count=0; op->oq_search.rs_attrs[count].an_name.bv_val; count++) {
-                       mapped_attrs[count] = op->oq_search.rs_attrs[count].an_name.bv_val;
-               }
-               mapped_attrs[count] = NULL;
-       }
-
-       rc = ldap_search_ext(lc->ld, mbase.bv_val, op->oq_search.rs_scope, mfilter.bv_val,
-                       mapped_attrs, op->oq_search.rs_attrsonly, op->o_ctrls, NULL, tv.tv_sec ? &tv
-                       : NULL, op->oq_search.rs_slimit, &msgid);
+#ifdef LDAP_BACK_PROXY_AUTHZ
+       rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
        if ( rc != LDAP_SUCCESS ) {
+               dontfreetext = 1;
+               goto finish;
+       }
+#endif /* LDAP_BACK_PROXY_AUTHZ */
+       
+       rs->sr_err = ldap_search_ext(lc->ld, mbase.bv_val,
+                       op->ors_scope, mfilter.bv_val,
+                       mapped_attrs, op->ors_attrsonly,
+#ifdef LDAP_BACK_PROXY_AUTHZ
+                       ctrls,
+#else /* ! LDAP_BACK_PROXY_AUTHZ */
+                       op->o_ctrls,
+#endif /* ! LDAP_BACK_PROXY_AUTHZ */
+                       NULL,
+                       tv.tv_sec ? &tv : NULL, op->ors_slimit,
+                       &msgid );
+
+       if ( rs->sr_err != LDAP_SUCCESS ) {
 fail:;
-               rc = ldap_back_op_result(li, lc, op, rs, msgid, rc, 0);
+               rc = ldap_back_op_result(lc, op, rs, msgid, 0);
                goto finish;
        }
 
@@ -229,19 +179,28 @@ fail:;
                        ldap_pvt_thread_yield();
 
                } else if (rc == LDAP_RES_SEARCH_ENTRY) {
-                       Entry ent;
+                       Entry ent = {0};
                        struct berval bdn;
+                       int abort = 0;
                        e = ldap_first_entry(lc->ld,res);
-                       if ( ldap_build_entry(op, e, &ent, &bdn, 1) == LDAP_SUCCESS ) {
-                               Attribute *a;
+                       if ( ( rc = ldap_build_entry(op, e, &ent, &bdn,
+                                               LDAP_BUILD_ENTRY_PRIVATE)) == LDAP_SUCCESS ) {
                                rs->sr_entry = &ent;
-                               rs->sr_attrs = op->oq_search.rs_attrs;
-                               send_search_entry( op, rs );
+                               rs->sr_attrs = op->ors_attrs;
+                               rs->sr_flags = 0;
+                               abort = send_search_entry( op, rs );
                                while (ent.e_attrs) {
+                                       Attribute *a;
+                                       BerVarray v;
+
                                        a = ent.e_attrs;
                                        ent.e_attrs = a->a_next;
+
+                                       v = a->a_vals;
                                        if (a->a_vals != &dummy)
                                                ber_bvarray_free(a->a_vals);
+                                       if (a->a_nvals != v)
+                                               ber_bvarray_free(a->a_nvals);
                                        ch_free(a);
                                }
                                
@@ -251,6 +210,10 @@ fail:;
                                        free( ent.e_ndn );
                        }
                        ldap_msgfree(res);
+                       if ( abort ) {
+                               ldap_abandon(lc->ld, msgid);
+                               goto finish;
+                       }
 
                } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
                        char            **references = NULL;
@@ -293,10 +256,11 @@ fail:;
                        }
 
                } else {
-                       rc = ldap_parse_result(lc->ld, res, &rs->sr_err, &match,
-                               (char **)&rs->sr_text, NULL, NULL, 1);
+                       rc = ldap_parse_result(lc->ld, res, &rs->sr_err,
+                                       &match.bv_val, (char **)&rs->sr_text,
+                                       NULL, NULL, 1);
                        if (rc != LDAP_SUCCESS ) rs->sr_err = rc;
-                       rs->sr_err = ldap_back_map_result(rs->sr_err);
+                       rs->sr_err = ldap_back_map_result(rs);
                        rc = 0;
                        break;
                }
@@ -305,81 +269,69 @@ fail:;
        if (rc == -1)
                goto fail;
 
-#ifdef ENABLE_REWRITE
        /*
         * Rewrite the matched portion of the search base, if required
         */
-       if ( match != NULL ) {
-               switch ( rewrite_session( li->rwinfo, "matchedDn",
-                               match, op->o_conn, (char **)&rs->sr_matched ) ) {
-               case REWRITE_REGEXEC_OK:
-                       if ( rs->sr_matched == NULL ) {
-                               rs->sr_matched = ( char * )match;
-                       }
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_LDAP, DETAIL1, 
-                               "[rw]  matchedDn:" " \"%s\" -> \"%s\"\n", match, rs->sr_matched, 0 );
-#else /* !NEW_LOGGING */
-                       Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:"
-                                       " \"%s\" -> \"%s\"\n%s",
-                                       match, rs->sr_matched, "" );
-#endif /* !NEW_LOGGING */
-                       break;
-                       
-               case REWRITE_REGEXEC_UNWILLING:
-                       
-               case REWRITE_REGEXEC_ERR:
-                       /* FIXME: no error, but no matched ... */
-                       rs->sr_matched = NULL;
-                       break;
-               }
-       }
-#else /* !ENABLE_REWRITE */
-       if ( match != NULL ) {
-               struct berval dn, mdn;
+       if ( match.bv_val && *match.bv_val ) {
+               struct berval mdn;
 
-               ber_str2bv(match, 0, 0, &dn);
-               ldap_back_dn_massage(li, &dn, &mdn, 0, 0);
+#ifdef ENABLE_REWRITE
+               dc.ctx = "matchedDN";
+#else
+               dc.tofrom = 0;
+               dc.normalized = 0;
+#endif
+               match.bv_len = strlen( match.bv_val );
+               ldap_back_dn_massage(&dc, &match, &mdn);
                rs->sr_matched = mdn.bv_val;
        }
-#endif /* !ENABLE_REWRITE */
        if ( rs->sr_v2ref ) {
                rs->sr_err = LDAP_REFERRAL;
        }
-       send_ldap_result( op, rs );
 
 finish:;
-       if ( match ) {
-               if ( rs->sr_matched != match ) {
+       send_ldap_result( op, rs );
+
+#ifdef LDAP_BACK_PROXY_AUTHZ
+       if ( ctrls && ctrls != op->o_ctrls ) {
+               free( ctrls[ 0 ] );
+               free( ctrls );
+       }
+#endif /* LDAP_BACK_PROXY_AUTHZ */
+
+       if ( match.bv_val ) {
+               if ( rs->sr_matched != match.bv_val ) {
                        free( (char *)rs->sr_matched );
                }
                rs->sr_matched = NULL;
-               LDAP_FREE(match);
+               LDAP_FREE( match.bv_val );
        }
        if ( rs->sr_text ) {
-               LDAP_FREE( (char *)rs->sr_text );
+               if ( !dontfreetext ) {
+                       LDAP_FREE( (char *)rs->sr_text );
+               }
                rs->sr_text = NULL;
        }
        if ( mapped_attrs ) {
                ch_free( mapped_attrs );
        }
-       if ( mfilter.bv_val != op->oq_search.rs_filterstr.bv_val ) {
+       if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
                ch_free( mfilter.bv_val );
        }
-       if ( mbase.bv_val != op->o_req_dn.bv_val ) {
+       if ( mbase.bv_val != op->o_req_ndn.bv_val ) {
                free( mbase.bv_val );
        }
        
        return rc;
 }
 
-int
+static int
 ldap_build_entry(
        Operation *op,
        LDAPMessage *e,
        Entry *ent,
        struct berval *bdn,
-       int private
+       int flags
 )
 {
        struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;
@@ -388,60 +340,55 @@ ldap_build_entry(
        Attribute *attr, **attrp;
        struct berval *bv;
        const char *text;
+       int last;
+       int private = flags & LDAP_BUILD_ENTRY_PRIVATE;
+       int normalize = flags & LDAP_BUILD_ENTRY_NORMALIZE;
+       dncookie dc;
+
+       /* safe assumptions ... */
+       assert( ent );
+       ent->e_bv.bv_val = NULL;
 
        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",
-                               bdn->bv_val, op->o_conn,
-                               &ent->e_name.bv_val ) ) {
-       case REWRITE_REGEXEC_OK:
-               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", 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:
+       dc.rwmap = &li->rwmap;
+#ifdef ENABLE_REWRITE
+       dc.conn = op->o_conn;
+       dc.rs = NULL;
+       dc.ctx = "searchResult";
+#else
+       dc.tofrom = 0;
+       dc.normalized = 0;
+#endif
+       if ( ldap_back_dn_massage( &dc, bdn, &ent->e_name ) ) {
                return LDAP_OTHER;
        }
-#else /* !ENABLE_REWRITE */
-       ldap_back_dn_massage( li, bdn, &ent->e_name, 0, 0 );
-#endif /* !ENABLE_REWRITE */
 
        /*
         * 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?
+        * FIXME: should we log anything, or delegate to dnNormalize?
         */
-       if ( dnNormalize2( NULL, &ent->e_name, &ent->e_nname ) != LDAP_SUCCESS ) {
+       if ( dnNormalize( 0, NULL, NULL, &ent->e_name, &ent->e_nname,
+               op->o_tmpmemctx ) != LDAP_SUCCESS )
+       {
                return LDAP_INVALID_DN_SYNTAX;
        }
        
-       ent->e_id = 0;
-       ent->e_attrs = 0;
-       ent->e_private = 0;
        attrp = &ent->e_attrs;
 
+#ifdef ENABLE_REWRITE
+       dc.ctx = "searchAttrDN";
+#endif
        while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
-               ldap_back_map(&li->at_map, &a, &mapped, BACKLDAP_REMAP);
+               ldap_back_map(&li->rwmap.rwm_at, &a, &mapped, BACKLDAP_REMAP);
                if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0')
                        continue;
                attr = (Attribute *)ch_malloc( sizeof(Attribute) );
@@ -468,6 +415,16 @@ ldap_build_entry(
 
                /* no subschemaSubentry */
                if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
+
+                       /* 
+                        * We eat target's subschemaSubentry because
+                        * a search for this value is likely not
+                        * to resolve to the appropriate backend;
+                        * later, the local subschemaSubentry is
+                        * added.
+                        */
+                       ( void )ber_scanf( &ber, "x" /* [W] */ );
+
                        ch_free(attr);
                        continue;
                }
@@ -485,14 +442,16 @@ ldap_build_entry(
                                attr->a_vals->bv_val = NULL;
                                attr->a_vals->bv_len = 0;
                        }
+                       last = 0;
+               } else {
+                       for ( last = 0; attr->a_vals[last].bv_val; last++ );
+               }
+               if ( last == 0 ) {
+                       /* empty */
                } else if ( attr->a_desc == slap_schema.si_ad_objectClass
                                || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) {
-                       int             last;
-
-                       for ( last = 0; attr->a_vals[last].bv_val; last++ );
-
                        for ( bv = attr->a_vals; bv->bv_val; bv++ ) {
-                               ldap_back_map(&li->oc_map, bv, &mapped,
+                               ldap_back_map(&li->rwmap.rwm_oc, bv, &mapped,
                                                BACKLDAP_REMAP);
                                if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') {
                                        LBER_FREE(bv->bv_val);
@@ -525,78 +484,33 @@ ldap_build_entry(
                 * ACLs to the target directory server, and letting
                 * everything pass thru the ldap backend.
                 */
-               } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
-                                       SLAPD_DN_SYNTAX ) == 0 ) {
-                       int             last;
-
-                       for ( last = 0; attr->a_vals[last].bv_val; last++ );
-
-                       for ( bv = attr->a_vals; bv->bv_val; bv++ ) {
-                               struct berval   newval;
-                               
-#ifdef ENABLE_REWRITE
-                               switch ( rewrite_session( li->rwinfo,
-                                                       "searchResult",
-                                                       bv->bv_val,
-                                                       op->o_conn, 
-                                                       &newval.bv_val )) {
-                               case REWRITE_REGEXEC_OK:
-                                       /* left as is */
-                                       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_val,
-                                               bv->bv_val, newval.bv_val );
-#endif /* !NEW_LOGGING */
-                                       free( bv->bv_val );
-                                       *bv = newval;
-                                       break;
-                                       
-                               case REWRITE_REGEXEC_UNWILLING:
-                                       LBER_FREE(bv->bv_val);
-                                       bv->bv_val = NULL;
-                                       if (--last < 0)
-                                               goto next_attr;
-                                       *bv = attr->a_vals[last];
-                                       attr->a_vals[last].bv_val = NULL;
-                                       bv--;
-                                       break;
+               } else if ( attr->a_desc->ad_type->sat_syntax ==
+                               slap_schema.si_syn_distinguishedName ) {
+                       ldap_dnattr_result_rewrite( &dc, attr->a_vals );
+               }
 
-                               case REWRITE_REGEXEC_ERR:
-                                       /*
-                                        * FIXME: better give up,
-                                        * skip the attribute
-                                        * or leave it untouched?
-                                        */
-                                       break;
-                               }
-#else /* !ENABLE_REWRITE */
-                               ldap_back_dn_massage( li, bv, &newval, 0, 0 );
-                               if ( bv->bv_val != newval.bv_val ) {
-                                       LBER_FREE( bv->bv_val );
-                               }
-                               *bv = newval;
-#endif /* !ENABLE_REWRITE */
+               if ( normalize && last && attr->a_desc->ad_type->sat_equality &&
+                       attr->a_desc->ad_type->sat_equality->smr_normalize ) {
+                       int i;
+
+                       attr->a_nvals = ch_malloc((last+1)*sizeof(struct berval));
+                       for (i=0; i<last; i++) {
+                               attr->a_desc->ad_type->sat_equality->smr_normalize(
+                                       SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+                                       attr->a_desc->ad_type->sat_syntax,
+                                       attr->a_desc->ad_type->sat_equality,
+                                       &attr->a_vals[i], &attr->a_nvals[i],
+                                       NULL /* op->o_tmpmemctx */ );
                        }
+                       attr->a_nvals[i].bv_val = NULL;
+                       attr->a_nvals[i].bv_len = 0;
+               } else {
+                       attr->a_nvals = attr->a_vals;
                }
-
-next_attr:;
-
-#ifdef SLAP_NVALUES
-               attr->a_nvals = attr->a_vals;
-#endif
                *attrp = attr;
                attrp = &attr->a_next;
        }
+
        /* make sure it's free'able */
        if (!private && ent->e_name.bv_val == bdn->bv_val)
                ber_dupbv( &ent->e_name, bdn );
@@ -618,25 +532,21 @@ ldap_back_entry_get(
        struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;    
        struct ldapconn *lc;
        int rc = 1, is_oc;
-       struct berval mapped = { 0, NULL }, bdn;
+       struct berval mapped = { 0, NULL }, bdn, mdn;
        LDAPMessage     *result = NULL, *e = NULL;
        char *gattr[3];
-       char *filter;
+       char *filter = NULL;
        Connection *oconn;
        SlapReply rs;
-
-       ldap_back_map(&li->at_map, &at->ad_cname, &mapped, BACKLDAP_MAP);
-       if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') {
-               return 1;
-       }
+       dncookie dc;
 
        /* Tell getconn this is a privileged op */
        is_oc = op->o_do_not_cache;
        op->o_do_not_cache = 1;
-       lc = ldap_back_getconn(li, op, &rs);
+       lc = ldap_back_getconn(op, &rs);
        oconn = op->o_conn;
        op->o_conn = NULL;
-       if ( !lc || !ldap_back_dobind(li, lc, op, &rs) ) {
+       if ( !lc || !ldap_back_dobind(lc, op, &rs) ) {
                op->o_do_not_cache = is_oc;
                op->o_conn = oconn;
                return 1;
@@ -644,6 +554,30 @@ ldap_back_entry_get(
        op->o_do_not_cache = is_oc;
        op->o_conn = oconn;
 
+       /*
+        * Rewrite the search base, if required
+        */
+       dc.rwmap = &li->rwmap;
+#ifdef ENABLE_REWRITE
+       dc.conn = op->o_conn;
+       dc.rs = &rs;
+       dc.ctx = "searchBase";
+#else
+       dc.tofrom = 1;
+       dc.normalized = 1;
+#endif
+       if ( ldap_back_dn_massage( &dc, ndn, &mdn ) ) {
+               return 1;
+       }
+
+       if ( at ) {
+               ldap_back_map(&li->rwmap.rwm_at, &at->ad_cname, &mapped, BACKLDAP_MAP);
+               if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') {
+                       rc = 1;
+                       goto cleanup;
+               }
+       }
+
        is_oc = (strcasecmp("objectclass", mapped.bv_val) == 0);
        if (oc && !is_oc) {
                gattr[0] = "objectclass";
@@ -655,16 +589,16 @@ ldap_back_entry_get(
        }
        if (oc) {
                char *ptr;
-               filter = ch_malloc(sizeof("(objectclass=)" + oc->soc_cname.bv_len));
+               ldap_back_map(&li->rwmap.rwm_oc, &oc->soc_cname, &mapped,
+                                               BACKLDAP_MAP);
+               filter = ch_malloc(sizeof("(objectclass=)") + mapped.bv_len);
                ptr = lutil_strcopy(filter, "(objectclass=");
-               ptr = lutil_strcopy(ptr, oc->soc_cname.bv_val);
+               ptr = lutil_strcopy(ptr, mapped.bv_val);
                *ptr++ = ')';
                *ptr++ = '\0';
-       } else {
-               filter = "(objectclass=*)";
        }
-               
-       if (ldap_search_ext_s(lc->ld, ndn->bv_val, LDAP_SCOPE_BASE, filter,
+
+       if (ldap_search_ext_s(lc->ld, mdn.bv_val, LDAP_SCOPE_BASE, filter,
                                gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
                                LDAP_NO_LIMIT, &result) != LDAP_SUCCESS)
        {
@@ -675,9 +609,9 @@ ldap_back_entry_get(
                goto cleanup;
        }
 
-       *ent = ch_malloc(sizeof(Entry));
+       *ent = ch_calloc(1,sizeof(Entry));
 
-       rc = ldap_build_entry(op, e, *ent, &bdn, 0);
+       rc = ldap_build_entry(op, e, *ent, &bdn, LDAP_BUILD_ENTRY_NORMALIZE);
 
        if (rc != LDAP_SUCCESS) {
                ch_free(*ent);
@@ -689,6 +623,14 @@ cleanup:
                ldap_msgfree(result);
        }
 
+       if ( filter ) {
+               ch_free( filter );
+       }
+
+       if ( mdn.bv_val != ndn->bv_val ) {
+               ch_free( mdn.bv_val );
+       }
+
        return(rc);
 }