diff --git a/servers/slapd/back-ldbm/alias.c b/servers/slapd/back-ldbm/alias.c new file mode 100644 index 0000000000..9d34440d91 --- /dev/null +++ b/servers/slapd/back-ldbm/alias.c @@ -0,0 +1,242 @@ +/* + * 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. + */ + +#include +#include +#include "slap.h" +#include "back-ldbm.h" + +extern Attribute *attr_find(); + +/* + * given an alias object, dereference it to its end point. + */ +Entry *derefAlias ( Backend *be, + Connection *conn, + Operation *op, + Entry *e + ) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + Attribute *a; + ID id; + int depth; + char **pastAliases; + + 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); + + /* free reader lock */ + cache_return_entry_r( &li->li_cache, e ); + e = NULL; + + /* + * ok, so what happens if there is an alias in the DN of a dereferenced + * alias object? + */ + if ( (id = dn2id( be, newDN )) == NOID || + (e = id2entry_r( be, id )) == 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" ); + } + 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; +} + +/* + * 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 +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + char *matched; + char *newDN; + int depth; + Entry *e = NULL; + + + 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; + ( (e = dn2entry_r( be, newDN, &matched )) == NULL) && + (depth < be->be_maxDerefDepth); + ++depth ) { + + if (*matched) { + char *submatch; + + if( e != NULL ) { + /* free reader lock */ + cache_return_entry_r( &li->li_cache, e ); + e = NULL; + } + + /* + * make sure there actually is an entry for the matched part + */ + if ( (e = dn2entry_r( be, matched, &submatch )) != NULL) { + char *remainder; /* part before the aliased part */ + Entry *newE; + 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 ((newE = derefAlias (be, conn, op, e)) == NULL) { + free (matched); + free (newDN); + break; /* no associated entry, dont deref */ + } + else { + + Debug( LDAP_DEBUG_TRACE, + "<= l&g we have %s vs %s \n", + matched, newE->e_dn, 0 ); + + if (!strcasecmp (matched, newE->e_dn)) { + /* newDN same as old so not an alias, no need to go further */ + free (newDN); + free (matched); + break; + } + + /* + * we have dereferenced the aliased part so put + * the new dn together + */ + free (newDN); + free (matched); + + newDN = ch_malloc (strlen(e->e_dn) + rlen + 1); + strcpy (newDN, remainder); + strcat (newDN, e->e_dn); + Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 ); + } + } + else { + break; /* there was no entry for the matched part */ + } + } + else { + break; /* there was no matched part */ + } + + if( e != NULL ) { + /* free reader lock */ + cache_return_entry_r( &li->li_cache, e ); + e = NULL; + } + } + + if( e != NULL ) { + /* free reader lock */ + cache_return_entry_r( &li->li_cache, e ); + e = NULL; + } + + /* + * the final part of the DN might be an alias + * so try to dereference it. + */ + + if ( (e = dn2entry_r( be, newDN, &matched )) != NULL) { + if ((e = derefAlias (be, conn, op, e)) != NULL) { + free (newDN); + newDN = strdup (e->e_dn); + } + } + + /* + * 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 ); + + return newDN; +} diff --git a/servers/slapd/suffixalias.c b/servers/slapd/suffixalias.c new file mode 100644 index 0000000000..f7c9534afe --- /dev/null +++ b/servers/slapd/suffixalias.c @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include +#include +#include "slap.h" + +/* + * given a dn (or root part), return an aliased dn if any of the + * alias suffixes match + */ +char *suffixAlias ( dn, op, be ) + char *dn; + Operation *op; + Backend *be; +{ + int i, dnLength; + + dnLength = strlen ( dn ); + op->o_suffix = NULL; + op->o_suffixAliased = NULL; + for ( i = 0; + be->be_suffixAlias != NULL && be->be_suffixAlias[i] != NULL; + i += 2) { + int aliasLength = strlen (be->be_suffixAlias[i]); + if (aliasLength > dnLength) { + continue; + } + + if (!strcasecmp(be->be_suffixAlias[i], + dn + (dnLength - aliasLength))) { + char *oldDN = dn; + op->o_suffixAliased = strdup ( be->be_suffixAlias[i] ); + dn = ch_malloc ( (dnLength - aliasLength) + + strlen (be->be_suffixAlias[ i+1 ]) + 1); + strncpy (dn, oldDN, dnLength - aliasLength); + strcpy (dn + (dnLength - aliasLength), be->be_suffixAlias[ i+1 ]); + op->o_suffix = strdup (dn); + Debug( LDAP_DEBUG_ARGS, "ALIAS: converted %s to %s", oldDN, dn, 0); + free (oldDN); + break; + } + } + return dn; +}