]> git.sur5r.net Git - openldap/commitdiff
Integrate LDBM changes into BDB2...
authorKurt Zeilenga <kurt@openldap.org>
Fri, 16 Jul 1999 01:53:38 +0000 (01:53 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Fri, 16 Jul 1999 01:53:38 +0000 (01:53 +0000)
servers/slapd/back-bdb2/add.c
servers/slapd/back-bdb2/alias.c
servers/slapd/back-bdb2/bind.c
servers/slapd/back-bdb2/compare.c
servers/slapd/back-bdb2/delete.c
servers/slapd/back-bdb2/dn2id.c [new file with mode: 0644]
servers/slapd/back-bdb2/group.c [new file with mode: 0644]
servers/slapd/back-bdb2/modify.c
servers/slapd/back-bdb2/modrdn.c
servers/slapd/back-bdb2/proto-back-bdb2.h [new file with mode: 0644]
servers/slapd/back-bdb2/search.c

index da41b7d830746e863724f2b0387ebacd009fb224..5c72225f76e7b9d997fa59314ecd1297fcd25772 100644 (file)
@@ -32,7 +32,8 @@ bdb2i_back_add_internal(
 
        if ( ( bdb2i_dn2id( be, e->e_ndn ) ) != NOID ) {
                entry_free( e );
-               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
+                       NULL, NULL, NULL, NULL );
                return( -1 );
        }
 
@@ -42,7 +43,7 @@ bdb2i_back_add_internal(
 
                entry_free( e );
                send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                return( -1 );
        }
 
@@ -55,19 +56,37 @@ bdb2i_back_add_internal(
        pdn = dn_parent( be, e->e_ndn );
 
        if( pdn != NULL && *pdn != '\0' && !be_issuffix(be, "") ) {
-               char *matched = NULL;
+               Entry *matched = NULL;
 
                assert( *pdn != '\0' );
 
                /* get parent with writer lock */
                if ( (p = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL ) {
-                       Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
-                           0, 0 );
+                       char *matched_dn;
+                       struct berval **refs;
+
+                       if( matched != NULL ) {
+                               matched_dn = ch_strdup( matched->e_dn );
+                               refs = is_entry_referral( matched )
+                                       ? get_entry_referrals( be, conn, op, matched )
+                                       : NULL;
+
+                               bdb2i_cache_return_entry_w( &li->li_cache, matched ); 
+
+                       } else {
+                               matched_dn = NULL;
+                               refs = default_referral;
+                       }
+
+                       Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
+                               0, 0, 0 );
+
                        send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                           matched, NULL, NULL );
+                           matched_dn, NULL, NULL, NULL );
 
                        if ( matched != NULL ) {
-                               free( matched );
+                               ber_bvecfree( refs );
+                               free( matched_dn );
                        }
 
                        entry_free( e );
@@ -77,21 +96,54 @@ bdb2i_back_add_internal(
 
                free(pdn);
 
-               if ( matched != NULL ) {
-                       free( matched );
-               }
-
                if ( ! access_allowed( be, conn, op, p,
                        "children", NULL, ACL_WRITE ) )
                {
+                       /* free parent and writer lock */
+                       bdb2i_cache_return_entry_w( &li->li_cache, p ); 
+
                        Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
                            0, 0 );
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                           NULL, NULL, NULL );
+                           NULL, NULL, NULL, NULL );
+
+                       entry_free( e );
+                       return -1;
+               }
+
+
+               if ( is_entry_alias( p ) ) {
+                       /* parent is an alias, don't allow add */
+
+                       /* free parent and writer lock */
+                       bdb2i_cache_return_entry_w( &li->li_cache, p ); 
+
+                       Debug( LDAP_DEBUG_TRACE, "parent is alias\n", 0,
+                           0, 0 );
+                       send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
+                           NULL, NULL, NULL, NULL );
+
+                       entry_free( e );
+                       return -1;
+               }
+
+               if ( is_entry_referral( p ) ) {
+                       /* parent is an referral, don't allow add */
+                       char *matched_dn = ch_strdup( matched->e_dn );
+                       struct berval **refs = is_entry_referral( matched )
+                                       ? get_entry_referrals( be, conn, op, matched )
+                                       : NULL;
 
                        /* free parent and writer lock */
                        bdb2i_cache_return_entry_w( &li->li_cache, p ); 
 
+                       Debug( LDAP_DEBUG_TRACE, "parent is referral\n", 0,
+                           0, 0 );
+                       send_ldap_result( conn, op, LDAP_REFERRAL,
+                           matched_dn, NULL, refs, NULL );
+
+                       ber_bvecfree( refs );
+                       free( matched_dn );
                        entry_free( e );
                        return -1;
                }
@@ -109,7 +161,7 @@ bdb2i_back_add_internal(
                                0, 0 );
 
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                           NULL, NULL, NULL );
+                           NULL, NULL, NULL, NULL );
 
                        entry_free( e );
                        return -1;
@@ -142,11 +194,9 @@ bdb2i_back_add_internal(
                /* free the entry */
                entry_free( e );
 
-               if(rc > 0) {
-                       send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL, NULL );
-               } else {
-                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
-               }
+               send_ldap_result( conn, op,
+                       rc > 0 ? LDAP_ALREADY_EXISTS : LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL, NULL );
 
                return( -1 );
        }
@@ -162,7 +212,8 @@ bdb2i_back_add_internal(
        if ( bdb2i_id2children_add( be, p, e ) != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "bdb2i_id2children_add failed\n", 0,
                    0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL, NULL );
 
                bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2CHILDREN", conn, op );
 
@@ -182,7 +233,8 @@ bdb2i_back_add_internal(
        if ( bdb2i_index_add_entry( be, e ) != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "bdb2i_index_add_entry failed\n", 0,
                    0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL, NULL );
 
                bdb2i_stop_timing( be->bd_info, time1, "ADD-INDEX", conn, op );
 
@@ -197,7 +249,8 @@ bdb2i_back_add_internal(
        if ( bdb2i_dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "bdb2i_dn2id_add failed\n", 0,
                    0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL, NULL );
 
                bdb2i_stop_timing( be->bd_info, time1, "ADD-DN2ID", conn, op );
 
@@ -213,7 +266,8 @@ bdb2i_back_add_internal(
                Debug( LDAP_DEBUG_TRACE, "bdb2i_id2entry_add failed\n", 0,
                    0, 0 );
                (void) bdb2i_dn2id_delete( be, e->e_ndn );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL, NULL );
 
                bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op );
 
@@ -222,7 +276,8 @@ bdb2i_back_add_internal(
 
        bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op );
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+       send_ldap_result( conn, op, LDAP_SUCCESS,
+                       NULL, NULL, NULL, NULL );
        rc = 0;
 
 return_results:;
@@ -255,10 +310,9 @@ bdb2_back_add(
        bdb2i_start_timing( be->bd_info, &time1 );
 
        if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
-
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                       NULL, NULL, NULL, NULL );
                return( -1 );
-
        }
 
        /*  check, if a new default attribute index will be created,
index 107b5bc9841c3c7a1460c8a8db1168a7b3677114..89834748fd2d53a8030ff4b3c8903467526acae0 100644 (file)
@@ -1,13 +1,6 @@
 /*
- * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and that due credit is given
- * to ITSD, Government of BC. The name of ITSD
- * may not be used to endorse or promote products derived from this
- * software without specific prior written permission. This software
- * is provided ``as is'' without express or implied warranty.
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 
 #include "portable.h"
 #include "back-bdb2.h"
 #include "proto-back-bdb2.h"
 
-/*
- * given an alias object, dereference it to its end point.
- * Entry returned has reader lock or is NULL.  Starting entry is not released.
- */
-Entry *bdb2i_derefAlias_r ( BackendDB     *be,
-                   Connection  *conn,
-                   Operation   *op,
-                   Entry       *e)
+static char* get_alias_dn(
+       Entry *e,
+       int *err,
+       char **errmsg );
+
+static char* new_superior(
+       char *dn,
+       char *oldSup,
+       char *newSup );
+
+static int dnlist_subordinate(
+       char** dnlist,
+       char *dn );
+
+Entry *bdb2i_deref_r(
+       Backend*        be,
+       Entry*          alias,
+       char*           dn,
+       int*            err,
+       Entry**         matched,
+       char**          text )
 {
-  /* to free cache entries */
-  struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-  Attribute *a;
-  int       depth;
-  char      *matched;
-  Entry     *origDN = e;
-
-  if (!e) return NULL;  /* be sure we have a starting entry */
-
-  Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );
-
-  /*
-   * try to deref fully, up to a maximum depth.  If the max depth exceeded
-   * then send an error
-   */
-  for ( depth = 0;
-       ( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
-         ( depth < be->be_maxDerefDepth );
-       ++depth) 
-  {
-
-    /* 
-     * make sure there is a defined aliasedobjectname.  
-     * can only have one value so just use first value (0) in the attr list. 
-     */            
-    if (a->a_vals[0] && a->a_vals[0]->bv_val) {
-      char *newDN, *oldDN;
-
-      Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", 
-            e->e_dn, a->a_vals[0]->bv_val, 0 );
-      newDN = ch_strdup (a->a_vals[0]->bv_val);
-      oldDN = ch_strdup (e->e_ndn);
-
-      /* 
-       * release past lock if not original
-       */
-      if ( (depth > 0) && e ) {
-          bdb2i_cache_return_entry_r(&li->li_cache, e);        
-      }
-
-      /* make sure new and old DN are not same to avoid loops */
-      dn_normalize_case (newDN);
-      if ( strcmp (newDN, oldDN) == 0 ) {
-       
-               Debug( LDAP_DEBUG_TRACE, 
-               "<= %s alias is same as current %s\n", 
-               oldDN, newDN, 0 );
-               send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
-                       NULL, "circular alias", NULL );
-               free (newDN);
-               free (oldDN);
-               break;
-      }
-
-      /* make sure new and original are not same to avoid deadlocks */
-      if ( strcmp (newDN, origDN->e_ndn) == 0 ) {
-               Debug( LDAP_DEBUG_TRACE, 
-               "<= %s alias is same as original %s\n", 
-               oldDN, origDN->e_ndn, 0 );
-               send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
-                       NULL, "circular alias", NULL );
-               free (newDN);
-               free (oldDN);
-               break;
-      }
-
-      /*
-       * ok, so what happens if there is an alias in the DN of a dereferenced
-       * alias object?  
-       */
-      if ( (e = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL ) {
-               /* could not deref return error  */
-               Debug( LDAP_DEBUG_TRACE, 
-               "<= %s is a dangling alias to %s\n", 
-               oldDN, newDN, 0 );
-               send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
-                       NULL, "dangling alias", NULL );
-
-                       if(matched != NULL) free(matched);
-       free (newDN);
-       free (oldDN);
-               break;
-      }
-
-      free (newDN);
-      free (oldDN);
-    }
-    else {
-      /*
-       * there was an aliasedobjectname defined but no data.
-       * this can't happen, right?
-       */
-               Debug( LDAP_DEBUG_TRACE, 
-               "<= %s has no data in aliasedobjectname attribute\n", 
-               (e && e->e_dn) ? e->e_dn : "(null)", 0, 0 );
-               send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
-                       NULL, "alias missing aliasedObjectname", NULL );
-               break;
-    }
-  }
-
-  /*
-   * warn if we pulled out due to exceeding the maximum deref depth
-   */
-  if ( depth >= be->be_maxDerefDepth ) {
-    Debug( LDAP_DEBUG_TRACE, 
-          "<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n", 
-          origDN->e_dn ? origDN->e_dn : "(null)",
-               be->be_maxDerefDepth,
-               (e && e->e_ndn) ? e->e_ndn : "(null)");
-    send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
-               NULL, "maximum alias dereference depth exceeded", NULL );
-  }
-
-  return e;
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       Entry *entry;
+       Entry *sup;
+       unsigned depth;
+       char **dnlist;
+
+       assert( ( alias != NULL && dn == NULL ) || ( alias == NULL && dn != NULL ) );
+
+       *matched = NULL;
+       *err = LDAP_SUCCESS;
+       *text = NULL;
+
+       if( alias == NULL ) {
+               dn = ch_strdup( dn );
+               entry = bdb2i_dn2entry_r( be, dn, &sup );
+
+       } else {
+               dn = ch_strdup( alias->e_ndn );
+               entry = alias;
+               sup = NULL;
+       }
+
+       dnlist = NULL;
+       charray_add( &dnlist, dn );
+
+       for( depth=0 ; ; depth++ ) {
+               if( entry != NULL ) {
+                       Entry *newe;
+                       char *aliasDN;
+
+                       /* have entry, may be an alias */
+
+                       if( !is_entry_alias( entry ) ) {
+                               /* entry is not an alias */
+                               break;
+                       }
+
+                       /* entry is alias */
+                       if( depth > be->be_max_deref_depth ) {
+                               *matched = entry;
+                               entry = NULL;
+                               *err = LDAP_ALIAS_DEREF_PROBLEM;
+                               *text = "maximum deref depth exceeded";
+                               break;
+                       }
+
+                       /* deref entry */
+                       aliasDN = get_alias_dn( entry, err, text );
+
+                       if( aliasDN == NULL ) {
+                               *matched = entry;
+                               entry = NULL;
+                               break;
+                       }
+
+                       /* check if aliasDN is a subordinate of any DN in our list */
+                       if( dnlist_subordinate( dnlist, aliasDN ) ) {
+                               *matched = entry;
+                               entry = NULL;
+                               *err = LDAP_ALIAS_PROBLEM;
+                               *text = "circular alias";
+                               break;
+                       }
+
+                       /* attempt to dereference alias */
+
+                       newe = bdb2i_dn2entry_r( be, aliasDN, &sup );
+
+                       if( newe != NULL ) {
+                               free( dn );
+                               bdb2i_cache_return_entry_r(&li->li_cache, entry );
+                               entry = newe;
+                               dn = ch_strdup( entry->e_ndn );
+                               charray_add( &dnlist, dn );
+                               continue;
+
+                       }
+                       
+                       if ( sup != NULL ) {
+                               bdb2i_cache_return_entry_r(&li->li_cache, entry );
+                               entry = NULL;
+                               continue;
+                       }
+
+                       /* no newe and no superior, we're done */
+                       break;
+
+               } else if( sup != NULL ) {
+                       /* have superior, may be an alias */
+                       Entry *newe;
+                       Entry *newSup;
+                       char *supDN;
+                       char *aliasDN;
+
+                       if( !is_entry_alias( sup ) ) {
+                               /* entry is not an alias */
+                               *matched = sup;
+                               sup = NULL;
+                               break;
+                       }
+
+                       /* entry is alias */
+                       if( depth > be->be_max_deref_depth ) {
+                               *matched = sup;
+                               entry = NULL;
+                               *err = LDAP_ALIAS_DEREF_PROBLEM;
+                               *text = "maximum deref depth exceeded";
+                               break;
+                       }
+
+                       /* deref entry */
+                       supDN = get_alias_dn( sup, err, text );
+
+                       if( supDN == NULL ) {
+                               *matched = sup;
+                               break;
+                       }
+
+                       aliasDN = new_superior( dn, sup->e_ndn, supDN );
+
+                       if( aliasDN == NULL ) {
+                               free(aliasDN);
+                               *matched = sup;
+                               *err = LDAP_ALIAS_PROBLEM;
+                               *text = "superior alias problem";
+                               break;
+                       }
+
+                       /* check if aliasDN is a subordinate of any DN in our list */
+                       if( dnlist_subordinate( dnlist, aliasDN ) ) {
+                               free(aliasDN);
+                               *matched = entry;
+                               entry = NULL;
+                               *err = LDAP_ALIAS_PROBLEM;
+                               *text = "subordinate circular alias";
+                               break;
+                       }
+
+                       /* attempt to dereference alias */
+                       newe = bdb2i_dn2entry_r( be, aliasDN, &newSup );
+
+                       if( newe != NULL ) {
+                               free(aliasDN);
+                               free( dn );
+                               bdb2i_cache_return_entry_r(&li->li_cache, sup );
+                               entry = newe;
+                               dn = ch_strdup( entry->e_ndn );
+                               charray_add( &dnlist, dn );
+                               continue;
+
+                       }
+                       
+                       if ( newSup != NULL ) {
+                               free( dn );
+                               bdb2i_cache_return_entry_r(&li->li_cache, sup );
+                               sup = newSup;
+                               dn = aliasDN;
+                               continue;
+                       }
+
+                       break;
+
+               } else {
+                       /* no newe and no superior, we're done */
+                       break;
+               }
+       }
+
+       free( dn );
+       return entry;
 }
 
