2 * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to ITSD, Government of BC. The name of ITSD
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
16 #include <ac/string.h>
17 #include <ac/socket.h>
19 #include "back-ldbm.h"
20 #include "proto-back-ldbm.h"
26 * input origEntry is should be locked/unlocked by caller.
28 * returns origEntry if origEntry is not an alias
29 * returns NULL if error
30 * otherwise returns read locked alias
32 Entry *deref_alias_r (
41 struct ldbminfo *li = (struct ldbminfo *) be->be_private;
44 char **aliases = NULL;
47 int rc = LDAP_SUCCESS;
50 * Aliases are only deref'ed during search operations.
51 * if deref_alias_r (or deref_dn) is needed by other op,
52 * this will need to become argument
54 const int access = ACL_SEARCH;
56 /* be sure we have a starting entry */
57 if( origEntry != NULL ) {
61 Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n",
62 origEntry->e_dn, 0, 0 );
65 * try to deref fully, up to a maximum depth. If the max depth exceeded
69 for ( depth = 0; e != NULL; depth++ )
74 if ( ! access_allowed( be, conn, op, e,
75 "entry", NULL, access ) )
77 Debug( LDAP_DEBUG_ACL,
78 "deref_alias_r: access to entry not allowed\n",
84 * aliased object names must be contained in an entry
85 * object class "alias".
87 a = attr_find(e->e_attrs, "objectclass");
90 /* no objectclass attribute */
94 bv.bv_val = "REFERRAL";
95 bv.bv_len = sizeof("REFERRAL")-1;
97 if (value_find(a->a_vals, &bv, a->a_syntax, 1) == 0) {
103 bv.bv_len = sizeof("ALIAS")-1;
105 if (value_find(a->a_vals, &bv, a->a_syntax, 1) != 0) {
110 if ( ! access_allowed( be, conn, op, e,
111 "aliasedobjectname", NULL, access ) )
113 Debug( LDAP_DEBUG_ACL,
114 "deref_alias_r: access to reference not allowed\n",
119 a = attr_find( e->e_attrs, "aliasedobjectname" );
123 * there was an aliasedobjectname defined but no data.
125 Debug( LDAP_DEBUG_TRACE,
126 "<= %s has no aliasedObjectName attribute\n",
128 send_ldap_result( conn, op, rc = LDAP_ALIAS_PROBLEM,
129 NULL, "alias missing aliasedObjectName", NULL, NULL );
134 * aliasedObjectName should be SINGLE-VALUED with a single value.
136 if ( a->a_vals[0] == NULL || a->a_vals[0]->bv_val != NULL ) {
138 * there was an aliasedobjectname defined but no data.
140 Debug( LDAP_DEBUG_TRACE,
141 "<= %s has no value aliasedObjectName attribute\n",
143 send_ldap_result( conn, op, rc = LDAP_ALIAS_PROBLEM,
144 NULL, "alias missing aliasedObjectName value", NULL, NULL );
148 if( a->a_vals[1] != NULL ) {
149 Debug( LDAP_DEBUG_TRACE,
150 "<= %s alias has multiple values\n",
152 send_ldap_result( conn, op, rc= LDAP_ALIAS_PROBLEM,
153 NULL, "multivalue aliasObjectName", NULL, NULL );
157 if( depth >= be->be_max_deref_depth ) {
158 /* depth limit exceeded */
159 Debug( LDAP_DEBUG_TRACE,
160 "<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n",
162 be->be_max_deref_depth,
164 send_ldap_result( conn, op, rc = LDAP_ALIAS_DEREF_PROBLEM,
165 NULL, "maximum deref depth exceeded", NULL, NULL );
169 charray_add( &aliases, e->e_ndn );
171 Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n",
172 e->e_dn, a->a_vals[0]->bv_val, 0 );
174 if( oldDN != NULL ) free( oldDN );
175 oldDN = ch_strdup( e->e_ndn );
178 * release past lock if not original
181 cache_return_entry_r(&li->li_cache, e);
185 if( newDN != NULL ) free( newDN );
186 newDN = ch_strdup( a->a_vals[0]->bv_val );
187 dn_normalize_case (newDN);
189 /* make sure new and old DN are not same to avoid loops */
190 if ( charray_inlist( aliases, newDN ) ) {
191 Debug( LDAP_DEBUG_TRACE,
192 "<= %s has circular alias %s\n",
193 origEntry->e_dn, newDN, 0 );
194 send_ldap_result( conn, op, rc = LDAP_LOOP_DETECT,
195 NULL, "circular alias", NULL, NULL );
200 * ok, so what happens if there is an alias in the DN of a dereferenced
203 if ( (e = dn2entry_r( be, newDN, NULL )) == NULL ) {
204 /* could not deref return error */
205 Debug( LDAP_DEBUG_TRACE,
206 "<= %s has dangling alias %s to %s\n",
207 origEntry->e_dn, oldDN, newDN );
208 send_ldap_result( conn, op, rc = LDAP_ALIAS_DEREF_PROBLEM,
209 NULL, "dangling alias", NULL, NULL );
214 if( e != NULL && origEntry != e && rc != LDAP_SUCCESS ) {
215 cache_return_entry_r(&li->li_cache, e);
219 charray_free( aliases );
220 if( newDN ) free(newDN);
221 if( oldDN ) free(oldDN);
228 * given a DN fully deref it and return the real DN or original DN if it fails
229 * This involves finding the last matched part then reconstructing forward.
233 * "cn=AliasUser,ou=OU,o=AliasedOrg,c=CA" where
234 * "o=AliasedOrg,c=CA" is an alias for
237 * "cn=AliasUser,ou=OU,o=Org,c=CA" is an alias for
238 * "cn=User,ou=OU,o=Org,c=CA"
241 * newDN is "cn=AliasUser,ou=OU,o=AliasedOrg,c=CA"
243 * 2) loop: e = d2entry_r( newDN, matched )
245 * matched is entry("o=AliasOrg,c=CA")
247 * 3) rmdr = remainder(newDN, matched)
248 * rmdr is "cn=AliasUser,ou=OU"
250 * 4) alias = deref(matched)
251 * alias is entry("o=Org,c=CA")
253 * 5) oldDN=newDN; newDN = rmdr + alias
254 * oldDN is "cn=AliasUser,ou=OU,o=AliasedOrg,c=CA"
255 * newDN is "cn=AliasUser,ou=OU,o=Org,c=CA"
257 * 6) compare(oldDN,newDN)
260 * 7) e = d2entry_r( newDN, matched )
262 * matched is entry("ou=OU,o=Org,c=CA")
264 * 8) rmdr = remainder(newDN, matched)
265 * rmdr is "cn=AliasUser"
267 * 9) alias = deref(matched)
268 * alias is entry("ou=OU,o=Org,c=CA")
270 *10) oldDN=newDN; newDN = rmdr + alias
271 * oldDN is "cn=AliasUser,ou=OU,o=Org,c=CA"
272 * newDN is "cn=AliasUser,ou=OU,o=Org,c=CA"
274 *11) compare(oldDN,newDN)
275 * break loop (step 2)
287 struct ldbminfo *li = (struct ldbminfo *) be->be_private;
289 char* remainder = NULL;
294 if (!dn) return NULL;
296 Debug( LDAP_DEBUG_TRACE,
297 "<= dereferencing dn: \"%s\"\n",
300 charray_add( &dns, "" );
302 newDN = ch_strdup( dn );
304 for ( depth = 0; charray_inlist( dns, newDN ) != 0; depth++ )
307 Entry* matched = NULL;
311 if( depth >= be->be_max_deref_depth ) {
312 /* depth limit exceeded */
316 e = dn2entry_r( be, newDN, &matched );
319 cache_return_entry_r(&li->li_cache, e);
323 if ( matched == NULL ) {
324 /* nothing matched */
328 charray_add( &dns, newDN );
330 Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched->e_dn, 0, 0 );
332 rlen = strlen( newDN ) - strlen( matched->e_ndn );
333 remainder = ch_malloc( rlen + 1 );
334 strncpy( remainder, newDN, rlen );
335 remainder[rlen] = '\0';
337 Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
339 alias = deref_alias_r( be, conn, op, matched );
341 cache_return_entry_r(&li->li_cache, matched);
343 if( alias == matched ) {
344 /* matched isn't an alias */
348 if( alias == NULL ) {
353 Debug( LDAP_DEBUG_TRACE, "<= derefenced to %s\n", alias->e_dn, 0, 0 );
356 newDN = ch_malloc( rlen + strlen( alias->e_ndn ) + 1 );
357 sprintf("%s%s", remainder, alias->e_ndn );
362 Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
364 cache_return_entry_r( &li->li_cache, alias );
369 if( remainder != NULL ) {
373 Debug( LDAP_DEBUG_TRACE, "<= %s\n", newDN, 0, 0 );