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