From 4242411a30472c128565aee95041d867e4721a61 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Thu, 15 Jul 1999 03:34:48 +0000 Subject: [PATCH] replace alias dereferencing code. --- servers/slapd/back-ldbm/alias.c | 556 +++++++++------------- servers/slapd/back-ldbm/proto-back-ldbm.h | 13 +- servers/slapd/back-ldbm/search.c | 32 +- 3 files changed, 257 insertions(+), 344 deletions(-) diff --git a/servers/slapd/back-ldbm/alias.c b/servers/slapd/back-ldbm/alias.c index e93f6b5256..470ba0a7e1 100644 --- a/servers/slapd/back-ldbm/alias.c +++ b/servers/slapd/back-ldbm/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,359 +12,274 @@ #include "back-ldbm.h" #include "proto-back-ldbm.h" -#ifdef SLAPD_ALIASES -/* - * dereference alias - * input origEntry is should be locked/unlocked by caller. - * - * returns origEntry if origEntry is not an alias - * returns NULL if error - * otherwise returns read locked alias - */ -Entry *deref_alias_r ( - Backend *be, - Connection *conn, - Operation *op, - Entry *origEntry, - int *err, - char **matched_dn -) +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 *deref_internal_r( + Backend* be, + Entry* alias, + char* dn, + int* err, + Entry** matched, + char** text ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *entry; + Entry *sup; unsigned depth; - Entry *e; - char **aliases = NULL; - char *newDN = NULL; - char *oldDN = NULL; - int rc = LDAP_SUCCESS; - - /* - * Aliases are only deref'ed during search operations. - * if deref_alias_r (or deref_dn) is needed by other op, - * this will need to become argument - */ - const int access = ACL_SEARCH; - - /* be sure we have a starting entry */ - if( origEntry != NULL ) { - return NULL; - } + char **dnlist; - Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", - origEntry->e_dn, 0, 0 ); - - /* - * try to deref fully, up to a maximum depth. If the max depth exceeded - * then send an error - */ - e = origEntry; - for ( depth = 0; e != NULL; depth++ ) - { - Attribute *a; - struct berval bv; - - if ( ! access_allowed( be, conn, op, e, - "entry", NULL, access ) ) - { - Debug( LDAP_DEBUG_ACL, - "deref_alias_r: access to entry not allowed\n", - 0, 0, 0 ); - break; - } + assert( ( alias != NULL && dn == NULL ) || ( alias == NULL && dn != NULL ) ); - /* - * aliased object names must be contained in an entry - * object class "alias". - */ - a = attr_find(e->e_attrs, "objectclass"); + *matched = NULL; + *err = LDAP_SUCCESS; + *text = NULL; - if( a == NULL ) { - /* no objectclass attribute */ - break; - } - - bv.bv_val = "REFERRAL"; - bv.bv_len = sizeof("REFERRAL")-1; - - if (value_find(a->a_vals, &bv, a->a_syntax, 1) == 0) { - /* is a referral */ - break; - } - - bv.bv_val = "ALIAS"; - bv.bv_len = sizeof("ALIAS")-1; - - if (value_find(a->a_vals, &bv, a->a_syntax, 1) != 0) { - /* not an alias */ - break; - } + if( alias == NULL ) { + dn = ch_strdup( dn ); + entry = dn2entry_r( be, dn, &sup ); - if ( ! access_allowed( be, conn, op, e, - "aliasedobjectname", NULL, access ) ) - { - Debug( LDAP_DEBUG_ACL, - "deref_alias_r: access to reference not allowed\n", - 0, 0, 0 ); - break; - } + } else { + dn = ch_strdup( alias->e_ndn ); + entry = alias; + sup = NULL; + } - a = attr_find( e->e_attrs, "aliasedobjectname" ); - - if( a == NULL ) { - /* - * there was an aliasedobjectname defined but no data. - */ - Debug( LDAP_DEBUG_TRACE, - "<= %s has no aliasedObjectName attribute\n", - e->e_dn, 0, 0 ); - send_ldap_result( conn, op, rc = LDAP_ALIAS_PROBLEM, - NULL, "alias missing aliasedObjectName", NULL, 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 = dn2entry_r( be, aliasDN, &sup ); + + if( newe != NULL ) { + free( dn ); + cache_return_entry_r(&li->li_cache, entry ); + entry = newe; + dn = ch_strdup( entry->e_ndn ); + charray_add( &dnlist, dn ); + continue; + + } + + if ( sup != NULL ) { + cache_return_entry_r(&li->li_cache, entry ); + entry = NULL; + continue; + } + + /* no newe and no superior, we're done */ break; - } - /* - * 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. - */ - Debug( LDAP_DEBUG_TRACE, - "<= %s has no value aliasedObjectName attribute\n", - e->e_dn, 0, 0 ); - send_ldap_result( conn, op, rc = LDAP_ALIAS_PROBLEM, - NULL, "alias missing aliasedObjectName value", NULL, NULL ); - 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 = dn2entry_r( be, aliasDN, &newSup ); + + if( newe != NULL ) { + free(aliasDN); + free( dn ); + 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 ); + cache_return_entry_r(&li->li_cache, sup ); + sup = newSup; + dn = aliasDN; + continue; + } - if( a->a_vals[1] != NULL ) { - Debug( LDAP_DEBUG_TRACE, - "<= %s alias has multiple values\n", - e->e_dn, 0, 0 ); - send_ldap_result( conn, op, rc= LDAP_ALIAS_PROBLEM, - NULL, "multivalue aliasObjectName", NULL, NULL ); break; - } - if( depth >= be->be_max_deref_depth ) { - /* depth limit exceeded */ - Debug( LDAP_DEBUG_TRACE, - "<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n", - origEntry->e_dn, - be->be_max_deref_depth, - e->e_ndn ); - send_ldap_result( conn, op, rc = LDAP_ALIAS_DEREF_PROBLEM, - NULL, "maximum deref depth exceeded", NULL, NULL ); + } else { + /* no newe and no superior, we're done */ break; } + } - charray_add( &aliases, e->e_ndn ); + free( dn ); + return entry; +} - Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", - e->e_dn, a->a_vals[0]->bv_val, 0 ); - if( oldDN != NULL ) free( oldDN ); - oldDN = ch_strdup( e->e_ndn ); +static char* get_alias_dn( + Entry *e, + int *err, + char **errmsg ) +{ + Attribute *a = attr_find( e->e_attrs, "aliasedobjectname" ); - /* - * release past lock if not original + if( a == NULL ) { + /* + * there was an aliasedobjectname defined but no data. */ - if ( depth > 0 ) { - cache_return_entry_r(&li->li_cache, e); - } - e = NULL; - - if( newDN != NULL ) free( newDN ); - newDN = ch_strdup( a->a_vals[0]->bv_val ); - dn_normalize_case (newDN); - - /* make sure new and old DN are not same to avoid loops */ - if ( charray_inlist( aliases, newDN ) ) { - Debug( LDAP_DEBUG_TRACE, - "<= %s has circular alias %s\n", - origEntry->e_dn, newDN, 0 ); - send_ldap_result( conn, op, rc = LDAP_LOOP_DETECT, - NULL, "circular alias", NULL, NULL ); - break; - } + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias missing aliasedObjectName attribute"; + return NULL; + } + /* + * aliasedObjectName should be SINGLE-VALUED with a single value. + */ + if ( a->a_vals[0] == NULL || a->a_vals[0]->bv_val != NULL ) { /* - * ok, so what happens if there is an alias in the DN of a dereferenced - * alias object? + * there was an aliasedobjectname defined but no data. */ - if ( (e = dn2entry_r( be, newDN, NULL )) == NULL ) { - /* could not deref return error */ - Debug( LDAP_DEBUG_TRACE, - "<= %s has dangling alias %s to %s\n", - origEntry->e_dn, oldDN, newDN ); - send_ldap_result( conn, op, rc = LDAP_ALIAS_DEREF_PROBLEM, - NULL, "dangling alias", NULL, NULL ); - break; - } + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias missing aliasedObjectName value"; + return NULL; } - if( e != NULL && origEntry != e && rc != LDAP_SUCCESS ) { - cache_return_entry_r(&li->li_cache, e); - e = NULL; + if( a->a_vals[1] != NULL ) { + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias has multivalued aliasedObjectName"; + return NULL; } - charray_free( aliases ); - if( newDN ) free(newDN); - if( oldDN ) free(oldDN); - - return e; + return a->a_vals[0]->bv_val; } - -/* - * 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. - * - * Example: - * - * "cn=AliasUser,ou=OU,o=AliasedOrg,c=CA" where - * "o=AliasedOrg,c=CA" is an alias for - * "o=Org,c=CA" - * and - * "cn=AliasUser,ou=OU,o=Org,c=CA" is an alias for - * "cn=User,ou=OU,o=Org,c=CA" - * - * 1) newDN = dn - * newDN is "cn=AliasUser,ou=OU,o=AliasedOrg,c=CA" - * - * 2) loop: e = d2entry_r( newDN, matched ) - * e is NULL - * matched is entry("o=AliasOrg,c=CA") - * - * 3) rmdr = remainder(newDN, matched) - * rmdr is "cn=AliasUser,ou=OU" - * - * 4) alias = deref(matched) - * alias is entry("o=Org,c=CA") - * - * 5) oldDN=newDN; newDN = rmdr + alias - * oldDN is "cn=AliasUser,ou=OU,o=AliasedOrg,c=CA" - * newDN is "cn=AliasUser,ou=OU,o=Org,c=CA" - * - * 6) compare(oldDN,newDN) - * goto loop (step 2) - * - * 7) e = d2entry_r( newDN, matched ) - * e is NULL - * matched is entry("ou=OU,o=Org,c=CA") - * - * 8) rmdr = remainder(newDN, matched) - * rmdr is "cn=AliasUser" - * - * 9) alias = deref(matched) - * alias is entry("ou=OU,o=Org,c=CA") - * - *10) oldDN=newDN; newDN = rmdr + alias - * oldDN is "cn=AliasUser,ou=OU,o=Org,c=CA" - * newDN is "cn=AliasUser,ou=OU,o=Org,c=CA" - * - *11) compare(oldDN,newDN) - * break loop (step 2) - * - *12) return newDN - * - */ -char *deref_dn ( - Backend *be, - Connection *conn, - Operation *op, - char *dn -) +char* new_superior( + char *dn, + char *oldSup, + char *newSup ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - unsigned depth; - char* remainder = NULL; - char* newDN; - - char **dns; - - if (!dn) return NULL; - - Debug( LDAP_DEBUG_TRACE, - "<= dereferencing dn: \"%s\"\n", - dn, 0, 0 ); - - charray_add( &dns, "" ); - - newDN = ch_strdup( dn ); + char *newDN; + size_t dnlen, olen, nlen; + assert( dn && oldSup && newSup ); - for ( depth = 0; charray_inlist( dns, newDN ) != 0; depth++ ) - { - Entry* e = NULL; - Entry* matched = NULL; - Entry* alias = NULL; - int rlen; - - if( depth >= be->be_max_deref_depth ) { - /* depth limit exceeded */ - break; - } - - e = dn2entry_r( be, newDN, &matched ); - - if( e != NULL ) { - cache_return_entry_r(&li->li_cache, e); - break; - } - - if ( matched == NULL ) { - /* nothing matched */ - break; - } + dnlen = strlen( dn ); + olen = strlen( oldSup ); + nlen = strlen( newSup ); - charray_add( &dns, newDN ); + newDN = ch_malloc( dnlen - olen + nlen + 1 ); - Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched->e_dn, 0, 0 ); + memcpy( newDN, dn, dnlen - olen ); + memcpy( &newDN[dnlen - olen], newSup, nlen ); + newDN[dnlen - olen + nlen] = '\0'; - rlen = strlen( newDN ) - strlen( matched->e_ndn ); - remainder = ch_malloc( rlen + 1 ); - strncpy( remainder, newDN, rlen ); - remainder[rlen] = '\0'; - - Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 ); - - alias = deref_alias_r( be, conn, op, matched ); - - cache_return_entry_r(&li->li_cache, matched); + return newDN; +} - if( alias == matched ) { - /* matched isn't an alias */ - break; - } +static int dnlist_subordinate( + char** dnlist, + char *dn ) +{ + int i; + assert( dnlist ); - if( alias == NULL ) { - /* alias error */ - break; + for( i = 0; dnlist[i] != NULL; i++ ) { + if( dn_issuffix( dnlist[i], dn ) ) { + return 1; } - - Debug( LDAP_DEBUG_TRACE, "<= derefenced to %s\n", alias->e_dn, 0, 0 ); - - free( newDN ); - newDN = ch_malloc( rlen + strlen( alias->e_ndn ) + 1 ); - sprintf("%s%s", remainder, alias->e_ndn ); - - free( remainder ); - remainder = NULL; - - Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 ); - - cache_return_entry_r( &li->li_cache, alias ); } - charray_free( dns ); - - if( remainder != NULL ) { - free( remainder ); - } - - Debug( LDAP_DEBUG_TRACE, "<= %s\n", newDN, 0, 0 ); - - return newDN; + return 0; } -#endif \ No newline at end of file + diff --git a/servers/slapd/back-ldbm/proto-back-ldbm.h b/servers/slapd/back-ldbm/proto-back-ldbm.h index 2d48d36611..6c2f90da0a 100644 --- a/servers/slapd/back-ldbm/proto-back-ldbm.h +++ b/servers/slapd/back-ldbm/proto-back-ldbm.h @@ -10,15 +10,18 @@ LDAP_BEGIN_DECL /* * alias.c */ -Entry *alias_dn2entry_r LDAP_P(( +Entry *deref_internal_r LDAP_P(( Backend *be, + Entry *e, char *dn, + int *err, Entry **matched, - int *err )); + char **text )); -Entry *alias2entry_r LDAP_P(( - Backend *be, - Entry *e )); +#define deref_entry_r( be, e, err, matched, text ) \ + deref_internal_r( be, e, NULL, err, matched, text ) +#define deref_dn_r( be, dn, err, matched, text ) \ + deref_internal_r( be, NULL, dn, err, matched, text) /* * attr.c diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c index 5ca3f1de3e..35dfabd0d8 100644 --- a/servers/slapd/back-ldbm/search.c +++ b/servers/slapd/back-ldbm/search.c @@ -37,6 +37,7 @@ ldbm_back_search( { struct ldbminfo *li = (struct ldbminfo *) be->be_private; int rc, err; + char *text; time_t stoptime; ID_BLOCK *candidates; ID id; @@ -49,19 +50,15 @@ ldbm_back_search( Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0); -#ifdef SLAPD_ALIASES /* get entry with reader lock */ if ( deref & LDAP_DEREF_FINDING ) { - e = alias_dn2entry_r( be, base, &matched, &err ); + e = deref_dn_r( be, base, &err, &matched, &text ); } else { e = dn2entry_r( be, base, &matched ); err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL; + text = NULL; } -#else - e = dn2entry_r( be, base, &matched ); - err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL; -#endif if ( e == NULL ) { char *matched_dn = NULL; @@ -69,16 +66,18 @@ ldbm_back_search( if ( matched != NULL ) { matched_dn = ch_strdup( matched->e_dn ); + refs = is_entry_referral( matched ) ? get_entry_referrals( be, conn, op, matched ) : NULL; + cache_return_entry_r( &li->li_cache, matched ); } else { refs = default_referral; } send_ldap_result( conn, op, err, - matched_dn, NULL, refs, NULL ); + matched_dn, text, refs, NULL ); if( matched != NULL ) { ber_bvecfree( refs ); @@ -94,7 +93,7 @@ ldbm_back_search( struct berval **refs = get_entry_referrals( be, conn, op, e ); - cache_return_entry_r( &li->li_cache, matched ); + cache_return_entry_r( &li->li_cache, e ); Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 ); @@ -181,18 +180,22 @@ ldbm_back_search( goto loop_continue; } -#ifdef SLAPD_ALIASES if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) { - Entry *newe; + Entry *matched; + int err; + char *text; - newe = alias2entry_r( be, e ); + e = deref_entry_r( be, e, &err, &matched, &text ); - if( newe == NULL ) { + if( e == NULL ) { + e = matched; goto loop_continue; } - cache_return_entry_r( &li->li_cache, e ); - e = newe; + if( e->e_id == id ) { + /* circular loop */ + goto loop_continue; + } /* need to skip alias which deref into scope */ if( scope & LDAP_SCOPE_ONELEVEL ) { @@ -214,7 +217,6 @@ ldbm_back_search( scopeok = 1; } -#endif /* * if it's a referral, add it to the list of referrals. only do -- 2.39.5