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