1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/rule.c,v 1.23.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 * Appends a rule to the double linked list of rules 26 * Helper for rewrite_rule_compile 27 */ 28 static int 29 append_rule( 30 struct rewrite_context *context, 31 struct rewrite_rule *rule 32 ) 33 { 34 struct rewrite_rule *r; 35 36 assert( context != NULL ); 37 assert( context->lc_rule != NULL ); 38 assert( rule != NULL ); 39 40 for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next ); 41 r->lr_next = rule; 42 rule->lr_prev = r; 43 44 return REWRITE_SUCCESS; 45 } 46 47 /* 48 * Appends an action to the linked list of actions 49 * Helper for rewrite_rule_compile 50 */ 51 static int 52 append_action( 53 struct rewrite_action **pbase, 54 struct rewrite_action *action 55 ) 56 { 57 struct rewrite_action **pa; 58 59 assert( pbase != NULL ); 60 assert( action != NULL ); 61 62 for ( pa = pbase; *pa != NULL; pa = &(*pa)->la_next ); 63 *pa = action; 64 65 return REWRITE_SUCCESS; 66 } 67 68 static int 69 destroy_action( 70 struct rewrite_action **paction 71 ) 72 { 73 struct rewrite_action *action; 74 75 assert( paction != NULL ); 76 assert( *paction != NULL ); 77 78 action = *paction; 79 80 /* do something */ 81 switch ( action->la_type ) { 82 case REWRITE_FLAG_GOTO: 83 case REWRITE_FLAG_USER: { 84 int *pi = (int *)action->la_args; 85 86 if ( pi ) { 87 free( pi ); 88 } 89 break; 90 } 91 92 default: 93 break; 94 } 95 96 free( action ); 97 *paction = NULL; 98 99 return 0; 100 } 101 102 static void 103 destroy_actions( 104 struct rewrite_action *paction 105 ) 106 { 107 struct rewrite_action *next; 108 109 for (; paction; paction = next) { 110 next = paction->la_next; 111 destroy_action( &paction ); 112 } 113 } 114 115 /* 116 */ 117 int 118 rewrite_rule_compile( 119 struct rewrite_info *info, 120 struct rewrite_context *context, 121 const char *pattern, 122 const char *result, 123 const char *flagstring 124 ) 125 { 126 int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE; 127 int mode = REWRITE_RECURSE; 128 int max_passes = info->li_max_passes_per_rule; 129 130 struct rewrite_rule *rule = NULL; 131 struct rewrite_subst *subst = NULL; 132 struct rewrite_action *action = NULL, *first_action = NULL; 133 134 const char *p; 135 136 assert( info != NULL ); 137 assert( context != NULL ); 138 assert( pattern != NULL ); 139 assert( result != NULL ); 140 141 /* 142 * A null flagstring should be allowed 143 */ 144 145 /* 146 * Take care of substitution string 147 */ 148 subst = rewrite_subst_compile( info, result ); 149 if ( subst == NULL ) { 150 return REWRITE_ERR; 151 } 152 153 /* 154 * Take care of flags 155 */ 156 for ( p = flagstring; p[ 0 ] != '\0'; p++ ) { 157 switch( p[ 0 ] ) { 158 159 /* 160 * REGEX flags 161 */ 162 case REWRITE_FLAG_HONORCASE: /* 'C' */ 163 /* 164 * Honor case (default is case insensitive) 165 */ 166 flags &= ~REWRITE_REGEX_ICASE; 167 break; 168 169 case REWRITE_FLAG_BASICREGEX: /* 'R' */ 170 /* 171 * Use POSIX Basic Regular Expression syntax 172 * instead of POSIX Extended Regular Expression 173 * syntax (default) 174 */ 175 flags &= ~REWRITE_REGEX_EXTENDED; 176 break; 177 178 /* 179 * Execution mode flags 180 */ 181 case REWRITE_FLAG_EXECONCE: /* ':' */ 182 /* 183 * Apply rule once only 184 */ 185 mode &= ~REWRITE_RECURSE; 186 mode |= REWRITE_EXEC_ONCE; 187 break; 188 189 /* 190 * Special action flags 191 */ 192 case REWRITE_FLAG_STOP: /* '@' */ 193 /* 194 * Bail out after applying rule 195 */ 196 action = calloc( sizeof( struct rewrite_action ), 1 ); 197 if ( action == NULL ) { 198 goto fail; 199 } 200 201 action->la_type = REWRITE_ACTION_STOP; 202 break; 203 204 case REWRITE_FLAG_UNWILLING: /* '#' */ 205 /* 206 * Matching objs will be marked as gone! 207 */ 208 action = calloc( sizeof( struct rewrite_action ), 1 ); 209 if ( action == NULL ) { 210 goto fail; 211 } 212 213 mode &= ~REWRITE_RECURSE; 214 mode |= REWRITE_EXEC_ONCE; 215 action->la_type = REWRITE_ACTION_UNWILLING; 216 break; 217 218 case REWRITE_FLAG_GOTO: /* 'G' */ 219 /* 220 * After applying rule, jump N rules 221 */ 222 223 case REWRITE_FLAG_USER: { /* 'U' */ 224 /* 225 * After applying rule, return user-defined 226 * error code 227 */ 228 char *next = NULL; 229 int *d; 230 231 if ( p[ 1 ] != '{' ) { 232 goto fail; 233 } 234 235 d = malloc( sizeof( int ) ); 236 if ( d == NULL ) { 237 goto fail; 238 } 239 240 d[ 0 ] = strtol( &p[ 2 ], &next, 0 ); 241 if ( next == &p[ 2 ] || next[0] != '}' ) { 242 free( d ); 243 goto fail; 244 } 245 246 action = calloc( sizeof( struct rewrite_action ), 1 ); 247 if ( action == NULL ) { 248 free( d ); 249 goto fail; 250 } 251 switch ( p[ 0 ] ) { 252 case REWRITE_FLAG_GOTO: 253 action->la_type = REWRITE_ACTION_GOTO; 254 break; 255 256 case REWRITE_FLAG_USER: 257 action->la_type = REWRITE_ACTION_USER; 258 break; 259 260 default: 261 assert(0); 262 } 263 264 action->la_args = (void *)d; 265 266 p = next; /* p is incremented by the for ... */ 267 268 break; 269 } 270 271 case REWRITE_FLAG_MAX_PASSES: { /* 'U' */ 272 /* 273 * Set the number of max passes per rule 274 */ 275 char *next = NULL; 276 277 if ( p[ 1 ] != '{' ) { 278 goto fail; 279 } 280 281 max_passes = strtol( &p[ 2 ], &next, 0 ); 282 if ( next == &p[ 2 ] || next[0] != '}' ) { 283 goto fail; 284 } 285 286 if ( max_passes < 1 ) { 287 /* FIXME: nonsense ... */ 288 max_passes = 1; 289 } 290 291 p = next; /* p is incremented by the for ... */ 292 293 break; 294 } 295 296 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */ 297 /* 298 * Ignore errors! 299 */ 300 action = calloc( sizeof( struct rewrite_action ), 1 ); 301 if ( action == NULL ) { 302 goto fail; 303 } 304 305 action->la_type = REWRITE_ACTION_IGNORE_ERR; 306 break; 307 308 /* 309 * Other flags ... 310 */ 311 default: 312 /* 313 * Unimplemented feature (complain only) 314 */ 315 break; 316 } 317 318 /* 319 * Stupid way to append to a list ... 320 */ 321 if ( action != NULL ) { 322 append_action( &first_action, action ); 323 action = NULL; 324 } 325 } 326 327 /* 328 * Finally, rule allocation 329 */ 330 rule = calloc( sizeof( struct rewrite_rule ), 1 ); 331 if ( rule == NULL ) { 332 goto fail; 333 } 334 335 /* 336 * REGEX compilation (luckily I don't need to take care of this ...) 337 */ 338 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) { 339 free( rule ); 340 goto fail; 341 } 342 343 /* 344 * Just to remember them ... 345 */ 346 rule->lr_pattern = strdup( pattern ); 347 rule->lr_subststring = strdup( result ); 348 rule->lr_flagstring = strdup( flagstring ); 349 350 /* 351 * Load compiled data into rule 352 */ 353 rule->lr_subst = subst; 354 355 /* 356 * Set various parameters 357 */ 358 rule->lr_flags = flags; /* don't really need any longer ... */ 359 rule->lr_mode = mode; 360 rule->lr_max_passes = max_passes; 361 rule->lr_action = first_action; 362 363 /* 364 * Append rule at the end of the rewrite context 365 */ 366 append_rule( context, rule ); 367 368 return REWRITE_SUCCESS; 369 370 fail: 371 destroy_actions( first_action ); 372 free( subst ); 373 return REWRITE_ERR; 374 } 375 376 /* 377 * Rewrites string according to rule; may return: 378 * OK: fine; if *result != NULL rule matched and rewrite succeeded. 379 * STOP: fine, rule matched; stop processing following rules 380 * UNWILL: rule matched; force 'unwilling to perform' 381 */ 382 int 383 rewrite_rule_apply( 384 struct rewrite_info *info, 385 struct rewrite_op *op, 386 struct rewrite_rule *rule, 387 const char *arg, 388 char **result 389 ) 390 { 391 size_t nmatch = REWRITE_MAX_MATCH; 392 regmatch_t match[ REWRITE_MAX_MATCH ]; 393 394 int rc = REWRITE_SUCCESS; 395 396 char *string; 397 int strcnt = 0; 398 struct berval val = { 0, NULL }; 399 400 assert( info != NULL ); 401 assert( op != NULL ); 402 assert( rule != NULL ); 403 assert( arg != NULL ); 404 assert( result != NULL ); 405 406 *result = NULL; 407 408 string = (char *)arg; 409 410 /* 411 * In case recursive match is required (default) 412 */ 413 recurse:; 414 415 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply" 416 " rule='%s' string='%s' [%d pass(es)]\n", 417 rule->lr_pattern, string, strcnt + 1 ); 418 419 op->lo_num_passes++; 420 421 rc = regexec( &rule->lr_regex, string, nmatch, match, 0 ); 422 if ( rc != 0 ) { 423 if ( *result == NULL && string != arg ) { 424 free( string ); 425 } 426 427 /* 428 * No match is OK; *result = NULL means no match 429 */ 430 return REWRITE_REGEXEC_OK; 431 } 432 433 rc = rewrite_subst_apply( info, op, rule->lr_subst, string, 434 match, &val ); 435 436 *result = val.bv_val; 437 val.bv_val = NULL; 438 if ( string != arg ) { 439 free( string ); 440 string = NULL; 441 } 442 443 if ( rc != REWRITE_REGEXEC_OK ) { 444 return rc; 445 } 446 447 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE 448 && op->lo_num_passes < info->li_max_passes 449 && ++strcnt < rule->lr_max_passes ) { 450 string = *result; 451 452 goto recurse; 453 } 454 455 return REWRITE_REGEXEC_OK; 456 } 457 458 int 459 rewrite_rule_destroy( 460 struct rewrite_rule **prule 461 ) 462 { 463 struct rewrite_rule *rule; 464 465 assert( prule != NULL ); 466 assert( *prule != NULL ); 467 468 rule = *prule; 469 470 if ( rule->lr_pattern ) { 471 free( rule->lr_pattern ); 472 rule->lr_pattern = NULL; 473 } 474 475 if ( rule->lr_subststring ) { 476 free( rule->lr_subststring ); 477 rule->lr_subststring = NULL; 478 } 479 480 if ( rule->lr_flagstring ) { 481 free( rule->lr_flagstring ); 482 rule->lr_flagstring = NULL; 483 } 484 485 if ( rule->lr_subst ) { 486 rewrite_subst_destroy( &rule->lr_subst ); 487 } 488 489 regfree( &rule->lr_regex ); 490 491 destroy_actions( rule->lr_action ); 492 493 free( rule ); 494 *prule = NULL; 495 496 return 0; 497 } 498 499