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