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 struct rewrite_context *lc1, *lc2;
41 lc1 = (struct rewrite_context *)c1;
42 lc2 = (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 );
149 * Add context to tree
151 rc = avl_insert( &info->li_context, (caddr_t)context,
152 rewrite_context_cmp, rewrite_context_dup );
154 free( context->lc_rule );
155 free( context->lc_name );
164 * Finds the next rule according to a goto action statement,
165 * or null in case of error.
166 * Helper for rewrite_context_apply.
168 static struct rewrite_rule *
170 struct rewrite_action *action,
171 struct rewrite_rule *rule
176 assert( action != NULL );
177 assert( action->la_args != NULL );
178 assert( rule != NULL );
180 n = ((int *)action->la_args)[ 0 ];
183 for ( ; n > 1 && rule != NULL ; n-- ) {
184 rule = rule->lr_next;
186 } else if ( n <= 0 ) {
187 for ( ; n < 1 && rule != NULL ; n++ ) {
188 rule = rule->lr_prev;
196 * Rewrites string according to context; may return:
197 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
198 * STOP: fine, rule matched; stop processing following rules
199 * UNWILL: rule matched; force 'unwilling to perform'
202 rewrite_context_apply(
203 struct rewrite_info *info,
204 struct rewrite_op *op,
205 struct rewrite_context *context,
210 struct rewrite_rule *rule;
211 char *s, *res = NULL;
212 int return_code = REWRITE_REGEXEC_OK;
214 assert( info != NULL );
215 assert( op != NULL );
216 assert( context != NULL );
217 assert( context->lc_rule != NULL );
218 assert( string != NULL );
219 assert( result != NULL );
222 assert( op->lo_depth > 0 );
224 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
225 " [depth=%d] string='%s'\n%s",
226 op->lo_depth, string, "" );
228 s = strdup( string );
230 for ( rule = context->lc_rule->lr_next;
231 rule != NULL && op->lo_num_passes < info->li_max_passes;
232 rule = rule->lr_next, op->lo_num_passes++ ) {
236 * Apply a single rule
238 rc = rewrite_rule_apply( info, op, rule, s, &res );
242 * OK with result != NULL if matched
243 * ERR if anything was wrong
244 * UNWILLING if the server should drop the request
245 * the latter case in honored immediately;
246 * the other two may require some special actions to take
251 case REWRITE_REGEXEC_ERR:
252 Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
253 " error ...\n%s%s%s", "", "", "");
256 * Checks for special actions to be taken
257 * in case of error ...
259 if ( rule->lr_action != NULL ) {
260 struct rewrite_action *action;
263 for ( action = rule->lr_action;
265 action = action->la_next ) {
266 switch ( action->la_type ) {
269 * This action takes precedence
270 * over the others in case of failure
272 case REWRITE_ACTION_IGNORE_ERR:
273 Debug( LDAP_DEBUG_ANY,
274 "==> rewrite_context_apply"
275 " ignoring error ...\n%s%s%s",
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 );