1/* $NetBSD: referral.c,v 1.1.1.3 2010/12/12 15:22:37 adam Exp $ */ 2 3/* referral.c - muck with referrals */ 4/* OpenLDAP: pkg/ldap/servers/slapd/referral.c,v 1.28.2.7 2010/04/13 20:23:18 kurt Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2010 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19#include "portable.h" 20 21#include <stdio.h> 22 23#include <ac/socket.h> 24#include <ac/errno.h> 25#include <ac/string.h> 26#include <ac/ctype.h> 27#include <ac/time.h> 28#include <ac/unistd.h> 29 30#include "slap.h" 31 32/* 33 * This routine generates the DN appropriate to return in 34 * an LDAP referral. 35 */ 36static char * referral_dn_muck( 37 const char * refDN, 38 struct berval * baseDN, 39 struct berval * targetDN ) 40{ 41 int rc; 42 struct berval bvin; 43 struct berval nrefDN = BER_BVNULL; 44 struct berval nbaseDN = BER_BVNULL; 45 struct berval ntargetDN = BER_BVNULL; 46 47 if( !baseDN ) { 48 /* no base, return target */ 49 return targetDN ? ch_strdup( targetDN->bv_val ) : NULL; 50 } 51 52 if( refDN ) { 53 bvin.bv_val = (char *)refDN; 54 bvin.bv_len = strlen( refDN ); 55 56 rc = dnPretty( NULL, &bvin, &nrefDN, NULL ); 57 if( rc != LDAP_SUCCESS ) { 58 /* Invalid refDN */ 59 return NULL; 60 } 61 } 62 63 if( !targetDN ) { 64 /* continuation reference 65 * if refDN present return refDN 66 * else return baseDN 67 */ 68 return nrefDN.bv_len ? nrefDN.bv_val : ch_strdup( baseDN->bv_val ); 69 } 70 71 rc = dnPretty( NULL, targetDN, &ntargetDN, NULL ); 72 if( rc != LDAP_SUCCESS ) { 73 /* Invalid targetDN */ 74 ch_free( nrefDN.bv_val ); 75 return NULL; 76 } 77 78 if( nrefDN.bv_len ) { 79 rc = dnPretty( NULL, baseDN, &nbaseDN, NULL ); 80 if( rc != LDAP_SUCCESS ) { 81 /* Invalid baseDN */ 82 ch_free( nrefDN.bv_val ); 83 ch_free( ntargetDN.bv_val ); 84 return NULL; 85 } 86 87 if( dn_match( &nbaseDN, &nrefDN ) ) { 88 ch_free( nrefDN.bv_val ); 89 ch_free( nbaseDN.bv_val ); 90 return ntargetDN.bv_val; 91 } 92 93 { 94 struct berval muck; 95 96 if( ntargetDN.bv_len < nbaseDN.bv_len ) { 97 ch_free( nrefDN.bv_val ); 98 ch_free( nbaseDN.bv_val ); 99 return ntargetDN.bv_val; 100 } 101 102 rc = strcasecmp( 103 &ntargetDN.bv_val[ntargetDN.bv_len-nbaseDN.bv_len], 104 nbaseDN.bv_val ); 105 if( rc ) { 106 /* target not subordinate to base */ 107 ch_free( nrefDN.bv_val ); 108 ch_free( nbaseDN.bv_val ); 109 return ntargetDN.bv_val; 110 } 111 112 muck.bv_len = ntargetDN.bv_len + nrefDN.bv_len - nbaseDN.bv_len; 113 muck.bv_val = ch_malloc( muck.bv_len + 1 ); 114 115 strncpy( muck.bv_val, ntargetDN.bv_val, 116 ntargetDN.bv_len-nbaseDN.bv_len ); 117 strcpy( &muck.bv_val[ntargetDN.bv_len-nbaseDN.bv_len], 118 nrefDN.bv_val ); 119 120 ch_free( nrefDN.bv_val ); 121 ch_free( nbaseDN.bv_val ); 122 ch_free( ntargetDN.bv_val ); 123 124 return muck.bv_val; 125 } 126 } 127 128 ch_free( nrefDN.bv_val ); 129 return ntargetDN.bv_val; 130} 131 132 133/* validate URL for global referral use 134 * LDAP URLs must not have: 135 * DN, attrs, scope, nor filter 136 * Any non-LDAP URL is okay 137 * 138 * XXYYZ: should return an error string 139 */ 140int validate_global_referral( const char *url ) 141{ 142 int rc; 143 LDAPURLDesc *lurl; 144 145 rc = ldap_url_parse_ext( url, &lurl, LDAP_PVT_URL_PARSE_NONE ); 146 147 switch( rc ) { 148 case LDAP_URL_SUCCESS: 149 break; 150 151 case LDAP_URL_ERR_BADSCHEME: 152 /* not LDAP hence valid */ 153 Debug( LDAP_DEBUG_CONFIG, "referral \"%s\": not LDAP.\n", url, 0, 0 ); 154 return 0; 155 156 default: 157 /* other error, bail */ 158 Debug( LDAP_DEBUG_ANY, 159 "referral: invalid URL (%s): %s (%d)\n", 160 url, "" /* ldap_url_error2str(rc) */, rc ); 161 return 1; 162 } 163 164 rc = 0; 165 166 if( lurl->lud_dn && *lurl->lud_dn ) { 167 Debug( LDAP_DEBUG_ANY, 168 "referral: URL (%s): contains DN\n", 169 url, 0, 0 ); 170 rc = 1; 171 172 } else if( lurl->lud_attrs ) { 173 Debug( LDAP_DEBUG_ANY, 174 "referral: URL (%s): requests attributes\n", 175 url, 0, 0 ); 176 rc = 1; 177 178 } else if( lurl->lud_scope != LDAP_SCOPE_DEFAULT ) { 179 Debug( LDAP_DEBUG_ANY, 180 "referral: URL (%s): contains explicit scope\n", 181 url, 0, 0 ); 182 rc = 1; 183 184 } else if( lurl->lud_filter ) { 185 Debug( LDAP_DEBUG_ANY, 186 "referral: URL (%s): contains explicit filter\n", 187 url, 0, 0 ); 188 rc = 1; 189 } 190 191 ldap_free_urldesc( lurl ); 192 return rc; 193} 194 195BerVarray referral_rewrite( 196 BerVarray in, 197 struct berval *base, 198 struct berval *target, 199 int scope ) 200{ 201 int i; 202 BerVarray refs; 203 struct berval *iv, *jv; 204 205 if ( in == NULL ) { 206 return NULL; 207 } 208 209 for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) { 210 /* just count them */ 211 } 212 213 if ( i < 1 ) { 214 return NULL; 215 } 216 217 refs = ch_malloc( ( i + 1 ) * sizeof( struct berval ) ); 218 219 for ( iv = in, jv = refs; !BER_BVISNULL( iv ); iv++ ) { 220 LDAPURLDesc *url; 221 char *dn; 222 int rc; 223 224 rc = ldap_url_parse_ext( iv->bv_val, &url, LDAP_PVT_URL_PARSE_NONE ); 225 if ( rc == LDAP_URL_ERR_BADSCHEME ) { 226 ber_dupbv( jv++, iv ); 227 continue; 228 229 } else if ( rc != LDAP_URL_SUCCESS ) { 230 continue; 231 } 232 233 dn = url->lud_dn; 234 url->lud_dn = referral_dn_muck( ( dn && *dn ) ? dn : NULL, 235 base, target ); 236 ldap_memfree( dn ); 237 238 if ( url->lud_scope == LDAP_SCOPE_DEFAULT ) { 239 url->lud_scope = scope; 240 } 241 242 jv->bv_val = ldap_url_desc2str( url ); 243 if ( jv->bv_val != NULL ) { 244 jv->bv_len = strlen( jv->bv_val ); 245 246 } else { 247 ber_dupbv( jv, iv ); 248 } 249 jv++; 250 251 ldap_free_urldesc( url ); 252 } 253 254 if ( jv == refs ) { 255 ch_free( refs ); 256 refs = NULL; 257 258 } else { 259 BER_BVZERO( jv ); 260 } 261 262 return refs; 263} 264 265 266BerVarray get_entry_referrals( 267 Operation *op, 268 Entry *e ) 269{ 270 Attribute *attr; 271 BerVarray refs; 272 unsigned i; 273 struct berval *iv, *jv; 274 275 AttributeDescription *ad_ref = slap_schema.si_ad_ref; 276 277 attr = attr_find( e->e_attrs, ad_ref ); 278 279 if( attr == NULL ) return NULL; 280 281 for( i=0; attr->a_vals[i].bv_val != NULL; i++ ) { 282 /* count references */ 283 } 284 285 if( i < 1 ) return NULL; 286 287 refs = ch_malloc( (i + 1) * sizeof(struct berval)); 288 289 for( iv=attr->a_vals, jv=refs; iv->bv_val != NULL; iv++ ) { 290 unsigned k; 291 ber_dupbv( jv, iv ); 292 293 /* trim the label */ 294 for( k=0; k<jv->bv_len; k++ ) { 295 if( isspace( (unsigned char) jv->bv_val[k] ) ) { 296 jv->bv_val[k] = '\0'; 297 jv->bv_len = k; 298 break; 299 } 300 } 301 302 if( jv->bv_len > 0 ) { 303 jv++; 304 } else { 305 free( jv->bv_val ); 306 } 307 } 308 309 if( jv == refs ) { 310 free( refs ); 311 refs = NULL; 312 313 } else { 314 jv->bv_val = NULL; 315 } 316 317 /* we should check that a referral value exists... */ 318 return refs; 319} 320 321 322int get_alias_dn( 323 Entry *e, 324 struct berval *ndn, 325 int *err, 326 const char **text ) 327{ 328 Attribute *a; 329 AttributeDescription *aliasedObjectName 330 = slap_schema.si_ad_aliasedObjectName; 331 332 a = attr_find( e->e_attrs, aliasedObjectName ); 333 334 if( a == NULL ) { 335 /* 336 * there was an aliasedobjectname defined but no data. 337 */ 338 *err = LDAP_ALIAS_PROBLEM; 339 *text = "alias missing aliasedObjectName attribute"; 340 return -1; 341 } 342 343 /* 344 * aliasedObjectName should be SINGLE-VALUED with a single value. 345 */ 346 if ( a->a_vals[0].bv_val == NULL ) { 347 /* 348 * there was an aliasedobjectname defined but no data. 349 */ 350 *err = LDAP_ALIAS_PROBLEM; 351 *text = "alias missing aliasedObjectName value"; 352 return -1; 353 } 354 355 if( a->a_nvals[1].bv_val != NULL ) { 356 *err = LDAP_ALIAS_PROBLEM; 357 *text = "alias has multivalued aliasedObjectName"; 358 return -1; 359 } 360 361 *ndn = a->a_nvals[0]; 362 363 return 0; 364} 365 366