-/*
- * given a DN fully deref it and return the real DN or original DN if it fails
- * This involves finding the last matched part then reconstructing forward
- * e.g. 
- * ou=MyOU,o=MyAliasedOrg,c=MyCountry where o=MyAliasedOrg is an alias for o=MyOrg
- * loop starts with newDN = ou=MyOU,o=MyAliasedOrg,c=MyCountry
- *   dn2entry_r on newDN gives null entry and o=MyAliasedOrg,c=MyCountry matched
- *   dn2entry_r on matched gives o=MyAliasedOrg,c=MyCountry entry
- *   remainder is ou=MyOU
- *   dereferencing o=MyAliasedOrg,c=MyCountry yields entry o=MyOrg,c=MyCountry
- *   release lock on o=MyAliasedOrg,c=MyCountry entry
- *   reconstructed dn is ou=MyOU,o=MyOrg,c=MyCountry
- *   release lock on o=MyOrg,c=MyCountry entry
- */
-char *bdb2i_derefDN ( BackendDB     *be,
-                Connection  *conn,
-                Operation   *op,
-                char        *dn
-)
-{
-  struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-  char         *matched = 0;
-  char         *newDN = NULL;
-  int  depth, i;
-  Entry        *eMatched;
-  Entry        *eDeref;
-  Entry         *eNew;
-  
-  if (!dn) return NULL;
-
-  Debug( LDAP_DEBUG_TRACE, 
-        "<= dereferencing dn: \"%s\"\n", 
-        dn, 0, 0 );
-  
-  newDN = ch_strdup ( dn );
-
-  /* while we don't have a matched dn, deref the DN */
-  for ( depth = 0;
-       ( (eMatched = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL) &&
-         (depth < be->be_maxDerefDepth);
-       ++depth ) {
-    
-    if ((matched != NULL) && *matched) {       
-      char *submatch;
-      
-      /* 
-       * make sure there actually is an entry for the matched part 
-       */
-      if ( (eMatched = bdb2i_dn2entry_r( be, matched, &submatch )) != NULL) {
-       char  *remainder; /* part before the aliased part */
-       int  rlen = strlen(newDN) - strlen(matched);
-       
-       Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
-       
-       remainder = ch_malloc (rlen + 1);
-       strncpy ( remainder, newDN, rlen );
-       remainder[rlen] = '\0';
-       
-       Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
-       
-       if ((eNew = bdb2i_derefAlias_r( be, conn, op, eMatched )) == NULL) {
-         free (matched);
-         matched = NULL;
-         free (newDN);
-         newDN = NULL;
-         free (remainder);
-         remainder = NULL;
-
-               bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
-               eMatched = NULL;
-         break; /*  no associated entry, dont deref */
+
+static char* get_alias_dn(
+       Entry *e,
+       int *err,
+       char **errmsg )
+{      
+       Attribute *a = attr_find( e->e_attrs, "aliasedobjectname" );
+
+       if( a == NULL ) {
+               /*
+                * there was an aliasedobjectname defined but no data.
+                */
+               *err = LDAP_ALIAS_PROBLEM;
+               *errmsg = "alias missing aliasedObjectName attribute";
+               return NULL;
        }
-       else {
-
-         Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );
-
-         i = strcasecmp (matched, eNew->e_dn);
-          /* free reader lock */
-          bdb2i_cache_return_entry_r(&li->li_cache, eNew);
-
-               free (matched);
-               matched = NULL;
-
-         if (! i) {
-           /* newDN same as old so not an alias, no need to go further */
-           free (newDN);
-           newDN = NULL;
-           free (remainder);
-
-               bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
-               eMatched = NULL;
-           break;
-         }
-
-         /* 
-          * we have dereferenced the aliased part so put
-          * the new dn together
-          */
-         free (newDN);
-         newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
-         strcpy (newDN, remainder);
-         strcat (newDN, eMatched->e_dn);
-         Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
-
-         free (remainder);
+
+       /* 
+        * aliasedObjectName should be SINGLE-VALUED with a single value. 
+        */                     
+       if ( a->a_vals[0] == NULL || a->a_vals[0]->bv_val != NULL ) {
+               /*
+                * there was an aliasedobjectname defined but no data.
+                */
+               *err = LDAP_ALIAS_PROBLEM;
+               *errmsg = "alias missing aliasedObjectName value";
+               return NULL;
        }
-        /* free reader lock */
-        bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
-      }
-      else {
-       if(submatch != NULL) free(submatch);
-       break; /* there was no entry for the matched part */
-      }
-    }
-    else {
-      break; /* there was no matched part */
-    }
-  }
-  
-       /* release lock if a match terminated the loop, there should be no
-        * outstanding locks at this point
-        */
-  if(eMatched != NULL) {
-    /* free reader lock */
-    bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
-  }
-
-  /*
-   * the final part of the DN might be an alias so try to dereference it.
-   * e.g. if we had started with dn = o=MyAliasedOrg,c=MyCountry the dn would match
-   * and the above loop complete but we would still be left with an aliased DN.
-   */
-  if (newDN != NULL) {
-    if ( (eNew = bdb2i_dn2entry_r( be, newDN, &matched )) != NULL) {
-      if ((eDeref = bdb2i_derefAlias_r( be, conn, op, eNew )) != NULL) {
-        free (newDN);
-        newDN = ch_strdup (eDeref->e_dn);
-        /* free reader lock */
-        bdb2i_cache_return_entry_r(&li->li_cache, eDeref);
-      }
-      /* free reader lock */
-      bdb2i_cache_return_entry_r(&li->li_cache, eNew);
-    }
-  }
-       if (matched != NULL) free(matched);
-  
-  /*
-   * warn if we exceeded the max depth as the resulting DN may not be dereferenced
-   */
-  if (depth >= be->be_maxDerefDepth) {
-       if (newDN) {
-       Debug( LDAP_DEBUG_TRACE, 
-               "<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n", 
-               dn, newDN, 0 );
-               free (newDN);
-               newDN = NULL;
-       } else {
-               Debug( LDAP_DEBUG_TRACE,
-                       "<= max deref depth exceeded in derefDN for \"%s\", result NULL\n",
-                       dn, 0, 0 );
+
+       if( a->a_vals[1] != NULL ) {
+               *err = LDAP_ALIAS_PROBLEM;
+               *errmsg = "alias has multivalued aliasedObjectName";
+               return NULL;
        }
-    send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM,
-               NULL, "maximum alias dereference depth exceeded for base", NULL );
-  }
 
-  if (newDN == NULL) {
-    newDN = ch_strdup ( dn );
-  }
-  
-  Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 ); 
+       return a->a_vals[0]->bv_val;
+}
+
+static char* new_superior(
+       char *dn,
+       char *oldSup,
+       char *newSup )
+{
+       char *newDN;
+       size_t dnlen, olen, nlen;
+       assert( dn && oldSup && newSup );
+
+       dnlen = strlen( dn );
+       olen = strlen( oldSup );
+       nlen = strlen( newSup );
+
+       newDN = ch_malloc( dnlen - olen + nlen + 1 );
+
+       memcpy( newDN, dn, dnlen - olen );
+       memcpy( &newDN[dnlen - olen], newSup, nlen );
+       newDN[dnlen - olen + nlen] = '\0';
 
-  return newDN;
+       return newDN;
 }
+
+static int dnlist_subordinate(
+       char** dnlist,
+       char *dn )
+{
+       int i;
+       assert( dnlist );
+
+       for( i = 0; dnlist[i] != NULL; i++ ) {
+               if( dn_issuffix( dnlist[i], dn ) ) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
index 6bb6006b9e53b5fe5fa9d976a3c875212f028389..5f2ae0d9a268afcfe1b4347a8d2e303454381de0 100644 (file)
@@ -74,7 +74,7 @@ bdb2i_back_bind_internal(
        Entry           *e;
        Attribute       *a;
        int             rc;
-       char            *matched;
+       Entry           *matched;
 #ifdef HAVE_KERBEROS
        char            krbname[MAX_K_NAME_SZ + 1];
        AUTH_DAT        ad;
@@ -86,12 +86,26 @@ bdb2i_back_bind_internal(
 
        /* get entry with reader lock */
        if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) {
+               char *matched_dn = NULL;
+               struct berval **refs = NULL;
+
+               if ( matched != NULL ) {
+                       matched_dn = ch_strdup( matched->e_dn );
+                       refs = is_entry_referral( matched )
+                               ? get_entry_referrals( be, conn, op, matched )
+                               : NULL;
+                       bdb2i_cache_return_entry_r( &li->li_cache, matched );
+               } else {
+                       refs = default_referral;
+               }
+
                /* allow noauth binds */
                rc = 1;
                if ( method == LDAP_AUTH_SIMPLE ) {
                        if( cred->bv_len == 0 ) {
                                /* SUCCESS */
-                               send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+                               send_ldap_result( conn, op, LDAP_SUCCESS,
+                                       NULL, NULL, NULL, NULL );
 
                        } else if ( be_isroot_pw( be, dn, cred ) ) {
                                /* front end will send result */
@@ -99,28 +113,30 @@ bdb2i_back_bind_internal(
                                rc = 0;
 
                        } else {
-                               send_ldap_result( conn, op,
-                                       LDAP_NO_SUCH_OBJECT, matched, NULL, NULL );
+                               send_ldap_result( conn, op, LDAP_REFERRAL,
+                                       matched_dn, NULL, refs, NULL );
                        }
 
                } else if ( method == LDAP_AUTH_SASL ) {
                        if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) {
                                /* insert DIGEST calls here */
-                               send_ldap_result( conn, op,
-                                       LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, NULL, NULL );
+                               send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
+                                       NULL, NULL, NULL, NULL );
 
                        } else {
-                               send_ldap_result( conn, op,
-                                       LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, NULL, NULL );
+                               send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
+                                       NULL, NULL, NULL, NULL );
                        }
 
                } else {
-                       send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                               matched, NULL, NULL );
+                       send_ldap_result( conn, op, LDAP_REFERRAL,
+                               matched_dn, NULL, refs, NULL );
                        rc = 1;
                }
+
                if ( matched != NULL ) {
-                       free( matched );
+                       ber_bvecfree( refs );
+                       free( matched_dn );
                }
                return( rc );
        }
@@ -133,7 +149,37 @@ bdb2i_back_bind_internal(
                "entry", NULL, ACL_AUTH ) )
        {
                send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
+               rc = 1;
+               goto return_results;
+       }
+
+       if ( is_entry_alias( e ) ) {
+               /* entry is a alias, don't allow bind */
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                       0, 0 );
+
+               send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
+                       NULL, NULL, NULL, NULL );
+
+               rc = 1;
+               goto return_results;
+       }
+
+
+       if ( is_entry_referral( e ) ) {
+               /* entry is a referral, don't allow bind */
+               struct berval **refs = get_entry_referrals( be,
+                       conn, op, e );
+
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                       0, 0 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       e->e_dn, NULL, refs, NULL );
+
+               ber_bvecfree( refs );
+
                rc = 1;
                goto return_results;
        }
