1 /* referral.c - muck with referrals */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/referral.c,v 1.28.2.5 2008/02/11 23:26:44 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
21 #include <ac/socket.h>
23 #include <ac/string.h>
26 #include <ac/unistd.h>
31 * This routine generates the DN appropriate to return in
34 static char * referral_dn_muck(
36 struct berval
* baseDN
,
37 struct berval
* targetDN
)
41 struct berval nrefDN
= BER_BVNULL
;
42 struct berval nbaseDN
= BER_BVNULL
;
43 struct berval ntargetDN
= BER_BVNULL
;
46 /* no base, return target */
47 return targetDN
? ch_strdup( targetDN
->bv_val
) : NULL
;
51 bvin
.bv_val
= (char *)refDN
;
52 bvin
.bv_len
= strlen( refDN
);
54 rc
= dnPretty( NULL
, &bvin
, &nrefDN
, NULL
);
55 if( rc
!= LDAP_SUCCESS
) {
62 /* continuation reference
63 * if refDN present return refDN
66 return nrefDN
.bv_len
? nrefDN
.bv_val
: ch_strdup( baseDN
->bv_val
);
69 rc
= dnPretty( NULL
, targetDN
, &ntargetDN
, NULL
);
70 if( rc
!= LDAP_SUCCESS
) {
71 /* Invalid targetDN */
72 ch_free( nrefDN
.bv_val
);
77 rc
= dnPretty( NULL
, baseDN
, &nbaseDN
, NULL
);
78 if( rc
!= LDAP_SUCCESS
) {
80 ch_free( nrefDN
.bv_val
);
81 ch_free( ntargetDN
.bv_val
);
85 if( dn_match( &nbaseDN
, &nrefDN
) ) {
86 ch_free( nrefDN
.bv_val
);
87 ch_free( nbaseDN
.bv_val
);
88 return ntargetDN
.bv_val
;
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
;
101 &ntargetDN
.bv_val
[ntargetDN
.bv_len
-nbaseDN
.bv_len
],
104 /* target not subordinate to base */
105 ch_free( nrefDN
.bv_val
);
106 ch_free( nbaseDN
.bv_val
);
107 return ntargetDN
.bv_val
;
110 muck
.bv_len
= ntargetDN
.bv_len
+ nrefDN
.bv_len
- nbaseDN
.bv_len
;
111 muck
.bv_val
= ch_malloc( muck
.bv_len
+ 1 );
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
],
118 ch_free( nrefDN
.bv_val
);
119 ch_free( nbaseDN
.bv_val
);
120 ch_free( ntargetDN
.bv_val
);
126 ch_free( nrefDN
.bv_val
);
127 return ntargetDN
.bv_val
;
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
136 * XXYYZ: should return an error string
138 int validate_global_referral( const char *url
)
143 rc
= ldap_url_parse_ext( url
, &lurl
, LDAP_PVT_URL_PARSE_NONE
);
146 case LDAP_URL_SUCCESS
:
149 case LDAP_URL_ERR_BADSCHEME
:
150 /* not LDAP hence valid */
151 Debug( LDAP_DEBUG_CONFIG
, "referral \"%s\": not LDAP.\n", url
, 0, 0 );
155 /* other error, bail */
156 Debug( LDAP_DEBUG_ANY
,
157 "referral: invalid URL (%s): %s (%d)\n",
158 url
, "" /* ldap_url_error2str(rc) */, rc
);
164 if( lurl
->lud_dn
&& *lurl
->lud_dn
) {
165 Debug( LDAP_DEBUG_ANY
,
166 "referral: URL (%s): contains DN\n",
170 } else if( lurl
->lud_attrs
) {
171 Debug( LDAP_DEBUG_ANY
,
172 "referral: URL (%s): requests attributes\n",
176 } else if( lurl
->lud_scope
!= LDAP_SCOPE_DEFAULT
) {
177 Debug( LDAP_DEBUG_ANY
,
178 "referral: URL (%s): contains explicit scope\n",
182 } else if( lurl
->lud_filter
) {
183 Debug( LDAP_DEBUG_ANY
,
184 "referral: URL (%s): contains explicit filter\n",
189 ldap_free_urldesc( lurl
);
193 BerVarray
referral_rewrite(
196 struct berval
*target
,
201 struct berval
*iv
, *jv
;
207 for ( i
= 0; !BER_BVISNULL( &in
[i
] ); i
++ ) {
208 /* just count them */
215 refs
= ch_malloc( ( i
+ 1 ) * sizeof( struct berval
) );
217 for ( iv
= in
, jv
= refs
; !BER_BVISNULL( iv
); iv
++ ) {
222 rc
= ldap_url_parse_ext( iv
->bv_val
, &url
, LDAP_PVT_URL_PARSE_NONE
);
223 if ( rc
== LDAP_URL_ERR_BADSCHEME
) {
224 ber_dupbv( jv
++, iv
);
227 } else if ( rc
!= LDAP_URL_SUCCESS
) {
232 url
->lud_dn
= referral_dn_muck( ( dn
&& *dn
) ? dn
: NULL
,
236 if ( url
->lud_scope
== LDAP_SCOPE_DEFAULT
) {
237 url
->lud_scope
= scope
;
240 jv
->bv_val
= ldap_url_desc2str( url
);
241 if ( jv
->bv_val
!= NULL
) {
242 jv
->bv_len
= strlen( jv
->bv_val
);
249 ldap_free_urldesc( url
);
264 BerVarray
get_entry_referrals(
271 struct berval
*iv
, *jv
;
273 AttributeDescription
*ad_ref
= slap_schema
.si_ad_ref
;
275 attr
= attr_find( e
->e_attrs
, ad_ref
);
277 if( attr
== NULL
) return NULL
;
279 for( i
=0; attr
->a_vals
[i
].bv_val
!= NULL
; i
++ ) {
280 /* count references */
283 if( i
< 1 ) return NULL
;
285 refs
= ch_malloc( (i
+ 1) * sizeof(struct berval
));
287 for( iv
=attr
->a_vals
, jv
=refs
; iv
->bv_val
!= NULL
; iv
++ ) {
292 for( k
=0; k
<jv
->bv_len
; k
++ ) {
293 if( isspace( (unsigned char) jv
->bv_val
[k
] ) ) {
294 jv
->bv_val
[k
] = '\0';
300 if( jv
->bv_len
> 0 ) {
315 /* we should check that a referral value exists... */
327 AttributeDescription
*aliasedObjectName
328 = slap_schema
.si_ad_aliasedObjectName
;
330 a
= attr_find( e
->e_attrs
, aliasedObjectName
);
334 * there was an aliasedobjectname defined but no data.
336 *err
= LDAP_ALIAS_PROBLEM
;
337 *text
= "alias missing aliasedObjectName attribute";
342 * aliasedObjectName should be SINGLE-VALUED with a single value.
344 if ( a
->a_vals
[0].bv_val
== NULL
) {
346 * there was an aliasedobjectname defined but no data.
348 *err
= LDAP_ALIAS_PROBLEM
;
349 *text
= "alias missing aliasedObjectName value";
353 if( a
->a_nvals
[1].bv_val
!= NULL
) {
354 *err
= LDAP_ALIAS_PROBLEM
;
355 *text
= "alias has multivalued aliasedObjectName";
359 *ndn
= a
->a_nvals
[0];