2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2005 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
19 #include <ac/string.h>
20 #include <ac/socket.h>
22 #include "back-ldbm.h"
23 #include "proto-back-ldbm.h"
26 static void new_superior(
28 struct berval *oldSup,
29 struct berval *newSup,
32 static int dnlist_subordinate(
36 Entry *deref_internal_r(
45 struct ldbminfo *li = (struct ldbminfo *) be->be_private;
51 assert( ( alias != NULL && dn_in == NULL )
52 || ( alias == NULL && dn_in != NULL ) );
55 *err = LDAP_NO_SUCH_OBJECT;
59 ber_dupbv( &dn, dn_in );
60 entry = dn2entry_r( be, &dn, &sup );
63 ber_dupbv( &dn, &alias->e_nname );
69 ber_bvarray_add( &dnlist, &dn );
71 for( depth=0 ; ; depth++ ) {
74 struct berval aliasDN;
76 /* have entry, may be an alias */
78 if( !is_entry_alias( entry ) ) {
79 /* entry is not an alias */
84 if( depth > be->be_max_deref_depth ) {
87 *err = LDAP_ALIAS_DEREF_PROBLEM;
88 *text = "maximum deref depth exceeded";
93 if( get_alias_dn( entry, &aliasDN, err, text )) {
99 /* check if aliasDN is a subordinate of any DN in our list */
100 if( dnlist_subordinate( dnlist, &aliasDN ) ) {
101 ch_free( aliasDN.bv_val );
104 *err = LDAP_ALIAS_PROBLEM;
105 *text = "circular alias";
109 /* attempt to dereference alias */
111 newe = dn2entry_r( be, &aliasDN, &sup );
112 ch_free( aliasDN.bv_val );
115 cache_return_entry_r(&li->li_cache, entry );
117 ber_dupbv( &dn, &entry->e_nname );
118 ber_bvarray_add( &dnlist, &dn );
123 cache_return_entry_r(&li->li_cache, entry );
128 /* no newe and no superior, we're done */
131 } else if( sup != NULL ) {
132 /* have superior, may be an alias */
136 struct berval aliasDN;
138 if( !is_entry_alias( sup ) ) {
139 /* entry is not an alias */
146 if( depth > be->be_max_deref_depth ) {
149 *err = LDAP_ALIAS_DEREF_PROBLEM;
150 *text = "maximum deref depth exceeded";
155 if( get_alias_dn( sup, &supDN, err, text )) {
160 new_superior( &dn, &sup->e_nname, &supDN, &aliasDN );
163 /* check if aliasDN is a subordinate of any DN in our list */
164 if( dnlist_subordinate( dnlist, &aliasDN ) ) {
165 free(aliasDN.bv_val);
168 *err = LDAP_ALIAS_PROBLEM;
169 *text = "subordinate circular alias";
173 /* attempt to dereference alias */
174 newe = dn2entry_r( be, &aliasDN, &newSup );
177 free(aliasDN.bv_val);
178 cache_return_entry_r(&li->li_cache, sup );
180 ber_dupbv( &dn, &entry->e_nname );
181 ber_bvarray_add( &dnlist, &dn );
185 if ( newSup != NULL ) {
186 cache_return_entry_r(&li->li_cache, sup );
188 ber_dupbv( &dn, &aliasDN );
195 /* no newe and no superior, we're done */
200 ber_bvarray_free( dnlist );
205 static void new_superior(
207 struct berval *oldSup,
208 struct berval *newSup,
209 struct berval *newDN )
211 size_t dnlen, olen, nlen;
212 assert( dn && oldSup && newSup && newDN );
215 olen = oldSup->bv_len;
216 nlen = newSup->bv_len;
218 newDN->bv_val = ch_malloc( dnlen - olen + nlen + 1 );
220 AC_MEMCPY( newDN->bv_val, dn->bv_val, dnlen - olen );
221 AC_MEMCPY( &newDN->bv_val[dnlen - olen], newSup->bv_val, nlen );
222 newDN->bv_val[dnlen - olen + nlen] = '\0';
227 static int dnlist_subordinate(
231 assert( dnlist != NULL );
233 for( ; dnlist->bv_val != NULL; dnlist++ ) {
234 if( dnIsSuffix( dnlist, dn ) ) {