@@ -141,7 +187,8 @@ bdb2i_back_bind_internal(
        switch ( method ) {
        case LDAP_AUTH_SIMPLE:
                if ( cred->bv_len == 0 ) {
-                       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+                       send_ldap_result( conn, op, LDAP_SUCCESS,
+                               NULL, NULL, NULL, NULL );
 
                        /* stop front end from sending result */
                        rc = 1;
@@ -161,14 +208,14 @@ bdb2i_back_bind_internal(
                        "userpassword", NULL, ACL_AUTH ) )
                {
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL);
+                               NULL, NULL, NULL, NULL);
                        rc = 1;
                        goto return_results;
                }
 
                if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
                        send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
-                               NULL, NULL, NULL);
+                               NULL, NULL, NULL, NULL);
 
                        /* stop front end from sending result */
                        rc = 1;
@@ -178,7 +225,7 @@ bdb2i_back_bind_internal(
                if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 )
                {
                        send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
-                               NULL, NULL, NULL);
+                               NULL, NULL, NULL, NULL);
                        /* stop front end from sending result */
                        rc = 1;
                        goto return_results;
@@ -190,7 +237,7 @@ bdb2i_back_bind_internal(
        case LDAP_AUTH_KRBV41:
                if ( bdb2i_krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
                        send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
-                               NULL, NULL, NULL);
+                               NULL, NULL, NULL, NULL);
                        rc = 1;
                        goto return_results;
                }
@@ -199,7 +246,7 @@ bdb2i_back_bind_internal(
                        "krbname", NULL, ACL_AUTH ) )
                {
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL);
+                               NULL, NULL, NULL, NULL);
                        rc = 1;
                        goto return_results;
                }
@@ -216,7 +263,7 @@ bdb2i_back_bind_internal(
                                break;
                        }
                        send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
-                               NULL, NULL, NULL);
+                               NULL, NULL, NULL, NULL);
                        rc = 1;
                        goto return_results;
                } else {        /* look for krbName match */
@@ -227,7 +274,7 @@ bdb2i_back_bind_internal(
 
                        if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) {
                                send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
-                                       NULL, NULL, NULL);
+                                       NULL, NULL, NULL, NULL);
                                rc = 1;
                                goto return_results;
                        }
@@ -236,7 +283,8 @@ bdb2i_back_bind_internal(
                break;
 
        case LDAP_AUTH_KRBV42:
-               send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_SUCCESS,
+                       NULL, NULL, NULL, NULL );
                /* stop front end from sending result */
                rc = 1;
                goto return_results;
@@ -247,7 +295,7 @@ bdb2i_back_bind_internal(
 
        default:
                send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
-                   NULL, "auth method not supported", NULL );
+                   NULL, "auth method not supported", NULL, NULL );
                rc = 1;
                goto return_results;
        }
@@ -282,7 +330,7 @@ bdb2_back_bind(
 
        if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                return( 1 );
        }
 
index 0da11c9194681c2c8cb78a85c5dd00b6451ba273..f2fa1dd164f82db2250f9aa8976a5d66ecadae92 100644 (file)
@@ -21,43 +21,77 @@ bdb2i_back_compare_internal(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char            *matched;
+       Entry           *matched;
        Entry           *e;
        Attribute       *a;
        int             rc;
+       int             manageDSAit = get_manageDSAit( op );
 
        /* get entry with reader lock */
        if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                       matched, NULL, NULL );
+               char *matched_dn = NULL;
+               struct berval **refs = NULL;
+
+               if ( matched != NULL ) {
+                       matched_dn = ch_strdup( matched->e_dn );
+                       refs = is_entry_referral( matched )
+                               ? get_entry_referrals( be, conn, op, matched )
+                               : NULL;
+                       bdb2i_cache_return_entry_r( &li->li_cache, matched );
+               } else {
+                       refs = default_referral;
+               }
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       matched_dn, NULL, refs, NULL );
+
+               if( matched != NULL ) {
+                       ber_bvecfree( refs );
+                       free( matched_dn );
+               }
 
-               if(matched == NULL) free(matched);
                return( 1 );
        }
 
-       /* check for deleted */
+       if (!manageDSAit && is_entry_referral( e ) ) {
+               /* entry is a referral, don't allow add */
+               struct berval **refs = get_entry_referrals( be,
+                       conn, op, e );
+
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                       0, 0 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       e->e_dn, NULL, refs, NULL );
+
+               ber_bvecfree( refs );
+
+               rc = 1;
+               goto return_results;
+       }
+
        if ( ! access_allowed( be, conn, op, e,
                ava->ava_type, &ava->ava_value, ACL_COMPARE ) )
        {
                send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                rc = 1;
                goto return_results;
        }
 
        if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
                send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                rc = 1;
                goto return_results;
        }
 
        if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 ) 
                send_ldap_result( conn, op, LDAP_COMPARE_TRUE,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
        else
                send_ldap_result( conn, op, LDAP_COMPARE_FALSE,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
 
        rc = 0;
 
@@ -86,7 +120,7 @@ bdb2_back_compare(
        if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
 
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                return( 1 );
 
        }
index 04a508afe0ded465ad7e31401549a712fb7a85b4..ca36c2bacff0501616aa555c0be664263ef8c533 100644 (file)
@@ -20,32 +20,63 @@ bdb2i_back_delete_internal(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char    *matched = NULL;
+       Entry   *matched = NULL;
        char    *pdn = NULL;
        Entry   *e, *p = NULL;
-       int     rc = -1;
+       int     rc = -1, manageDSAit;
 
        Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_delete: %s\n", dn, 0, 0);
 
        /* get entry with writer lock */
        if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
+               char *matched_dn = NULL;
+               struct berval **refs = NULL;
+
                Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: no such object %s\n",
                        dn, 0, 0);
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                       matched, NULL, NULL );
+
                if ( matched != NULL ) {
-                       free( matched );
+                       matched_dn = ch_strdup( matched->e_dn );
+                       refs = is_entry_referral( matched )
+                               ? get_entry_referrals( be, conn, op, matched )
+                               : NULL;
+                       bdb2i_cache_return_entry_r( &li->li_cache, matched );
+               } else {
+                       refs = default_referral;
                }
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       matched_dn, NULL, refs, NULL );
+
+               if( matched != NULL ) {
+                       ber_bvecfree( refs );
+                       free( matched_dn );
+               }
+
                return( -1 );
        }
 
-       /* check for deleted */
+       if (!manageDSAit && is_entry_referral( e ) ) {
+               /* entry is a referral, don't allow add */
+               struct berval **refs = get_entry_referrals( be,
+                       conn, op, e );
+
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                       0, 0 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       e->e_dn, NULL, refs, NULL );
+
+               ber_bvecfree( refs );
+               goto return_results;
+       }
+
 
        if ( bdb2i_has_children( be, e ) ) {
                Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: non leaf %s\n",
                        dn, 0, 0);
                send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 
@@ -57,7 +88,7 @@ bdb2i_back_delete_internal(
                        "<=- bdb2i_back_delete: insufficient access %s\n",
                        dn, 0, 0);
                send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 #endif
