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