]> git.sur5r.net Git - openldap/commitdiff
attribute & objectclass mapping rules
authorMark Valence <mrv@openldap.org>
Mon, 19 Feb 2001 19:14:12 +0000 (19:14 +0000)
committerMark Valence <mrv@openldap.org>
Mon, 19 Feb 2001 19:14:12 +0000 (19:14 +0000)
servers/slapd/back-ldap/add.c
servers/slapd/back-ldap/attribute.c
servers/slapd/back-ldap/back-ldap.h
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/compare.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/group.c
servers/slapd/back-ldap/init.c
servers/slapd/back-ldap/modify.c
servers/slapd/back-ldap/search.c

index f282ee0f9098cf2ea6045cfcf741398da03a59ba..de1b4c1a9703bbb8ffc783f60fc122c665e5d46c 100644 (file)
@@ -58,8 +58,7 @@ ldap_back_add(
        int i;
        Attribute *a;
        LDAPMod **attrs;
-
-       char *mdn;
+       char *mdn, *mapped;
 
        lc = ldap_back_getconn(li, conn, op);
        if ( !lc || !ldap_back_dobind( lc, op ) ) {
@@ -77,14 +76,20 @@ ldap_back_add(
        
        /* Create array of LDAPMods for ldap_add() */
        attrs = (LDAPMod **)ch_malloc(sizeof(LDAPMod *)*i);
-       attrs[i-1] = 0;
 
-       for (i=0, a=e->e_attrs; a; i++, a=a->a_next) {
-               attrs[i] = (LDAPMod *)ch_malloc(sizeof(LDAPMod));
-               attrs[i]->mod_op = LDAP_MOD_BVALUES;
-               attrs[i]->mod_type = a->a_desc->ad_cname->bv_val;
-               attrs[i]->mod_vals.modv_bvals = a->a_vals;
+       for (i=0, a=e->e_attrs; a; a=a->a_next) {
+               mapped = ldap_back_map(&li->at_map, a->a_desc->ad_cname->bv_val, 0);
+               if (mapped != NULL) {
+                       attrs[i] = (LDAPMod *)ch_malloc(sizeof(LDAPMod));
+                       if (attrs[i] != NULL) {
+                               attrs[i]->mod_op = LDAP_MOD_BVALUES;
+                               attrs[i]->mod_type = mapped;
+                               attrs[i]->mod_vals.modv_bvals = a->a_vals;
+                               i++;
+                       }
+               }
        }
+       attrs[i] = NULL;
 
        ldap_add_s(lc->ld, mdn, attrs);
        for (--i; i>= 0; --i)
index df465f6619b7f90352bd262314cb72e2b615498e..e8b49e052adcbdf5d03e78c9d3f3d6075e506d30 100644 (file)
@@ -31,10 +31,10 @@ ldap_back_attribute(
 )
 {
        struct ldapinfo *li = (struct ldapinfo *) be->be_private;    
-       int rc = 1, i, j, count;
+       int rc = 1, i, j, count, is_oc;
        Attribute *attr;
        struct berval **abv, **v;
-       char **vs;
+       char **vs, *mapped;
        LDAPMessage     *result, *e;
        char *gattr[2];
        LDAP *ld;
@@ -42,6 +42,7 @@ ldap_back_attribute(
        *vals = NULL;
        if (target != NULL && strcmp(target->e_ndn, e_ndn) == 0) {
                /* we already have a copy of the entry */
+               /* attribute and objectclass mapping has already been done */
                if ((attr = attr_find(target->e_attrs, entry_at)) == NULL)
                        return(1);
 
@@ -61,31 +62,49 @@ ldap_back_attribute(
                }
 
        } else {
+               mapped = ldap_back_map(&li->at_map, entry_at->ad_cname->bv_val, 0);
+               if (mapped == NULL)
+                       return(1);
+
                if (ldap_initialize(&ld, li->url) != LDAP_SUCCESS) {
                        return(1);
                }
 
                if (ldap_bind_s(ld, li->binddn, li->bindpw, LDAP_AUTH_SIMPLE) == LDAP_SUCCESS) {
-                       gattr[0] = entry_at->ad_cname->bv_val;
+                       gattr[0] = mapped;
                        gattr[1] = NULL;
                        if (ldap_search_ext_s(ld, e_ndn, LDAP_SCOPE_BASE, "(objectclass=*)",
                                                                        gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
                                                                        LDAP_NO_LIMIT, &result) == LDAP_SUCCESS)
                        {
                                if ((e = ldap_first_entry(ld, result)) != NULL) {
-                                       vs = ldap_get_values(ld, e, entry_at->ad_cname->bv_val);
+                                       vs = ldap_get_values(ld, e, mapped);
                                        if (vs != NULL) {
                                                for ( count = 0; vs[count] != NULL; count++ ) { }
                                                v = (struct berval **) ch_calloc( (count + 1), sizeof(struct berval *) );
                                                if (v == NULL) {
                                                        ldap_value_free(vs);
                                                } else {
+                                                       is_oc = (strcasecmp("objectclass", mapped) == 0);
                                                        for ( i = 0, j = 0; i < count; i++) {
-                                                               v[j] = ber_bvstr( vs[i] );
-                                                               if( v[j] == NULL )
+                                                               if (!is_oc) {
+                                                                       v[j] = ber_bvstr( vs[i] );
+                                                                       if( v[j] == NULL )
+                                                                               ch_free(vs[i]);
+                                                                       else
+                                                                               j++;
+                                                               } else {
+                                                                       mapped = ldap_back_map(&li->oc_map, vs[i], 1);
+                                                                       if (mapped) {
+                                                                               mapped = ch_strdup( mapped );
+                                                                               if (mapped) {
+                                                                                       v[j] = ber_bvstr( mapped );
+                                                                                       if (v[j])
+                                                                                               j++;
+                                                                               }
+                                                                       }
                                                                        ch_free(vs[i]);
-                                                               else
-                                                                       j++;
+                                                               }
                                                        }
                                                        v[j] = NULL;
                                                        *vals = v;
index fdbe1a2d9c0d4504ffb19f79e738e7719f58bee0..aafb09f794f0701ec93864461ff8494c4b30c516 100644 (file)
@@ -52,6 +52,18 @@ struct ldapconn {
        int             bound;
 };
 
+struct ldapmap {
+       int drop_missing;
+
+       Avlnode *map;
+       Avlnode *remap;
+};
+
+struct ldapmapping {
+       char *src;
+       char *dst;
+};
+
 struct ldapinfo {
        char *url;
 #if 0 /* unused! */
@@ -62,6 +74,9 @@ struct ldapinfo {
        char *bindpw;
        ldap_pvt_thread_mutex_t         conn_mutex;
        Avlnode *conntree;
+
+       struct ldapmap oc_map;
+       struct ldapmap at_map;
 };
 
 struct ldapconn *ldap_back_getconn(struct ldapinfo *li, struct slap_conn *conn,
@@ -76,7 +91,14 @@ char *ldap_back_dn_restore(struct ldapinfo *li, char *dn, int normalized);
 
 int conn_cmp(const void *, const void *);
 int conn_dup(void *, void *);
-                       
+
+int mapping_cmp (const void *, const void *);
+int mapping_dup (void *, void *);
+
+char *ldap_back_map ( struct ldapmap *map, char *s, int remap );
+char *ldap_back_map_filter ( struct ldapinfo *li, char *f, int remap );
+char **ldap_back_map_attrs ( struct ldapinfo *li, char **a, int remap );
+
 LDAP_END_DECL
 
 #endif
index 6fa83775b13a87549c583edea8770afd01314862..89ef3f517b27dcb69e15e71c52a783112daf71f0 100644 (file)
@@ -199,7 +199,7 @@ ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op)
                err = avl_insert( &li->conntree, (caddr_t)lc,
                        conn_cmp, conn_dup );
 
-#if 1
+#if 0
                myprint( li->conntree );
 #endif
                
index e5db2342a7e41ab64c27ff71c17b7a64d2cfdea6..4221d6fbcd76b4f3a1643d4f7cc8ca46f9a34617 100644 (file)
@@ -57,7 +57,7 @@ ldap_back_compare(
 {
        struct ldapinfo *li = (struct ldapinfo *) be->be_private;
        struct ldapconn *lc;
-       char *mdn;
+       char *mdn, *mapped_oc, *mapped_at;
 
        lc = ldap_back_getconn(li, conn, op);
        if (!lc || !ldap_back_dobind( lc, op ) ) {
@@ -69,7 +69,15 @@ ldap_back_compare(
                return -1;
        }       
 
-       ldap_compare_s( lc->ld, mdn, ava->aa_desc->ad_cname->bv_val, ava->aa_value->bv_val );
+       mapped_oc = ldap_back_map(&li->oc_map, ava->aa_desc->ad_cname->bv_val, 0);
+       if (mapped_oc == NULL)
+               return( -1 );
+
+       mapped_at = ldap_back_map(&li->at_map, ava->aa_value->bv_val, 0);
+       if (mapped_oc == NULL)
+               return( -1 );
+
+       ldap_compare_s( lc->ld, mdn, mapped_oc, mapped_at );
 
        free( mdn );
        
index 5113ed617d08e3e888d6cef3eb492aae7d12c137..5fb1f3a6c1ea63396e48dc3f79b9eeab91e510bb 100644 (file)
@@ -141,7 +141,7 @@ ldap_back_db_config(
                         return( 1 );
                }
                
-                dn = ch_strdup( argv[1] );
+               dn = ch_strdup( argv[1] );
                charray_add( &li->suffix_massage, dn );
                (void) dn_normalize( dn );
                charray_add( &li->suffix_massage, dn );
@@ -154,6 +154,92 @@ ldap_back_db_config(
                free( dn );
                free( massaged_dn );
 
+       /* objectclass/attribute mapping */
+       } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
+               struct ldapmap *map;
+               struct ldapmapping *mapping;
+               char *src, *dst;
+
+               if ( argc < 3 || argc > 4 ) {
+                       fprintf( stderr,
+       "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
+                               fname, lineno );
+                       return( 1 );
+               }
+
+               if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
+                       map = &li->oc_map;
+               } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
+                       map = &li->at_map;
+               } else {
+                       fprintf( stderr,
+       "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
+                               fname, lineno );
+                       return( 1 );
+               }
+
+               if ( strcasecmp( argv[2], "*" ) != 0 ) {
+                       src = argv[2];
+                       if ( argc < 4 )
+                               dst = "";
+                       else if ( strcasecmp( argv[3], "*" ) == 0 )
+                               dst = src;
+                       else
+                               dst = argv[3];
+               } else {
+                       if ( argc < 4 ) {
+                               map->drop_missing = 1;
+                               return 0;
+                       }
+                       if ( strcasecmp( argv[3], "*" ) == 0 ) {
+                               map->drop_missing = 0;
+                               return 0;
+                       }
+
+                       src = argv[3];
+                       dst = src;
+               }
+
+               if ( ( map == &li->at_map )
+                       && ( strcasecmp( src, "objectclass" ) == 0
+                               || strcasecmp( dst, "objectclass" ) == 0 ) )
+               {
+                       fprintf( stderr,
+                               "%s: line %d: objectclass attribute cannot be mapped\n",
+                               fname, lineno );
+               }
+
+               mapping = (struct ldapmapping *)ch_calloc( 2, sizeof(struct ldapmapping) );
+               if ( mapping == NULL ) {
+                       fprintf( stderr,
+                               "%s: line %d: out of memory\n",
+                               fname, lineno );
+                       return( 1 );
+               }
+               mapping->src = ch_strdup(src);
+               mapping->dst = ch_strdup(dst);
+               if ( *dst != 0 ) {
+                       mapping[1].src = mapping->dst;
+                       mapping[1].dst = mapping->src;
+               } else {
+                       mapping[1].src = mapping->src;
+                       mapping[1].dst = mapping->dst;
+               }
+
+               if ( avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL
+                       || avl_find( map->remap, (caddr_t)&mapping[1], mapping_cmp ) != NULL)
+               {
+                       fprintf( stderr,
+                               "%s: line %d: duplicate mapping found (ignored)\n",
+                               fname, lineno );
+                       return 0;
+               }
+
+               avl_insert( &map->map, (caddr_t)mapping,
+                                       mapping_cmp, mapping_dup );
+               avl_insert( &map->remap, (caddr_t)&mapping[1],
+                                       mapping_cmp, mapping_dup );
+
        /* anything else */
        } else {
                fprintf( stderr,
@@ -162,3 +248,160 @@ ldap_back_db_config(
        }
        return 0;
 }
+
+int
+mapping_cmp ( const void *c1, const void *c2 )
+{
+       struct ldapmapping *map1 = (struct ldapmapping *)c1;
+       struct ldapmapping *map2 = (struct ldapmapping *)c2;
+
+       return ( strcasecmp(map1->src, map2->src) );
+}
+
+int
+mapping_dup ( void *c1, void *c2 )
+{
+       struct ldapmapping *map1 = (struct ldapmapping *)c1;
+       struct ldapmapping *map2 = (struct ldapmapping *)c2;
+
+       return( ( strcasecmp(map1->src, map2->src) == 0 ) ? -1 : 0 );
+}
+
+char *
+ldap_back_map ( struct ldapmap *map, char *s, int remap )
+{
+       Avlnode *tree;
+       struct ldapmapping *mapping, fmapping;
+
+       if (remap)
+               tree = map->remap;
+       else
+               tree = map->map;
+
+       fmapping.src = s;
+       mapping = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, mapping_cmp );
+       if (mapping != NULL) {
+               if ( *mapping->dst == 0 )
+                       return(NULL);
+               return(mapping->dst);
+       }
+
+       if (map->drop_missing)
+               return(NULL);
+
+       return(s);
+}
+
+char *
+ldap_back_map_filter ( struct ldapinfo *li, char *f, int remap )
+{
+       char *nf, *m, *p, *q, *s, c;
+       int len, extra, plen, in_quote;
+
+       if (f == NULL)
+               return(NULL);
+
+       len = strlen(f);
+       extra = len;
+       len *= 2;
+       nf = ch_malloc( len + 1 );
+       if (nf == NULL)
+               return(NULL);
+
+       /* this loop assumes the filter ends with one
+        * of the delimiter chars -- probably ')'.
+        */
+
+       s = nf;
+       q = NULL;
+       in_quote = 0;
+       for (p = f; c = *p; p++) {
+               if (c == '"') {
+                       in_quote = !in_quote;
+                       if (q != NULL) {
+                               plen = p - q;
+                               memcpy(s, q, plen);
+                               s += plen;
+                               q = NULL;
+                       }
+                       *s++ = c;
+               } else if (in_quote) {
+                       /* ignore everything in quotes --
+                        * what about attrs in DNs?
+                        */
+                       *s++ = c;
+               } else if (c != '(' && c != ')'
+                       && c != '=' && c != '>' && c != '<'
+                       && c != '|' && c != '&')
+               {
+                       if (q == NULL)
+                               q = p;
+               } else {
+                       if (q != NULL) {
+                               *p = 0;
+                               m = ldap_back_map(&li->at_map, q, remap);
+                               if (m == NULL)
+                                       m = ldap_back_map(&li->oc_map, q, remap);
+                               if (m == NULL) {
+                                       m = q;
+                               }
+                               extra += p - q;
+                               plen = strlen(m);
+                               extra -= plen;
+                               if (extra < 0) {
+                                       while (extra < 0) {
+                                               extra += len;
+                                               len *= 2;
+                                       }
+                                       s -= (long)nf;
+                                       nf = ch_realloc(nf, len + 1);
+                                       if (nf == NULL) {
+                                               free(nf);
+                                               return(NULL);
+                                       }
+                                       s += (long)nf;
+                               }
+                               memcpy(s, m, plen);
+                               s += plen;
+                               *p = c;
+                               q = NULL;
+                       }
+                       *s++ = c;
+               }
+       }
+       *s = 0;
+       return(nf);
+}
+
+char **
+ldap_back_map_attrs ( struct ldapinfo *li, char **a, int remap )
+{
+       int i, j, count;
+       char **na, *mapped;
+
+       if (a == NULL)
+               return(NULL);
+
+       for (count = 0; a[count] != NULL; count++) {
+               /*  */
+       }
+
+       na = (char **)ch_calloc( count + 1, sizeof(char *) );
+       if (na == NULL)
+               return(NULL);
+
+       for (i = 0, j = 0; i < count; i++) {
+               mapped = ldap_back_map(&li->at_map, a[i], remap);
+               if (mapped != NULL) {
+                       mapped = ch_strdup(mapped);
+                       if (mapped == NULL) {
+                               charray_free(na);
+                               return(NULL);
+                       }
+                       na[j] = mapped;
+                       j++;
+               }
+       }
+       return(na);
+}
+
index 94ec953ba053e41446141c3ea30c174f06efefc9..52d10b3164d4df805fd9bfd893ebaa3c768a169f 100644 (file)
@@ -43,8 +43,8 @@ ldap_back_group(
        LDAP *ld;
 
        AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
-       const char *group_oc_name = NULL;
-       const char *group_at_name = group_at->ad_cname->bv_val;
+       char *group_oc_name = NULL;
+       char *group_at_name = group_at->ad_cname->bv_val;
 
        if( group_oc->soc_names && group_oc->soc_names[0] ) {
                group_oc_name = group_oc->soc_names[0];
@@ -54,6 +54,7 @@ ldap_back_group(
 
        if (target != NULL && strcmp(target->e_ndn, gr_ndn) == 0) {
                /* we already have a copy of the entry */
+               /* attribute and objectclass mapping has already been done */
                e = target;
 
                if( is_entry_objectclass( e, group_oc ) ) {
@@ -69,6 +70,13 @@ ldap_back_group(
                        return(1);
 
        } else {
+               group_oc_name = ldap_back_map(&li->oc_map, group_oc_name, 0);
+               if (group_oc_name == NULL)
+                       return(1);
+               group_at_name = ldap_back_map(&li->at_map, group_at_name, 0);
+               if (group_at_name == NULL)
+                       return(1);
+
                filter = ch_malloc(sizeof("(&(objectclass=)(=))")
                                                        + strlen(group_oc_name)
                                                        + strlen(group_at_name)
index 9d49b424a05730585c05ba0467b6b55ee7210f3b..96e1acbd79402e1add26e7a0d6495d8f2b6e0b2b 100644 (file)
@@ -103,10 +103,24 @@ ldap_back_db_init(
 )
 {
        struct ldapinfo *li;
+       struct ldapmapping *mapping;
 
        li = (struct ldapinfo *) ch_calloc( 1, sizeof(struct ldapinfo) );
        ldap_pvt_thread_mutex_init( &li->conn_mutex );
 
+       mapping = (struct ldapmapping *)ch_calloc( 2, sizeof(struct ldapmapping) );
+       if ( mapping != NULL ) {
+               mapping->src = ch_strdup("objectclass");
+               mapping->dst = ch_strdup("objectclass");
+               mapping[1].src = mapping->src;
+               mapping[1].dst = mapping->dst;
+
+               avl_insert( &li->at_map.map, (caddr_t)mapping,
+                                       mapping_cmp, mapping_dup );
+               avl_insert( &li->at_map.remap, (caddr_t)&mapping[1],
+                                       mapping_cmp, mapping_dup );
+       }
+
        be->be_private = li;
 
        return li == NULL;
@@ -122,6 +136,14 @@ conn_free(
        free( lc );
 }
 
+static void
+mapping_free ( struct ldapmapping *mapping )
+{
+       ch_free( mapping->src );
+       ch_free( mapping->dst );
+       ch_free( mapping );
+}
+
 int
 ldap_back_db_destroy(
     Backend    *be
@@ -153,6 +175,11 @@ ldap_back_db_destroy(
                 if (li->conntree) {
                        avl_free( li->conntree, (AVL_FREE) conn_free );
                }
+
+               avl_free( li->oc_map.remap, NULL );
+               avl_free( li->oc_map.map, (AVL_FREE) mapping_free );
+               avl_free( li->at_map.remap, NULL );
+               avl_free( li->at_map.map, (AVL_FREE) mapping_free );
                
                ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
                ldap_pvt_thread_mutex_destroy( &li->conn_mutex );
index 9b11c27b5736a7fc79f9272c8a67a322c7e5356a..fb7bfc669934a136b826f78b218698eadb5c7856 100644 (file)
@@ -61,8 +61,7 @@ ldap_back_modify(
        LDAPMod *mods;
        Modifications *ml;
        int i;
-
-       char *mdn;
+       char *mdn, *mapped;
 
        lc = ldap_back_getconn(li, conn, op);
        if ( !lc || !ldap_back_dobind( lc, op ) ) {
@@ -86,16 +85,17 @@ ldap_back_modify(
                return( -1 );
        }
 
-       modv[i] = 0;
-
-       for (i=0, ml=modlist; ml; i++, ml=ml->sml_next) {
-               modv[i] = &mods[i];
-               mods[i].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
-               mods[i].mod_type = ml->sml_desc->ad_cname->bv_val;
-               mods[i].mod_bvalues = ml->sml_bvalues;
+       for (i=0, ml=modlist; ml; ml=ml->sml_next) {
+               mapped = ldap_back_map(&li->at_map, ml->sml_desc->ad_cname->bv_val, 0);
+               if (mapped != NULL) {
+                       modv[i] = &mods[i];
+                       mods[i].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
+                       mods[i].mod_type = mapped;
+                       mods[i].mod_bvalues = ml->sml_bvalues;
+                       i++;
+               }
        }
-
-       
+       modv[i] = 0;
 
        ldap_modify_s( lc->ld, mdn, modv );
        free( mdn );
index 240a85736b2b576eb67f09b049fa30925d3fee68..441ad98c8ec4b37dffc2a2127b198e4110572bee 100644 (file)
@@ -70,10 +70,9 @@ ldap_back_search(
        struct ldapconn *lc;
        struct timeval  tv;
        LDAPMessage             *res, *e;
-       int                     i, rc, msgid, sres = LDAP_SUCCESS; 
+       int     count, rc, msgid, sres = LDAP_SUCCESS; 
        char *match = NULL, *err = NULL;
-
-       char *mbase;
+       char *mbase, *mapped_filter, **mapped_attrs;
 
        lc = ldap_back_getconn(li, conn, op);
        if ( !lc ) {
@@ -96,17 +95,41 @@ ldap_back_search(
                return -1;
        }
 
-       if ((msgid = ldap_search(lc->ld, mbase, scope, filterstr, attrs,
+       mapped_filter = ldap_back_map_filter(li, (char *)filterstr, 0);
+       if ( mapped_filter == NULL ) {
+               mapped_filter = (char *)filterstr;
+       }
+
+       mapped_attrs = ldap_back_map_attrs(li, attrs, 0);
+       if ( mapped_attrs == NULL ) {
+               mapped_attrs = attrs;
+       }
+
+       if ((msgid = ldap_search(lc->ld, mbase, scope, mapped_filter, mapped_attrs,
                attrsonly)) == -1)
-fail:          return( ldap_back_op_result(lc, op) );
+       {
+fail:
+               if (match)
+                       free(match);
+               if (err)
+                       free(err);
+               if (mapped_attrs != attrs)
+                       charray_free(mapped_attrs);
+               if (mapped_filter != filterstr)
+                       free(mapped_filter);
+               free(mbase);
+               return( ldap_back_op_result(lc, op) );
+       }
 
        /* We pull apart the ber result, stuff it into a slapd entry, and
         * let send_search_entry stuff it back into ber format. Slow & ugly,
         * but this is necessary for version matching, and for ACL processing.
         */
        
-       for (i=0, rc=0; rc != -1;
-               rc = ldap_result(lc->ld, LDAP_RES_ANY, 0, &tv, &res)) {
+       for (   count=0, rc=0;
+                       rc != -1;
+                       rc = ldap_result(lc->ld, LDAP_RES_ANY, 0, &tv, &res))
+       {
                int ab;
 
                /* check for abandon */
@@ -116,15 +139,16 @@ fail:             return( ldap_back_op_result(lc, op) );
 
                if (ab) {
                        ldap_abandon(lc->ld, msgid);
-               } else if (rc == 0) {
+                       goto finish;
+               }
+               if (rc == 0) {
                        tv.tv_sec = 0;
                        tv.tv_usec = 100000;
                        ldap_pvt_thread_yield();
-                       continue;
                } else if (rc == LDAP_RES_SEARCH_ENTRY) {
                        e = ldap_first_entry(lc->ld,res);
-                       ldap_send_entry(be, op, lc, e, attrs, attrsonly);
-                       i++;
+                       ldap_send_entry(be, op, lc, e, mapped_attrs, attrsonly);
+                       count++;
                        ldap_msgfree(res);
                } else {
                        sres = ldap_result2error(lc->ld, res, 1);
@@ -132,24 +156,26 @@ fail:             return( ldap_back_op_result(lc, op) );
                        ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &err);
                        ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match);
                        rc = 0;
-               }
-               if (ab)
-                       return (0);
-               else if (rc == 0)
                        break;
+               }
        }
 
        if (rc == -1)
                goto fail;
 
        send_search_result( conn, op, sres,
-               match, err, NULL, NULL, i );
+               match, err, NULL, NULL, count );
+
+finish:
        if (match)
                free(match);
        if (err)
                free(err);
-       if (mbase) 
-               free(mbase);
+       if (mapped_attrs != attrs)
+               charray_free(mapped_attrs);
+       if (mapped_filter != filterstr)
+               free(mapped_filter);
+       free(mbase);
        return( 0 );
 }
 
@@ -164,11 +190,12 @@ ldap_send_entry(
 )
 {
        struct ldapinfo *li = (struct ldapinfo *) be->be_private;
-       char *a;
+       char *a, *mapped;
        Entry ent;
        BerElement *ber = NULL;
        Attribute *attr, **attrp;
        struct berval *dummy = NULL;
+       struct berval *bv;
        const char *text;
 
        ent.e_dn = ldap_back_dn_restore( li, ldap_get_dn(lc->ld, e), 0 );
@@ -183,21 +210,47 @@ ldap_send_entry(
                        a != NULL;
                        a = ldap_next_attribute(lc->ld, e, ber))
        {
+               mapped = ldap_back_map(&li->at_map, a, 1);
+               if (mapped == NULL)
+                       continue;
                attr = (Attribute *)ch_malloc( sizeof(Attribute) );
                if (attr == NULL)
                        continue;
                attr->a_next = 0;
                attr->a_desc = NULL;
-               slap_str2ad(a, &attr->a_desc, &text);
+               if (slap_str2ad(mapped, &attr->a_desc, &text) != LDAP_SUCCESS) {
+                       ch_free(attr);
+                       continue;
+               }
                attr->a_vals = ldap_get_values_len(lc->ld, e, a);
-               if (!attr->a_vals)
+               if (!attr->a_vals) {
                        attr->a_vals = &dummy;
+               } else if ( strcasecmp( mapped, "objectclass" ) == 0 ) {
+                       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;
+                                       if (--last < 0)
+                                               break;
+                                       attr->a_vals[i] = attr->a_vals[last];
+                                       attr->a_vals[last] = NULL;
+                                       i--;
+                               } else if ( mapped != bv->bv_val ) {
+                                       ch_free(bv->bv_val);
+                                       bv->bv_val = ch_strdup( mapped );
+                                       bv->bv_len = strlen( mapped );
+                               }
+                       }
+               }
                *attrp = attr;
                attrp = &attr->a_next;
        }
        send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, NULL );
-       for (;ent.e_attrs;) {
-               attr=ent.e_attrs;
+       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)