@@ -68,7 +99,7 @@ bdb2i_back_delete_internal(
                        Debug( LDAP_DEBUG_TRACE,
                                "<=- bdb2i_back_delete: parent does not exist\n", 0, 0, 0);
                        send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
 
@@ -79,7 +110,7 @@ bdb2i_back_delete_internal(
                        Debug( LDAP_DEBUG_TRACE,
                                "<=- bdb2i_back_delete: no access to parent\n", 0, 0, 0 );
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
 
@@ -89,7 +120,7 @@ bdb2i_back_delete_internal(
                        Debug( LDAP_DEBUG_TRACE,
                                "<=- bdb2i_back_delete: no parent & not root\n", 0, 0, 0);
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
        }
@@ -99,7 +130,7 @@ bdb2i_back_delete_internal(
                        "<=- bdb2i_back_delete: operations error %s\n",
                        dn, 0, 0);
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                goto return_results;
        }
 
@@ -109,7 +140,7 @@ bdb2i_back_delete_internal(
                        "<=- bdb2i_back_delete: operations error %s\n",
                        dn, 0, 0);
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                               NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 
@@ -119,11 +150,12 @@ bdb2i_back_delete_internal(
                        "<=- bdb2i_back_delete: operations error %s\n",
                        dn, 0, 0);
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                               NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+       send_ldap_result( conn, op, LDAP_SUCCESS,
+               NULL, NULL, NULL, NULL );
        rc = 0;
 
 return_results:;
@@ -161,9 +193,8 @@ bdb2_back_delete(
 
        if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                return( -1 );
-
        }
 
        ret = bdb2i_back_delete_internal( be, conn, op, dn );
diff --git a/servers/slapd/back-bdb2/dn2id.c b/servers/slapd/back-bdb2/dn2id.c
new file mode 100644 (file)
index 0000000..e77cabf
--- /dev/null
@@ -0,0 +1,206 @@
+/* dn2id.c - routines to deal with the dn2id index */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+int
+bdb2i_dn2id_add(
+    BackendDB  *be,
+    char       *dn,
+    ID         id
+)
+{
+       int             rc, flags;
+       struct dbcache  *db;
+       Datum           key, data;
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+       ldbm_datum_init( key );
+       ldbm_datum_init( data );
+
+       Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id_add( \"%s\", %ld )\n", dn, id, 0 );
+
+       if ( (db = bdb2i_cache_open( be, "dn2id", BDB2_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "Could not open/create dn2id%s\n",
+                   BDB2_SUFFIX, 0, 0 );
+               return( -1 );
+       }
+
+       dn = ch_strdup( dn );
+       dn_normalize_case( dn );
+
+       key.dptr = dn;
+       key.dsize = strlen( dn ) + 1;
+       data.dptr = (char *) &id;
+       data.dsize = sizeof(ID);
+
+       flags = LDBM_INSERT;
+       if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
+
+       rc = bdb2i_cache_store( db, key, data, flags );
+
+       free( dn );
+       bdb2i_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id_add %d\n", rc, 0, 0 );
+       return( rc );
+}
+
+ID
+bdb2i_dn2id(
+    BackendDB  *be,
+    char       *dn
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct dbcache  *db;
+       ID              id;
+       Datum           key, data;
+
+       ldbm_datum_init( key );
+       ldbm_datum_init( data );
+
+       dn = ch_strdup( dn );
+       Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id( \"%s\" )\n", dn, 0, 0 );
+       dn_normalize_case( dn );
+
+       /* first check the cache */
+       if ( (id = bdb2i_cache_find_entry_dn2id( be, &li->li_cache, dn )) != NOID ) {
+               free( dn );
+               Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id %ld (in cache)\n", id,
+                       0, 0 );
+               return( id );
+       }
+
+       if ( (db = bdb2i_cache_open( be, "dn2id", BDB2_SUFFIX, LDBM_WRCREAT ))
+               == NULL ) {
+               free( dn );
+               Debug( LDAP_DEBUG_ANY, "<= bdb2i_dn2id could not open dn2id%s\n",
+                       BDB2_SUFFIX, 0, 0 );
+               return( NOID );
+       }
+
+       key.dptr = dn;
+       key.dsize = strlen( dn ) + 1;
+
+       data = bdb2i_cache_fetch( db, key );
+
+       bdb2i_cache_close( be, db );
+       free( dn );
+
+       if ( data.dptr == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id NOID\n", 0, 0, 0 );
+               return( NOID );
+       }
+
+       (void) memcpy( (char *) &id, data.dptr, sizeof(ID) );
+
+       ldbm_datum_free( db->dbc_db, data );
+
+       Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id %ld\n", id, 0, 0 );
+       return( id );
+}
+
+int
+bdb2i_dn2id_delete(
+    BackendDB  *be,
+    char       *dn
+)
+{
+       struct dbcache  *db;
+       Datum           key;
+       int             rc;
+
+       ldbm_datum_init( key );
+
+       Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id_delete( \"%s\" )\n", dn, 0, 0 );
+
+       if ( (db = bdb2i_cache_open( be, "dn2id", BDB2_SUFFIX, LDBM_WRCREAT ))
+           == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                   "<= bdb2i_dn2id_delete could not open dn2id%s\n", BDB2_SUFFIX,
+                   0, 0 );
+               return( -1 );
+       }
+
+       dn = ch_strdup( dn );
+       dn_normalize_case( dn );
+       key.dptr = dn;
+       key.dsize = strlen( dn ) + 1;
+
+       rc = bdb2i_cache_delete( db, key );
+
+       free( dn );
+
+       bdb2i_cache_close( be, db );
+
+       Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id_delete %d\n", rc, 0, 0 );
+       return( rc );
+}
+
+/*
+ * dn2entry - look up dn in the cache/indexes and return the corresponding
+ * entry.
+ */
+
+Entry *
+bdb2i_dn2entry_rw(
+    BackendDB  *be,
+    char       *dn,
+    Entry      **matched,
+    int         rw
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       ID              id;
+       Entry           *e = NULL;
+       char            *pdn;
+
+       Debug(LDAP_DEBUG_TRACE, "dn2entry_%s: dn: \"%s\"\n",
+               rw ? "w" : "r", dn, 0);
+
+       if( matched != NULL ) {
+               /* caller cares about match */
+               *matched = NULL;
+       }
+
+       if ( (id = bdb2i_dn2id( be, dn )) != NOID &&
+               (e = bdb2i_id2entry_rw( be, id, rw )) != NULL )
+       {
+               return( e );
+       }
+
+       if ( id != NOID ) {
+               Debug(LDAP_DEBUG_ANY,
+                       "dn2entry_%s: no entry for valid id (%ld), dn \"%s\"\n",
+                       rw ? "w" : "r", id, dn);
+               /* must have been deleted from underneath us */
+               /* treat as if NOID was found */
+       }
+
+       /* caller doesn't care about match */
+       if( matched == NULL ) return NULL;
+
+       /* entry does not exist - see how much of the dn does exist */
+       /* dn_parent checks returns NULL if dn is suffix */
+       if ( (pdn = dn_parent( be, dn )) != NULL ) {
+               /* get entry with reader lock */
+               if ( (e = bdb2i_dn2entry_r( be, pdn, matched )) != NULL ) {
+                       *matched = e;
+               }
+               free( pdn );
+       }
+
+       return( NULL );
+}
+
+
diff --git a/servers/slapd/back-bdb2/group.c b/servers/slapd/back-bdb2/group.c
new file mode 100644 (file)
index 0000000..6e39375
--- /dev/null
@@ -0,0 +1,181 @@
+/* group.c - bdb2 backend acl group routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+
+/* return 0 IFF op_dn is a value in member attribute
+ * of entry with gr_dn AND that entry has an objectClass
+ * value of groupOfNames
+ */
+static int
+bdb2i_back_group_internal(
+       BackendDB       *be,
+       Entry   *target,
+       char    *gr_ndn,
+       char    *op_ndn,
+       char    *objectclassValue,
+       char    *groupattrName
+)
+{
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;    
+       Entry *e;
+       int rc = 1;
+       Attribute *attr;
+       struct berval bv;
+
+       Debug( LDAP_DEBUG_ARGS,
+               "=> bdb2i_back_group: gr dn: \"%s\"\n",
+               gr_ndn, 0, 0 ); 
+       Debug( LDAP_DEBUG_ARGS,
+               "=> bdb2i_back_group: op dn: \"%s\"\n",
+               op_ndn, 0, 0 ); 
+       Debug( LDAP_DEBUG_ARGS,
+               "=> bdb2i_back_group: objectClass: \"%s\" attrName: \"%s\"\n", 
+               objectclassValue, groupattrName, 0 ); 
+
+       Debug( LDAP_DEBUG_ARGS,
+               "=> bdb2i_back_group: tr dn: \"%s\"\n",
+               target->e_ndn, 0, 0 ); 
+
+       if (strcmp(target->e_ndn, gr_ndn) == 0) {
+               /* we already have a LOCKED copy of the entry */
+               e = target;
+               Debug( LDAP_DEBUG_ARGS,
+                       "=> bdb2i_back_group: target is group: \"%s\"\n",
+                       gr_ndn, 0, 0 ); 
+
+       } else {
+               /* can we find group entry with reader lock */
+               if ((e = bdb2i_dn2entry_r(be, gr_ndn, NULL )) == NULL) {
+                       Debug( LDAP_DEBUG_ACL,
+                               "=> bdb2i_back_group: cannot find group: \"%s\"\n",
+                                       gr_ndn, 0, 0 ); 
+                       return( 1 );
+               }
+
+               Debug( LDAP_DEBUG_ACL,
+                       "=> bdb2i_back_group: found group: \"%s\"\n",
+                       gr_ndn, 0, 0 ); 
+       }
+
+       /* find it's objectClass and member attribute values
+        * make sure this is a group entry
+        * finally test if we can find op_dn in the member attribute value list
+        */
+        
+       rc = 1;
+
+       if ((attr = attr_find(e->e_attrs, "objectclass")) == NULL)  {
+               Debug( LDAP_DEBUG_ACL,
+                       "<= bdb2i_back_group: failed to find objectClass\n", 0, 0, 0 ); 
+               goto return_results;
+       }
+
+       bv.bv_val = "ALIAS";
+       bv.bv_len = sizeof("ALIAS")-1;
+
+       if (value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
+               Debug( LDAP_DEBUG_ACL,
+                       "<= bdb2i_back_group: group is an alias\n", 0, 0, 0 ); 
+               goto return_results;
+       }
+
+       bv.bv_val = "REFERRAL";
+       bv.bv_len = sizeof("REFERRAL")-1;
+
+       if (value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
+               Debug( LDAP_DEBUG_ACL,
+                       "<= bdb2i_back_group: group is a referral\n", 0, 0, 0 ); 
+               goto return_results;
+       }
+
+       bv.bv_val = objectclassValue;
+       bv.bv_len = strlen( bv.bv_val );
+
+       if (value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
+               Debug( LDAP_DEBUG_ACL,
+                       "<= bdb2i_back_group: failed to find %s in objectClass\n",
+                       objectclassValue, 0, 0 ); 
+               goto return_results;
+       }
+
+       if ((attr = attr_find(e->e_attrs, groupattrName)) == NULL) {
+               Debug( LDAP_DEBUG_ACL,
+                       "<= bdb2i_back_group: failed to find %s\n",
+                       groupattrName, 0, 0 ); 
+               goto return_results;
+       }
+
+       Debug( LDAP_DEBUG_ACL,
+               "<= bdb2i_back_group: found objectClass %s and %s\n",
+               objectclassValue, groupattrName, 0 ); 
+
+
+       bv.bv_val = op_ndn;
+       bv.bv_len = strlen( op_ndn );         
+
+       if (value_find( attr->a_vals, &bv, attr->a_syntax, 1) != 0 ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "<= bdb2i_back_group: \"%s\" not in \"%s\": %s\n", 
+                       op_ndn, gr_ndn, groupattrName ); 
+               goto return_results;
+       }
+
+       Debug( LDAP_DEBUG_ACL,
+               "<= bdb2i_back_group: \"%s\" is in \"%s\": %s\n", 
+               op_ndn, gr_ndn, groupattrName ); 
+       rc = 0;
+
+return_results:
+       if( target != e ) {
+               /* free entry and reader lock */
+               bdb2i_cache_return_entry_r( &li->li_cache, e );                 
+       }
+
+       Debug( LDAP_DEBUG_ARGS, "bdb2i_back_group: rc: %d\n", rc, 0, 0 ); 
+       return(rc);
+}
+
+
+int
+bdb2_back_group(
+       BackendDB       *be,
+       Entry   *target,
+       char    *gr_ndn,
+       char    *op_ndn,
+       char    *objectclassValue,
+       char    *groupattrName
+)
+{
+       DB_LOCK         lock;
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+       struct timeval  time1;
+       int             ret;
+
+       bdb2i_start_timing( be->bd_info, &time1 );
+
+       if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
+
+               return( 1 );
+
+       }
+
+       ret = bdb2i_back_group_internal( be, target, gr_ndn, op_ndn,
+                                       objectclassValue, groupattrName );
+
+       (void) bdb2i_leave_backend_r( lock );
+       bdb2i_stop_timing( be->bd_info, time1, "GRP", NULL, NULL );
+
+       return( ret );
+}
+
+
index 61a3a7201c7044ace60f9f7137d6a5251d72fb88..98f9a8782d4367321e9a422db2283b67df1b15e1 100644 (file)
@@ -104,7 +104,8 @@ bdb2i_back_modify_internal(
        Debug(LDAP_DEBUG_ARGS, "bdb2i_back_modify:\n", 0, 0, 0);
 
        if ( (err = acl_check_modlist( be, conn, op, e, modlist )) != LDAP_SUCCESS ) {
-               send_ldap_result( conn, op, err, NULL, NULL, NULL );
+               send_ldap_result( conn, op, err,
+                       NULL, NULL, NULL, NULL );
                goto error_return;
        }
 
@@ -141,7 +142,8 @@ bdb2i_back_modify_internal(
 
                if ( err != LDAP_SUCCESS ) {
                        /* unlock entry, delete from cache */
-                       send_ldap_result( conn, op, err, NULL, NULL, NULL );
+                       send_ldap_result( conn, op, err,
+                               NULL, NULL, NULL, NULL );
                        goto error_return;
                }
        }
@@ -150,7 +152,7 @@ bdb2i_back_modify_internal(
        if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
                Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
                send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto error_return;
        }
 
@@ -165,7 +167,7 @@ bdb2i_back_modify_internal(
        /* modify indexes */
        if ( bdb2i_index_add_mods( be, modlist, e->e_id ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto error_return;
        }
 
@@ -180,11 +182,12 @@ bdb2i_back_modify_internal(
        /* change the entry itself */
        if ( bdb2i_id2entry_add( be, e ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto error_return;
        }
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+       send_ldap_result( conn, op, LDAP_SUCCESS,
+               NULL, NULL, NULL, NULL );
        bdb2i_cache_return_entry_w( &li->li_cache, e );
        return( 0 );
 
@@ -206,15 +209,15 @@ bdb2_back_modify(
        DB_LOCK         lock;
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        struct timeval  time1;
-       int             ret;
-       char            *matched;
+       int             ret, manageDSAit;
+       Entry           *matched;
        Entry           *e;
 
        bdb2i_start_timing( be->bd_info, &time1 );
 
        if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                return( -1 );
        }
 
@@ -230,15 +233,53 @@ bdb2_back_modify(
        }
 
        if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                       matched, NULL, NULL );
+               char *matched_dn = NULL;
+               struct berval **refs = NULL;
+
                if ( matched != NULL ) {
-                       free( matched );
+                       matched_dn = ch_strdup( matched->e_dn );
+                       refs = is_entry_referral( matched )
+                               ? get_entry_referrals( be, conn, op, matched )
+                               : NULL;
+                       bdb2i_cache_return_entry_r( &li->li_cache, matched );
+               } else {
+                       refs = default_referral;
                }
-               return( -1 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       matched_dn, NULL, refs, NULL );
+
+               if( matched != NULL ) {
+                       ber_bvecfree( refs );
+                       free( matched_dn );
+               }
+
+               ret = -1;
+               goto done;
+       }
+
+       if (!manageDSAit && is_entry_referral( e ) ) {
+               /* entry is a referral, don't allow add */
+               struct berval **refs = get_entry_referrals( be,
+                       conn, op, e );
+
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                       0, 0 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       e->e_dn, NULL, refs, NULL );
+
+               bdb2i_cache_return_entry_w( &li->li_cache, e );
+
+               ber_bvecfree( refs );
+
+               ret = -1;
+               goto done;
        }
 
-        ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist, e );
+       ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist, e );
+
+done:
        (void) bdb2i_leave_backend_w( lock );
        bdb2i_stop_timing( be->bd_info, time1, "MOD", conn, op );
 
