]> git.sur5r.net Git - openldap/blob - servers/slapd/referral.c
5ab81c9686c66e89803cdf86654566e243165c1f
[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 BVarray referral_rewrite(
217         BVarray in,
218         struct berval *base,
219         struct berval *target,
220         int scope )
221 {
222         int i;
223         BVarray refs;
224         struct berval *iv, *jv;
225
226         if( in == NULL ) return NULL;
227
228         for( i=0; in[i].bv_val != NULL ; i++ ) {
229                 /* just count them */
230         }
231
232         if( i < 1 ) return NULL;
233
234         refs = ch_malloc( (i+1) * sizeof( struct berval ) );
235
236         for( iv=in,jv=refs; iv->bv_val != NULL ; iv++ ) {
237                 LDAPURLDesc *url;
238                 int rc = ldap_url_parse_ext( iv->bv_val, &url );
239
240                 if( rc == LDAP_URL_ERR_BADSCHEME ) {
241                         ber_dupbv( jv++, iv );
242                         continue;
243
244                 } else if( rc != LDAP_URL_SUCCESS ) {
245                         continue;
246                 }
247
248                 {
249                         char *dn = url->lud_dn;
250                         url->lud_dn = referral_dn_muck(
251                                 ( dn && *dn ) ? dn : NULL,
252                                 base ? base->bv_val : NULL,
253                                 target ? target->bv_val : NULL ); 
254
255                         ldap_memfree( dn );
256                 }
257
258                 if( url->lud_scope == LDAP_SCOPE_DEFAULT ) {
259                         url->lud_scope = scope;
260                 }
261
262                 jv->bv_val = ldap_url_desc2str( url );
263                 jv->bv_len = strlen( jv->bv_val );
264
265                 ldap_free_urldesc( url );
266                 jv++;
267         }
268
269         if( jv == refs ) {
270                 ch_free( refs );
271                 refs = NULL;
272
273         } else {
274                 jv->bv_val = NULL;
275         }
276
277         return refs;
278 }
279
280
281 BVarray get_entry_referrals(
282         Backend *be,
283         Connection *conn,
284         Operation *op,
285         Entry *e )
286 {
287         Attribute *attr;
288         BVarray refs;
289         unsigned i;
290         struct berval *iv, *jv;
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].bv_val != 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( iv=attr->a_vals, jv=refs; iv->bv_val != NULL; iv++ ) {
307                 unsigned k;
308                 ber_dupbv( jv, iv );
309
310                 /* trim the label */
311                 for( k=0; k<jv->bv_len; k++ ) {
312                         if( isspace(jv->bv_val[k]) ) {
313                                 jv->bv_val[k] = '\0';
314                                 jv->bv_len = k;
315                                 break;
316                         }
317                 }
318
319                 if(     jv->bv_len > 0 ) {
320                         jv++;
321                 } else {
322                         free( jv->bv_val );
323                 }
324         }
325
326         if( jv == refs ) {
327                 free( refs );
328                 refs = NULL;
329
330         } else {
331                 jv->bv_val = NULL;
332         }
333
334         /* we should check that a referral value exists... */
335         return refs;
336 }
337