Home | History | Annotate | Line # | Download | only in slapd
referral.c revision 1.1
      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/>.
      4  *
      5  * Copyright 1998-2008 The OpenLDAP Foundation.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted only as authorized by the OpenLDAP
     10  * Public License.
     11  *
     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>.
     15  */
     16 
     17 #include "portable.h"
     18 
     19 #include <stdio.h>
     20 
     21 #include <ac/socket.h>
     22 #include <ac/errno.h>
     23 #include <ac/string.h>
     24 #include <ac/ctype.h>
     25 #include <ac/time.h>
     26 #include <ac/unistd.h>
     27 
     28 #include "slap.h"
     29 
     30 /*
     31  * This routine generates the DN appropriate to return in
     32  * an LDAP referral.
     33  */
     34 static char * referral_dn_muck(
     35 	const char * refDN,
     36 	struct berval * baseDN,
     37 	struct berval * targetDN )
     38 {
     39 	int rc;
     40 	struct berval bvin;
     41 	struct berval nrefDN = BER_BVNULL;
     42 	struct berval nbaseDN = BER_BVNULL;
     43 	struct berval ntargetDN = BER_BVNULL;
     44 
     45 	if( !baseDN ) {
     46 		/* no base, return target */
     47 		return targetDN ? ch_strdup( targetDN->bv_val ) : NULL;
     48 	}
     49 
     50 	if( refDN ) {
     51 		bvin.bv_val = (char *)refDN;
     52 		bvin.bv_len = strlen( refDN );
     53 
     54 		rc = dnPretty( NULL, &bvin, &nrefDN, NULL );
     55 		if( rc != LDAP_SUCCESS ) {
     56 			/* Invalid refDN */
     57 			return NULL;
     58 		}
     59 	}
     60 
     61 	if( !targetDN ) {
     62 		/* continuation reference
     63 		 *	if refDN present return refDN
     64 		 *  else return baseDN
     65 		 */
     66 		return nrefDN.bv_len ? nrefDN.bv_val : ch_strdup( baseDN->bv_val );
     67 	}
     68 
     69 	rc = dnPretty( NULL, targetDN, &ntargetDN, NULL );
     70 	if( rc != LDAP_SUCCESS ) {
     71 		/* Invalid targetDN */
     72 		ch_free( nrefDN.bv_val );
     73 		return NULL;
     74 	}
     75 
     76 	if( nrefDN.bv_len ) {
     77 		rc = dnPretty( NULL, baseDN, &nbaseDN, NULL );
     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 ) ) {
     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, LDAP_PVT_URL_PARSE_NONE );
    144 
    145 	switch( rc ) {
    146 	case LDAP_URL_SUCCESS:
    147 		break;
    148 
    149 	case LDAP_URL_ERR_BADSCHEME:
    150 		/* not LDAP hence valid */
    151 		Debug( LDAP_DEBUG_CONFIG, "referral \"%s\": not LDAP.\n", url, 0, 0 );
    152 		return 0;
    153 
    154 	default:
    155 		/* other error, bail */
    156 		Debug( LDAP_DEBUG_ANY,
    157 			"referral: invalid URL (%s): %s (%d)\n",
    158 			url, "" /* ldap_url_error2str(rc) */, rc );
    159 		return 1;
    160 	}
    161 
    162 	rc = 0;
    163 
    164 	if( lurl->lud_dn && *lurl->lud_dn ) {
    165 		Debug( LDAP_DEBUG_ANY,
    166 			"referral: URL (%s): contains DN\n",
    167 			url, 0, 0 );
    168 		rc = 1;
    169 
    170 	} else if( lurl->lud_attrs ) {
    171 		Debug( LDAP_DEBUG_ANY,
    172 			"referral: URL (%s): requests attributes\n",
    173 			url, 0, 0 );
    174 		rc = 1;
    175 
    176 	} else if( lurl->lud_scope != LDAP_SCOPE_DEFAULT ) {
    177 		Debug( LDAP_DEBUG_ANY,
    178 			"referral: URL (%s): contains explicit scope\n",
    179 			url, 0, 0 );
    180 		rc = 1;
    181 
    182 	} else if( lurl->lud_filter ) {
    183 		Debug( LDAP_DEBUG_ANY,
    184 			"referral: URL (%s): contains explicit filter\n",
    185 			url, 0, 0 );
    186 		rc = 1;
    187 	}
    188 
    189 	ldap_free_urldesc( lurl );
    190 	return rc;
    191 }
    192 
    193 BerVarray referral_rewrite(
    194 	BerVarray in,
    195 	struct berval *base,
    196 	struct berval *target,
    197 	int scope )
    198 {
    199 	int		i;
    200 	BerVarray	refs;
    201 	struct berval	*iv, *jv;
    202 
    203 	if ( in == NULL ) {
    204 		return NULL;
    205 	}
    206 
    207 	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
    208 		/* just count them */
    209 	}
    210 
    211 	if ( i < 1 ) {
    212 		return NULL;
    213 	}
    214 
    215 	refs = ch_malloc( ( i + 1 ) * sizeof( struct berval ) );
    216 
    217 	for ( iv = in, jv = refs; !BER_BVISNULL( iv ); iv++ ) {
    218 		LDAPURLDesc	*url;
    219 		char		*dn;
    220 		int		rc;
    221 
    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 );
    225 			continue;
    226 
    227 		} else if ( rc != LDAP_URL_SUCCESS ) {
    228 			continue;
    229 		}
    230 
    231 		dn = url->lud_dn;
    232 		url->lud_dn = referral_dn_muck( ( dn && *dn ) ? dn : NULL,
    233 				base, target );
    234 		ldap_memfree( dn );
    235 
    236 		if ( url->lud_scope == LDAP_SCOPE_DEFAULT ) {
    237 			url->lud_scope = scope;
    238 		}
    239 
    240 		jv->bv_val = ldap_url_desc2str( url );
    241 		if ( jv->bv_val != NULL ) {
    242 			jv->bv_len = strlen( jv->bv_val );
    243 
    244 		} else {
    245 			ber_dupbv( jv, iv );
    246 		}
    247 		jv++;
    248 
    249 		ldap_free_urldesc( url );
    250 	}
    251 
    252 	if ( jv == refs ) {
    253 		ch_free( refs );
    254 		refs = NULL;
    255 
    256 	} else {
    257 		BER_BVZERO( jv );
    258 	}
    259 
    260 	return refs;
    261 }
    262 
    263 
    264 BerVarray get_entry_referrals(
    265 	Operation *op,
    266 	Entry *e )
    267 {
    268 	Attribute *attr;
    269 	BerVarray refs;
    270 	unsigned i;
    271 	struct berval *iv, *jv;
    272 
    273 	AttributeDescription *ad_ref = slap_schema.si_ad_ref;
    274 
    275 	attr = attr_find( e->e_attrs, ad_ref );
    276 
    277 	if( attr == NULL ) return NULL;
    278 
    279 	for( i=0; attr->a_vals[i].bv_val != NULL; i++ ) {
    280 		/* count references */
    281 	}
    282 
    283 	if( i < 1 ) return NULL;
    284 
    285 	refs = ch_malloc( (i + 1) * sizeof(struct berval));
    286 
    287 	for( iv=attr->a_vals, jv=refs; iv->bv_val != NULL; iv++ ) {
    288 		unsigned k;
    289 		ber_dupbv( jv, iv );
    290 
    291 		/* trim the label */
    292 		for( k=0; k<jv->bv_len; k++ ) {
    293 			if( isspace( (unsigned char) jv->bv_val[k] ) ) {
    294 				jv->bv_val[k] = '\0';
    295 				jv->bv_len = k;
    296 				break;
    297 			}
    298 		}
    299 
    300 		if(	jv->bv_len > 0 ) {
    301 			jv++;
    302 		} else {
    303 			free( jv->bv_val );
    304 		}
    305 	}
    306 
    307 	if( jv == refs ) {
    308 		free( refs );
    309 		refs = NULL;
    310 
    311 	} else {
    312 		jv->bv_val = NULL;
    313 	}
    314 
    315 	/* we should check that a referral value exists... */
    316 	return refs;
    317 }
    318 
    319 
    320 int get_alias_dn(
    321 	Entry *e,
    322 	struct berval *ndn,
    323 	int *err,
    324 	const char **text )
    325 {
    326 	Attribute *a;
    327 	AttributeDescription *aliasedObjectName
    328 		= slap_schema.si_ad_aliasedObjectName;
    329 
    330 	a = attr_find( e->e_attrs, aliasedObjectName );
    331 
    332 	if( a == NULL ) {
    333 		/*
    334 		 * there was an aliasedobjectname defined but no data.
    335 		 */
    336 		*err = LDAP_ALIAS_PROBLEM;
    337 		*text = "alias missing aliasedObjectName attribute";
    338 		return -1;
    339 	}
    340 
    341 	/*
    342 	 * aliasedObjectName should be SINGLE-VALUED with a single value.
    343 	 */
    344 	if ( a->a_vals[0].bv_val == NULL ) {
    345 		/*
    346 		 * there was an aliasedobjectname defined but no data.
    347 		 */
    348 		*err = LDAP_ALIAS_PROBLEM;
    349 		*text = "alias missing aliasedObjectName value";
    350 		return -1;
    351 	}
    352 
    353 	if( a->a_nvals[1].bv_val != NULL ) {
    354 		*err = LDAP_ALIAS_PROBLEM;
    355 		*text = "alias has multivalued aliasedObjectName";
    356 		return -1;
    357 	}
    358 
    359 	*ndn = a->a_nvals[0];
    360 
    361 	return 0;
    362 }
    363 
    364