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