1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/subst.c,v 1.22.2.3 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 "rewrite-int.h" 23 24 /* 25 * Compiles a substitution pattern 26 */ 27 struct rewrite_subst * 28 rewrite_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 AC_MEMCPY( subs[ nsub ].bv_val, begin, l ); 197 subs[ nsub ].bv_val[ l ] = '\0'; 198 } else { 199 subs[ nsub ].bv_val = NULL; 200 subs[ nsub ].bv_len = 0; 201 } 202 203 s = calloc( sizeof( struct rewrite_subst ), 1 ); 204 if ( s == NULL ) { 205 goto cleanup; 206 } 207 208 s->lt_subs_len = subs_len; 209 s->lt_subs = subs; 210 s->lt_num_submatch = nsub; 211 s->lt_submatch = submatch; 212 213 cleanup:; 214 free( result ); 215 216 return s; 217 } 218 219 /* 220 * Copies the match referred to by submatch and fetched in string by match. 221 * Helper for rewrite_rule_apply. 222 */ 223 static int 224 submatch_copy( 225 struct rewrite_submatch *submatch, 226 const char *string, 227 const regmatch_t *match, 228 struct berval *val 229 ) 230 { 231 int c, l; 232 const char *s; 233 234 assert( submatch != NULL ); 235 assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS 236 || submatch->ls_type == REWRITE_SUBMATCH_XMAP ); 237 assert( string != NULL ); 238 assert( match != NULL ); 239 assert( val != NULL ); 240 assert( val->bv_val == NULL ); 241 242 c = submatch->ls_submatch; 243 s = string + match[ c ].rm_so; 244 l = match[ c ].rm_eo - match[ c ].rm_so; 245 246 val->bv_len = l; 247 val->bv_val = malloc( l + 1 ); 248 if ( val->bv_val == NULL ) { 249 return REWRITE_ERR; 250 } 251 252 AC_MEMCPY( val->bv_val, s, l ); 253 val->bv_val[ l ] = '\0'; 254 255 return REWRITE_SUCCESS; 256 } 257 258 /* 259 * Substitutes a portion of rewritten string according to substitution 260 * pattern using submatches 261 */ 262 int 263 rewrite_subst_apply( 264 struct rewrite_info *info, 265 struct rewrite_op *op, 266 struct rewrite_subst *subst, 267 const char *string, 268 const regmatch_t *match, 269 struct berval *val 270 ) 271 { 272 struct berval *submatch = NULL; 273 char *res = NULL; 274 int n = 0, l, cl; 275 int rc = REWRITE_REGEXEC_OK; 276 277 assert( info != NULL ); 278 assert( op != NULL ); 279 assert( subst != NULL ); 280 assert( string != NULL ); 281 assert( match != NULL ); 282 assert( val != NULL ); 283 284 assert( val->bv_val == NULL ); 285 286 val->bv_val = NULL; 287 val->bv_len = 0; 288 289 /* 290 * Prepare room for submatch expansion 291 */ 292 if ( subst->lt_num_submatch > 0 ) { 293 submatch = calloc( sizeof( struct berval ), 294 subst->lt_num_submatch ); 295 if ( submatch == NULL ) { 296 return REWRITE_REGEXEC_ERR; 297 } 298 } 299 300 /* 301 * Resolve submatches (simple subst, map expansion and so). 302 */ 303 for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) { 304 struct berval key = { 0, NULL }; 305 306 submatch[ n ].bv_val = NULL; 307 308 /* 309 * Get key 310 */ 311 switch ( subst->lt_submatch[ n ].ls_type ) { 312 case REWRITE_SUBMATCH_ASIS: 313 case REWRITE_SUBMATCH_XMAP: 314 rc = submatch_copy( &subst->lt_submatch[ n ], 315 string, match, &key ); 316 if ( rc != REWRITE_SUCCESS ) { 317 rc = REWRITE_REGEXEC_ERR; 318 goto cleanup; 319 } 320 break; 321 322 case REWRITE_SUBMATCH_MAP_W_ARG: 323 switch ( subst->lt_submatch[ n ].ls_map->lm_type ) { 324 case REWRITE_MAP_GET_OP_VAR: 325 case REWRITE_MAP_GET_SESN_VAR: 326 case REWRITE_MAP_GET_PARAM: 327 rc = REWRITE_SUCCESS; 328 break; 329 330 default: 331 rc = rewrite_subst_apply( info, op, 332 subst->lt_submatch[ n ].ls_map->lm_subst, 333 string, match, &key); 334 } 335 336 if ( rc != REWRITE_SUCCESS ) { 337 goto cleanup; 338 } 339 break; 340 341 default: 342 Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 ); 343 rc = REWRITE_ERR; 344 break; 345 } 346 347 if ( rc != REWRITE_SUCCESS ) { 348 rc = REWRITE_REGEXEC_ERR; 349 goto cleanup; 350 } 351 352 /* 353 * Resolve key 354 */ 355 switch ( subst->lt_submatch[ n ].ls_type ) { 356 case REWRITE_SUBMATCH_ASIS: 357 submatch[ n ] = key; 358 rc = REWRITE_SUCCESS; 359 break; 360 361 case REWRITE_SUBMATCH_XMAP: 362 rc = rewrite_xmap_apply( info, op, 363 subst->lt_submatch[ n ].ls_map, 364 &key, &submatch[ n ] ); 365 free( key.bv_val ); 366 key.bv_val = NULL; 367 break; 368 369 case REWRITE_SUBMATCH_MAP_W_ARG: 370 rc = rewrite_map_apply( info, op, 371 subst->lt_submatch[ n ].ls_map, 372 &key, &submatch[ n ] ); 373 free( key.bv_val ); 374 key.bv_val = NULL; 375 break; 376 377 default: 378 /* 379 * When implemented, this might return the 380 * exit status of a rewrite context, 381 * which may include a stop, or an 382 * unwilling to perform 383 */ 384 rc = REWRITE_ERR; 385 break; 386 } 387 388 if ( rc != REWRITE_SUCCESS ) { 389 rc = REWRITE_REGEXEC_ERR; 390 goto cleanup; 391 } 392 393 /* 394 * Increment the length of the resulting string 395 */ 396 l += submatch[ n ].bv_len; 397 } 398 399 /* 400 * Alloc result buffer 401 */ 402 l += subst->lt_subs_len; 403 res = malloc( l + 1 ); 404 if ( res == NULL ) { 405 rc = REWRITE_REGEXEC_ERR; 406 goto cleanup; 407 } 408 409 /* 410 * Apply submatches (possibly resolved thru maps) 411 */ 412 for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) { 413 if ( subst->lt_subs[ n ].bv_val != NULL ) { 414 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, 415 subst->lt_subs[ n ].bv_len ); 416 cl += subst->lt_subs[ n ].bv_len; 417 } 418 AC_MEMCPY( res + cl, submatch[ n ].bv_val, 419 submatch[ n ].bv_len ); 420 cl += submatch[ n ].bv_len; 421 } 422 if ( subst->lt_subs[ n ].bv_val != NULL ) { 423 AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, 424 subst->lt_subs[ n ].bv_len ); 425 cl += subst->lt_subs[ n ].bv_len; 426 } 427 res[ cl ] = '\0'; 428 429 val->bv_val = res; 430 val->bv_len = l; 431 432 cleanup:; 433 if ( submatch ) { 434 for ( ; --n >= 0; ) { 435 if ( submatch[ n ].bv_val ) { 436 free( submatch[ n ].bv_val ); 437 } 438 } 439 free( submatch ); 440 } 441 442 return rc; 443 } 444 445 /* 446 * frees data 447 */ 448 int 449 rewrite_subst_destroy( 450 struct rewrite_subst **psubst 451 ) 452 { 453 int n; 454 struct rewrite_subst *subst; 455 456 assert( psubst != NULL ); 457 assert( *psubst != NULL ); 458 459 subst = *psubst; 460 461 for ( n = 0; n < subst->lt_num_submatch; n++ ) { 462 if ( subst->lt_subs[ n ].bv_val ) { 463 free( subst->lt_subs[ n ].bv_val ); 464 subst->lt_subs[ n ].bv_val = NULL; 465 } 466 467 switch ( subst->lt_submatch[ n ].ls_type ) { 468 case REWRITE_SUBMATCH_ASIS: 469 break; 470 471 case REWRITE_SUBMATCH_XMAP: 472 rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map ); 473 break; 474 475 case REWRITE_SUBMATCH_MAP_W_ARG: 476 rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map ); 477 break; 478 479 default: 480 break; 481 } 482 } 483 484 free( subst->lt_submatch ); 485 subst->lt_submatch = NULL; 486 487 /* last one */ 488 if ( subst->lt_subs[ n ].bv_val ) { 489 free( subst->lt_subs[ n ].bv_val ); 490 subst->lt_subs[ n ].bv_val = NULL; 491 } 492 493 free( subst->lt_subs ); 494 subst->lt_subs = NULL; 495 496 free( subst ); 497 *psubst = NULL; 498 499 return 0; 500 } 501 502