ldapmap.c revision 1.1
1/* $OpenLDAP: pkg/ldap/libraries/librewrite/ldapmap.c,v 1.12.2.4 2008/02/11 23:26:42 kurt Exp $ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 2000-2008 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15/* ACKNOWLEDGEMENT: 16 * This work was initially developed by Pierangelo Masarati for 17 * inclusion in OpenLDAP Software. 18 */ 19 20#include <portable.h> 21 22#define LDAP_DEPRECATED 1 23#include "rewrite-int.h" 24#include "rewrite-map.h" 25 26typedef enum { 27 MAP_LDAP_UNKNOWN, 28 MAP_LDAP_EVERYTIME, 29 MAP_LDAP_NOW, 30 MAP_LDAP_LATER 31} bindwhen_t; 32 33/* 34 * LDAP map data structure 35 */ 36struct ldap_map_data { 37 char *lm_url; 38 LDAPURLDesc *lm_lud; 39 int lm_version; 40 char *lm_binddn; 41 struct berval lm_cred; 42 43 bindwhen_t lm_when; 44 45 LDAP *lm_ld; 46 47 int lm_wantdn; 48 char *lm_attrs[ 2 ]; 49 50#ifdef USE_REWRITE_LDAP_PVT_THREADS 51 ldap_pvt_thread_mutex_t lm_mutex; 52#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 53}; 54 55static void 56map_ldap_free( 57 struct ldap_map_data *data 58) 59{ 60 assert( data != NULL ); 61 62 if ( data->lm_url != NULL ) { 63 free( data->lm_url ); 64 } 65 66 if ( data->lm_lud != NULL ) { 67 ldap_free_urldesc( data->lm_lud ); 68 } 69 70 if ( data->lm_binddn != NULL ) { 71 free( data->lm_binddn ); 72 } 73 74 if ( data->lm_cred.bv_val != NULL ) { 75 memset( data->lm_cred.bv_val, 0, data->lm_cred.bv_len ); 76 free( data->lm_cred.bv_val ); 77 data->lm_cred.bv_val = NULL; 78 data->lm_cred.bv_len = 0; 79 } 80 81 if ( data->lm_when != MAP_LDAP_EVERYTIME && data->lm_ld != NULL ) { 82 ldap_unbind_ext( data->lm_ld, NULL, NULL ); 83 } 84 85 free( data ); 86} 87 88static void * 89map_ldap_parse( 90 const char *fname, 91 int lineno, 92 int argc, 93 char **argv 94) 95{ 96 struct ldap_map_data *data; 97 char *p, *uri; 98 99 assert( fname != NULL ); 100 assert( argv != NULL ); 101 102 data = calloc( sizeof( struct ldap_map_data ), 1 ); 103 if ( data == NULL ) { 104 return NULL; 105 } 106 107 if ( argc < 1 ) { 108 Debug( LDAP_DEBUG_ANY, 109 "[%s:%d] ldap map needs URI\n%s", 110 fname, lineno, "" ); 111 free( data ); 112 return NULL; 113 } 114 115 uri = argv[ 0 ]; 116 if ( strncasecmp( uri, "uri=", STRLENOF( "uri=" ) ) == 0 ) { 117 uri += STRLENOF( "uri=" ); 118 } 119 120 data->lm_url = strdup( uri ); 121 if ( data->lm_url == NULL ) { 122 map_ldap_free( data ); 123 return NULL; 124 } 125 126 if ( ldap_url_parse( uri, &data->lm_lud ) != REWRITE_SUCCESS ) { 127 Debug( LDAP_DEBUG_ANY, 128 "[%s:%d] illegal URI '%s'\n", 129 fname, lineno, argv[ 0 ] ); 130 map_ldap_free( data ); 131 return NULL; 132 } 133 134 /* trim everything after [host][:port] */ 135 p = strchr( data->lm_url, '/' ); 136 assert( p[ 1 ] == '/' ); 137 if ( ( p = strchr( p + 2, '/' ) ) != NULL ) { 138 p[ 0 ] = '\0'; 139 } 140 141 if ( data->lm_lud->lud_attrs == NULL ) { 142 data->lm_attrs[ 0 ] = LDAP_NO_ATTRS; 143 data->lm_wantdn = 1; 144 145 } else { 146 if ( data->lm_lud->lud_attrs[ 1 ] != NULL ) { 147 Debug( LDAP_DEBUG_ANY, 148 "[%s:%d] only one attribute allowed in URI\n", 149 fname, lineno, 0 ); 150 map_ldap_free( data ); 151 return NULL; 152 } 153 154 if ( strcasecmp( data->lm_lud->lud_attrs[ 0 ], "dn" ) == 0 155 || strcasecmp( data->lm_lud->lud_attrs[ 0 ], "entryDN" ) == 0 ) 156 { 157 ldap_memfree( data->lm_lud->lud_attrs[ 0 ] ); 158 ldap_memfree( data->lm_lud->lud_attrs ); 159 data->lm_lud->lud_attrs = NULL; 160 data->lm_attrs[ 0 ] = LDAP_NO_ATTRS; 161 data->lm_wantdn = 1; 162 163 } else { 164 data->lm_attrs[ 0 ] = data->lm_lud->lud_attrs[ 0 ]; 165 } 166 } 167 168 data->lm_attrs[ 1 ] = NULL; 169 170 /* safe defaults */ 171 data->lm_version = LDAP_VERSION3; 172 173 for ( argc--, argv++; argc > 0; argc--, argv++ ) { 174 if ( strncasecmp( argv[ 0 ], "binddn=", STRLENOF( "binddn=" ) ) == 0 ) { 175 char *p = argv[ 0 ] + STRLENOF( "binddn=" ); 176 int l; 177 178 if ( p[ 0 ] == '\"' || p [ 0 ] == '\'' ) { 179 l = strlen( p ) - 2; 180 p++; 181 if ( p[ l ] != p[ 0 ] ) { 182 map_ldap_free( data ); 183 return NULL; 184 } 185 } else { 186 l = strlen( p ); 187 } 188 189 data->lm_binddn = strdup( p ); 190 if ( data->lm_binddn == NULL ) { 191 map_ldap_free( data ); 192 return NULL; 193 } 194 195 if ( data->lm_binddn[ l ] == '\"' 196 || data->lm_binddn[ l ] == '\'' ) { 197 data->lm_binddn[ l ] = '\0'; 198 } 199 200 /* deprecated */ 201 } else if ( strncasecmp( argv[ 0 ], "bindpw=", STRLENOF( "bindpw=" ) ) == 0 ) { 202 ber_str2bv( argv[ 0 ] + STRLENOF( "bindpw=" ), 0, 1, &data->lm_cred ); 203 if ( data->lm_cred.bv_val == NULL ) { 204 map_ldap_free( data ); 205 return NULL; 206 } 207 208 } else if ( strncasecmp( argv[ 0 ], "credentials=", STRLENOF( "credentials=" ) ) == 0 ) { 209 ber_str2bv( argv[ 0 ] + STRLENOF( "credentials=" ), 0, 1, &data->lm_cred ); 210 if ( data->lm_cred.bv_val == NULL ) { 211 map_ldap_free( data ); 212 return NULL; 213 } 214 215 } else if ( strncasecmp( argv[ 0 ], "bindwhen=", STRLENOF( "bindwhen=" ) ) == 0 ) { 216 char *p = argv[ 0 ] + STRLENOF( "bindwhen=" ); 217 218 if ( strcasecmp( p, "now" ) == 0 ) { 219 int rc; 220 221 data->lm_when = MAP_LDAP_NOW; 222 223 /* 224 * Init LDAP handler ... 225 */ 226 rc = ldap_initialize( &data->lm_ld, data->lm_url ); 227 if ( rc != LDAP_SUCCESS ) { 228 map_ldap_free( data ); 229 return NULL; 230 } 231 232 ldap_set_option( data->lm_ld, 233 LDAP_OPT_PROTOCOL_VERSION, 234 (void *)&data->lm_version ); 235 236#ifdef USE_REWRITE_LDAP_PVT_THREADS 237 ldap_pvt_thread_mutex_init( &data->lm_mutex ); 238#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 239 240 } else if ( strcasecmp( p, "later" ) == 0 ) { 241 data->lm_when = MAP_LDAP_LATER; 242 243#ifdef USE_REWRITE_LDAP_PVT_THREADS 244 ldap_pvt_thread_mutex_init( &data->lm_mutex ); 245#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 246 247 } else if ( strcasecmp( p, "everytime" ) == 0 ) { 248 data->lm_when = MAP_LDAP_EVERYTIME; 249 } else { 250 /* ignore ... */ 251 } 252 253 } else if ( strncasecmp( argv[ 0 ], "version=", STRLENOF( "version=" ) ) == 0 ) { 254 if ( lutil_atoi( &data->lm_version, argv[ 0 ] + STRLENOF( "version=" ) ) ) { 255 map_ldap_free( data ); 256 return NULL; 257 } 258 259 switch ( data->lm_version ) { 260 case LDAP_VERSION2: 261 case LDAP_VERSION3: 262 break; 263 264 default: 265 Debug( LDAP_DEBUG_ANY, 266 "[%s:%d] unknown version %s\n", 267 fname, lineno, p ); 268 map_ldap_free( data ); 269 return NULL; 270 } 271 272 } else { 273 Debug( LDAP_DEBUG_ANY, 274 "[%s:%d] unknown option %s (ignored)\n", 275 fname, lineno, argv[0] ); 276 } 277 } 278 279 if ( data->lm_when == MAP_LDAP_UNKNOWN ) { 280 data->lm_when = MAP_LDAP_EVERYTIME; 281 } 282 283 return ( void * )data; 284} 285 286static int 287map_ldap_apply( 288 void *private, 289 const char *filter, 290 struct berval *val 291 292) 293{ 294 LDAP *ld; 295 LDAPMessage *res = NULL, *entry; 296 int rc; 297 struct ldap_map_data *data = private; 298 LDAPURLDesc *lud = data->lm_lud; 299 300 int first_try = 1, set_version = 0; 301 302 assert( private != NULL ); 303 assert( filter != NULL ); 304 assert( val != NULL ); 305 306 val->bv_val = NULL; 307 val->bv_len = 0; 308 309 if ( data->lm_when == MAP_LDAP_EVERYTIME ) { 310 rc = ldap_initialize( &ld, data->lm_url ); 311 set_version = 1; 312 313 } else { 314#ifdef USE_REWRITE_LDAP_PVT_THREADS 315 ldap_pvt_thread_mutex_lock( &data->lm_mutex ); 316#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 317 318 rc = LDAP_SUCCESS; 319 320 if ( data->lm_when == MAP_LDAP_LATER && data->lm_ld == NULL ) { 321 rc = ldap_initialize( &data->lm_ld, data->lm_url ); 322 set_version = 1; 323 } 324 325 ld = data->lm_ld; 326 } 327 328 if ( rc != LDAP_SUCCESS ) { 329 rc = REWRITE_ERR; 330 goto rc_return; 331 } 332 333do_bind:; 334 if ( set_version ) { 335 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, 336 (void *)&data->lm_version ); 337 set_version = 0; 338 } 339 340 if ( data->lm_binddn != NULL ) { 341 rc = ldap_sasl_bind_s( ld, data->lm_binddn, 342 LDAP_SASL_SIMPLE, &data->lm_cred, 343 NULL, NULL, NULL ); 344 if ( rc == LDAP_SERVER_DOWN && first_try ) { 345 first_try = 0; 346 if ( ldap_initialize( &ld, data->lm_url ) != LDAP_SUCCESS ) { 347 rc = REWRITE_ERR; 348 goto rc_return; 349 } 350 set_version = 1; 351 goto do_bind; 352 353 } else if ( rc != REWRITE_SUCCESS ) { 354 rc = REWRITE_ERR; 355 goto rc_return; 356 } 357 } 358 359 rc = ldap_search_ext_s( ld, lud->lud_dn, lud->lud_scope, ( char * )filter, 360 data->lm_attrs, 0, NULL, NULL, NULL, 1, &res ); 361 if ( rc == LDAP_SERVER_DOWN && first_try ) { 362 first_try = 0; 363 if ( ldap_initialize( &ld, data->lm_url ) != LDAP_SUCCESS ) { 364 rc = REWRITE_ERR; 365 goto rc_return; 366 } 367 set_version = 1; 368 goto do_bind; 369 370 } else if ( rc != LDAP_SUCCESS ) { 371 rc = REWRITE_ERR; 372 goto rc_return; 373 } 374 375 if ( ldap_count_entries( ld, res ) != 1 ) { 376 ldap_msgfree( res ); 377 rc = REWRITE_ERR; 378 goto rc_return; 379 } 380 381 entry = ldap_first_entry( ld, res ); 382 assert( entry != NULL ); 383 384 if ( data->lm_wantdn == 1 ) { 385 /* 386 * dn is newly allocated, so there's no need to strdup it 387 */ 388 val->bv_val = ldap_get_dn( ld, entry ); 389 val->bv_len = strlen( val->bv_val ); 390 391 } else { 392 struct berval **values; 393 394 values = ldap_get_values_len( ld, entry, data->lm_attrs[ 0 ] ); 395 if ( values != NULL ) { 396 if ( values[ 0 ] != NULL && values[ 0 ]->bv_val != NULL ) { 397#if 0 398 /* NOTE: in principle, multiple values 399 * should not be acceptable according 400 * to the current API; ignore by now */ 401 if ( values[ 1 ] != NULL ) { 402 /* error */ 403 } 404#endif 405 ber_dupbv( val, values[ 0 ] ); 406 } 407 ldap_value_free_len( values ); 408 } 409 } 410 411 ldap_msgfree( res ); 412 413 if ( val->bv_val == NULL ) { 414 rc = REWRITE_ERR; 415 goto rc_return; 416 } 417 418rc_return:; 419 if ( data->lm_when == MAP_LDAP_EVERYTIME ) { 420 if ( ld != NULL ) { 421 ldap_unbind_ext( ld, NULL, NULL ); 422 } 423 424 } else { 425 data->lm_ld = ld; 426#ifdef USE_REWRITE_LDAP_PVT_THREADS 427 ldap_pvt_thread_mutex_unlock( &data->lm_mutex ); 428#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 429 } 430 431 return rc; 432} 433 434static int 435map_ldap_destroy( 436 void *private 437) 438{ 439 struct ldap_map_data *data = private; 440 441 assert( private != NULL ); 442 443 map_ldap_free( data ); 444 445 return 0; 446} 447 448const rewrite_mapper rewrite_ldap_mapper = { 449 "ldap", 450 map_ldap_parse, 451 map_ldap_apply, 452 map_ldap_destroy 453}; 454 455