X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldbm%2Falias.c;h=104dbbee514ac0150849a4eb917524073a0eeec8;hb=426ca14a868b6edb638b48e14593542a365fcc4b;hp=b7fbcf5328685ccdedb171207c453f2887322303;hpb=0c38adcfd8ebf140353791f18ddfa80a056bc416;p=openldap diff --git a/servers/slapd/back-ldbm/alias.c b/servers/slapd/back-ldbm/alias.c index b7fbcf5328..104dbbee51 100644 --- a/servers/slapd/back-ldbm/alias.c +++ b/servers/slapd/back-ldbm/alias.c @@ -1,235 +1,231 @@ +/* $OpenLDAP$ */ /* - * 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-2003 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ #include "portable.h" #include -#include -#include /* Get struct sockaddr for slap.h */ +#include +#include #include "slap.h" #include "back-ldbm.h" #include "proto-back-ldbm.h" -/* - * given an alias object, dereference it to its end point. - * entry returned has reader lock - */ -Entry *derefAlias_r ( Backend *be, - Connection *conn, - Operation *op, - Entry *e) + +static void new_superior( + struct berval *dn, + struct berval *oldSup, + struct berval *newSup, + struct berval *res ); + +static int dnlist_subordinate( + BerVarray dnlist, + struct berval *dn ); + +Entry *deref_internal_r( + Backend* be, + Entry* alias, + struct berval* dn_in, + int* err, + Entry** matched, + const char** text ) { - Attribute *a; - int depth; - char **pastAliases; - char *matched; - - 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 = strdup (a->a_vals[0]->bv_val); - oldDN = strdup (e->e_dn); - - /* - * ok, so what happens if there is an alias in the DN of a dereferenced - * alias object? - */ - if ( (e = 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_PROBLEM, "", - "Dangling Alias" ); - - if(matched != NULL) free(matched); - } - 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_dn, 0, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "", - "Alias missing aliasedobjectname" ); - } - } - - /* - * warn if we pulled out due to exceeding the maximum deref depth - */ - if ( depth >= be->be_maxDerefDepth ) { - Debug( LDAP_DEBUG_TRACE, - "<= %s exceeded maximum deref depth %d\n", - e->e_dn, be->be_maxDerefDepth, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "", - "Maximum alias dereference depth exceeded" ); - } - - return e; + struct berval dn; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *entry; + Entry *sup; + unsigned depth; + BerVarray dnlist; + + assert( ( alias != NULL && dn_in == NULL ) + || ( alias == NULL && dn_in != NULL ) ); + + *matched = NULL; + *err = LDAP_NO_SUCH_OBJECT; + *text = NULL; + + if( alias == NULL ) { + ber_dupbv( &dn, dn_in ); + entry = dn2entry_r( be, &dn, &sup ); + + } else { + ber_dupbv( &dn, &alias->e_nname ); + entry = alias; + sup = NULL; + } + + dnlist = NULL; + ber_bvarray_add( &dnlist, &dn ); + + for( depth=0 ; ; depth++ ) { + if( entry != NULL ) { + Entry *newe; + struct berval 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 */ + if( get_alias_dn( entry, &aliasDN, err, text )) { + *matched = entry; + entry = NULL; + break; + } + + /* check if aliasDN is a subordinate of any DN in our list */ + if( dnlist_subordinate( dnlist, &aliasDN ) ) { + ch_free( aliasDN.bv_val ); + *matched = entry; + entry = NULL; + *err = LDAP_ALIAS_PROBLEM; + *text = "circular alias"; + break; + } + + /* attempt to dereference alias */ + + newe = dn2entry_r( be, &aliasDN, &sup ); + ch_free( aliasDN.bv_val ); + + if( newe != NULL ) { + cache_return_entry_r(&li->li_cache, entry ); + entry = newe; + ber_dupbv( &dn, &entry->e_nname ); + ber_bvarray_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; + + } else if( sup != NULL ) { + /* have superior, may be an alias */ + Entry *newe; + Entry *newSup; + struct berval supDN; + struct berval 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 */ + if( get_alias_dn( sup, &supDN, err, text )) { + *matched = sup; + break; + } + + new_superior( &dn, &sup->e_nname, &supDN, &aliasDN ); + free(supDN.bv_val); + + /* check if aliasDN is a subordinate of any DN in our list */ + if( dnlist_subordinate( dnlist, &aliasDN ) ) { + free(aliasDN.bv_val); + *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.bv_val); + cache_return_entry_r(&li->li_cache, sup ); + entry = newe; + ber_dupbv( &dn, &entry->e_nname ); + ber_bvarray_add( &dnlist, &dn ); + continue; + } + + if ( newSup != NULL ) { + cache_return_entry_r(&li->li_cache, sup ); + sup = newSup; + ber_dupbv( &dn, &aliasDN ); + continue; + } + + break; + + } else { + /* no newe and no superior, we're done */ + break; + } + } + + ber_bvarray_free( dnlist ); + return entry; } -/* - * given a DN fully deref it and return the real DN or original DN if it fails - */ -char *derefDN ( Backend *be, - Connection *conn, - Operation *op, - char *dn -) + +static void new_superior( + struct berval *dn, + struct berval *oldSup, + struct berval *newSup, + struct berval *newDN ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched; - char *newDN; - int depth; - Entry *eMatched; - Entry *eDeref; - Entry *eNew; - - - Debug( LDAP_DEBUG_TRACE, - "<= dereferencing dn %s\n", - dn, 0, 0 ); - - newDN = strdup ( dn ); - - /* while we don't have a matched dn, deref the DN */ - for ( depth = 0; - ( (eMatched = dn2entry_r( be, newDN, &matched )) == NULL) && - (depth < be->be_maxDerefDepth); - ++depth ) { - - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eMatched); - - if (*matched) { - char *submatch; - - /* - * make sure there actually is an entry for the matched part - */ - if ( (eMatched = 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 = derefAlias_r( be, conn, op, eMatched )) == NULL) { - free (matched); - free (newDN); - free (remainder); - break; /* no associated entry, dont deref */ - } - else { - - Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 ); - - if (!strcasecmp (matched, eNew->e_dn)) { - /* newDN same as old so not an alias, no need to go further */ - free (newDN); - free (matched); - free (remainder); - break; - } - - /* - * we have dereferenced the aliased part so put - * the new dn together - */ - free (newDN); - free (matched); - - 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); - - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eNew); + size_t dnlen, olen, nlen; + assert( dn && oldSup && newSup && newDN ); + + dnlen = dn->bv_len; + olen = oldSup->bv_len; + nlen = newSup->bv_len; + + newDN->bv_val = ch_malloc( dnlen - olen + nlen + 1 ); + + AC_MEMCPY( newDN->bv_val, dn->bv_val, dnlen - olen ); + AC_MEMCPY( &newDN->bv_val[dnlen - olen], newSup->bv_val, nlen ); + newDN->bv_val[dnlen - olen + nlen] = '\0'; + + return; +} + +static int dnlist_subordinate( + BerVarray dnlist, + struct berval *dn ) +{ + assert( dnlist ); + + for( ; dnlist->bv_val != NULL; dnlist++ ) { + if( dnIsSuffix( dnlist, dn ) ) { + return 1; + } } - /* free reader lock */ - 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 */ - } - } - - /* - * the final part of the DN might be an alias - * so try to dereference it. - */ - if ( (eNew = dn2entry_r( be, newDN, &matched )) != NULL) { - if ((eDeref = derefAlias_r( be, conn, op, eNew )) != NULL) { - free (newDN); - newDN = strdup (eDeref->e_dn); - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eDeref); - } - /* free reader lock */ - cache_return_entry_r(&li->li_cache, eNew); - } - - /* - * warn if we exceeded the max depth as the resulting DN may not be dereferenced - */ - if (depth >= be->be_maxDerefDepth) { - Debug( LDAP_DEBUG_TRACE, - "<= max deref depth exceeded in derefDN for %s, result %s\n", - dn, newDN, 0 ); - send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "", - "Maximum alias dereference depth exceeded for base" ); - } - - Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of %s\n", newDN, 0, 0 ); - - free(matched); - - return newDN; + + return 0; }