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 "rewrite-int.h" 23 24/* 25 * Compiles a substitution pattern 26 */ 27struct rewrite_subst * 28rewrite_subst_compile( 29 struct rewrite_info *info, 30 const char *str 31) 32{ 33 size_t subs_len; 34 struct berval *subs = NULL, *tmps; 35 struct rewrite_submatch *submatch = NULL; 36 37 struct rewrite_subst *s = NULL; 38 39 char *result, *begin, *p; 40 int nsub = 0, l; 41 42 assert( info != NULL ); 43 assert( str != NULL ); 44 45 result = strdup( str ); 46 if ( result == NULL ) { 47 return NULL; 48 } 49 50 /* 51 * Take care of substitution string 52 */ 53 for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) { 54 55 /* 56 * Keep only single escapes '%' 57 */ 58 if ( !IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) { 59 continue; 60 } 61 62 if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 1 ] ) ) { 63 /* Pull &p[1] over p, including the trailing '\0' */ 64 AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) ); 65 continue; 66 } 67 68 tmps = ( struct berval * )realloc( subs, 69 sizeof( struct berval )*( nsub + 1 ) ); 70 if ( tmps == NULL ) { 71 goto cleanup; 72 } 73 subs = tmps; 74 75 /* 76 * I think an `if l > 0' at runtime is better outside than 77 * inside a function call ... 78 */ 79 l = p - begin; 80 if ( l > 0 ) { 81 subs_len += l; 82 subs[ nsub ].bv_len = l; 83 subs[ nsub ].bv_val = malloc( l + 1 ); 84 if ( subs[ nsub ].bv_val == NULL ) { 85 goto cleanup; 86 } 87 AC_MEMCPY( subs[ nsub ].bv_val, begin, l ); 88 subs[ nsub ].bv_val[ l ] = '\0'; 89 } else { 90 subs[ nsub ].bv_val = NULL; 91 subs[ nsub ].bv_len = 0; 92 } 93 94 /* 95 * Substitution pattern 96 */ 97 if ( isdigit( (unsigned char) p[ 1 ] ) ) { 98 struct rewrite_submatch *tmpsm; 99 int d = p[ 1 ] - '0'; 100 101 /* 102 * Add a new value substitution scheme 103 */ 104 105 tmpsm = ( struct rewrite_submatch * )realloc( submatch, 106 sizeof( struct rewrite_submatch )*( nsub + 1 ) ); 107 if ( tmpsm == NULL ) { 108 goto cleanup; 109 } 110 submatch = tmpsm; 111 submatch[ nsub ].ls_submatch = d; 112 113 /* 114 * If there is no argument, use default 115 * (substitute substring as is) 116 */ 117 if ( p[ 2 ] != '{' ) { 118 submatch[ nsub ].ls_type = 119 REWRITE_SUBMATCH_ASIS; 120 submatch[ nsub ].ls_map = NULL; 121 begin = ++p + 1; 122 123 } else { 124 struct rewrite_map *map; 125 126 submatch[ nsub ].ls_type = 127 REWRITE_SUBMATCH_XMAP; 128 129 map = rewrite_xmap_parse( info, 130 p + 3, (const char **)&begin ); 131 if ( map == NULL ) { 132 goto cleanup; 133 } 134 submatch[ nsub ].ls_map = map; 135 p = begin - 1; 136 } 137 138 /* 139 * Map with args ... 140 */ 141 } else if ( p[ 1 ] == '{' ) { 142 struct rewrite_map *map; 143 struct rewrite_submatch *tmpsm; 144 145 map = rewrite_map_parse( info, p + 2, 146 (const char **)&begin ); 147 if ( map == NULL ) { 148 goto cleanup; 149 } 150 p = begin - 1; 151 152 /* 153 * Add a new value substitution scheme 154 */ 155 tmpsm = ( struct rewrite_submatch * )realloc( submatch, 156 sizeof( struct rewrite_submatch )*( nsub + 1 ) ); 157 if ( tmpsm == NULL ) { 158 goto cleanup; 159 } 160 submatch = tmpsm; 161 submatch[ nsub ].ls_type = 162 REWRITE_SUBMATCH_MAP_W_ARG; 163 submatch[ nsub ].ls_map = map; 164 165 /* 166 * Escape '%' ... 167 */ 168 } else if ( p[ 1 ] == '%' ) { 169 AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) ); 170 continue; 171 172 } else { 173 goto cleanup; 174 } 175 176 nsub++; 177 } 178 179 /* 180 * Last part of string 181 */ 182 tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) ); 183 if ( tmps == NULL ) { 184 /* 185 * XXX need to free the value subst stuff! 186 */ 187 free( subs ); 188 goto cleanup; 189 } 190 subs = tmps; 191 l = p - begin; 192 if ( l > 0 ) { 193 subs_len += l; 194 subs[ nsub ].bv_len = l; 195 subs[ nsub ].bv_val = malloc( l + 1 ); 196 if ( subs[ nsub ].bv_val == NULL ) { 197 free( subs ); 198 goto cleanup; 199 } 200 AC_MEMCPY( subs[ nsub ].bv_val, begin, l ); 201 subs[ nsub ].bv_val[ l ] = '\0'; 202 } else { 203 subs[ nsub ].bv_val = NULL; 204 subs[ nsub ].bv_len = 0; 205 } 206 207 s = calloc( sizeof( struct rewrite_subst ), 1 ); 208 if ( s == NULL ) { 209 goto cleanup; 210 } 211 212 s->lt_subs_len = subs_len; 213 s->lt_subs = subs; 214 s->lt_num_submatch = nsub; 215 s->lt_submatch = submatch; 216 217cleanup:; 218 free( result ); 219 220 return s; 221} 222 223/* 224 * Copies the match referred to by submatch and fetched in string by match. 225 * Helper for rewrite_rule_apply. 226 */ 227static int 228submatch_copy( 229 struct rewrite_submatch *submatch, 230 const char *string, 231 const regmatch_t *match, 232 struct berval *val 233) 234{ 235 int c, l; 236 const char *s; 237 238 assert( submatch != NULL ); 239 assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS 240 || submatch->ls_type == REWRITE_SUBMATCH_XMAP ); 241 assert( string != NULL ); 242 assert( match != NULL ); 243 assert( val != NULL ); 244 assert( val->bv_val == NULL ); 245 246 c = submatch->ls_submatch; 247 s = string + match[ c ].rm_so; 248 l = match[ c ].rm_eo - match[ c ].rm_so; 249 250 val->bv_len = l; 251 val->bv_val = malloc( l + 1 ); 252 if ( val->bv_val == NULL ) { 253 return REWRITE_ERR; 254 } 255 256 AC_MEMCPY( val->bv_val, s, l ); 257 val->bv_val[ l ] = '\0'; 258 259 return REWRITE_SUCCESS; 260} 261 262/* 263 * Substitutes a portion of rewritten string according to substitution 264 * pattern using submatches 265 */ 266int 267rewrite_subst_apply( 268 struct rewrite_info *info, 269 struct rewrite_op *op, 270 struct rewrite_subst *subst, 271 const char *string, 272 const regmatch_t *match, 273 struct berval *val 274) 275{ 276 struct berval *submatch = NULL; 277 char *res = NULL; 278 int n = 0, l, cl; 279 int rc = REWRITE_REGEXEC_OK; 280 281 assert( info != NULL ); 282 assert( op != NULL ); 283 assert( subst != NULL ); 284 assert( string != NULL ); 285 assert( match != NULL ); 286 assert( val != NULL ); 287 288 assert( val->bv_val == NULL ); 289 290 val->bv_val = NULL; 291 val->bv_len = 0; 292 293 /* 294 * Prepare room for submatch expansion 295 */ 296 if ( subst->lt_num_submatch > 0 ) { 297 submatch = calloc( sizeof( struct berval ), 298 subst->lt_num_submatch ); 299 if ( submatch == NULL ) { 300 return REWRITE_REGEXEC_ERR; 301 } 302 } 303 304 /* 305 * Resolve submatches (simple subst, map expansion and so). 306 */ 307 for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) { 308 struct berval key = { 0, NULL }; 309 310 submatch[ n ].bv_val = NULL; 311 312 /* 313 * Get key 314 */ 315 switch ( subst->lt_submatch[ n ].ls_type ) { 316 case REWRITE_SUBMATCH_ASIS: 317 case REWRITE_SUBMATCH_XMAP: 318 rc = submatch_copy( &subst->lt_submatch[ n ], 319 string, match, &key ); 320 if ( rc != REWRITE_SUCCESS ) { 321 rc = REWRITE_REGEXEC_ERR; 322 goto cleanup; 323 } 324 break; 325 326 case REWRITE_SUBMATCH_MAP_W_ARG: 327 switch ( subst->lt_submatch[ n ].ls_map->lm_type ) { 328 case REWRITE_MAP_GET_OP_VAR: 329 case REWRITE_MAP_GET_SESN_VAR: 330 case REWRITE_MAP_GET_PARAM: 331 rc = REWRITE_SUCCESS; 332 break; 333 334 default: 335 rc = rewrite_subst_apply( info, op, 336 subst->lt_submatch[ n ].ls_map->lm_subst, 337 string, match, &key); 338 } 339 340 if ( rc != REWRITE_SUCCESS ) { 341 goto cleanup; 342 } 343 break; 344 345 default: 346 Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 ); 347 rc = REWRITE_ERR; 348 break; 349 } 350 351 if ( rc != REWRITE_SUCCESS ) { 352 rc = REWRITE_REGEXEC_ERR; 353 goto cleanup; 354 } 355 356 /* 357 * Resolve key 358 */ 359 switch ( subst->lt_submatch[ n ].ls_type ) { 360 case REWRITE_SUBMATCH_ASIS: 361 submatch[ n ] = key; 362 rc = REWRITE_SUCCESS; 363 break; 364 365 case REWRITE_SUBMATCH_XMAP: 366 rc = rewrite_xmap_apply( info, op, 367 subst->lt_submatch[ n ].ls_map, 368 &key, &submatch[ n ] ); 369 free( key.bv_val ); 370 key.bv_val = NULL; 371 break; 372 373 case REWRITE_SUBMATCH_MAP_W_ARG: 374 rc = rewrite_map_apply( info, op, 375 subst->lt_submatch[ n ].ls_map, 376 &key, &submatch[ n ] ); 377 free( key.bv_val ); 378 key.bv_val = NULL; 379 break; 380 381 default: 382 /* 383 * When implemented, this might return the 384 * exit status of a rewrite context, 385 * which may include a stop, or an 386 * unwilling to perform 387 */ 388 rc = REWRITE_ERR; 389 break; 390 } 391 392 if ( rc != REWRITE_SUCCESS ) { 393 rc = REWRITE_REGEXEC_ERR; 394 goto cleanup; 395 } 396 397 /* 398 * Increment the length of the resulting string 399 */ 400 l += submatch[ n ].bv_len; 401 } 402 403 /* 404 * Alloc result buffer 405 */ 406 l += subst->lt_subs_len; 407 res = malloc( l + 1 ); 408 if ( res == NULL ) { 409 rc = REWRITE_REGEXEC_ERR; 410 goto cleanup; 411 } 412 413 /* 414 * Apply submatches (possibly resolved thru maps) 415 */ 416 for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) { 417 if ( subst->lt_subs[ n ].bv_val != NULL ) { 418 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, 419 subst->lt_subs[ n ].bv_len ); 420 cl += subst->lt_subs[ n ].bv_len; 421 } 422 AC_MEMCPY( res + cl, submatch[ n ].bv_val, 423 submatch[ n ].bv_len ); 424 cl += submatch[ n ].bv_len; 425 } 426 if ( subst->lt_subs[ n ].bv_val != NULL ) { 427 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, 428 subst->lt_subs[ n ].bv_len ); 429 cl += subst->lt_subs[ n ].bv_len; 430 } 431 res[ cl ] = '\0'; 432 433 val->bv_val = res; 434 val->bv_len = l; 435 436cleanup:; 437 if ( submatch ) { 438 for ( ; --n >= 0; ) { 439 if ( submatch[ n ].bv_val ) { 440 free( submatch[ n ].bv_val ); 441 } 442 } 443 free( submatch ); 444 } 445 446 return rc; 447} 448 449/* 450 * frees data 451 */ 452int 453rewrite_subst_destroy( 454 struct rewrite_subst **psubst 455) 456{ 457 int n; 458 struct rewrite_subst *subst; 459 460 assert( psubst != NULL ); 461 assert( *psubst != NULL ); 462 463 subst = *psubst; 464 465 for ( n = 0; n < subst->lt_num_submatch; n++ ) { 466 if ( subst->lt_subs[ n ].bv_val ) { 467 free( subst->lt_subs[ n ].bv_val ); 468 subst->lt_subs[ n ].bv_val = NULL; 469 } 470 471 switch ( subst->lt_submatch[ n ].ls_type ) { 472 case REWRITE_SUBMATCH_ASIS: 473 break; 474 475 case REWRITE_SUBMATCH_XMAP: 476 rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map ); 477 break; 478 479 case REWRITE_SUBMATCH_MAP_W_ARG: 480 rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map ); 481 break; 482 483 default: 484 break; 485 } 486 } 487 488 free( subst->lt_submatch ); 489 subst->lt_submatch = NULL; 490 491 /* last one */ 492 if ( subst->lt_subs[ n ].bv_val ) { 493 free( subst->lt_subs[ n ].bv_val ); 494 subst->lt_subs[ n ].bv_val = NULL; 495 } 496 497 free( subst->lt_subs ); 498 subst->lt_subs = NULL; 499 500 free( subst ); 501 *psubst = NULL; 502 503 return 0; 504} 505 506