X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldbm%2Falias.c;h=17da4e7fabb6512b43d683634eebdb536662173a;hb=affa8f5a65191abbc40c5b4f9c3ecfd117065dba;hp=b9c0d9481d6e904375e83909915393f133dbe4ec;hpb=708e5abb08c4c633431e0014ad12632af1a38fef;p=openldap diff --git a/servers/slapd/back-ldbm/alias.c b/servers/slapd/back-ldbm/alias.c index b9c0d9481d..17da4e7fab 100644 --- a/servers/slapd/back-ldbm/alias.c +++ b/servers/slapd/back-ldbm/alias.c @@ -1,232 +1,291 @@ +/* $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-2000 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ +#include "portable.h" + #include -#include +#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 int get_alias_dn( + Entry *e, + struct berval *al, + int *err, + const char **errmsg ); + +static void new_superior( + struct berval *dn, + struct berval *oldSup, + struct berval *newSup, + struct berval *res ); + +static int dnlist_subordinate( + BVarray dnlist, + struct berval *dn ); + +Entry *deref_internal_r( + Backend* be, + Entry* alias, + struct berval* dn_in, + int* err, + Entry** matched, + const char** text ) +{ + struct berval dn; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Entry *entry; + Entry *sup; + unsigned depth; + BVarray 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; + 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 ) { + free( dn.bv_val ); + cache_return_entry_r(&li->li_cache, entry ); + entry = newe; + ber_dupbv( &dn, &entry->e_nname ); + 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); + free( dn.bv_val ); + cache_return_entry_r(&li->li_cache, sup ); + entry = newe; + ber_dupbv( &dn, &entry->e_nname ); + bvarray_add( &dnlist, &dn ); + continue; + } + + if ( newSup != NULL ) { + free( dn.bv_val ); + 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; + } + } + + free( dn.bv_val ); + bvarray_free( dnlist ); + return entry; +} + + +static int get_alias_dn( + Entry *e, + struct berval *ndn, + int *err, + const char **errmsg ) +{ + int rc; + Attribute *a; + AttributeDescription *aliasedObjectName + = slap_schema.si_ad_aliasedObjectName; + + 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 -1; + } + + /* + * 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 -1; + } + + if( a->a_vals[1] != NULL ) { + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias has multivalued aliasedObjectName"; + return -1; + } + + rc = dnNormalize2( NULL, a->a_vals[0], ndn ); + if( rc != LDAP_SUCCESS ) { + *err = LDAP_ALIAS_PROBLEM; + *errmsg = "alias aliasedObjectName value is invalid"; + return -1; + } + + return 0; +} + +static void new_superior( + struct berval *dn, + struct berval *oldSup, + struct berval *newSup, + struct berval *newDN ) { - 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; + 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; } -/* - * 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 int dnlist_subordinate( + BVarray dnlist, + struct berval *dn ) { - 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); + 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; }