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