1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/context.c,v 1.15.2.3 2008/02/11 23:26:42 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2000-2008 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",
222 op
->lo_depth
, string
, 0 );
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
;
324 if ( s
!= string
&& s
!= res
) {
329 for ( action
= rule
->lr_action
;
331 action
= action
->la_next
) {
333 switch ( action
->la_type
) {
336 * This ends the rewrite context
339 case REWRITE_ACTION_STOP
:
340 goto rc_end_of_context
;
343 * This instructs the server to return
344 * an `unwilling to perform' error
347 case REWRITE_ACTION_UNWILLING
:
348 return_code
= REWRITE_REGEXEC_UNWILLING
;
349 goto rc_end_of_context
;
352 * This causes the processing to
353 * jump n rules back and forth
355 case REWRITE_ACTION_GOTO
:
356 rule
= rewrite_action_goto( action
, rule
);
357 if ( rule
== NULL
) {
358 return_code
= REWRITE_REGEXEC_ERR
;
359 goto rc_end_of_context
;
364 * This ends the rewrite context
365 * and returns a user-defined
368 case REWRITE_ACTION_USER
:
369 return_code
= ((int *)action
->la_args
)[ 0 ];
370 goto rc_end_of_context
;
379 * If result was OK and string didn't match,
380 * in case of last rule we need to set the
381 * result back to the string
383 } else if ( rule
->lr_next
== NULL
) {
390 * A STOP has propagated ...
392 case REWRITE_REGEXEC_STOP
:
393 goto rc_end_of_context
;
396 * This will instruct the server to return
397 * an `unwilling to perform' error message
399 case REWRITE_REGEXEC_UNWILLING
:
400 return_code
= REWRITE_REGEXEC_UNWILLING
;
401 goto rc_end_of_context
;
404 * A user-defined error code has propagated ...
407 assert( rc
>= REWRITE_REGEXEC_USER
);
408 goto rc_end_of_context
;
412 rc_continue
:; /* sent here by actions that require to continue */
419 Debug( LDAP_DEBUG_TRACE
, "==> rewrite_context_apply"
420 " [depth=%d] res={%d,'%s'}\n",
421 op
->lo_depth
, return_code
, ( res
? res
: "NULL" ) );
423 assert( op
->lo_depth
> 0 );
430 rewrite_context_free(
434 struct rewrite_context
*context
= (struct rewrite_context
*)tmp
;
436 assert( tmp
!= NULL
);
438 rewrite_context_destroy( &context
);
442 rewrite_context_destroy(
443 struct rewrite_context
**pcontext
446 struct rewrite_context
*context
;
447 struct rewrite_rule
*r
;
449 assert( pcontext
!= NULL
);
450 assert( *pcontext
!= NULL
);
454 assert( context
->lc_rule
!= NULL
);
456 for ( r
= context
->lc_rule
->lr_next
; r
; ) {
457 struct rewrite_rule
*cr
= r
;
460 rewrite_rule_destroy( &cr
);
463 free( context
->lc_rule
);
464 context
->lc_rule
= NULL
;
466 assert( context
->lc_name
!= NULL
);
467 free( context
->lc_name
);
468 context
->lc_name
= NULL
;