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 <ac/string.h>
29 #include "rewrite-int.h"
32 * Compares two struct rewrite_context based on the name;
41 struct rewrite_context *lc1, *lc2;
43 lc1 = (struct rewrite_context *)c1;
44 lc2 = (struct rewrite_context *)c2;
48 assert( lc1->lc_name != NULL );
49 assert( lc2->lc_name != NULL );
51 return strcasecmp( lc1->lc_name, lc2->lc_name );
55 * Returns -1 in case a duplicate struct rewrite_context
56 * has been inserted; used by avl stuff
64 struct rewrite_context *lc1, *lc2;
66 lc1 = (struct rewrite_context *)c1;
67 lc2 = (struct rewrite_context *)c2;
71 assert( lc1->lc_name != NULL );
72 assert( lc2->lc_name != NULL );
74 return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 );
78 * Finds the context named rewriteContext in the context tree
80 struct rewrite_context *
82 struct rewrite_info *info,
83 const char *rewriteContext
86 struct rewrite_context *context, c;
88 assert( info != NULL );
89 assert( rewriteContext != NULL );
92 * Fetches the required rewrite context
94 c.lc_name = (char *)rewriteContext;
95 context = (struct rewrite_context *)avl_find( info->li_context,
96 (caddr_t)&c, rewrite_context_cmp );
97 if ( context == NULL ) {
102 * De-aliases the context if required
104 if ( context->lc_alias ) {
105 return context->lc_alias;
112 * Creates a new context called rewriteContext and stores in into the tree
114 struct rewrite_context *
115 rewrite_context_create(
116 struct rewrite_info *info,
117 const char *rewriteContext
120 struct rewrite_context *context;
123 assert( info != NULL );
124 assert( rewriteContext != NULL );
126 context = calloc( sizeof( struct rewrite_context ), 1 );
127 if ( context == NULL ) {
134 context->lc_name = strdup( rewriteContext );
135 if ( context->lc_name == NULL ) {
141 * The first, empty rule
143 context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 );
144 if ( context->lc_rule == NULL ) {
145 free( context->lc_name );
151 * Add context to tree
153 rc = avl_insert( &info->li_context, (caddr_t)context,
154 rewrite_context_cmp, rewrite_context_dup );
156 free( context->lc_rule );
157 free( context->lc_name );
166 * Finds the next rule according to a goto action statement,
167 * or null in case of error.
168 * Helper for rewrite_context_apply.
170 static struct rewrite_rule *
172 struct rewrite_action *action,
173 struct rewrite_rule *rule
178 assert( action != NULL );
179 assert( action->la_args != NULL );
180 assert( rule != NULL );
182 n = ((int *)action->la_args)[ 0 ];
185 for ( ; n > 1 && rule != NULL ; n-- ) {
186 rule = rule->lr_next;
188 } else if ( n <= 0 ) {
189 for ( ; n < 1 && rule != NULL ; n++ ) {
190 rule = rule->lr_prev;
198 * Rewrites string according to context; may return:
199 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
200 * STOP: fine, rule matched; stop processing following rules
201 * UNWILL: rule matched; force 'unwilling to perform'
204 rewrite_context_apply(
205 struct rewrite_info *info,
206 struct rewrite_op *op,
207 struct rewrite_context *context,
212 struct rewrite_rule *rule;
213 char *s, *res = NULL;
214 int return_code = REWRITE_REGEXEC_OK;
216 assert( info != NULL );
217 assert( op != NULL );
218 assert( context != NULL );
219 assert( context->lc_rule != NULL );
220 assert( string != NULL );
221 assert( result != NULL );
224 assert( op->lo_depth > 0 );
226 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
227 " [depth=%d] string='%s'\n%s",
228 op->lo_depth, string, "" );
230 s = strdup( string );
232 for ( rule = context->lc_rule->lr_next;
233 rule != NULL && op->lo_num_passes < info->li_max_passes;
234 rule = rule->lr_next, op->lo_num_passes++ ) {
238 * Apply a single rule
240 rc = rewrite_rule_apply( info, op, rule, s, &res );
244 * OK with result != NULL if matched
245 * ERR if anything was wrong
246 * UNWILLING if the server should drop the request
247 * the latter case in honored immediately;
248 * the other two may require some special actions to take
253 case REWRITE_REGEXEC_ERR:
254 Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply"
255 " error ...\n%s%s%s", "", "", "");
258 * Checks for special actions to be taken
259 * in case of error ...
261 if ( rule->lr_action != NULL ) {
262 struct rewrite_action *action;
265 for ( action = rule->lr_action;
267 action = action->la_next ) {
268 switch ( action->la_type ) {
271 * This action takes precedence
272 * over the others in case of failure
274 case REWRITE_ACTION_IGNORE_ERR:
275 Debug( LDAP_DEBUG_ANY,
276 "==> rewrite_context_apply"
277 " ignoring error ...\n%s%s%s",
283 * Goto is honored only if it comes
286 case REWRITE_ACTION_GOTO:
288 rule = rewrite_action_goto( action, rule );
289 if ( rule == NULL ) {
290 return_code = REWRITE_REGEXEC_ERR;
291 goto rc_end_of_context;
297 * Other actions are ignored
305 if ( rule->lr_next == NULL ) {
313 * Default behavior is to bail out ...
315 return_code = REWRITE_REGEXEC_ERR;
316 goto rc_end_of_context;
319 * OK means there were no errors or special return codes;
320 * if res is defined, it means the rule matched and we
321 * got a sucessful rewriting
323 case REWRITE_REGEXEC_OK:
326 * It matched! Check for actions ...
329 struct rewrite_action *action;
334 for ( action = rule->lr_action;
336 action = action->la_next ) {
338 switch ( action->la_type ) {
341 * This ends the rewrite context
344 case REWRITE_ACTION_STOP:
345 goto rc_end_of_context;
348 * This instructs the server to return
349 * an `unwilling to perform' error
352 case REWRITE_ACTION_UNWILLING:
353 return_code = REWRITE_REGEXEC_UNWILLING;
354 goto rc_end_of_context;
357 * This causes the processing to
358 * jump n rules back and forth
360 case REWRITE_ACTION_GOTO:
361 rule = rewrite_action_goto( action, rule );
362 if ( rule == NULL ) {
363 return_code = REWRITE_REGEXEC_ERR;
364 goto rc_end_of_context;
375 * If result was OK and string didn't match,
376 * in case of last rule we need to set the
377 * result back to the string
379 } else if ( rule->lr_next == NULL ) {
386 * A STOP has propagated ...
388 case REWRITE_REGEXEC_STOP:
389 goto rc_end_of_context;
392 * This will instruct the server to return
393 * an `unwilling to perform' error message
395 case REWRITE_REGEXEC_UNWILLING:
396 return_code = REWRITE_REGEXEC_UNWILLING;
397 goto rc_end_of_context;
401 rc_continue:; /* sent here by actions that require to continue */
408 Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply"
409 " [depth=%d] res={%d,'%s'}\n",
410 op->lo_depth, return_code, ( res ? res : "NULL" ) );
412 assert( op->lo_depth > 0 );