]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/alias.c
Add OpenLDAP RCSid to *.[ch] in clients, libraries, and servers.
[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         return entry;
209 }
210
211
212 static char* get_alias_dn(
213         Entry *e,
214         int *err,
215         char **errmsg )
216 {       
217         Attribute *a = attr_find( e->e_attrs, "aliasedobjectname" );
218
219         if( a == NULL ) {
220                 /*
221                  * there was an aliasedobjectname defined but no data.
222                  */
223                 *err = LDAP_ALIAS_PROBLEM;
224                 *errmsg = "alias missing aliasedObjectName attribute";
225                 return NULL;
226         }
227
228         /* 
229          * aliasedObjectName should be SINGLE-VALUED with a single value. 
230          */                     
231         if ( a->a_vals[0] == NULL || a->a_vals[0]->bv_val == NULL ) {
232                 /*
233                  * there was an aliasedobjectname defined but no data.
234                  */
235                 *err = LDAP_ALIAS_PROBLEM;
236                 *errmsg = "alias missing aliasedObjectName value";
237                 return NULL;
238         }
239
240         if( a->a_vals[1] != NULL ) {
241                 *err = LDAP_ALIAS_PROBLEM;
242                 *errmsg = "alias has multivalued aliasedObjectName";
243                 return NULL;
244         }
245
246         return a->a_vals[0]->bv_val;
247 }
248
249 char* new_superior(
250         char *dn,
251         char *oldSup,
252         char *newSup )
253 {
254         char *newDN;
255         size_t dnlen, olen, nlen;
256         assert( dn && oldSup && newSup );
257
258         dnlen = strlen( dn );
259         olen = strlen( oldSup );
260         nlen = strlen( newSup );
261
262         newDN = ch_malloc( dnlen - olen + nlen + 1 );
263
264         memcpy( newDN, dn, dnlen - olen );
265         memcpy( &newDN[dnlen - olen], newSup, nlen );
266         newDN[dnlen - olen + nlen] = '\0';
267
268         return newDN;
269 }
270
271 static int dnlist_subordinate(
272         char** dnlist,
273         char *dn )
274 {
275         int i;
276         assert( dnlist );
277
278         for( i = 0; dnlist[i] != NULL; i++ ) {
279                 if( dn_issuffix( dnlist[i], dn ) ) {
280                         return 1;
281                 }
282         }
283
284         return 0;
285 }
286