]> git.sur5r.net Git - openldap/blob - servers/slapd/referral.c
liberally accept many LDAPv2/LDAPv3 stuff in DN (quoted parts, ';' as rdn separator...
[openldap] / servers / slapd / referral.c
1 /* referral.c - muck with referrals */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/errno.h>
14 #include <ac/signal.h>
15 #include <ac/string.h>
16 #include <ac/ctype.h>
17 #include <ac/time.h>
18 #include <ac/unistd.h>
19
20 #include <ldap_pvt.h>
21
22 #include "slap.h"
23
24 /*
25  * This routine generates the DN appropriate to return in
26  * an LDAP referral.
27  */
28 static char * referral_dn_muck(
29         const char * refDN,
30         const char * baseDN,
31         const char * targetDN )
32 {
33         char *tmp;
34         char *nrefDN = NULL;
35         char *nbaseDN = NULL;
36         char *ntargetDN = NULL;
37
38         if( !baseDN ) {
39                 /* no base, return target */
40                 return targetDN ? ch_strdup( targetDN ) : NULL;
41         }
42
43         if( refDN ) {
44                 nrefDN = dn_validate( tmp = ch_strdup( refDN ) );
45                 if( !nrefDN ) {
46                         /* Invalid refDN */
47                         ch_free( tmp );
48                         return NULL;
49                 }
50         }
51
52         if( !targetDN ) {
53                 /* continuation reference
54                  *      if refDN present return refDN
55                  *  else return baseDN
56                  */
57                 return nrefDN ? nrefDN : ch_strdup( baseDN );
58         }
59
60         ntargetDN = dn_validate( tmp = ch_strdup( targetDN ) );
61         if( !ntargetDN ) {
62                 ch_free( tmp );
63                 ch_free( nrefDN );
64                 return NULL;
65         }
66
67         if( nrefDN ) {
68                 nbaseDN = dn_validate( tmp = ch_strdup( baseDN ) );
69                 if( !nbaseDN ) {
70                         /* Invalid baseDN */
71                         ch_free( ntargetDN );
72                         ch_free( nrefDN );
73                         ch_free( tmp );
74                         return NULL;
75                 }
76
77                 if( strcasecmp( nbaseDN, nrefDN ) == 0 ) {
78                         ch_free( nrefDN );
79                         ch_free( nbaseDN );
80                         return ntargetDN;
81                 }
82
83                 {
84                         /*
85                          * FIXME: string based mucking
86                          */
87                         char *muck;
88                         size_t reflen, baselen, targetlen, mucklen;
89
90                         reflen = strlen( nrefDN );
91                         baselen = strlen( nbaseDN );
92                         targetlen = strlen( ntargetDN );
93
94                         if( targetlen < baselen ) {
95                                 ch_free( nrefDN );
96                                 ch_free( nbaseDN );
97                                 return ntargetDN;
98                         }
99
100                         if( strcasecmp( &ntargetDN[targetlen-baselen], nbaseDN ) ) {
101                                 /* target not subordinate to base */
102                                 ch_free( nrefDN );
103                                 ch_free( nbaseDN );
104                                 return ntargetDN;
105                         }
106
107                         mucklen = targetlen + reflen - baselen;
108                         muck = ch_malloc( 1 + mucklen );
109
110                         strncpy( muck, ntargetDN, targetlen-baselen );
111                         strcpy( &muck[targetlen-baselen], nrefDN );
112
113                         ch_free( nrefDN );
114                         ch_free( nbaseDN );
115                         ch_free( ntargetDN );
116
117                         return muck;
118                 }
119         }
120
121         return ntargetDN;
122 }
123
124
125 /* validate URL for global referral use
126  *   LDAP URLs must not have:
127  *     DN, attrs, scope, nor filter
128  *   Any non-LDAP URL is okay
129  *
130  *   XXYYZ: should return an error string
131  */
132 int validate_global_referral( const char *url )
133 {
134         int rc;
135         LDAPURLDesc *lurl;
136
137         rc = ldap_url_parse_ext( url, &lurl );
138
139         switch( rc ) {
140         case LDAP_URL_SUCCESS:
141                 break;
142
143         case LDAP_URL_ERR_BADSCHEME:
144                 /* not LDAP hence valid */
145                 return 0;
146
147         default:
148                 /* other error, bail */
149 #ifdef NEW_LOGGING
150                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
151                         "referral: invalid URL (%s): %s (%d)\n",
152                         url, "" /* ldap_url_error2str(rc) */, rc ));
153 #else
154                 Debug( LDAP_DEBUG_ANY,
155                         "referral: invalid URL (%s): %s (%d)\n",
156                         url, "" /* ldap_url_error2str(rc) */, rc );
157 #endif
158                 return 1;
159         }
160
161         rc = 0;
162
163         if( lurl->lud_dn && *lurl->lud_dn ) {
164 #ifdef NEW_LOGGING
165                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
166                         "referral: URL (%s): contains DN\n",
167                         url ));
168 #else
169                 Debug( LDAP_DEBUG_ANY,
170                         "referral: URL (%s): contains DN\n",
171                         url, 0, 0 );
172 #endif
173                 rc = 1;
174
175         } else if( lurl->lud_attrs ) {
176 #ifdef NEW_LOGGING
177                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
178                         "referral: URL (%s): requests attributes\n",
179                         url ));
180 #else
181                 Debug( LDAP_DEBUG_ANY,
182                         "referral: URL (%s): requests attributes\n",
183                         url, 0, 0 );
184 #endif
185                 rc = 1;
186
187         } else if( lurl->lud_scope != LDAP_SCOPE_DEFAULT ) {
188 #ifdef NEW_LOGGING
189                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
190                         "referral: URL (%s): contains explicit scope\n",
191                         url ));
192 #else
193                 Debug( LDAP_DEBUG_ANY,
194                         "referral: URL (%s): contains explicit scope\n",
195                         url, 0, 0 );
196 #endif
197                 rc = 1;
198
199         } else if( lurl->lud_filter ) {
200 #ifdef NEW_LOGGING
201                 LDAP_LOG(( "config", LDAP_LEVEL_CRIT,
202                         "referral: URL (%s): contains explicit filter\n",
203                         url ));
204 #else
205                 Debug( LDAP_DEBUG_ANY,
206                         "referral: URL (%s): contains explicit filter\n",
207                         url, 0, 0 );
208 #endif
209                 rc = 1;
210         }
211
212         ldap_free_urldesc( lurl );
213         return rc;
214 }
215
216 struct berval ** referral_rewrite(
217         struct berval **in,
218         const char *base,
219         const char *target,
220         int scope )
221 {
222         int i, j;
223         struct berval **refs;
224
225         if( in == NULL ) return NULL;
226
227         for( i=0; in[i] != NULL ; i++ ) {
228                 /* just count them */
229         }
230
231         if( i < 1 ) return NULL;
232
233         refs = ch_malloc( (i+1) * sizeof( struct berval * ) );
234
235         for( i=0,j=0; in[i] != NULL ; i++ ) {
236                 LDAPURLDesc *url;
237                 int rc = ldap_url_parse_ext( in[i]->bv_val, &url );
238
239                 if( rc == LDAP_URL_ERR_BADSCHEME ) {
240                         refs[j++] = ber_bvdup( in[i] );
241                         continue;
242
243                 } else if( rc != LDAP_URL_SUCCESS ) {
244                         continue;
245                 }
246
247                 {
248                         char *dn = url->lud_dn;
249                         url->lud_dn = referral_dn_muck(
250                                 ( dn && *dn ) ? dn : NULL, base, target ); 
251
252                         ldap_memfree( dn );
253                 }
254
255                 if( url->lud_scope == LDAP_SCOPE_DEFAULT ) {
256                         url->lud_scope = scope;
257                 }
258
259                 refs[j] = ch_malloc( sizeof( struct berval ) );
260
261                 refs[j]->bv_val = ldap_url_desc2str( url );
262                 refs[j]->bv_len = strlen( refs[j]->bv_val );
263
264                 ldap_free_urldesc( url );
265                 j++;
266         }
267
268         if( j == 0 ) {
269                 ch_free( refs );
270                 refs = NULL;
271
272         } else {
273                 refs[j] = NULL;
274         }
275
276         return refs;
277 }
278
279
280 struct berval **get_entry_referrals(
281         Backend *be,
282         Connection *conn,
283         Operation *op,
284         Entry *e,
285         const char *dn,
286         int scope )
287 {
288         Attribute *attr;
289         struct berval **refs;
290         unsigned i, j;
291
292         AttributeDescription *ad_ref = slap_schema.si_ad_ref;
293
294         attr = attr_find( e->e_attrs, ad_ref );
295
296         if( attr == NULL ) return NULL;
297
298         for( i=0; attr->a_vals[i] != NULL; i++ ) {
299                 /* count references */
300         }
301
302         if( i < 1 ) return NULL;
303
304         refs = ch_malloc( (i + 1) * sizeof(struct berval *));
305
306         for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) {
307                 unsigned k;
308                 struct berval *ref = ber_bvdup( attr->a_vals[i] );
309
310                 /* trim the label */
311                 for( k=0; k<ref->bv_len; k++ ) {
312                         if( isspace(ref->bv_val[k]) ) {
313                                 ref->bv_val[k] = '\0';
314                                 ref->bv_len = k;
315                                 break;
316                         }
317                 }
318
319                 if(     ref->bv_len > 0 ) {
320                         refs[j++] = ref;
321
322                 } else {
323                         ber_bvfree( ref );
324                 }
325         }
326
327         if( j == 0 ) {
328                 ber_bvecfree( refs );
329                 refs = NULL;
330
331         } else {
332                 refs[j] = NULL;
333         }
334
335         /* we should check that a referral value exists... */
336         return refs;
337 }
338