]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/alias.c
More struct berval conversions
[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 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         BVarray 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         BVarray 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         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                                 free( dn.bv_val );
113                                 cache_return_entry_r(&li->li_cache, entry );
114                                 entry = newe;
115                                 ber_dupbv( &dn, &entry->e_nname );
116                                 bvarray_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                         struct berval supDN;
134                         struct berval 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                         if( get_alias_dn( sup, &supDN, err, text )) {
154                                 *matched = sup;
155                                 break;
156                         }
157
158                         new_superior( &dn, &sup->e_nname, &supDN, &aliasDN );
159                         free(supDN.bv_val);
160
161                         /* check if aliasDN is a subordinate of any DN in our list */
162                         if( dnlist_subordinate( dnlist, &aliasDN ) ) {
163                                 free(aliasDN.bv_val);
164                                 *matched = entry;
165                                 entry = NULL;
166                                 *err = LDAP_ALIAS_PROBLEM;
167                                 *text = "subordinate circular alias";
168                                 break;
169                         }
170
171                         /* attempt to dereference alias */
172                         newe = dn2entry_r( be, &aliasDN, &newSup );
173
174                         if( newe != NULL ) {
175                                 free(aliasDN.bv_val);
176                                 free( dn.bv_val );
177                                 cache_return_entry_r(&li->li_cache, sup );
178                                 entry = newe;
179                                 ber_dupbv( &dn, &entry->e_nname );
180                                 bvarray_add( &dnlist, &dn );
181                                 continue;
182                         }
183                         
184                         if ( newSup != NULL ) {
185                                 free( dn.bv_val );
186                                 cache_return_entry_r(&li->li_cache, sup );
187                                 sup = newSup;
188                                 ber_dupbv( &dn, &aliasDN );
189                                 continue;
190                         }
191
192                         break;
193
194                 } else {
195                         /* no newe and no superior, we're done */
196                         break;
197                 }
198         }
199
200         free( dn.bv_val );
201         bvarray_free( dnlist );
202         return entry;
203 }
204
205
206 static int get_alias_dn(
207         Entry *e,
208         struct berval *ndn,
209         int *err,
210         const char **errmsg )
211 {       
212         int rc;
213         Attribute *a;
214         AttributeDescription *aliasedObjectName
215                 = slap_schema.si_ad_aliasedObjectName;
216
217         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 -1;
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 -1;
238         }
239
240         if( a->a_vals[1] != NULL ) {
241                 *err = LDAP_ALIAS_PROBLEM;
242                 *errmsg = "alias has multivalued aliasedObjectName";
243                 return -1;
244         }
245
246         rc = dnNormalize2( NULL, a->a_vals[0], ndn );
247         if( rc != LDAP_SUCCESS ) {
248                 *err = LDAP_ALIAS_PROBLEM;
249                 *errmsg = "alias aliasedObjectName value is invalid";
250                 return -1;
251         }
252
253         return 0;
254 }
255
256 static void new_superior(
257         struct berval *dn,
258         struct berval *oldSup,
259         struct berval *newSup,
260         struct berval *newDN )
261 {
262         size_t dnlen, olen, nlen;
263         assert( dn && oldSup && newSup && newDN );
264
265         dnlen = dn->bv_len;
266         olen = oldSup->bv_len;
267         nlen = newSup->bv_len;
268
269         newDN->bv_val = ch_malloc( dnlen - olen + nlen + 1 );
270
271         AC_MEMCPY( newDN->bv_val, dn->bv_val, dnlen - olen );
272         AC_MEMCPY( &newDN->bv_val[dnlen - olen], newSup->bv_val, nlen );
273         newDN->bv_val[dnlen - olen + nlen] = '\0';
274
275         return;
276 }
277
278 static int dnlist_subordinate(
279         BVarray dnlist,
280         struct berval *dn )
281 {
282         assert( dnlist );
283
284         for( ; dnlist->bv_val != NULL; dnlist++ ) {
285                 if( dnIsSuffix( dnlist, dn ) ) {
286                         return 1;
287                 }
288         }
289
290         return 0;
291 }