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