index 0aca35b508046865cd5bd9d93dd8505294d837ba..97c16ddfe30350c5029e61216f009c023e3ea9be 100644 (file)
@@ -36,12 +36,12 @@ bdb2i_back_modrdn_internal(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       char            *matched = NULL;
+       Entry           *matched = NULL;
        char            *p_dn = NULL, *p_ndn = NULL;
        char            *new_dn = NULL, *new_ndn = NULL;
        char            sep[2];
        Entry           *e, *p = NULL;
-       int                     rc = -1;
+       int                     rc = -1, manageDSAit;
        /* Added to support LDAP v2 correctly (deleteoldrdn thing) */
        char            *new_rdn_val = NULL;    /* Val of new rdn */
        char            *new_rdn_type = NULL;   /* Type of new rdn */
@@ -65,14 +65,46 @@ bdb2i_back_modrdn_internal(
 
        /* get entry with writer lock */
        if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
-               send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
-                       matched, NULL, NULL );
+               char *matched_dn = NULL;
+               struct berval **refs = NULL;
+
                if ( matched != NULL ) {
-                       free( matched );
+                       matched_dn = ch_strdup( matched->e_dn );
+                       refs = is_entry_referral( matched )
+                               ? get_entry_referrals( be, conn, op, matched )
+                               : NULL;
+                       bdb2i_cache_return_entry_r( &li->li_cache, matched );
+               } else {
+                       refs = default_referral;
+               }
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       matched_dn, NULL, refs, NULL );
+
+               if( matched != NULL ) {
+                       ber_bvecfree( refs );
+                       free( matched_dn );
                }
+
                return( -1 );
        }
 
+       if (!manageDSAit && is_entry_referral( e ) ) {
+               /* entry is a referral, don't allow add */
+               struct berval **refs = get_entry_referrals( be,
+                       conn, op, e );
+
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                       0, 0 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       e->e_dn, NULL, refs, NULL );
+
+               ber_bvecfree( refs );
+
+               goto return_results;
+       }
+
 #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
                /* check parent for "children" acl */
        if ( ! access_allowed( be, conn, op, e,
@@ -81,7 +113,7 @@ bdb2i_back_modrdn_internal(
                Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
                        0, 0 );
                send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 #endif
@@ -92,7 +124,7 @@ bdb2i_back_modrdn_internal(
                        Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
                                0, 0, 0);
                        send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
 
@@ -103,7 +135,7 @@ bdb2i_back_modrdn_internal(
                        Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
                                0, 0 );
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
 
@@ -119,7 +151,7 @@ bdb2i_back_modrdn_internal(
                        Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
                                0, 0, 0);
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
 
@@ -152,7 +184,7 @@ bdb2i_back_modrdn_internal(
                               "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
                               np_ndn, 0, 0);
                        send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
 
@@ -168,7 +200,7 @@ bdb2i_back_modrdn_internal(
                               "ldbm_back_modrdn: no wr to newSup children\n",
                               0, 0, 0 );
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL );
+                               NULL, NULL, NULL, NULL );
                        goto return_results;
                }
 
@@ -192,7 +224,8 @@ bdb2i_back_modrdn_internal(
               new_ndn, 0, 0 );
 
        if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
-               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL, NULL );
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 
@@ -207,7 +240,7 @@ bdb2i_back_modrdn_internal(
        /* delete old one */
        if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 
@@ -221,7 +254,7 @@ bdb2i_back_modrdn_internal(
        /* add new one */
        if ( bdb2i_dn2id_add( be,  e->e_ndn, e->e_id ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;
        }
 
@@ -235,7 +268,7 @@ bdb2i_back_modrdn_internal(
                       "ldbm_back_modrdn: can't figure out type of newrdn\n",
                       0, 0, 0 );
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;            
 
        }
@@ -246,7 +279,7 @@ bdb2i_back_modrdn_internal(
                       "ldbm_back_modrdn: can't figure out val of newrdn\n",
                       0, 0, 0 );
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;            
 
        }
@@ -263,7 +296,7 @@ bdb2i_back_modrdn_internal(
                       "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
                       0, 0, 0 );
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;            
 
        }
@@ -274,7 +307,7 @@ bdb2i_back_modrdn_internal(
                       "ldbm_back_modrdn: can't figure out the old_rdn type\n",
                       0, 0, 0 );
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results;            
                
        }
@@ -326,7 +359,7 @@ bdb2i_back_modrdn_internal(
                                       "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
                                       0, 0, 0 );
                                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                                       NULL, NULL, NULL );
+                                       NULL, NULL, NULL, NULL );
                                goto return_results;            
 
 
@@ -380,11 +413,12 @@ bdb2i_back_modrdn_internal(
        if ( bdb2i_id2entry_add( be, e ) != 0 ) {
                entry_free( e );
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                goto return_results_after;
        }
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL );
+       send_ldap_result( conn, op, LDAP_SUCCESS,
+               NULL, NULL, NULL, NULL );
        rc = 0;
        goto return_results_after;      
 
@@ -399,8 +433,6 @@ return_results_after:
        if( p_dn != NULL ) free( p_dn );
        if( p_ndn != NULL ) free( p_ndn );
 
-       if( matched != NULL ) free( matched );
-
        /* LDAP v2 supporting correct attribute handling. */
        if( new_rdn_type != NULL ) free(new_rdn_type);
        if( new_rdn_val != NULL ) free(new_rdn_val);
@@ -444,7 +476,7 @@ bdb2_back_modrdn(
 
        if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                return( -1 );
 
        }
