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