]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/alias.c
b9c0d9481d6e904375e83909915393f133dbe4ec
[openldap] / servers / slapd / back-ldbm / alias.c
1 /*
2  * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
3  * All rights reserved.
4  *
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.
11  */
12
13 #include <stdio.h>
14 #include <string.h>
15 #include "slap.h"
16 #include "back-ldbm.h"
17 #include "proto-back-ldbm.h"
18
19 /*
20  * given an alias object, dereference it to its end point.
21  * entry returned has reader lock 
22  */
23 Entry *derefAlias_r ( Backend     *be,
24                     Connection  *conn,
25                     Operation   *op,
26                     Entry       *e)
27 {
28   Attribute *a;
29   int       depth;
30   char      **pastAliases;
31   char      *matched;
32
33   Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );
34
35   /*
36    * try to deref fully, up to a maximum depth.  If the max depth exceeded
37    * then send an error
38    */
39   for ( depth = 0;
40         ( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
41           ( depth < be->be_maxDerefDepth );
42         ++depth) 
43   {
44
45     /* 
46      * make sure there is a defined aliasedobjectname.  
47      * can only have one value so just use first value (0) in the attr list. 
48      */     
49     if (a->a_vals[0] && a->a_vals[0]->bv_val) {
50       char *newDN, *oldDN;
51
52       Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", 
53              e->e_dn, a->a_vals[0]->bv_val, 0 );
54       newDN = strdup (a->a_vals[0]->bv_val);
55       oldDN = strdup (e->e_dn);
56
57       /*
58        * ok, so what happens if there is an alias in the DN of a dereferenced
59        * alias object?  
60        */
61       if ( (e = dn2entry_r( be, newDN, &matched )) == NULL ) {
62
63         /* could not deref return error  */
64         Debug( LDAP_DEBUG_TRACE, 
65                "<= %s is a dangling alias to %s\n", 
66                oldDN, newDN, 0 );
67         send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
68                           "Dangling Alias" );
69
70                         if(matched != NULL) free(matched);
71       }
72       free (newDN);
73       free (oldDN);
74     }
75     else {
76       /*
77        * there was an aliasedobjectname defined but no data.
78        * this can't happen, right?
79        */
80         Debug( LDAP_DEBUG_TRACE, 
81                "<= %s has no data in aliasedobjectname attribute\n", 
82                e->e_dn, 0, 0 );
83         send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
84                           "Alias missing aliasedobjectname" );
85     }
86   }
87
88   /*
89    * warn if we pulled out due to exceeding the maximum deref depth
90    */
91   if ( depth >= be->be_maxDerefDepth ) {
92     Debug( LDAP_DEBUG_TRACE, 
93            "<= %s exceeded maximum deref depth %d\n", 
94            e->e_dn, be->be_maxDerefDepth, 0 );
95     send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
96                         "Maximum alias dereference depth exceeded" );
97   }
98
99   return e;
100 }
101
102 /*
103  * given a DN fully deref it and return the real DN or original DN if it fails
104  */
105 char *derefDN ( Backend     *be,
106                 Connection  *conn,
107                 Operation   *op,
108                 char        *dn
109 )
110 {
111   struct ldbminfo *li = (struct ldbminfo *) be->be_private;
112   char  *matched;
113   char  *newDN;
114   int   depth;
115   Entry         *eMatched;
116   Entry         *eDeref;
117   Entry         *eNew;
118   
119
120   Debug( LDAP_DEBUG_TRACE, 
121          "<= dereferencing dn %s\n", 
122          dn, 0, 0 );
123   
124   newDN = strdup ( dn );
125   
126   /* while we don't have a matched dn, deref the DN */
127   for ( depth = 0;
128         ( (eMatched = dn2entry_r( be, newDN, &matched )) == NULL) &&
129           (depth < be->be_maxDerefDepth);
130         ++depth ) {
131     
132     /* free reader lock */
133     cache_return_entry_r(&li->li_cache, eMatched);
134
135     if (*matched) {     
136       char *submatch;
137       
138       /* 
139        * make sure there actually is an entry for the matched part 
140        */
141       if ( (eMatched = dn2entry_r( be, matched, &submatch )) != NULL) {
142         char  *remainder; /* part before the aliased part */
143         int  rlen = strlen(newDN) - strlen(matched);
144         
145         Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
146         
147         remainder = ch_malloc (rlen + 1);
148         strncpy ( remainder, newDN, rlen );
149         remainder[rlen] = '\0';
150         
151         Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
152         
153         if ((eNew = derefAlias_r( be, conn, op, eMatched )) == NULL) {
154           free (matched);
155           free (newDN);
156           free (remainder);
157           break; /*  no associated entry, dont deref */
158         }
159         else {
160
161           Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );
162
163           if (!strcasecmp (matched, eNew->e_dn)) {
164             /* newDN same as old so not an alias, no need to go further */
165             free (newDN);
166             free (matched);
167             free (remainder);
168             break;
169           }
170
171           /* 
172            * we have dereferenced the aliased part so put
173            * the new dn together
174            */
175           free (newDN);
176           free (matched);
177           
178           newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
179           strcpy (newDN, remainder);
180           strcat (newDN, eMatched->e_dn);
181           Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
182
183           free (remainder);
184
185           /* free reader lock */
186           cache_return_entry_r(&li->li_cache, eNew);
187         }
188         /* free reader lock */
189         cache_return_entry_r(&li->li_cache, eMatched);
190       }
191       else {
192         if(submatch != NULL) free(submatch);
193         break; /* there was no entry for the matched part */
194       }
195     }
196     else {
197       break; /* there was no matched part */
198     }
199   }
200   
201   /*
202    * the final part of the DN might be an alias 
203    * so try to dereference it.
204    */
205   if ( (eNew = dn2entry_r( be, newDN, &matched )) != NULL) {
206     if ((eDeref = derefAlias_r( be, conn, op, eNew )) != NULL) {
207       free (newDN);
208       newDN = strdup (eDeref->e_dn);
209       /* free reader lock */
210       cache_return_entry_r(&li->li_cache, eDeref);
211     }
212     /* free reader lock */
213     cache_return_entry_r(&li->li_cache, eNew);
214   }
215   
216   /*
217    * warn if we exceeded the max depth as the resulting DN may not be dereferenced
218    */
219   if (depth >= be->be_maxDerefDepth) {
220     Debug( LDAP_DEBUG_TRACE, 
221            "<= max deref depth exceeded in derefDN for %s, result %s\n", 
222            dn, newDN, 0 );
223     send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
224                       "Maximum alias dereference depth exceeded for base" );
225   }
226   
227   Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of  %s\n", newDN, 0, 0 ); 
228
229   free(matched);
230
231   return newDN;
232 }