diff --git a/servers/slapd/back-bdb2/proto-back-bdb2.h b/servers/slapd/back-bdb2/proto-back-bdb2.h
new file mode 100644 (file)
index 0000000..e6ac08c
--- /dev/null
@@ -0,0 +1,245 @@
+#ifndef _PROTO_BACK_BDB2
+#define _PROTO_BACK_BDB2
+
+#include <ldap_cdefs.h>
+
+#include <ac/time.h>           /* Needed in add.c compare.c struct timeval */
+
+#include "external.h"
+
+LDAP_BEGIN_DECL
+
+/*
+ * add.c
+ */
+int bdb2i_release_add_lock LDAP_P(());
+
+/*
+ * alias.c
+ */
+
+Entry * bdb2i_deref_r LDAP_P((
+       Backend *be,
+       Entry *e,
+       char *dn,
+       int *err,
+       Entry **matched,
+       char **text ));
+
+#define deref_entry_r( be, e, err, matched, text ) \
+       bdb2i_deref_r( be, e, NULL, err, matched, text )
+#define deref_dn_r( be, dn, err, matched, text ) \
+       bdb2i_deref_r( be, NULL, dn, err, matched, text )
+
+/*
+ * attr.c
+ */
+
+void bdb2i_attr_masks LDAP_P(( struct ldbminfo *li, char *type, int *indexmask,
+ int *syntaxmask ));
+void bdb2i_attr_index_config LDAP_P(( struct ldbminfo *li, char *fname,
+ int lineno, int argc, char **argv, int init ));
+
+/*
+ * cache.c
+ */
+
+int bdb2i_cache_add_entry_rw LDAP_P(( struct cache *cache, Entry *e, int rw ));
+int bdb2i_cache_update_entry LDAP_P(( struct cache *cache, Entry *e ));
+void bdb2i_cache_return_entry_rw LDAP_P(( struct cache *cache, Entry *e,
+ int rw ));
+#define bdb2i_cache_return_entry_r(c, e) bdb2i_cache_return_entry_rw((c), (e), 0)
+#define bdb2i_cache_return_entry_w(c, e) bdb2i_cache_return_entry_rw((c), (e), 1)
+
+ID bdb2i_cache_find_entry_dn2id LDAP_P(( BackendDB *be, struct cache *cache,
+ char *dn ));
+Entry * bdb2i_cache_find_entry_id LDAP_P(( struct cache *cache, ID id, int rw ));
+int bdb2i_cache_delete_entry LDAP_P(( struct cache *cache, Entry *e ));
+
+/*
+ * dbcache.c
+ */
+
+struct dbcache * bdb2i_cache_open LDAP_P(( BackendDB *be, char *name, char *suffix,
+ int flags ));
+void bdb2i_cache_close LDAP_P(( BackendDB *be, struct dbcache *db ));
+void bdb2i_cache_really_close LDAP_P(( BackendDB *be, struct dbcache *db ));
+void bdb2i_cache_flush_all LDAP_P(( BackendDB *be ));
+Datum bdb2i_cache_fetch LDAP_P(( struct dbcache *db, Datum key ));
+int bdb2i_cache_store LDAP_P(( struct dbcache *db, Datum key, Datum data, int flags ));
+int bdb2i_cache_delete LDAP_P(( struct dbcache *db, Datum key ));
+
+/*
+ * dn2id.c
+ */
+
+int bdb2i_dn2id_add LDAP_P(( BackendDB *be, char *dn, ID id ));
+ID bdb2i_dn2id LDAP_P(( BackendDB *be, char *dn ));
+int bdb2i_dn2id_delete LDAP_P(( BackendDB *be, char *dn ));
+
+Entry * bdb2i_dn2entry_rw LDAP_P((
+       BackendDB *be,
+       char *dn,
+       Entry **matched,
+       int rw ));
+
+#define bdb2i_dn2entry_r(be, dn, m) bdb2i_dn2entry_rw((be), (dn), (m), 0)
+#define bdb2i_dn2entry_w(be, dn, m) bdb2i_dn2entry_rw((be), (dn), (m), 1)
+
+/*
+ * entry.c
+ */
+int bdb2_back_entry_release_rw LDAP_P(( BackendDB *be, Entry *e, int rw ));
+
+/*
+ * filterindex.c
+ */
+
+ID_BLOCK * bdb2i_filter_candidates LDAP_P(( BackendDB *be, Filter *f ));
+
+/*
+ * id2children.c
+ */
+
+int bdb2i_id2children_add LDAP_P(( BackendDB *be, Entry *p, Entry *e ));
+int bdb2i_id2children_remove LDAP_P(( BackendDB *be, Entry *p, Entry *e ));
+int bdb2i_has_children LDAP_P(( BackendDB *be, Entry *p ));
+
+/*
+ * id2entry.c
+ */
+
+int bdb2i_id2entry_add LDAP_P(( BackendDB *be, Entry *e ));
+int bdb2i_id2entry_delete LDAP_P(( BackendDB *be, Entry *e ));
+
+Entry * bdb2i_id2entry_rw LDAP_P(( BackendDB *be, ID id, int rw )); 
+#define bdb2i_id2entry_r(be, id)  bdb2i_id2entry_rw((be), (id), 0)
+#define bdb2i_id2entry_w(be, id)  bdb2i_id2entry_rw((be), (id), 1)
+
+/*
+ * idl.c
+ */
+
+ID_BLOCK * bdb2i_idl_alloc LDAP_P(( unsigned int nids ));
+ID_BLOCK * bdb2i_idl_allids LDAP_P(( BackendDB *be ));
+void bdb2i_idl_free LDAP_P(( ID_BLOCK *idl ));
+ID_BLOCK * bdb2i_idl_fetch LDAP_P(( BackendDB *be, struct dbcache *db, Datum key ));
+int bdb2i_idl_insert_key LDAP_P(( BackendDB *be, struct dbcache *db, Datum key, ID id ));
+int bdb2i_idl_insert LDAP_P(( ID_BLOCK **idl, ID id, unsigned int maxids ));
+int bdb2i_idl_delete_key LDAP_P(( BackendDB *be, struct dbcache *db, Datum key, ID id ));
+ID_BLOCK * bdb2i_idl_intersection LDAP_P(( BackendDB *be, ID_BLOCK *a, ID_BLOCK *b ));
+ID_BLOCK * bdb2i_idl_union LDAP_P(( BackendDB *be, ID_BLOCK *a, ID_BLOCK *b ));
+ID_BLOCK * bdb2i_idl_notin LDAP_P(( BackendDB *be, ID_BLOCK *a, ID_BLOCK *b ));
+ID bdb2i_idl_firstid LDAP_P(( ID_BLOCK *idl ));
+ID bdb2i_idl_nextid LDAP_P(( ID_BLOCK *idl, ID id ));
+
+/*
+ * index.c
+ */
+
+int bdb2i_index_add_entry LDAP_P(( BackendDB *be, Entry *e ));
+int bdb2i_index_add_mods LDAP_P(( BackendDB *be, LDAPModList *ml, ID id ));
+ID_BLOCK * bdb2i_index_read LDAP_P(( BackendDB *be, char *type, int indextype, char *val ));
+int bdb2i_index_add_values LDAP_P(( BackendDB *be, char *type, struct berval **vals, ID  id ));
+
+/*
+ * kerberos.c
+ */
+
+#ifdef HAVE_KERBEROS
+/* bdb2i_krbv4_ldap_auth LDAP_P(( BackendDB *be, struct berval *cred, AUTH_DAT *ad )); */
+#endif
+
+/*
+ * modify.c
+ * These prototypes are placed here because they are used by modify and
+ * modify rdn which are implemented in different files. 
+ *
+ * We need bdb2i_back_modify_internal here because of LDAP modrdn & modify use 
+ * it. If we do not add this, there would be a bunch of code replication 
+ * here and there and of course the likelihood of bugs increases.
+ * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99
+ *
+ */
+
+int bdb2i_add_values LDAP_P(( Entry *e, LDAPMod *mod, char *dn ));
+int bdb2i_delete_values LDAP_P(( Entry *e, LDAPMod *mod, char *dn ));
+int bdb2i_replace_values LDAP_P(( Entry *e, LDAPMod *mod, char *dn ));
+int bdb2i_back_modify_internal LDAP_P((Backend *be, Connection *conn, Operation *op,
+                                char *dn, LDAPModList *mods, Entry *e));
+/*
+ * nextid.c
+ */
+
+ID bdb2i_next_id LDAP_P(( BackendDB *be ));
+void bdb2i_next_id_return LDAP_P(( BackendDB *be, ID id ));
+ID bdb2i_next_id_get LDAP_P(( BackendDB *be ));
+int bdb2i_next_id_save LDAP_P(( BackendDB *be ));
+
+/*
+ *  startup.c
+ */
+
+int bdb2i_back_startup     LDAP_P(( BackendInfo *bi ));
+int bdb2i_back_shutdown    LDAP_P(( BackendInfo *bi ));
+int bdb2i_back_db_startup  LDAP_P(( BackendDB *be ));
+int bdb2i_back_db_shutdown LDAP_P(( BackendDB *be ));
+
+/*
+ *  timing.c
+ */
+
+void bdb2i_uncond_start_timing LDAP_P(( struct timeval *time1 ));
+#define bdb2i_start_timing(bi,time1)  if ( with_timing( bi )) bdb2i_uncond_start_timing( (time1) )
+void bdb2i_uncond_stop_timing LDAP_P(( struct timeval time1,
+  char *func, Connection *conn, Operation *op, int level ));
+#define bdb2i_stop_timing(bi,time1,func,conn,op)  if ( with_timing( bi )) bdb2i_uncond_stop_timing( (time1), (func), (conn), (op), LDAP_DEBUG_ANY )
+
+/*
+ * porter.c
+ */
+
+int bdb2i_enter_backend_rw  LDAP_P(( DB_LOCK *lock, int writer ));
+#define bdb2i_enter_backend_r(lock)  bdb2i_enter_backend_rw((lock), 0 )
+#define bdb2i_enter_backend_w(lock)  bdb2i_enter_backend_rw((lock), 1 )
+int bdb2i_leave_backend_rw LDAP_P(( DB_LOCK lock, int writer ));
+#define bdb2i_leave_backend_r(lock)  bdb2i_leave_backend_rw((lock), 0 )
+#define bdb2i_leave_backend_w(lock)  bdb2i_leave_backend_rw((lock), 1 )
+
+/*
+ *  txn.c
+ */
+
+int bdb2i_txn_head_init  LDAP_P(( BDB2_TXN_HEAD *head ));
+void bdb2i_txn_attr_config LDAP_P((
+ struct ldbminfo  *li,
+ char *attr,
+ int open ));
+int bdb2i_txn_open_files LDAP_P(( BackendDB *be ));
+void bdb2i_txn_close_files LDAP_P(( BackendDB *be ));
+BDB2_TXN_FILES *bdb2i_get_db_file_cache LDAP_P((
+ struct ldbminfo *li,
+ char *name ));
+int bdb2i_check_additional_attr_index LDAP_P(( struct ldbminfo *li ));
+void bdb2i_check_default_attr_index_add LDAP_P((
+ struct ldbminfo *li,
+ Entry *e ));
+void bdb2i_check_default_attr_index_mod LDAP_P((
+ struct ldbminfo *li,
+ LDAPModList *modlist ));
+ID bdb2i_get_nextid  LDAP_P(( BackendDB *be ));
+int bdb2i_put_nextid LDAP_P(( BackendDB *be, ID id ));
+LDBM bdb2i_db_open LDAP_P(( char *name, int type, int rw, int mode,
+ int dbcachesize ));
+int bdb2i_db_store   LDAP_P(( LDBM ldbm, Datum key, Datum data, int flags ));
+int bdb2i_db_delete  LDAP_P(( LDBM ldbm, Datum key ));
+Datum bdb2i_db_fetch LDAP_P(( LDBM ldbm, Datum key ));
+Datum bdb2i_db_firstkey LDAP_P(( LDBM ldbm, DBC **dbch ));
+Datum bdb2i_db_nextkey  LDAP_P(( LDBM ldbm, Datum key, DBC *dbcp ));
+int bdb2i_start_transction   LDAP_P(( DB_TXNMGR *txmgr ));
+int bdb2i_finish_transaction LDAP_P(( ));
+int bdb2i_set_txn_checkpoint LDAP_P(( DB_TXNMGR *txmgr, int forced ));
+
+
+LDAP_END_DECL
+#endif
index 86c4438c56fea7d08a4c9b4315e3a67a7536ecb9..63d709475cde4632ed4f4d83cdf9924b15a4bdb0 100644 (file)
 #include "back-bdb2.h"
 #include "proto-back-bdb2.h"
 
