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