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%s%s%s", "", "", "");
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%s%s%s",
282 * Goto is honored only if it comes
285 case REWRITE_ACTION_GOTO:
287 rule = rewrite_action_goto( action, rule );
288 if ( rule == NULL ) {
289 return_code = REWRITE_REGEXEC_ERR;
290 goto rc_end_of_context;
296 * Other actions are ignored
304 if ( rule->lr_next == NULL ) {
312 * Default behavior is to bail out ...
314 return_code = REWRITE_REGEXEC_ERR;
315 goto rc_end_of_context;
318 * OK means there were no errors or special return codes;
319 * if res is defined, it means the rule matched and we
320 * got a sucessful rewriting
322 case REWRITE_REGEXEC_OK:
325 * It matched! Check for actions ...
328 struct rewrite_action *action;
333 for ( action = rule->lr_action;
335 action = action->la_next ) {
337 switch ( action->la_type ) {
340 * This ends the rewrite context
343 case REWRITE_ACTION_STOP:
344 goto rc_end_of_context;
347 * This instructs the server to return
348 * an `unwilling to perform' error
351 case REWRITE_ACTION_UNWILLING:
352 return_code = REWRITE_REGEXEC_UNWILLING;
353 goto rc_end_of_context;
356 * This causes the processing to
357 * jump n rules back and forth
359 case REWRITE_ACTION_GOTO:
360 rule = rewrite_action_goto( action, rule );
361 if ( rule == NULL ) {
362 return_code = REWRITE_REGEXEC_ERR;
363 goto rc_end_of_context;
374 * If result was OK and string didn't match,
375 * in case of last rule we need to set the
376 * result back to the string
378 } else if ( rule->lr_next == NULL ) {
385 * A STOP has propagated ...
387 case REWRITE_REGEXEC_STOP:
388 goto rc_end_of_context;
391 * This will instruct the server to return
392 * an `unwilling to perform' error message
394 case REWRITE_REGEXEC_UNWILLING:
395 return_code = REWRITE_REGEXEC_UNWILLING;
396 goto rc_end_of_context;
400 rc_continue:; /* sent here by actions that require to continue */
407 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
408 " [depth=%d] res={%d,'%s'}\n",
409 op->lo_depth, return_code, ( res ? res : "NULL" ) );
411 assert( op->lo_depth > 0 );
418 rewrite_context_free(
422 struct rewrite_context *context = (struct rewrite_context *)tmp;
426 rewrite_context_destroy( &context );
430 rewrite_context_destroy(
431 struct rewrite_context **pcontext
434 struct rewrite_context *context;
435 struct rewrite_rule *r;
442 assert( context->lc_rule );
444 for ( r = context->lc_rule->lr_next; r; ) {
445 struct rewrite_rule *cr = r;
448 rewrite_rule_destroy( &cr );
451 free( context->lc_rule );
452 context->lc_rule = NULL;
454 assert( context->lc_name );
455 free( context->lc_name );
456 context->lc_name = NULL;