]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/alias.c
f04428ad14f58f56baa45dc7a94e4f8a665eb51d
[openldap] / servers / slapd / back-ldbm / alias.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10 #include <ac/string.h>
11 #include <ac/socket.h>
12 #include "slap.h"
13 #include "back-ldbm.h"
14 #include "proto-back-ldbm.h"
15
16
17 static char* get_alias_dn(
18         Entry *e,
19         int *err,
20         const char **errmsg );
21
22 static char* new_superior(
23         const char *dn,
24         const char *oldSup,
25         const char *newSup );
26
27 static int dnlist_subordinate(
28         char** dnlist,
29         const char *dn );
30
31 Entry *deref_internal_r(
32         Backend*        be,
33         Entry*          alias,
34         const char*             dn_in,
35         int*            err,
36         Entry**         matched,
37         const char**            text )
38 {
39         char *dn;
40         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
41         Entry *entry;
42         Entry *sup;
43         unsigned depth;
44         char **dnlist;
45
46         assert( ( alias != NULL && dn_in == NULL )
47                 || ( alias == NULL && dn_in != NULL ) );
48
49         *matched = NULL;
50         *err = LDAP_NO_SUCH_OBJECT;
51         *text = NULL;
52
53         if( alias == NULL ) {
54                 dn = ch_strdup( dn_in );
55                 entry = dn2entry_r( be, dn, &sup );
56
57         } else {
58                 dn = ch_strdup( alias->e_ndn );
59                 entry = alias;
60                 sup = NULL;
61         }
62
63         dnlist = NULL;
64         charray_add( &dnlist, dn );
65
66         for( depth=0 ; ; depth++ ) {
67                 if( entry != NULL ) {
68                         Entry *newe;
69                         char *aliasDN;
70
71                         /* have entry, may be an alias */
72
73                         if( !is_entry_alias( entry ) ) {
74                                 /* entry is not an alias */
75                                 break;
76                         }
77
78                         /* entry is alias */
79                         if( depth > be->be_max_deref_depth ) {
80                                 *matched = entry;
81                                 entry = NULL;
82                                 *err = LDAP_ALIAS_DEREF_PROBLEM;
83                                 *text = "maximum deref depth exceeded";
84                                 break;
85                         }
86
87                         /* deref entry */
88                         aliasDN = get_alias_dn( entry, err, text );
89
90                         if( aliasDN == NULL ) {
91                                 *matched = entry;
92                                 entry = NULL;
93                                 break;
94                         }
95
96                         /* check if aliasDN is a subordinate of any DN in our list */
97                         if( dnlist_subordinate( dnlist, aliasDN ) ) {
98                                 ch_free( aliasDN );
99                                 *matched = entry;
100                                 entry = NULL;
101                                 *err = LDAP_ALIAS_PROBLEM;
102                                 *text = "circular alias";
103                                 break;
104                         }
105
106                         /* attempt to dereference alias */
107
108                         newe = dn2entry_r( be, aliasDN, &sup );
109                         ch_free( aliasDN );
110
111                         if( newe != NULL ) {
112                                 free( dn );
113                                 cache_return_entry_r(&li->li_cache, entry );
114                                 entry = newe;
115                                 dn = ch_strdup( entry->e_ndn );
116                                 charray_add( &dnlist, dn );
117                                 continue;
118                         }
119                         
120                         if ( sup != NULL ) {
121                                 cache_return_entry_r(&li->li_cache, entry );
122                                 entry = NULL;
123                                 continue;
124                         }
125
126                         /* no newe and no superior, we're done */
127                         break;
128
129                 } else if( sup != NULL ) {
130                         /* have superior, may be an alias */
131                         Entry *newe;
132                         Entry *newSup;
133                         char *supDN;
134                         char *aliasDN;
135
136                         if( !is_entry_alias( sup ) ) {
137                                 /* entry is not an alias */
138                                 *matched = sup;
139                                 sup = NULL;
140                                 break;
141                         }
142
143                         /* entry is alias */
144                         if( depth > be->be_max_deref_depth ) {
145                                 *matched = sup;
146                                 entry = NULL;
147                                 *err = LDAP_ALIAS_DEREF_PROBLEM;
148                                 *text = "maximum deref depth exceeded";
149                                 break;
150                         }
151
152                         /* deref entry */
153                         supDN = get_alias_dn( sup, err, text );
154
155                         if( supDN == NULL ) {
156                                 *matched = sup;
157                                 break;
158                         }
159
160                         aliasDN = new_superior( dn, sup->e_ndn, supDN );
161                         free(supDN);
162
163                         if( aliasDN == NULL ) {
164                                 free(aliasDN);
165                                 *matched = sup;
166                                 *err = LDAP_ALIAS_PROBLEM;
167                                 *text = "superior alias problem";
168                                 break;
169                         }
170
171                         /* check if aliasDN is a subordinate of any DN in our list */
172                         if( dnlist_subordinate( dnlist, aliasDN ) ) {
173                                 free(aliasDN);
174                                 *matched = entry;
175                                 entry = NULL;
176                                 *err = LDAP_ALIAS_PROBLEM;
177                                 *text = "subordinate circular alias";
178                                 break;
179                         }
180
181                         /* attempt to dereference alias */
182                         newe = dn2entry_r( be, aliasDN, &newSup );
183
184                         if( newe != NULL ) {
185                                 free(aliasDN);
186                                 free( dn );
187                                 cache_return_entry_r(&li->li_cache, sup );
188                                 entry = newe;
189                                 dn = ch_strdup( entry->e_ndn );
190                                 charray_add( &dnlist, dn );
191                                 continue;
192
193                         }
194                         
195                         if ( newSup != NULL ) {
196                                 free( dn );
197                                 cache_return_entry_r(&li->li_cache, sup );
198                                 sup = newSup;
199                                 dn = aliasDN;
200                                 continue;
201                         }
202
203                         break;
204
205                 } else {
206                         /* no newe and no superior, we're done */
207                         break;
208                 }
209         }
210
211         free( dn );
212         charray_free( dnlist );
213         return entry;
214 }
215
216
217 static char* get_alias_dn(
218         Entry *e,
219         int *err,
220         const char **errmsg )
221 {       
222         char *dn;
223         Attribute *a;
224         AttributeDescription *aliasedObjectName = slap_schema.si_ad_aliasedObjectName;
225
226         a = attr_find( e->e_attrs, aliasedObjectName );
227
228         if( a == NULL ) {
229                 /*
230                  * there was an aliasedobjectname defined but no data.
231                  */
232                 *err = LDAP_ALIAS_PROBLEM;
233                 *errmsg = "alias missing aliasedObjectName attribute";
234                 return NULL;
235         }
236
237         /* 
238          * aliasedObjectName should be SINGLE-VALUED with a single value. 
239          */                     
240         if ( a->a_vals[0] == NULL || a->a_vals[0]->bv_val == NULL ) {
241                 /*
242                  * there was an aliasedobjectname defined but no data.
243                  */
244                 *err = LDAP_ALIAS_PROBLEM;
245                 *errmsg = "alias missing aliasedObjectName value";
246                 return NULL;
247         }
248
249         if( a->a_vals[1] != NULL ) {
250                 *err = LDAP_ALIAS_PROBLEM;
251                 *errmsg = "alias has multivalued aliasedObjectName";
252                 return NULL;
253         }
254
255         dn = ch_strdup( a->a_vals[0]->bv_val );
256
257         if( dn_normalize(dn) == NULL ) {
258                 ch_free( dn );
259                 *err = LDAP_ALIAS_PROBLEM;
260                 *errmsg = "alias aliasedObjectName value is invalid";
261                 return NULL;
262         }
263
264         return dn;
265 }
266
267 static char* new_superior(
268         const char *dn,
269         const char *oldSup,
270         const char *newSup )
271 {
272         char *newDN;
273         size_t dnlen, olen, nlen;
274         assert( dn && oldSup && newSup );
275
276         dnlen = strlen( dn );
277         olen = strlen( oldSup );
278         nlen = strlen( newSup );
279
280         newDN = ch_malloc( dnlen - olen + nlen + 1 );
281
282         AC_MEMCPY( newDN, dn, dnlen - olen );
283         AC_MEMCPY( &newDN[dnlen - olen], newSup, nlen );
284         newDN[dnlen - olen + nlen] = '\0';
285
286         return newDN;
287 }
288
289 static int dnlist_subordinate(
290         char** dnlist,
291         const char *dn )
292 {
293         int i;
294         assert( dnlist );
295
296         for( i = 0; dnlist[i] != NULL; i++ ) {
297                 if( dn_issuffix( dnlist[i], dn ) ) {
298                         return 1;
299                 }
300         }
301
302         return 0;
303 }
304