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