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#include "rewrite-int.h" 29#include "rewrite-map.h" 30 31static int num_mappers; 32static const rewrite_mapper **mappers; 33#define MAPPER_ALLOC 8 34 35struct rewrite_map * 36rewrite_map_parse( 37 struct rewrite_info *info, 38 const char *string, 39 const char **currpos 40) 41{ 42 struct rewrite_map *map = NULL; 43 struct rewrite_subst *subst = NULL; 44 char *s, *begin = NULL, *end; 45 const char *p; 46 int l, cnt, mtx = 0, rc = 0; 47 48 assert( info != NULL ); 49 assert( string != NULL ); 50 assert( currpos != NULL ); 51 52 *currpos = NULL; 53 54 /* 55 * Go to the end of the map invocation (the right closing brace) 56 */ 57 for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) { 58 if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) { 59 /* 60 * '%' marks the beginning of a new map 61 */ 62 if ( p[ 1 ] == '{' ) { 63 cnt++; 64 /* 65 * '%' followed by a digit may mark the beginning 66 * of an old map 67 */ 68 } else if ( isdigit( (unsigned char) p[ 1 ] ) && p[ 2 ] == '{' ) { 69 cnt++; 70 p++; 71 } 72 73 if ( p[ 1 ] != '\0' ) { 74 p++; 75 } 76 77 } else if ( p[ 0 ] == '}' ) { 78 cnt--; 79 } 80 } 81 if ( cnt != 0 ) { 82 return NULL; 83 } 84 *currpos = p; 85 86 /* 87 * Copy the map invocation 88 */ 89 l = p - string - 1; 90 s = calloc( sizeof( char ), l + 1 ); 91 if ( s == NULL ) { 92 return NULL; 93 } 94 AC_MEMCPY( s, string, l ); 95 s[ l ] = 0; 96 97 /* 98 * Isolate the map name (except for variable deref) 99 */ 100 switch ( s[ 0 ] ) { 101 case REWRITE_OPERATOR_VARIABLE_GET: 102 case REWRITE_OPERATOR_PARAM_GET: 103 break; 104 105 default: 106 begin = strchr( s, '(' ); 107 if ( begin == NULL ) { 108 rc = -1; 109 goto cleanup; 110 } 111 begin[ 0 ] = '\0'; 112 begin++; 113 break; 114 } 115 116 /* 117 * Check for special map types 118 */ 119 p = s; 120 switch ( p[ 0 ] ) { 121 case REWRITE_OPERATOR_SUBCONTEXT: 122 case REWRITE_OPERATOR_COMMAND: 123 case REWRITE_OPERATOR_VARIABLE_SET: 124 case REWRITE_OPERATOR_VARIABLE_GET: 125 case REWRITE_OPERATOR_PARAM_GET: 126 p++; 127 break; 128 } 129 130 /* 131 * Variable set and get may be repeated to indicate session-wide 132 * instead of operation-wide variables 133 */ 134 switch ( p[ 0 ] ) { 135 case REWRITE_OPERATOR_VARIABLE_SET: 136 case REWRITE_OPERATOR_VARIABLE_GET: 137 p++; 138 break; 139 } 140 141 /* 142 * Variable get token can be appended to variable set to mean store 143 * AND rewrite 144 */ 145 if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) { 146 p++; 147 } 148 149 /* 150 * Check the syntax of the variable name 151 */ 152 if ( !isalpha( (unsigned char) p[ 0 ] ) ) { 153 rc = -1; 154 goto cleanup; 155 } 156 for ( p++; p[ 0 ] != '\0'; p++ ) { 157 if ( !isalnum( (unsigned char) p[ 0 ] ) ) { 158 rc = -1; 159 goto cleanup; 160 } 161 } 162 163 /* 164 * Isolate the argument of the map (except for variable deref) 165 */ 166 switch ( s[ 0 ] ) { 167 case REWRITE_OPERATOR_VARIABLE_GET: 168 case REWRITE_OPERATOR_PARAM_GET: 169 break; 170 171 default: 172 end = strrchr( begin, ')' ); 173 if ( end == NULL ) { 174 rc = -1; 175 goto cleanup; 176 } 177 end[ 0 ] = '\0'; 178 179 /* 180 * Compile the substitution pattern of the map argument 181 */ 182 subst = rewrite_subst_compile( info, begin ); 183 if ( subst == NULL ) { 184 rc = -1; 185 goto cleanup; 186 } 187 break; 188 } 189 190 /* 191 * Create the map 192 */ 193 map = calloc( sizeof( struct rewrite_map ), 1 ); 194 if ( map == NULL ) { 195 rc = -1; 196 goto cleanup; 197 } 198 memset( map, 0, sizeof( struct rewrite_map ) ); 199 200#ifdef USE_REWRITE_LDAP_PVT_THREADS 201 if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { 202 rc = -1; 203 goto cleanup; 204 } 205 ++mtx; 206#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 207 208 /* 209 * No subst for variable deref 210 */ 211 switch ( s[ 0 ] ) { 212 case REWRITE_OPERATOR_VARIABLE_GET: 213 case REWRITE_OPERATOR_PARAM_GET: 214 break; 215 216 default: 217 map->lm_subst = subst; 218 break; 219 } 220 221 /* 222 * Parses special map types 223 */ 224 switch ( s[ 0 ] ) { 225 226 /* 227 * Subcontext 228 */ 229 case REWRITE_OPERATOR_SUBCONTEXT: /* '>' */ 230 231 /* 232 * Fetch the rewrite context 233 * it MUST have been defined previously 234 */ 235 map->lm_type = REWRITE_MAP_SUBCONTEXT; 236 map->lm_name = strdup( s + 1 ); 237 if ( map->lm_name == NULL ) { 238 rc = -1; 239 goto cleanup; 240 } 241 map->lm_data = rewrite_context_find( info, s + 1 ); 242 if ( map->lm_data == NULL ) { 243 rc = -1; 244 goto cleanup; 245 } 246 break; 247 248 /* 249 * External command (not implemented yet) 250 */ 251 case REWRITE_OPERATOR_COMMAND: /* '|' */ 252 rc = -1; 253 goto cleanup; 254 255 /* 256 * Variable set 257 */ 258 case REWRITE_OPERATOR_VARIABLE_SET: /* '&' */ 259 if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) { 260 if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) { 261 map->lm_type = REWRITE_MAP_SETW_SESN_VAR; 262 map->lm_name = strdup( s + 3 ); 263 } else { 264 map->lm_type = REWRITE_MAP_SET_SESN_VAR; 265 map->lm_name = strdup( s + 2 ); 266 } 267 } else { 268 if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { 269 map->lm_type = REWRITE_MAP_SETW_OP_VAR; 270 map->lm_name = strdup( s + 2 ); 271 } else { 272 map->lm_type = REWRITE_MAP_SET_OP_VAR; 273 map->lm_name = strdup( s + 1 ); 274 } 275 } 276 if ( map->lm_name == NULL ) { 277 rc = -1; 278 goto cleanup; 279 } 280 break; 281 282 /* 283 * Variable dereference 284 */ 285 case REWRITE_OPERATOR_VARIABLE_GET: /* '*' */ 286 if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { 287 map->lm_type = REWRITE_MAP_GET_SESN_VAR; 288 map->lm_name = strdup( s + 2 ); 289 } else { 290 map->lm_type = REWRITE_MAP_GET_OP_VAR; 291 map->lm_name = strdup( s + 1 ); 292 } 293 if ( map->lm_name == NULL ) { 294 rc = -1; 295 goto cleanup; 296 } 297 break; 298 299 /* 300 * Parameter 301 */ 302 case REWRITE_OPERATOR_PARAM_GET: /* '$' */ 303 map->lm_type = REWRITE_MAP_GET_PARAM; 304 map->lm_name = strdup( s + 1 ); 305 if ( map->lm_name == NULL ) { 306 rc = -1; 307 goto cleanup; 308 } 309 break; 310 311 /* 312 * Built-in map 313 */ 314 default: 315 map->lm_type = REWRITE_MAP_BUILTIN; 316 map->lm_name = strdup( s ); 317 if ( map->lm_name == NULL ) { 318 rc = -1; 319 goto cleanup; 320 } 321 map->lm_data = rewrite_builtin_map_find( info, s ); 322 if ( map->lm_data == NULL ) { 323 rc = -1; 324 goto cleanup; 325 } 326 break; 327 328 } 329 330cleanup: 331 free( s ); 332 if ( rc ) { 333 if ( subst != NULL ) { 334 free( subst ); 335 } 336 if ( map ) { 337#ifdef USE_REWRITE_LDAP_PVT_THREADS 338 if ( mtx ) { 339 ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); 340 } 341#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 342 343 if ( map->lm_name ) { 344 free( map->lm_name ); 345 map->lm_name = NULL; 346 } 347 free( map ); 348 map = NULL; 349 } 350 } 351 352 return map; 353} 354 355/* 356 * Applies the new map type 357 */ 358int 359rewrite_map_apply( 360 struct rewrite_info *info, 361 struct rewrite_op *op, 362 struct rewrite_map *map, 363 struct berval *key, 364 struct berval *val 365) 366{ 367 int rc = REWRITE_SUCCESS; 368 369 assert( info != NULL ); 370 assert( op != NULL ); 371 assert( map != NULL ); 372 assert( key != NULL ); 373 assert( val != NULL ); 374 375 val->bv_val = NULL; 376 val->bv_len = 0; 377 378 switch ( map->lm_type ) { 379 case REWRITE_MAP_SUBCONTEXT: 380 rc = rewrite_context_apply( info, op, 381 ( struct rewrite_context * )map->lm_data, 382 key->bv_val, &val->bv_val ); 383 if ( val->bv_val != NULL ) { 384 if ( val->bv_val == key->bv_val ) { 385 val->bv_len = key->bv_len; 386 key->bv_val = NULL; 387 } else { 388 val->bv_len = strlen( val->bv_val ); 389 } 390 } 391 break; 392 393 case REWRITE_MAP_SET_OP_VAR: 394 case REWRITE_MAP_SETW_OP_VAR: 395 rc = rewrite_var_set( &op->lo_vars, map->lm_name, 396 key->bv_val, 1 ) 397 ? REWRITE_SUCCESS : REWRITE_ERR; 398 if ( rc == REWRITE_SUCCESS ) { 399 if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) { 400 val->bv_val = strdup( "" ); 401 } else { 402 val->bv_val = strdup( key->bv_val ); 403 val->bv_len = key->bv_len; 404 } 405 if ( val->bv_val == NULL ) { 406 rc = REWRITE_ERR; 407 } 408 } 409 break; 410 411 case REWRITE_MAP_GET_OP_VAR: { 412 struct rewrite_var *var; 413 414 var = rewrite_var_find( op->lo_vars, map->lm_name ); 415 if ( var == NULL ) { 416 rc = REWRITE_ERR; 417 } else { 418 val->bv_val = strdup( var->lv_value.bv_val ); 419 val->bv_len = var->lv_value.bv_len; 420 if ( val->bv_val == NULL ) { 421 rc = REWRITE_ERR; 422 } 423 } 424 break; 425 } 426 427 case REWRITE_MAP_SET_SESN_VAR: 428 case REWRITE_MAP_SETW_SESN_VAR: 429 if ( op->lo_cookie == NULL ) { 430 rc = REWRITE_ERR; 431 break; 432 } 433 rc = rewrite_session_var_set( info, op->lo_cookie, 434 map->lm_name, key->bv_val ); 435 if ( rc == REWRITE_SUCCESS ) { 436 if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) { 437 val->bv_val = strdup( "" ); 438 } else { 439 val->bv_val = strdup( key->bv_val ); 440 val->bv_len = key->bv_len; 441 } 442 if ( val->bv_val == NULL ) { 443 rc = REWRITE_ERR; 444 } 445 } 446 break; 447 448 case REWRITE_MAP_GET_SESN_VAR: 449 rc = rewrite_session_var_get( info, op->lo_cookie, 450 map->lm_name, val ); 451 break; 452 453 case REWRITE_MAP_GET_PARAM: 454 rc = rewrite_param_get( info, map->lm_name, val ); 455 break; 456 457 case REWRITE_MAP_BUILTIN: { 458 struct rewrite_builtin_map *bmap = map->lm_data; 459 460 if ( bmap->lb_mapper && bmap->lb_mapper->rm_apply ) 461 rc = bmap->lb_mapper->rm_apply( bmap->lb_private, key->bv_val, 462 val ); 463 else 464 rc = REWRITE_ERR; 465 break; 466 break; 467 } 468 469 default: 470 rc = REWRITE_ERR; 471 break; 472 } 473 474 return rc; 475} 476 477void 478rewrite_builtin_map_free( 479 void *tmp 480) 481{ 482 struct rewrite_builtin_map *map = ( struct rewrite_builtin_map * )tmp; 483 484 assert( map != NULL ); 485 486 if ( map->lb_mapper && map->lb_mapper->rm_destroy ) 487 map->lb_mapper->rm_destroy( map->lb_private ); 488 489 free( map->lb_name ); 490 free( map ); 491} 492 493int 494rewrite_map_destroy( 495 struct rewrite_map **pmap 496) 497{ 498 struct rewrite_map *map; 499 500 assert( pmap != NULL ); 501 assert( *pmap != NULL ); 502 503 map = *pmap; 504 505#ifdef USE_REWRITE_LDAP_PVT_THREADS 506 ldap_pvt_thread_mutex_lock( &map->lm_mutex ); 507#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 508 509 if ( map->lm_name ) { 510 free( map->lm_name ); 511 map->lm_name = NULL; 512 } 513 514 if ( map->lm_subst ) { 515 rewrite_subst_destroy( &map->lm_subst ); 516 } 517 518#ifdef USE_REWRITE_LDAP_PVT_THREADS 519 ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); 520 ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); 521#endif /* USE_REWRITE_LDAP_PVT_THREADS */ 522 523 free( map ); 524 *pmap = NULL; 525 526 return 0; 527} 528 529/* ldapmap.c */ 530extern const rewrite_mapper rewrite_ldap_mapper; 531 532const rewrite_mapper * 533rewrite_mapper_find( 534 const char *name 535) 536{ 537 int i; 538 539 if ( !strcasecmp( name, "ldap" )) 540 return &rewrite_ldap_mapper; 541 542 for (i=0; i<num_mappers; i++) 543 if ( !strcasecmp( name, mappers[i]->rm_name )) 544 return mappers[i]; 545 return NULL; 546} 547 548int 549rewrite_mapper_register( 550 const rewrite_mapper *map 551) 552{ 553 if ( num_mappers % MAPPER_ALLOC == 0 ) { 554 const rewrite_mapper **mnew; 555 mnew = realloc( mappers, (num_mappers + MAPPER_ALLOC) * 556 sizeof( rewrite_mapper * )); 557 if ( mnew ) 558 mappers = mnew; 559 else 560 return -1; 561 } 562 mappers[num_mappers++] = map; 563 return 0; 564} 565 566int 567rewrite_mapper_unregister( 568 const rewrite_mapper *map 569) 570{ 571 int i; 572 573 for (i = 0; i<num_mappers; i++) { 574 if ( mappers[i] == map ) { 575 num_mappers--; 576 mappers[i] = mappers[num_mappers]; 577 mappers[num_mappers] = NULL; 578 return 0; 579 } 580 } 581 /* not found */ 582 return -1; 583} 584