2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2000-2004 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 * This work was initially developed by Pierangelo Masarati for
17 * inclusion in OpenLDAP Software.
22 #include "rewrite-int.h"
25 * Compares two struct rewrite_context based on the name;
34 const struct rewrite_context *lc1, *lc2;
36 lc1 = (const struct rewrite_context *)c1;
37 lc2 = (const struct rewrite_context *)c2;
41 assert( lc1->lc_name != NULL );
42 assert( lc2->lc_name != NULL );
44 return strcasecmp( lc1->lc_name, lc2->lc_name );
48 * Returns -1 in case a duplicate struct rewrite_context
49 * has been inserted; used by avl stuff
57 struct rewrite_context *lc1, *lc2;
59 lc1 = (struct rewrite_context *)c1;
60 lc2 = (struct rewrite_context *)c2;
64 assert( lc1->lc_name != NULL );
65 assert( lc2->lc_name != NULL );
67 return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
71 * Finds the context named rewriteContext in the context tree
73 struct rewrite_context *
75 struct rewrite_info *info,
76 const char *rewriteContext
79 struct rewrite_context *context, c;
81 assert( info != NULL );
82 assert( rewriteContext != NULL );
85 * Fetches the required rewrite context
87 c.lc_name = (char *)rewriteContext;
88 context = (struct rewrite_context *)avl_find( info->li_context,
89 (caddr_t)&c, rewrite_context_cmp );
90 if ( context == NULL ) {
95 * De-aliases the context if required
97 if ( context->lc_alias ) {
98 return context->lc_alias;
105 * Creates a new context called rewriteContext and stores in into the tree
107 struct rewrite_context *
108 rewrite_context_create(
109 struct rewrite_info *info,
110 const char *rewriteContext
113 struct rewrite_context *context;
116 assert( info != NULL );
117 assert( rewriteContext != NULL );
119 context = calloc( sizeof( struct rewrite_context ), 1 );
120 if ( context == NULL ) {
127 context->lc_name = strdup( rewriteContext );
128 if ( context->lc_name == NULL ) {
134 * The first, empty rule
136 context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
137 if ( context->lc_rule == NULL ) {
138 free( context->lc_name );
142 memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) );
145 * Add context to tree
147 rc = avl_insert( &info->li_context, (caddr_t)context,
148 rewrite_context_cmp, rewrite_context_dup );
150 free( context->lc_rule );
151 free( context->lc_name );
160 * Finds the next rule according to a goto action statement,
161 * or null in case of error.
162 * Helper for rewrite_context_apply.
164 static struct rewrite_rule *
166 struct rewrite_action *action,
167 struct rewrite_rule *rule
172 assert( action != NULL );
173 assert( action->la_args != NULL );
174 assert( rule != NULL );
176 n = ((int *)action->la_args)[ 0 ];
179 for ( ; n > 1 && rule != NULL ; n-- ) {
180 rule = rule->lr_next;
182 } else if ( n <= 0 ) {
183 for ( ; n < 1 && rule != NULL ; n++ ) {
184 rule = rule->lr_prev;
192 * Rewrites string according to context; may return:
193 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
194 * STOP: fine, rule matched; stop processing following rules
195 * UNWILL: rule matched; force 'unwilling to perform'
198 rewrite_context_apply(
199 struct rewrite_info *info,
200 struct rewrite_op *op,
201 struct rewrite_context *context,
206 struct rewrite_rule *rule;
207 char *s, *res = NULL;
208 int return_code = REWRITE_REGEXEC_OK;
210 assert( info != NULL );
211 assert( op != NULL );
212 assert( context != NULL );
213 assert( context->lc_rule != NULL );
214 assert( string != NULL );
215 assert( result != NULL );
218 assert( op->lo_depth > 0 );
220 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
221 " [depth=%d] string='%s'\n%s",
222 op->lo_depth, string, "" );
224 s = strdup( string );
226 for ( rule = context->lc_rule->lr_next;
227 rule != NULL && op->lo_num_passes < info->li_max_passes;
228 rule = rule->lr_next, op->lo_num_passes++ ) {
232 * Apply a single rule
234 rc = rewrite_rule_apply( info, op, rule, s, &res );
238 * OK with result != NULL if matched
239 * ERR if anything was wrong
240 * UNWILLING if the server should drop the request
241 * the latter case in honored immediately;
242 * the other two may require some special actions to take
247 case REWRITE_REGEXEC_ERR:
248 Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
249 " error ...\n", 0, 0, 0);
252 * Checks for special actions to be taken
253 * in case of error ...
255 if ( rule->lr_action != NULL ) {
256 struct rewrite_action *action;
259 for ( action = rule->lr_action;
261 action = action->la_next ) {
262 switch ( action->la_type ) {
265 * This action takes precedence
266 * over the others in case of failure
268 case REWRITE_ACTION_IGNORE_ERR:
269 Debug( LDAP_DEBUG_ANY,
270 "==> rewrite_context_apply"
271 " ignoring error ...\n", 0, 0, 0 );
276 * Goto is honored only if it comes
279 case REWRITE_ACTION_GOTO:
281 rule = rewrite_action_goto( action, rule );
282 if ( rule == NULL ) {
283 return_code = REWRITE_REGEXEC_ERR;
284 goto rc_end_of_context;
290 * Other actions are ignored
298 if ( rule->lr_next == NULL ) {
306 * Default behavior is to bail out ...
308 return_code = REWRITE_REGEXEC_ERR;
309 goto rc_end_of_context;
312 * OK means there were no errors or special return codes;
313 * if res is defined, it means the rule matched and we
314 * got a sucessful rewriting
316 case REWRITE_REGEXEC_OK:
319 * It matched! Check for actions ...
322 struct rewrite_action *action;
327 for ( action = rule->lr_action;
329 action = action->la_next ) {
331 switch ( action->la_type ) {
334 * This ends the rewrite context
337 case REWRITE_ACTION_STOP:
338 goto rc_end_of_context;
341 * This instructs the server to return
342 * an `unwilling to perform' error
345 case REWRITE_ACTION_UNWILLING:
346 return_code = REWRITE_REGEXEC_UNWILLING;
347 goto rc_end_of_context;
350 * This causes the processing to
351 * jump n rules back and forth
353 case REWRITE_ACTION_GOTO:
354 rule = rewrite_action_goto( action, rule );
355 if ( rule == NULL ) {
356 return_code = REWRITE_REGEXEC_ERR;
357 goto rc_end_of_context;
362 * This ends the rewrite context
363 * and returns a user-defined
366 case REWRITE_ACTION_USER:
367 return_code = ((int *)action->la_args)[ 0 ];
368 goto rc_end_of_context;
377 * If result was OK and string didn't match,
378 * in case of last rule we need to set the
379 * result back to the string
381 } else if ( rule->lr_next == NULL ) {
388 * A STOP has propagated ...
390 case REWRITE_REGEXEC_STOP:
391 goto rc_end_of_context;
394 * This will instruct the server to return
395 * an `unwilling to perform' error message
397 case REWRITE_REGEXEC_UNWILLING:
398 return_code = REWRITE_REGEXEC_UNWILLING;
399 goto rc_end_of_context;
402 * A user-defined error code has propagated ...
405 assert( rc >= REWRITE_REGEXEC_USER );
406 goto rc_end_of_context;
410 rc_continue:; /* sent here by actions that require to continue */
417 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
418 " [depth=%d] res={%d,'%s'}\n",
419 op->lo_depth, return_code, ( res ? res : "NULL" ) );
421 assert( op->lo_depth > 0 );
428 rewrite_context_free(
432 struct rewrite_context *context = (struct rewrite_context *)tmp;
436 rewrite_context_destroy( &context );
440 rewrite_context_destroy(
441 struct rewrite_context **pcontext
444 struct rewrite_context *context;
445 struct rewrite_rule *r;
452 assert( context->lc_rule );
454 for ( r = context->lc_rule->lr_next; r; ) {
455 struct rewrite_rule *cr = r;
458 rewrite_rule_destroy( &cr );
461 free( context->lc_rule );
462 context->lc_rule = NULL;
464 assert( context->lc_name );
465 free( context->lc_name );
466 context->lc_name = NULL;