]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/alias.c
Sync with HEAD
[openldap] / servers / slapd / back-ldbm / alias.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2005 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15
16 #include "portable.h"
17
18 #include <stdio.h>
19 #include <ac/string.h>
20 #include <ac/socket.h>
21 #include "slap.h"
22 #include "back-ldbm.h"
23 #include "proto-back-ldbm.h"
24
25
26 static void new_superior(
27         struct berval *dn,
28         struct berval *oldSup,
29         struct berval *newSup,
30         struct berval *res );
31
32 static int dnlist_subordinate(
33         BerVarray dnlist,
34         struct berval *dn );
35
36 Entry *deref_internal_r(
37         Backend*        be,
38         Entry*          alias,
39         struct berval*  dn_in,
40         int*            err,
41         Entry**         matched,
42         const char**            text )
43 {
44         struct berval dn;
45         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
46         Entry *entry;
47         Entry *sup;
48         unsigned depth;
49         BerVarray dnlist;
50
51         assert( ( alias != NULL && dn_in == NULL )
52                 || ( alias == NULL && dn_in != NULL ) );
53
54         *matched = NULL;
55         *err = LDAP_NO_SUCH_OBJECT;
56         *text = NULL;
57
58         if( alias == NULL ) {
59                 ber_dupbv( &dn, dn_in );
60                 entry = dn2entry_r( be, &dn, &sup );
61
62         } else {
63                 ber_dupbv( &dn, &alias->e_nname );
64                 entry = alias;
65                 sup = NULL;
66         }
67
68         dnlist = NULL;
69         ber_bvarray_add( &dnlist, &dn );
70
71         for( depth=0 ; ; depth++ ) {
72                 if( entry != NULL ) {
73                         Entry *newe;
74                         struct berval aliasDN;
75
76                         /* have entry, may be an alias */
77
78                         if( !is_entry_alias( entry ) ) {
79                                 /* entry is not an alias */
80                                 break;
81                         }
82
83                         /* entry is alias */
84                         if( depth > be->be_max_deref_depth ) {
85                                 *matched = entry;
86                                 entry = NULL;
87                                 *err = LDAP_ALIAS_DEREF_PROBLEM;
88                                 *text = "maximum deref depth exceeded";
89                                 break;
90                         }
91
92                         /* deref entry */
93                         if( get_alias_dn( entry, &aliasDN, err, text )) {
94                                 *matched = entry;
95                                 entry = NULL;
96                                 break;
97                         }
98
99                         /* check if aliasDN is a subordinate of any DN in our list */
100                         if( dnlist_subordinate( dnlist, &aliasDN ) ) {
101                                 ch_free( aliasDN.bv_val );
102                                 *matched = entry;
103                                 entry = NULL;
104                                 *err = LDAP_ALIAS_PROBLEM;
105                                 *text = "circular alias";
106                                 break;
107                         }
108
109                         /* attempt to dereference alias */
110
111                         newe = dn2entry_r( be, &aliasDN, &sup );
112                         ch_free( aliasDN.bv_val );
113
114                         if( newe != NULL ) {
115                                 cache_return_entry_r(&li->li_cache, entry );
116                                 entry = newe;
117                                 ber_dupbv( &dn, &entry->e_nname );
118                                 ber_bvarray_add( &dnlist, &dn );
119                                 continue;
120                         }
121                         
122                         if ( sup != NULL ) {
123                                 cache_return_entry_r(&li->li_cache, entry );
124                                 entry = NULL;
125                                 continue;
126                         }
127
128                         /* no newe and no superior, we're done */
129                         break;
130
131                 } else if( sup != NULL ) {
132                         /* have superior, may be an alias */
133                         Entry *newe;
134                         Entry *newSup;
135                         struct berval supDN;
136                         struct berval aliasDN;
137
138                         if( !is_entry_alias( sup ) ) {
139                                 /* entry is not an alias */
140                                 *matched = sup;
141                                 sup = NULL;
142                                 break;
143                         }
144
145                         /* entry is alias */
146                         if( depth > be->be_max_deref_depth ) {
147                                 *matched = sup;
148                                 entry = NULL;
149                                 *err = LDAP_ALIAS_DEREF_PROBLEM;
150                                 *text = "maximum deref depth exceeded";
151                                 break;
152                         }
153
154                         /* deref entry */
155                         if( get_alias_dn( sup, &supDN, err, text )) {
156                                 *matched = sup;
157                                 break;
158                         }
159
160                         new_superior( &dn, &sup->e_nname, &supDN, &aliasDN );
161                         free(supDN.bv_val);
162
163                         /* check if aliasDN is a subordinate of any DN in our list */
164                         if( dnlist_subordinate( dnlist, &aliasDN ) ) {
165                                 free(aliasDN.bv_val);
166                                 *matched = entry;
167                                 entry = NULL;
168                                 *err = LDAP_ALIAS_PROBLEM;
169                                 *text = "subordinate circular alias";
170                                 break;
171                         }
172
173                         /* attempt to dereference alias */
174                         newe = dn2entry_r( be, &aliasDN, &newSup );
175
176                         if( newe != NULL ) {
177                                 free(aliasDN.bv_val);
178                                 cache_return_entry_r(&li->li_cache, sup );
179                                 entry = newe;
180                                 ber_dupbv( &dn, &entry->e_nname );
181                                 ber_bvarray_add( &dnlist, &dn );
182                                 continue;
183                         }
184                         
185                         if ( newSup != NULL ) {
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         ber_bvarray_free( dnlist );
201         return entry;
202 }
203
204
205 static void new_superior(
206         struct berval *dn,
207         struct berval *oldSup,
208         struct berval *newSup,
209         struct berval *newDN )
210 {
211         size_t dnlen, olen, nlen;
212         assert( dn && oldSup && newSup && newDN );
213
214         dnlen = dn->bv_len;
215         olen = oldSup->bv_len;
216         nlen = newSup->bv_len;
217
218         newDN->bv_val = ch_malloc( dnlen - olen + nlen + 1 );
219
220         AC_MEMCPY( newDN->bv_val, dn->bv_val, dnlen - olen );
221         AC_MEMCPY( &newDN->bv_val[dnlen - olen], newSup->bv_val, nlen );
222         newDN->bv_val[dnlen - olen + nlen] = '\0';
223
224         return;
225 }
226
227 static int dnlist_subordinate(
228         BerVarray dnlist,
229         struct berval *dn )
230 {
231         assert( dnlist );
232
233         for( ; dnlist->bv_val != NULL; dnlist++ ) {
234                 if( dnIsSuffix( dnlist, dn ) ) {
235                         return 1;
236                 }
237         }
238
239         return 0;
240 }