1 /******************************************************************************
3 * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
6 * Permission is granted to anyone to use this software for any purpose
7 * on any computer system, and to alter it and redistribute it, subject
8 * to the following restrictions:
10 * 1. The author is not responsible for the consequences of use of this
11 * software, no matter how awful, even if they arise from flaws in it.
13 * 2. The origin of this software must not be misrepresented, either by
14 * explicit claim or by omission. Since few users ever read sources,
15 * credits should appear in the documentation.
17 * 3. Altered versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software. Since few users
19 * ever read sources, credits should appear in the documentation.
21 * 4. This notice may not be removed or altered.
23 ******************************************************************************/
27 #include "rewrite-int.h"
30 * Compares two struct rewrite_context based on the name;
39 const struct rewrite_context *lc1, *lc2;
41 lc1 = (const struct rewrite_context *)c1;
42 lc2 = (const struct rewrite_context *)c2;
46 assert( lc1->lc_name != NULL );
47 assert( lc2->lc_name != NULL );
49 return strcasecmp( lc1->lc_name, lc2->lc_name );
53 * Returns -1 in case a duplicate struct rewrite_context
54 * has been inserted; used by avl stuff
62 struct rewrite_context *lc1, *lc2;
64 lc1 = (struct rewrite_context *)c1;
65 lc2 = (struct rewrite_context *)c2;
69 assert( lc1->lc_name != NULL );
70 assert( lc2->lc_name != NULL );
72 return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
76 * Finds the context named rewriteContext in the context tree
78 struct rewrite_context *
80 struct rewrite_info *info,
81 const char *rewriteContext
84 struct rewrite_context *context, c;
86 assert( info != NULL );
87 assert( rewriteContext != NULL );
90 * Fetches the required rewrite context
92 c.lc_name = (char *)rewriteContext;
93 context = (struct rewrite_context *)avl_find( info->li_context,
94 (caddr_t)&c, rewrite_context_cmp );
95 if ( context == NULL ) {
100 * De-aliases the context if required
102 if ( context->lc_alias ) {
103 return context->lc_alias;
110 * Creates a new context called rewriteContext and stores in into the tree
112 struct rewrite_context *
113 rewrite_context_create(
114 struct rewrite_info *info,
115 const char *rewriteContext
118 struct rewrite_context *context;
121 assert( info != NULL );
122 assert( rewriteContext != NULL );
124 context = calloc( sizeof( struct rewrite_context ), 1 );
125 if ( context == NULL ) {
132 context->lc_name = strdup( rewriteContext );
133 if ( context->lc_name == NULL ) {
139 * The first, empty rule
141 context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
142 if ( context->lc_rule == NULL ) {
143 free( context->lc_name );
147 memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) );
150 * Add context to tree
152 rc = avl_insert( &info->li_context, (caddr_t)context,
153 rewrite_context_cmp, rewrite_context_dup );
155 free( context->lc_rule );
156 free( context->lc_name );
165 * Finds the next rule according to a goto action statement,
166 * or null in case of error.
167 * Helper for rewrite_context_apply.
169 static struct rewrite_rule *
171 struct rewrite_action *action,
172 struct rewrite_rule *rule
177 assert( action != NULL );
178 assert( action->la_args != NULL );
179 assert( rule != NULL );
181 n = ((int *)action->la_args)[ 0 ];
184 for ( ; n > 1 && rule != NULL ; n-- ) {
185 rule = rule->lr_next;
187 } else if ( n <= 0 ) {
188 for ( ; n < 1 && rule != NULL ; n++ ) {
189 rule = rule->lr_prev;
197 * Rewrites string according to context; may return:
198 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
199 * STOP: fine, rule matched; stop processing following rules
200 * UNWILL: rule matched; force 'unwilling to perform'
203 rewrite_context_apply(
204 struct rewrite_info *info,
205 struct rewrite_op *op,
206 struct rewrite_context *context,
211 struct rewrite_rule *rule;
212 char *s, *res = NULL;
213 int return_code = REWRITE_REGEXEC_OK;
215 assert( info != NULL );
216 assert( op != NULL );
217 assert( context != NULL );
218 assert( context->lc_rule != NULL );
219 assert( string != NULL );
220 assert( result != NULL );
223 assert( op->lo_depth > 0 );
225 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
226 " [depth=%d] string='%s'\n%s",
227 op->lo_depth, string, "" );
229 s = strdup( string );
231 for ( rule = context->lc_rule->lr_next;
232 rule != NULL && op->lo_num_passes < info->li_max_passes;
233 rule = rule->lr_next, op->lo_num_passes++ ) {
237 * Apply a single rule
239 rc = rewrite_rule_apply( info, op, rule, s, &res );
243 * OK with result != NULL if matched
244 * ERR if anything was wrong
245 * UNWILLING if the server should drop the request
246 * the latter case in honored immediately;
247 * the other two may require some special actions to take
252 case REWRITE_REGEXEC_ERR:
253 Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
254 " error ...\n", 0, 0, 0);
257 * Checks for special actions to be taken
258 * in case of error ...
260 if ( rule->lr_action != NULL ) {
261 struct rewrite_action *action;
264 for ( action = rule->lr_action;
266 action = action->la_next ) {
267 switch ( action->la_type ) {
270 * This action takes precedence
271 * over the others in case of failure
273 case REWRITE_ACTION_IGNORE_ERR:
274 Debug( LDAP_DEBUG_ANY,
275 "==> rewrite_context_apply"
276 " ignoring error ...\n", 0, 0, 0 );
281 * Goto is honored only if it comes
284 case REWRITE_ACTION_GOTO:
286 rule = rewrite_action_goto( action, rule );
287 if ( rule == NULL ) {
288 return_code = REWRITE_REGEXEC_ERR;
289 goto rc_end_of_context;
295 * Other actions are ignored
303 if ( rule->lr_next == NULL ) {
311 * Default behavior is to bail out ...
313 return_code = REWRITE_REGEXEC_ERR;
314 goto rc_end_of_context;
317 * OK means there were no errors or special return codes;
318 * if res is defined, it means the rule matched and we
319 * got a sucessful rewriting
321 case REWRITE_REGEXEC_OK:
324 * It matched! Check for actions ...
327 struct rewrite_action *action;
332 for ( action = rule->lr_action;
334 action = action->la_next ) {
336 switch ( action->la_type ) {
339 * This ends the rewrite context
342 case REWRITE_ACTION_STOP:
343 goto rc_end_of_context;
346 * This instructs the server to return
347 * an `unwilling to perform' error
350 case REWRITE_ACTION_UNWILLING:
351 return_code = REWRITE_REGEXEC_UNWILLING;
352 goto rc_end_of_context;
355 * This causes the processing to
356 * jump n rules back and forth
358 case REWRITE_ACTION_GOTO:
359 rule = rewrite_action_goto( action, rule );
360 if ( rule == NULL ) {
361 return_code = REWRITE_REGEXEC_ERR;
362 goto rc_end_of_context;
373 * If result was OK and string didn't match,
374 * in case of last rule we need to set the
375 * result back to the string
377 } else if ( rule->lr_next == NULL ) {
384 * A STOP has propagated ...
386 case REWRITE_REGEXEC_STOP:
387 goto rc_end_of_context;
390 * This will instruct the server to return
391 * an `unwilling to perform' error message
393 case REWRITE_REGEXEC_UNWILLING:
394 return_code = REWRITE_REGEXEC_UNWILLING;
395 goto rc_end_of_context;
399 rc_continue:; /* sent here by actions that require to continue */
406 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
407 " [depth=%d] res={%d,'%s'}\n",
408 op->lo_depth, return_code, ( res ? res : "NULL" ) );
410 assert( op->lo_depth > 0 );
417 rewrite_context_free(
421 struct rewrite_context *context = (struct rewrite_context *)tmp;
425 rewrite_context_destroy( &context );
429 rewrite_context_destroy(
430 struct rewrite_context **pcontext
433 struct rewrite_context *context;
434 struct rewrite_rule *r;
441 assert( context->lc_rule );
443 for ( r = context->lc_rule->lr_next; r; ) {
444 struct rewrite_rule *cr = r;
447 rewrite_rule_destroy( &cr );
450 free( context->lc_rule );
451 context->lc_rule = NULL;
453 assert( context->lc_name );
454 free( context->lc_name );
455 context->lc_name = NULL;