1 /* $NetBSD: context.c,v 1.1.1.3 2010/12/12 15:22:12 adam Exp $ */ 2 3 /* OpenLDAP: pkg/ldap/libraries/librewrite/context.c,v 1.15.2.5 2010/04/13 20:23:08 kurt Exp */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 2000-2010 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 * Compares two struct rewrite_context based on the name; 28 * used by avl stuff 29 */ 30 static int 31 rewrite_context_cmp( 32 const void *c1, 33 const void *c2 34 ) 35 { 36 const struct rewrite_context *lc1, *lc2; 37 38 lc1 = (const struct rewrite_context *)c1; 39 lc2 = (const struct rewrite_context *)c2; 40 41 assert( c1 != NULL ); 42 assert( c2 != NULL ); 43 assert( lc1->lc_name != NULL ); 44 assert( lc2->lc_name != NULL ); 45 46 return strcasecmp( lc1->lc_name, lc2->lc_name ); 47 } 48 49 /* 50 * Returns -1 in case a duplicate struct rewrite_context 51 * has been inserted; used by avl stuff 52 */ 53 static int 54 rewrite_context_dup( 55 void *c1, 56 void *c2 57 ) 58 { 59 struct rewrite_context *lc1, *lc2; 60 61 lc1 = (struct rewrite_context *)c1; 62 lc2 = (struct rewrite_context *)c2; 63 64 assert( c1 != NULL ); 65 assert( c2 != NULL ); 66 assert( lc1->lc_name != NULL ); 67 assert( lc2->lc_name != NULL ); 68 69 return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 ); 70 } 71 72 /* 73 * Finds the context named rewriteContext in the context tree 74 */ 75 struct rewrite_context * 76 rewrite_context_find( 77 struct rewrite_info *info, 78 const char *rewriteContext 79 ) 80 { 81 struct rewrite_context *context, c; 82 83 assert( info != NULL ); 84 assert( rewriteContext != NULL ); 85 86 /* 87 * Fetches the required rewrite context 88 */ 89 c.lc_name = (char *)rewriteContext; 90 context = (struct rewrite_context *)avl_find( info->li_context, 91 (caddr_t)&c, rewrite_context_cmp ); 92 if ( context == NULL ) { 93 return NULL; 94 } 95 96 /* 97 * De-aliases the context if required 98 */ 99 if ( context->lc_alias ) { 100 return context->lc_alias; 101 } 102 103 return context; 104 } 105 106 /* 107 * Creates a new context called rewriteContext and stores in into the tree 108 */ 109 struct rewrite_context * 110 rewrite_context_create( 111 struct rewrite_info *info, 112 const char *rewriteContext 113 ) 114 { 115 struct rewrite_context *context; 116 int rc; 117 118 assert( info != NULL ); 119 assert( rewriteContext != NULL ); 120 121 context = calloc( sizeof( struct rewrite_context ), 1 ); 122 if ( context == NULL ) { 123 return NULL; 124 } 125 126 /* 127 * Context name 128 */ 129 context->lc_name = strdup( rewriteContext ); 130 if ( context->lc_name == NULL ) { 131 free( context ); 132 return NULL; 133 } 134 135 /* 136 * The first, empty rule 137 */ 138 context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 ); 139 if ( context->lc_rule == NULL ) { 140 free( context->lc_name ); 141 free( context ); 142 return NULL; 143 } 144 memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) ); 145 146 /* 147 * Add context to tree 148 */ 149 rc = avl_insert( &info->li_context, (caddr_t)context, 150 rewrite_context_cmp, rewrite_context_dup ); 151 if ( rc == -1 ) { 152 free( context->lc_rule ); 153 free( context->lc_name ); 154 free( context ); 155 return NULL; 156 } 157 158 return context; 159 } 160 161 /* 162 * Finds the next rule according to a goto action statement, 163 * or null in case of error. 164 * Helper for rewrite_context_apply. 165 */ 166 static struct rewrite_rule * 167 rewrite_action_goto( 168 struct rewrite_action *action, 169 struct rewrite_rule *rule 170 ) 171 { 172 int n; 173 174 assert( action != NULL ); 175 assert( action->la_args != NULL ); 176 assert( rule != NULL ); 177 178 n = ((int *)action->la_args)[ 0 ]; 179 180 if ( n > 0 ) { 181 for ( ; n > 1 && rule != NULL ; n-- ) { 182 rule = rule->lr_next; 183 } 184 } else if ( n <= 0 ) { 185 for ( ; n < 1 && rule != NULL ; n++ ) { 186 rule = rule->lr_prev; 187 } 188 } 189 190 return rule; 191 } 192 193 /* 194 * Rewrites string according to context; may return: 195 * OK: fine; if *result != NULL rule matched and rewrite succeeded. 196 * STOP: fine, rule matched; stop processing following rules 197 * UNWILL: rule matched; force 'unwilling to perform' 198 */ 199 int 200 rewrite_context_apply( 201 struct rewrite_info *info, 202 struct rewrite_op *op, 203 struct rewrite_context *context, 204 const char *string, 205 char **result 206 ) 207 { 208 struct rewrite_rule *rule; 209 char *s, *res = NULL; 210 int return_code = REWRITE_REGEXEC_OK; 211 212 assert( info != NULL ); 213 assert( op != NULL ); 214 assert( context != NULL ); 215 assert( context->lc_rule != NULL ); 216 assert( string != NULL ); 217 assert( result != NULL ); 218 219 op->lo_depth++; 220 assert( op->lo_depth > 0 ); 221 222 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply" 223 " [depth=%d] string='%s'\n", 224 op->lo_depth, string, 0 ); 225 226 s = (char *)string; 227 228 for ( rule = context->lc_rule->lr_next; 229 rule != NULL && op->lo_num_passes < info->li_max_passes; 230 rule = rule->lr_next, op->lo_num_passes++ ) { 231 int rc; 232 233 /* 234 * Apply a single rule 235 */ 236 rc = rewrite_rule_apply( info, op, rule, s, &res ); 237 238 /* 239 * A rule may return: 240 * OK with result != NULL if matched 241 * ERR if anything was wrong 242 * UNWILLING if the server should drop the request 243 * the latter case in honored immediately; 244 * the other two may require some special actions to take 245 * place. 246 */ 247 switch ( rc ) { 248 249 case REWRITE_REGEXEC_ERR: 250 Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply" 251 " error ...\n", 0, 0, 0); 252 253 /* 254 * Checks for special actions to be taken 255 * in case of error ... 256 */ 257 if ( rule->lr_action != NULL ) { 258 struct rewrite_action *action; 259 int do_continue = 0; 260 261 for ( action = rule->lr_action; 262 action != NULL; 263 action = action->la_next ) { 264 switch ( action->la_type ) { 265 266 /* 267 * This action takes precedence 268 * over the others in case of failure 269 */ 270 case REWRITE_ACTION_IGNORE_ERR: 271 Debug( LDAP_DEBUG_ANY, 272 "==> rewrite_context_apply" 273 " ignoring error ...\n", 0, 0, 0 ); 274 do_continue = 1; 275 break; 276 277 /* 278 * Goto is honored only if it comes 279 * after ignore error 280 */ 281 case REWRITE_ACTION_GOTO: 282 if ( do_continue ) { 283 rule = rewrite_action_goto( action, rule ); 284 if ( rule == NULL ) { 285 return_code = REWRITE_REGEXEC_ERR; 286 goto rc_end_of_context; 287 } 288 } 289 break; 290 291 /* 292 * Other actions are ignored 293 */ 294 default: 295 break; 296 } 297 } 298 299 if ( do_continue ) { 300 if ( rule->lr_next == NULL ) { 301 res = s; 302 } 303 goto rc_continue; 304 } 305 } 306 307 /* 308 * Default behavior is to bail out ... 309 */ 310 return_code = REWRITE_REGEXEC_ERR; 311 goto rc_end_of_context; 312 313 /* 314 * OK means there were no errors or special return codes; 315 * if res is defined, it means the rule matched and we 316 * got a sucessful rewriting 317 */ 318 case REWRITE_REGEXEC_OK: 319 320 /* 321 * It matched! Check for actions ... 322 */ 323 if ( res != NULL ) { 324 struct rewrite_action *action; 325 326 if ( s != string && s != res ) { 327 free( s ); 328 } 329 s = res; 330 331 for ( action = rule->lr_action; 332 action != NULL; 333 action = action->la_next ) { 334 335 switch ( action->la_type ) { 336 337 /* 338 * This ends the rewrite context 339 * successfully 340 */ 341 case REWRITE_ACTION_STOP: 342 goto rc_end_of_context; 343 344 /* 345 * This instructs the server to return 346 * an `unwilling to perform' error 347 * message 348 */ 349 case REWRITE_ACTION_UNWILLING: 350 return_code = REWRITE_REGEXEC_UNWILLING; 351 goto rc_end_of_context; 352 353 /* 354 * This causes the processing to 355 * jump n rules back and forth 356 */ 357 case REWRITE_ACTION_GOTO: 358 rule = rewrite_action_goto( action, rule ); 359 if ( rule == NULL ) { 360 return_code = REWRITE_REGEXEC_ERR; 361 goto rc_end_of_context; 362 } 363 break; 364 365 /* 366 * This ends the rewrite context 367 * and returns a user-defined 368 * error code 369 */ 370 case REWRITE_ACTION_USER: 371 return_code = ((int *)action->la_args)[ 0 ]; 372 goto rc_end_of_context; 373 374 default: 375 /* ... */ 376 break; 377 } 378 } 379 380 /* 381 * If result was OK and string didn't match, 382 * in case of last rule we need to set the 383 * result back to the string 384 */ 385 } else if ( rule->lr_next == NULL ) { 386 res = s; 387 } 388 389 break; 390 391 /* 392 * A STOP has propagated ... 393 */ 394 case REWRITE_REGEXEC_STOP: 395 goto rc_end_of_context; 396 397 /* 398 * This will instruct the server to return 399 * an `unwilling to perform' error message 400 */ 401 case REWRITE_REGEXEC_UNWILLING: 402 return_code = REWRITE_REGEXEC_UNWILLING; 403 goto rc_end_of_context; 404 405 /* 406 * A user-defined error code has propagated ... 407 */ 408 default: 409 assert( rc >= REWRITE_REGEXEC_USER ); 410 goto rc_end_of_context; 411 412 } 413 414 rc_continue:; /* sent here by actions that require to continue */ 415 416 } 417 418 rc_end_of_context:; 419 *result = res; 420 421 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply" 422 " [depth=%d] res={%d,'%s'}\n", 423 op->lo_depth, return_code, ( res ? res : "NULL" ) ); 424 425 assert( op->lo_depth > 0 ); 426 op->lo_depth--; 427 428 return return_code; 429 } 430 431 void 432 rewrite_context_free( 433 void *tmp 434 ) 435 { 436 struct rewrite_context *context = (struct rewrite_context *)tmp; 437 438 assert( tmp != NULL ); 439 440 rewrite_context_destroy( &context ); 441 } 442 443 int 444 rewrite_context_destroy( 445 struct rewrite_context **pcontext 446 ) 447 { 448 struct rewrite_context *context; 449 struct rewrite_rule *r; 450 451 assert( pcontext != NULL ); 452 assert( *pcontext != NULL ); 453 454 context = *pcontext; 455 456 assert( context->lc_rule != NULL ); 457 458 for ( r = context->lc_rule->lr_next; r; ) { 459 struct rewrite_rule *cr = r; 460 461 r = r->lr_next; 462 rewrite_rule_destroy( &cr ); 463 } 464 465 free( context->lc_rule ); 466 context->lc_rule = NULL; 467 468 assert( context->lc_name != NULL ); 469 free( context->lc_name ); 470 context->lc_name = NULL; 471 472 free( context ); 473 *pcontext = NULL; 474 475 return 0; 476 } 477