From: Kurt Zeilenga Date: Fri, 16 Jul 1999 01:53:38 +0000 (+0000) Subject: Integrate LDBM changes into BDB2... X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=78ebd3d965c6d8af64cdcd4fb346949d855b0dbc;p=openldap Integrate LDBM changes into BDB2... --- diff --git a/servers/slapd/back-bdb2/add.c b/servers/slapd/back-bdb2/add.c index da41b7d830..5c72225f76 100644 --- a/servers/slapd/back-bdb2/add.c +++ b/servers/slapd/back-bdb2/add.c @@ -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, diff --git a/servers/slapd/back-bdb2/alias.c b/servers/slapd/back-bdb2/alias.c index 107b5bc984..89834748fd 100644 --- a/servers/slapd/back-bdb2/alias.c +++ b/servers/slapd/back-bdb2/alias.c @@ -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" @@ -19,302 +12,273 @@ #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; +} + diff --git a/servers/slapd/back-bdb2/bind.c b/servers/slapd/back-bdb2/bind.c index 6bb6006b9e..5f2ae0d9a2 100644 --- a/servers/slapd/back-bdb2/bind.c +++ b/servers/slapd/back-bdb2/bind.c @@ -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 ); } diff --git a/servers/slapd/back-bdb2/compare.c b/servers/slapd/back-bdb2/compare.c index 0da11c9194..f2fa1dd164 100644 --- a/servers/slapd/back-bdb2/compare.c +++ b/servers/slapd/back-bdb2/compare.c @@ -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 ); } diff --git a/servers/slapd/back-bdb2/delete.c b/servers/slapd/back-bdb2/delete.c index 04a508afe0..ca36c2bacf 100644 --- a/servers/slapd/back-bdb2/delete.c +++ b/servers/slapd/back-bdb2/delete.c @@ -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 index 0000000000..e77cabfa20 --- /dev/null +++ b/servers/slapd/back-bdb2/dn2id.c @@ -0,0 +1,206 @@ +/* dn2id.c - routines to deal with the dn2id index */ + +#include "portable.h" + +#include + +#include +#include + +#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 index 0000000000..6e393757e3 --- /dev/null +++ b/servers/slapd/back-bdb2/group.c @@ -0,0 +1,181 @@ +/* group.c - bdb2 backend acl group routine */ + +#include "portable.h" + +#include + +#include +#include + +#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 ); +} + + diff --git a/servers/slapd/back-bdb2/modify.c b/servers/slapd/back-bdb2/modify.c index 61a3a7201c..98f9a8782d 100644 --- a/servers/slapd/back-bdb2/modify.c +++ b/servers/slapd/back-bdb2/modify.c @@ -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 ); diff --git a/servers/slapd/back-bdb2/modrdn.c b/servers/slapd/back-bdb2/modrdn.c index 0aca35b508..97c16ddfe3 100644 --- a/servers/slapd/back-bdb2/modrdn.c +++ b/servers/slapd/back-bdb2/modrdn.c @@ -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 index 0000000000..e6ac08c6e6 --- /dev/null +++ b/servers/slapd/back-bdb2/proto-back-bdb2.h @@ -0,0 +1,245 @@ +#ifndef _PROTO_BACK_BDB2 +#define _PROTO_BACK_BDB2 + +#include + +#include /* 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 diff --git a/servers/slapd/back-bdb2/search.c b/servers/slapd/back-bdb2/search.c index 86c4438c56..63d709475c 100644 --- a/servers/slapd/back-bdb2/search.c +++ b/servers/slapd/back-bdb2/search.c @@ -12,20 +12,12 @@ #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 );