-static ID_BLOCK        *base_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
-static ID_BLOCK        *onelevel_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
-static ID_BLOCK        *subtree_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
-
-#define GRABSIZE       BUFSIZ
-
-#define MAKE_SPACE( n ) { \
-       if ( rcur + (n) > rbuf + rmaxsize ) { \
-               int     offset = rcur - rbuf; \
-               rbuf =  ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
-               rmaxsize += GRABSIZE; \
-               rcur = rbuf + offset; \
-       } \
-}
+static ID_BLOCK *base_candidate(
+       Backend *be, Entry *e );
+
+static ID_BLOCK *search_candidates(
+       Backend *be, Entry *e, Filter *filter,
+       int scope, int deref, int manageDSAit );
 
 static int
 bdb2i_back_search_internal(
@@ -44,18 +36,76 @@ bdb2i_back_search_internal(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       int             err;
+       int             rc, err;
+       char *text;
        time_t          stoptime;
        ID_BLOCK                *candidates;
        ID              id;
        Entry           *e;
-       Attribute       *ref;
-       struct berval **refs;
-       char            *matched = NULL;
+       struct berval **v2refs = NULL;
+       Entry   *matched = NULL;
+       char    *realbase = NULL;
        int             nentries = 0;
-       char            *realBase;
+       int             manageDSAit = get_manageDSAit( op );
+
+       Debug(LDAP_DEBUG_TRACE, "=> bdb2_back_search\n", 0, 0, 0);
+
+       /* get entry with reader lock */
+       if ( deref & LDAP_DEREF_FINDING ) {
+               e = deref_dn_r( be, base, &err, &matched, &text );
+
+       } else {
+               e = bdb2i_dn2entry_r( be, base, &matched );
+               err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL;
+               text = NULL;
+       }
+
+       if ( e == NULL ) {
+               char *matched_dn = NULL;
+               struct berval **refs = NULL;
+
+               if ( matched != NULL ) {
+                       matched_dn = ch_strdup( matched->e_dn );
+
+                       refs = is_entry_referral( matched )
+                               ? get_entry_referrals( be, conn, op, matched )
+                               : NULL;
+
+                       bdb2i_cache_return_entry_r( &li->li_cache, matched );
+               } else {
+                       refs = default_referral;
+               }
+
+               send_ldap_result( conn, op, err,
+                       matched_dn, text, refs, NULL );
+
+               if( matched != NULL ) {
+                       ber_bvecfree( refs );
+                       free( matched_dn );
+               }
 
-       Debug(LDAP_DEBUG_ARGS, "=> bdb2i_back_search\n", 0, 0, 0);
+               return 1;
+       }
+
+       if (!manageDSAit && is_entry_referral( e ) ) {
+               /* entry is a referral, don't allow add */
+               char *matched_dn = ch_strdup( e->e_dn );
+               struct berval **refs = get_entry_referrals( be,
+                       conn, op, e );
+
+               bdb2i_cache_return_entry_r( &li->li_cache, e );
+
+               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+                   0, 0 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                   matched_dn, NULL, refs, NULL );
+
+               ber_bvecfree( refs );
+               free( matched_dn );
+
+               return 1;
+       }
 
        if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
                tlimit = -1;    /* allow root to set no limit */
@@ -64,6 +114,7 @@ bdb2i_back_search_internal(
                    be->be_timelimit : tlimit;
                stoptime = op->o_time + tlimit;
        }
+
        if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
                slimit = -1;    /* allow root to set no limit */
        } else {
@@ -71,199 +122,183 @@ bdb2i_back_search_internal(
                    be->be_sizelimit : slimit;
        }
 
-       /*
-        * check and apply aliasing where the dereferencing applies to
-        * the subordinates of the base
-        */
-
-       switch ( deref ) {
-       case LDAP_DEREF_FINDING:
-       case LDAP_DEREF_ALWAYS:
-               realBase = bdb2i_derefDN ( be, conn, op, base );
-               break;
-       default:
-               realBase = ch_strdup(base);
-       }
-
-       (void) dn_normalize_case( realBase );
-
-       Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
-               realBase, 0, 0 );
-
-       switch ( scope ) {
-       case LDAP_SCOPE_BASE:
-               candidates = base_candidates( be, conn, op, realBase, filter,
-                   attrs, attrsonly, &matched, &err );
-               break;
-
-       case LDAP_SCOPE_ONELEVEL:
-               candidates = onelevel_candidates( be, conn, op, realBase, filter,
-                   attrs, attrsonly, &matched, &err );
-               break;
+       if ( scope == LDAP_SCOPE_BASE) {
+               candidates = base_candidate( be, e );
 
-       case LDAP_SCOPE_SUBTREE:
-               candidates = subtree_candidates( be, conn, op, realBase, filter,
-                   attrs, attrsonly, &matched, NULL, &err, 1 );
-               break;
-
-       default:
-               send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
-                       NULL, "Bad scope", NULL );
-               if( realBase != NULL) {
-                       free( realBase );
-               }
-               return( -1 );
+       } else {
+               candidates = search_candidates( be, e, filter,
+                   scope, deref, manageDSAit );
        }
 
-       /* null candidates means we could not find the base object */
+       /* need normalized dn below */
+       realbase = ch_strdup( e->e_ndn );
+       bdb2i_cache_return_entry_r( &li->li_cache, e );
+
        if ( candidates == NULL ) {
-               send_ldap_result( conn, op, err, matched, NULL, NULL );
-               if ( matched != NULL ) {
-                       free( matched );
-               }
-               if( realBase != NULL) {
-                       free( realBase );
-               }
-               return( -1 );
-       }
+               /* no candidates */
+               Debug( LDAP_DEBUG_TRACE, "no candidates\n", 0,
+                   0, 0 );
 
-       if ( matched != NULL ) {
-               free( matched );
-       }
+               send_search_result( conn, op,
+                       LDAP_SUCCESS,
+                       NULL, NULL, NULL, NULL, 0 );
 
-       refs = NULL;
+               rc = 1;
+               goto done;
+       }
 
        for ( id = bdb2i_idl_firstid( candidates ); id != NOID;
-           id = bdb2i_idl_nextid( candidates, id ) ) {
+           id = bdb2i_idl_nextid( candidates, id ) )
+       {
+               int             scopeok = 0;
+
                /* check for abandon */
                ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+
                if ( op->o_abandon ) {
                        ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
-                       bdb2i_idl_free( candidates );
-                       ber_bvecfree( refs );
-                       if( realBase != NULL) {
-                               free( realBase );
-                       }
-                       return( 0 );
+                       rc = 0;
+                       goto done;
                }
+
                ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
 
                /* check time limit */
                if ( tlimit != -1 && slap_get_time() > stoptime ) {
                        send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
-                               NULL, NULL, refs, nentries );
-                       bdb2i_idl_free( candidates );
-                       ber_bvecfree( refs );
-                       if( realBase != NULL) {
-                               free( realBase );
-                       }
-                       return( 0 );
+                               NULL, NULL, v2refs, NULL, nentries );
+                       rc = 0;
+                       goto done;
                }
 
                /* get the entry with reader lock */
-               if ( (e = bdb2i_id2entry_r( be, id )) == NULL ) {
-                       Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n",
-                              id, 0, 0 );
-                       continue;
+               e = bdb2i_id2entry_r( be, id );
+
+               if ( e == NULL ) {
+                       Debug( LDAP_DEBUG_ARGS, "search: candidate %ld not found\n",
+                               id, 0, 0 );
+
+                       goto loop_continue;
+               }
+
+               if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) {
+                       Entry *matched;
+                       int err;
+                       char *text;
+                       
+                       e = deref_entry_r( be, e, &err, &matched, &text );
+
+                       if( e == NULL ) {
+                               e = matched;
+                               goto loop_continue;
+                       }
+
+                       if( e->e_id == id ) {
+                               /* circular loop */
+                               goto loop_continue;
+                       }
+
+                       /* need to skip alias which deref into scope */
+                       if( scope & LDAP_SCOPE_ONELEVEL ) {
+                               char *pdn = dn_parent( NULL, e->e_ndn );
+                               if ( pdn != NULL ) {
+                                       if( strcmp( pdn, realbase ) ) {
+                                               free( pdn );
+                                               goto loop_continue;
+                                       }
+                                       free(pdn);
+                               }
+
+                       } else if ( dn_issuffix( e->e_ndn, realbase ) ) {
+                               /* alias is within scope */
+                               Debug( LDAP_DEBUG_ARGS, "search: \"%s\" in subtree\n",
+                                       e->e_dn, 0, 0 );
+                               goto loop_continue;
+                       }
+
+                       scopeok = 1;
                }
 
                /*
                 * if it's a referral, add it to the list of referrals. only do
-                * this for subtree searches, and don't check the filter explicitly
-                * here since it's only a candidate anyway.
+                * this for non-base searches, and don't check the filter
+                * explicitly here since it's only a candidate anyway.
                 */
-               if ( scope == LDAP_SCOPE_SUBTREE &&
-                       e->e_ndn != NULL &&
-                       strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
-                       (ref = attr_find( e->e_attrs, "ref" )) != NULL )
+               if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
+                       is_entry_referral( e ) )
                {
+                       struct berval **refs = get_entry_referrals(
+                               be, conn, op, e );
+
                        send_search_reference( be, conn, op,
-                               e, ref->a_vals, &refs );
+                               e, refs, scope, NULL, &v2refs );
 
-               /* otherwise it's an entry - see if it matches the filter */
-               } else {
-                       /* if it matches the filter and scope, send it */
-                       if ( test_filter( be, conn, op, e, filter ) == 0 ) {
-                               int             scopeok;
-                               char    *dn;
+                       ber_bvecfree( refs );
 
-                               /* check scope */
-                               scopeok = 1;
-                               if ( scope == LDAP_SCOPE_ONELEVEL ) {
-                                       if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
-                                               (void) dn_normalize_case( dn );
-                                               scopeok = (dn == realBase)
-                                                       ? 1
-                                                       : (strcmp( dn, realBase ) ? 0 : 1 );
-                                               free( dn );
-                                       } else {
-                                               scopeok = (realBase == NULL || *realBase == '\0');
-                                       }
-                               } else if ( scope == LDAP_SCOPE_SUBTREE ) {
-                                       dn = ch_strdup( e->e_ndn );
-                                       scopeok = dn_issuffix( dn, realBase );
+                       goto loop_continue;
+               }
+
+               /* if it matches the filter and scope, send it */
+               if ( test_filter( be, conn, op, e, filter ) == 0 ) {
+                       char    *dn;
+
+                       /* check scope */
+                       if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
+                               if ( (dn = dn_parent( be, e->e_ndn )) != NULL ) {
+                                       (void) dn_normalize_case( dn );
+                                       scopeok = (dn == realbase)
+                                               ? 1
+                                               : (strcmp( dn, realbase ) ? 0 : 1 );
                                        free( dn );
+
+                               } else {
+                                       scopeok = (realbase == NULL || *realbase == '\0');
                                }
 
-                               if ( scopeok ) {
-                                       /* check size limit */
-                                       if ( --slimit == -1 ) {
-                                               bdb2i_cache_return_entry_r( &li->li_cache, e );
-                                               send_search_result( conn, op, LDAP_SIZELIMIT_EXCEEDED,
-                                                       NULL, NULL, refs, nentries );
-                                               bdb2i_idl_free( candidates );
-                                               ber_bvecfree( refs );
-
-                                               if( realBase != NULL) {
-                                                       free( realBase );
-                                               }
-                                               return( 0 );
-                                       }
+                       } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
+                               dn = ch_strdup( e->e_ndn );
+                               scopeok = dn_issuffix( dn, realbase );
+                               free( dn );
 
-                                       /*
-                                        * check and apply aliasing where the dereferencing applies to
-                                        * the subordinates of the base
-                                        */
-                                       switch ( deref ) {
-                                       case LDAP_DEREF_SEARCHING:
-                                       case LDAP_DEREF_ALWAYS:
-                                               {
-                                                       Entry *newe = bdb2i_derefAlias_r( be, conn, op, e );
-                                                       if ( newe == NULL ) { /* problem with the alias */
-                                                               bdb2i_cache_return_entry_r( &li->li_cache, e );
-                                                               e = NULL;
-                                                       }
-                                                       else if ( newe != e ) { /* reassign e */
-                                                               bdb2i_cache_return_entry_r( &li->li_cache, e );
-                                                               e = newe;
-                                                       }
-                                               }
-                                               break;
-                                       }
+                       } else {
+                               scopeok = 1;
+                       }
+
+                       if ( scopeok ) {
+                               /* check size limit */
+                               if ( --slimit == -1 ) {
+                                       bdb2i_cache_return_entry_r( &li->li_cache, e );
+                                       send_search_result( conn, op,
+                                               LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
+                                               v2refs, NULL, nentries );
+                                       rc = 0;
+                                       goto done;
+                               }
 
-                                       if (e) {
-                                               switch ( send_search_entry( be, conn, op, e,
-                                                       attrs, attrsonly, 0, NULL ) ) {
-                                               case 0:         /* entry sent ok */
-                                                       nentries++;
-                                                       break;
-                                               case 1:         /* entry not sent */
-                                                       break;
-                                               case -1:        /* connection closed */
-                                                       bdb2i_cache_return_entry_r( &li->li_cache, e );
-                                                       bdb2i_idl_free( candidates );
-                                                       ber_bvecfree( refs );
-
-                                                       if( realBase != NULL) {
-                                                               free( realBase );
-                                                       }
-                                                       return( 0 );
-                                               }
+                               if (e) {
+                                       switch ( send_search_entry( be, conn, op, e,
+                                               attrs, attrsonly, 0, NULL ) ) {
+                                       case 0:         /* entry sent ok */
+                                               nentries++;
+                                               break;
+                                       case 1:         /* entry not sent */
+                                               break;
+                                       case -1:        /* connection closed */
+                                               bdb2i_cache_return_entry_r( &li->li_cache, e );
+                                               rc = 0;
+                                               goto done;
                                        }
                                }
+                       } else {
+                               Debug( LDAP_DEBUG_TRACE, "candidate %ld scope not okay\n",
+                                       id, 0, 0 );
                        }
+               } else {
+                       Debug( LDAP_DEBUG_TRACE, "candidate %ld does match filter\n",
+                               id, 0, 0 );
                }
 
+loop_continue:
                if( e != NULL ) {
                        /* free reader lock */
                        bdb2i_cache_return_entry_r( &li->li_cache, e );
@@ -271,19 +306,19 @@ bdb2i_back_search_internal(
 
                ldap_pvt_thread_yield();
        }
-       bdb2i_idl_free( candidates );
-
        send_search_result( conn, op,
-               refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
-               NULL, NULL, refs, nentries );
+               v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
+               NULL, NULL, v2refs, NULL, nentries );
 
-       ber_bvecfree( refs );
+       rc = 0;
 
-       if( realBase != NULL) {
-               free( realBase );
-       }
+done:
+       bdb2i_idl_free( candidates );
+
+       ber_bvecfree( v2refs );
+       if( realbase ) free( realbase );
 
-       return( 0 );
+       return rc;
 }
 
 
