1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/xmap.c,v 1.12.2.3 2008/02/11 23:26:43 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 #include <stdio.h> 23 24 #ifdef HAVE_PWD_H 25 #include <pwd.h> 26 #endif 27 28 #define LDAP_DEPRECATED 1 29 #include "rewrite-int.h" 30 #include "rewrite-map.h" 31 32 /* 33 * Global data 34 */ 35 #ifdef USE_REWRITE_LDAP_PVT_THREADS 36 ldap_pvt_thread_mutex_t xpasswd_mutex; 37 static int xpasswd_mutex_init = 0; 38 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 39 40 /* 41 * Map parsing 42 * NOTE: these are old-fashion maps; new maps will be parsed on separate 43 * config lines, and referred by name. 44 */ 45 struct rewrite_map * 46 rewrite_xmap_parse( 47 struct rewrite_info *info, 48 const char *s, 49 const char **currpos 50 ) 51 { 52 struct rewrite_map *map; 53 54 assert( info != NULL ); 55 assert( s != NULL ); 56 assert( currpos != NULL ); 57 58 Debug( LDAP_DEBUG_ARGS, "rewrite_xmap_parse: %s\n%s%s", 59 s, "", "" ); 60 61 *currpos = NULL; 62 63 map = calloc( sizeof( struct rewrite_map ), 1 ); 64 if ( map == NULL ) { 65 Debug( LDAP_DEBUG_ANY, "rewrite_xmap_parse:" 66 " calloc failed\n%s%s%s", "", "", "" ); 67 return NULL; 68 } 69 70 /* 71 * Experimental passwd map: 72 * replaces the uid with the matching gecos from /etc/passwd file 73 */ 74 if ( strncasecmp(s, "xpasswd", 7 ) == 0 ) { 75 map->lm_type = REWRITE_MAP_XPWDMAP; 76 map->lm_name = strdup( "xpasswd" ); 77 78 assert( s[7] == '}' ); 79 *currpos = s + 8; 80 81 #ifdef USE_REWRITE_LDAP_PVT_THREADS 82 if ( !xpasswd_mutex_init ) { 83 if ( ldap_pvt_thread_mutex_init( &xpasswd_mutex ) ) { 84 free( map ); 85 return NULL; 86 } 87 } 88 ++xpasswd_mutex_init; 89 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 90 91 /* Don't really care if fails */ 92 return map; 93 94 /* 95 * Experimental file map: 96 * looks up key in a `key value' ascii file 97 */ 98 } else if ( strncasecmp( s, "xfile", 5 ) == 0 ) { 99 char *filename; 100 const char *p; 101 int l; 102 int c = 5; 103 104 map->lm_type = REWRITE_MAP_XFILEMAP; 105 106 if ( s[ c ] != '(' ) { 107 free( map ); 108 return NULL; 109 } 110 111 /* Must start with '/' for security concerns */ 112 c++; 113 if ( s[ c ] != '/' ) { 114 free( map ); 115 return NULL; 116 } 117 118 for ( p = s + c; p[ 0 ] != '\0' && p[ 0 ] != ')'; p++ ); 119 if ( p[ 0 ] != ')' ) { 120 free( map ); 121 return NULL; 122 } 123 124 l = p - s - c; 125 filename = calloc( sizeof( char ), l + 1 ); 126 AC_MEMCPY( filename, s + c, l ); 127 filename[ l ] = '\0'; 128 129 map->lm_args = ( void * )fopen( filename, "r" ); 130 free( filename ); 131 132 if ( map->lm_args == NULL ) { 133 free( map ); 134 return NULL; 135 } 136 137 *currpos = p + 1; 138 139 #ifdef USE_REWRITE_LDAP_PVT_THREADS 140 if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { 141 fclose( ( FILE * )map->lm_args ); 142 free( map ); 143 return NULL; 144 } 145 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 146 147 return map; 148 149 /* 150 * Experimental ldap map: 151 * looks up key on the fly (not implemented!) 152 */ 153 } else if ( strncasecmp(s, "xldap", 5 ) == 0 ) { 154 char *p; 155 char *url; 156 int l, rc; 157 int c = 5; 158 LDAPURLDesc *lud; 159 160 if ( s[ c ] != '(' ) { 161 free( map ); 162 return NULL; 163 } 164 c++; 165 166 p = strchr( s, '}' ); 167 if ( p == NULL ) { 168 free( map ); 169 return NULL; 170 } 171 p--; 172 173 *currpos = p + 2; 174 175 /* 176 * Add two bytes for urlencoding of '%s' 177 */ 178 l = p - s - c; 179 url = calloc( sizeof( char ), l + 3 ); 180 AC_MEMCPY( url, s + c, l ); 181 url[ l ] = '\0'; 182 183 /* 184 * Urlencodes the '%s' for ldap_url_parse 185 */ 186 p = strchr( url, '%' ); 187 if ( p != NULL ) { 188 AC_MEMCPY( p + 3, p + 1, strlen( p + 1 ) + 1 ); 189 p[ 1 ] = '2'; 190 p[ 2 ] = '5'; 191 } 192 193 rc = ldap_url_parse( url, &lud ); 194 free( url ); 195 196 if ( rc != LDAP_SUCCESS ) { 197 free( map ); 198 return NULL; 199 } 200 assert( lud != NULL ); 201 202 map->lm_args = ( void * )lud; 203 map->lm_type = REWRITE_MAP_XLDAPMAP; 204 205 #ifdef USE_REWRITE_LDAP_PVT_THREADS 206 if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { 207 ldap_free_urldesc( lud ); 208 free( map ); 209 return NULL; 210 } 211 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 212 213 return map; 214 215 /* Unhandled map */ 216 } 217 218 free( map ); 219 return NULL; 220 } 221 222 /* 223 * Map key -> value resolution 224 * NOTE: these are old-fashion maps; new maps will be parsed on separate 225 * config lines, and referred by name. 226 */ 227 int 228 rewrite_xmap_apply( 229 struct rewrite_info *info, 230 struct rewrite_op *op, 231 struct rewrite_map *map, 232 struct berval *key, 233 struct berval *val 234 ) 235 { 236 int rc = REWRITE_SUCCESS; 237 238 assert( info != NULL ); 239 assert( op != NULL ); 240 assert( map != NULL ); 241 assert( key != NULL ); 242 assert( val != NULL ); 243 244 val->bv_val = NULL; 245 val->bv_len = 0; 246 247 switch ( map->lm_type ) { 248 #ifdef HAVE_GETPWNAM 249 case REWRITE_MAP_XPWDMAP: { 250 struct passwd *pwd; 251 252 #ifdef USE_REWRITE_LDAP_PVT_THREADS 253 ldap_pvt_thread_mutex_lock( &xpasswd_mutex ); 254 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 255 256 pwd = getpwnam( key->bv_val ); 257 if ( pwd == NULL ) { 258 259 #ifdef USE_REWRITE_LDAP_PVT_THREADS 260 ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); 261 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 262 263 rc = LDAP_NO_SUCH_OBJECT; 264 break; 265 } 266 267 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS 268 if ( pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0' ) { 269 int l = strlen( pwd->pw_gecos ); 270 271 val->bv_val = strdup( pwd->pw_gecos ); 272 if ( val->bv_val == NULL ) { 273 274 #ifdef USE_REWRITE_LDAP_PVT_THREADS 275 ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); 276 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 277 278 rc = REWRITE_ERR; 279 break; 280 } 281 val->bv_len = l; 282 } else 283 #endif /* HAVE_STRUCT_PASSWD_PW_GECOS */ 284 { 285 val->bv_val = strdup( key->bv_val ); 286 val->bv_len = key->bv_len; 287 } 288 289 #ifdef USE_REWRITE_LDAP_PVT_THREADS 290 ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); 291 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 292 293 break; 294 } 295 #endif /* HAVE_GETPWNAM*/ 296 297 case REWRITE_MAP_XFILEMAP: { 298 char buf[1024]; 299 300 if ( map->lm_args == NULL ) { 301 rc = REWRITE_ERR; 302 break; 303 } 304 305 #ifdef USE_REWRITE_LDAP_PVT_THREADS 306 ldap_pvt_thread_mutex_lock( &map->lm_mutex ); 307 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 308 309 rewind( ( FILE * )map->lm_args ); 310 311 while ( fgets( buf, sizeof( buf ), ( FILE * )map->lm_args ) ) { 312 char *p; 313 int blen; 314 315 blen = strlen( buf ); 316 if ( buf[ blen - 1 ] == '\n' ) { 317 buf[ blen - 1 ] = '\0'; 318 } 319 320 p = strtok( buf, " " ); 321 if ( p == NULL ) { 322 #ifdef USE_REWRITE_LDAP_PVT_THREADS 323 ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); 324 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 325 rc = REWRITE_ERR; 326 goto rc_return; 327 } 328 if ( strcasecmp( p, key->bv_val ) == 0 329 && ( p = strtok( NULL, "" ) ) ) { 330 val->bv_val = strdup( p ); 331 if ( val->bv_val == NULL ) { 332 return REWRITE_ERR; 333 } 334 335 val->bv_len = strlen( p ); 336 337 #ifdef USE_REWRITE_LDAP_PVT_THREADS 338 ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); 339 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 340 341 goto rc_return; 342 } 343 } 344 345 #ifdef USE_REWRITE_LDAP_PVT_THREADS 346 ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); 347 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 348 349 rc = REWRITE_ERR; 350 351 break; 352 } 353 354 case REWRITE_MAP_XLDAPMAP: { 355 LDAP *ld; 356 char filter[1024]; 357 LDAPMessage *res = NULL, *entry; 358 LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args; 359 int attrsonly = 0; 360 char **values; 361 362 assert( lud != NULL ); 363 364 /* 365 * No mutex because there is no write on the map data 366 */ 367 368 ld = ldap_init( lud->lud_host, lud->lud_port ); 369 if ( ld == NULL ) { 370 rc = REWRITE_ERR; 371 goto rc_return; 372 } 373 374 snprintf( filter, sizeof( filter ), lud->lud_filter, 375 key->bv_val ); 376 377 if ( strcasecmp( lud->lud_attrs[ 0 ], "dn" ) == 0 ) { 378 attrsonly = 1; 379 } 380 rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope, 381 filter, lud->lud_attrs, attrsonly, &res ); 382 if ( rc != LDAP_SUCCESS ) { 383 ldap_unbind( ld ); 384 rc = REWRITE_ERR; 385 goto rc_return; 386 } 387 388 if ( ldap_count_entries( ld, res ) != 1 ) { 389 ldap_unbind( ld ); 390 rc = REWRITE_ERR; 391 goto rc_return; 392 } 393 394 entry = ldap_first_entry( ld, res ); 395 if ( entry == NULL ) { 396 ldap_msgfree( res ); 397 ldap_unbind( ld ); 398 rc = REWRITE_ERR; 399 goto rc_return; 400 } 401 if ( attrsonly == 1 ) { 402 val->bv_val = ldap_get_dn( ld, entry ); 403 if ( val->bv_val == NULL ) { 404 ldap_msgfree( res ); 405 ldap_unbind( ld ); 406 rc = REWRITE_ERR; 407 goto rc_return; 408 } 409 } else { 410 values = ldap_get_values( ld, entry, 411 lud->lud_attrs[0] ); 412 if ( values == NULL ) { 413 ldap_msgfree( res ); 414 ldap_unbind( ld ); 415 rc = REWRITE_ERR; 416 goto rc_return; 417 } 418 val->bv_val = strdup( values[ 0 ] ); 419 ldap_value_free( values ); 420 } 421 val->bv_len = strlen( val->bv_val ); 422 423 ldap_msgfree( res ); 424 ldap_unbind( ld ); 425 426 rc = REWRITE_SUCCESS; 427 } 428 } 429 430 rc_return:; 431 return rc; 432 } 433 434 int 435 rewrite_xmap_destroy( 436 struct rewrite_map **pmap 437 ) 438 { 439 struct rewrite_map *map; 440 441 assert( pmap != NULL ); 442 assert( *pmap != NULL ); 443 444 map = *pmap; 445 446 switch ( map->lm_type ) { 447 case REWRITE_MAP_XPWDMAP: 448 #ifdef USE_REWRITE_LDAP_PVT_THREADS 449 --xpasswd_mutex_init; 450 if ( !xpasswd_mutex_init ) { 451 ldap_pvt_thread_mutex_destroy( &xpasswd_mutex ); 452 } 453 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 454 455 break; 456 457 case REWRITE_MAP_XFILEMAP: 458 #ifdef USE_REWRITE_LDAP_PVT_THREADS 459 ldap_pvt_thread_mutex_lock( &map->lm_mutex ); 460 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 461 462 if ( map->lm_args ) { 463 fclose( ( FILE * )map->lm_args ); 464 map->lm_args = NULL; 465 } 466 467 #ifdef USE_REWRITE_LDAP_PVT_THREADS 468 ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); 469 ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); 470 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 471 break; 472 473 case REWRITE_MAP_XLDAPMAP: 474 #ifdef USE_REWRITE_LDAP_PVT_THREADS 475 ldap_pvt_thread_mutex_lock( &map->lm_mutex ); 476 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 477 478 if ( map->lm_args ) { 479 ldap_free_urldesc( ( LDAPURLDesc * )map->lm_args ); 480 map->lm_args = NULL; 481 } 482 483 #ifdef USE_REWRITE_LDAP_PVT_THREADS 484 ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); 485 ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); 486 #endif /* USE_REWRITE_LDAP_PVT_THREADS */ 487 break; 488 489 default: 490 break; 491 492 } 493 494 free( map->lm_name ); 495 free( map ); 496 *pmap = NULL; 497 498 return 0; 499 } 500 501