@@ -312,7 +347,7 @@ bdb2_back_search(
 
        if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
                send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                       NULL, NULL, NULL );
+                       NULL, NULL, NULL, NULL );
                return( -1 );
 
        }
@@ -328,191 +363,126 @@ bdb2_back_search(
 
 
 static ID_BLOCK *
-base_candidates(
-    BackendDB  *be,
-    Connection *conn,
-    Operation  *op,
-    char       *base,
-    Filter     *filter,
-    char       **attrs,
-    int                attrsonly,
-    char       **matched,
-    int                *err
+base_candidate(
+    Backend    *be,
+       Entry   *e
 )
 {
-       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        ID_BLOCK                *idl;
-       Entry           *e;
-
-       Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
 
-       *err = LDAP_SUCCESS;
-
-       /* get entry with reader lock */
-       if ( (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) {
-               *err = LDAP_NO_SUCH_OBJECT;
-               return( NULL );
-       }
-
-       /* check for deleted */
+       Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n",
+               e->e_dn, 0, 0);
 
        idl = bdb2i_idl_alloc( 1 );
        bdb2i_idl_insert( &idl, e->e_id, 1 );
 
-
-       /* free reader lock */
-       bdb2i_cache_return_entry_r( &li->li_cache, e );
-
        return( idl );
 }
 
 static ID_BLOCK *
-onelevel_candidates(
-    BackendDB  *be,
-    Connection *conn,
-    Operation  *op,
-    char       *base,
+search_candidates(
+    Backend    *be,
+    Entry      *e,
     Filter     *filter,
-    char       **attrs,
-    int                attrsonly,
-    char       **matched,
-    int                *err
+    int                scope,
+       int             deref,
+       int             manageDSAit
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       Entry           *e = NULL;
-       Filter          *f;
-       char            buf[20];
        ID_BLOCK                *candidates;
+       Filter          *f, *rf, *af, *lf;
 
-       Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
+       Debug(LDAP_DEBUG_TRACE, "search_candidates: base=\"%s\" s=%d d=%d\n",
+               e->e_ndn, scope, deref );
 
-       *err = LDAP_SUCCESS;
+       f = NULL;
 
-       /* get the base object with reader lock */
-       if ( base != NULL && *base != '\0' &&
-               (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
-       {
-               *err = LDAP_NO_SUCH_OBJECT;
-               return( NULL );
+       if( !manageDSAit ) {
+               /* match referrals */
+               rf = (Filter *) ch_malloc( sizeof(Filter) );
+               rf->f_next = NULL;
+               rf->f_choice = LDAP_FILTER_OR;
+               rf->f_or = (Filter *) ch_malloc( sizeof(Filter) );
+               rf->f_or->f_choice = LDAP_FILTER_EQUALITY;
+               rf->f_or->f_avtype = ch_strdup( "objectclass" );
+               rf->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
+               rf->f_or->f_avvalue.bv_len = sizeof("REFERRAL")-1;
+               rf->f_or->f_next = filter;
+               f = rf;
+       } else {
+               rf = NULL;
+               f = filter;
        }
 
-       /*
-        * modify the filter to be something like this:
-        *
-        *      parent=baseobject & originalfilter
-        */
-
-       f = (Filter *) ch_malloc( sizeof(Filter) );
-       f->f_next = NULL;
-       f->f_choice = LDAP_FILTER_AND;
-       f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
-       f->f_and->f_choice = LDAP_FILTER_EQUALITY;
-       f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
-       sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
-       f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
-       f->f_and->f_ava.ava_value.bv_len = strlen( buf );
-       f->f_and->f_next = filter;
-
-       /* from here, it's just like subtree_candidates */
-       candidates = subtree_candidates( be, conn, op, base, f, attrs,
-           attrsonly, matched, e, err, 0 );
-
-       /* free up just the filter stuff we allocated above */
-       f->f_and->f_next = NULL;
-       filter_free( f );
-
-       /* free entry and reader lock */
-       if( e != NULL ) {
-               bdb2i_cache_return_entry_r( &li->li_cache, e );
+       if( deref & LDAP_DEREF_SEARCHING ) {
+               /* match aliases */
+               af = (Filter *) ch_malloc( sizeof(Filter) );
+               af->f_next = NULL;
+               af->f_choice = LDAP_FILTER_OR;
+               af->f_or = (Filter *) ch_malloc( sizeof(Filter) );
+               af->f_or->f_choice = LDAP_FILTER_EQUALITY;
+               af->f_or->f_avtype = ch_strdup( "objectclass" );
+               af->f_or->f_avvalue.bv_val = ch_strdup( "ALIAS" );
+               af->f_or->f_avvalue.bv_len = sizeof("ALIAS")-1;
+               af->f_or->f_next = f;
+               f = af;
+       } else {
+               af = NULL;
        }
-       return( candidates );
-}
 
-static ID_BLOCK *
-subtree_candidates(
-    BackendDB  *be,
-    Connection *conn,
-    Operation  *op,
-    char       *base,
-    Filter     *filter,
-    char       **attrs,
-    int                attrsonly,
-    char       **matched,
-    Entry      *e,
-    int                *err,
-    int                lookupbase
-)
-{
-       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       Filter          *f, **filterarg_ptr;
-       ID_BLOCK                *candidates;
+       if ( scope == LDAP_SCOPE_SUBTREE ) {
+               lf = (Filter *) ch_malloc( sizeof(Filter) );
+               lf->f_next = NULL;
+               lf->f_choice = LDAP_FILTER_AND;
+               lf->f_and = (Filter *) ch_malloc( sizeof(Filter) );
 
-       Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
-               base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
-
-       /*
-        * get the base object - unless we already have it (from one-level).
-        * also, unless this is a one-level search or a subtree search
-        * starting at the very top of our subtree, we need to modify the
-        * filter to be something like this:
-        *
-        *      dn=*baseobjectdn & (originalfilter | ref=*)
-        *
-        * the "objectclass=referral" part is used to select referrals to return
-        */
-
-       *err = LDAP_SUCCESS;
-       f = NULL;
-       if ( lookupbase ) {
-               e = NULL;
+               lf->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
+               lf->f_and->f_sub_type = ch_strdup( "dn" );
+               lf->f_and->f_sub_initial = NULL;
+               lf->f_and->f_sub_any = NULL;
+               lf->f_and->f_sub_final = ch_strdup( e->e_ndn );
 
-               if ( base != NULL && *base != '\0' &&
-                       (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
-               {
-                       *err = LDAP_NO_SUCH_OBJECT;
-                       return( NULL );
-               }
+               lf->f_and->f_next = f;
+               f = lf;
 
-               if (e) {
-                       bdb2i_cache_return_entry_r( &li->li_cache, e );
-               }
+       } else if ( scope == LDAP_SCOPE_ONELEVEL ) {
+               char buf[16];
 
-               f = (Filter *) ch_malloc( sizeof(Filter) );
-               f->f_next = NULL;
-               f->f_choice = LDAP_FILTER_OR;
-               f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
-               f->f_or->f_choice = LDAP_FILTER_EQUALITY;
-               f->f_or->f_avtype = ch_strdup( "objectclass" );
-               /* Patch to use normalized uppercase */
-               f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
-               f->f_or->f_avvalue.bv_len = sizeof( "REFERRAL" )-1;
-               filterarg_ptr = &f->f_or->f_next;
-               *filterarg_ptr = filter;
-               filter = f;
-
-               if ( ! be_issuffix( be, base ) ) {
-                       f = (Filter *) ch_malloc( sizeof(Filter) );
-                       f->f_next = NULL;
-                       f->f_choice = LDAP_FILTER_AND;
-                       f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
-                       f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
-                       f->f_and->f_sub_type = ch_strdup( "dn" );
-                       f->f_and->f_sub_initial = NULL;
-                       f->f_and->f_sub_any = NULL;
-                       f->f_and->f_sub_final = ch_strdup( base );
-                       value_normalize( f->f_and->f_sub_final, SYNTAX_DN|SYNTAX_CIS );
-                       f->f_and->f_next = filter;
-                       filter = f;
-               }
+               lf = (Filter *) ch_malloc( sizeof(Filter) );
+               lf->f_next = NULL;
+               lf->f_choice = LDAP_FILTER_AND;
+               lf->f_and = (Filter *) ch_malloc( sizeof(Filter) );
+
+               lf->f_and->f_choice = LDAP_FILTER_EQUALITY;
+               lf->f_and->f_ava.ava_type = ch_strdup( "id2children" );
+               sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
+               lf->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
+               lf->f_and->f_ava.ava_value.bv_len = strlen( buf );
+
+               lf->f_and->f_next = f;
+               f = lf;
+
+       } else {
+               lf = NULL;
        }
 
-       candidates = bdb2i_filter_candidates( be, filter );
+       candidates = bdb2i_filter_candidates( be, f );
+
+       /* free up filter additions we allocated above */
+       if( lf != NULL ) {
+               lf->f_and->f_next = NULL;
+               filter_free( lf );
+       }
+
+       if( af != NULL ) {
+               af->f_or->f_next = NULL;
+               filter_free( af );
+       }
 
-       /* free up just the parts we allocated above */
-       if ( f != NULL ) {
-               *filterarg_ptr = NULL;
-               filter_free( f );
+       if( rf != NULL ) {
+               rf->f_or->f_next = NULL;
+               filter_free( rf );
        }
 
        return( candidates );