2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2000-2004 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 * Appends a rule to the double linked list of rules
26 * Helper for rewrite_rule_compile
30 struct rewrite_context *context,
31 struct rewrite_rule *rule
34 struct rewrite_rule *r;
36 assert( context != NULL );
37 assert( context->lc_rule != NULL );
38 assert( rule != NULL );
40 for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next );
44 return REWRITE_SUCCESS;
48 * Appends an action to the linked list of actions
49 * Helper for rewrite_rule_compile
53 struct rewrite_action **pbase,
54 struct rewrite_action *action
57 struct rewrite_action **pa;
59 assert( pbase != NULL );
60 assert( action != NULL );
62 for ( pa = pbase; *pa != NULL; pa = &(*pa)->la_next );
65 return REWRITE_SUCCESS;
70 struct rewrite_action **paction
73 struct rewrite_action *action;
81 switch ( action->la_type ) {
82 case REWRITE_FLAG_GOTO:
83 case REWRITE_FLAG_USER: {
84 int *pi = (int *)action->la_args;
103 * In case of error it returns NULL and does not free all the memory
104 * it allocated; as this is a once only phase, and an error at this stage
105 * would require the server to stop, there is no need to be paranoid
106 * about memory allocation
109 rewrite_rule_compile(
110 struct rewrite_info *info,
111 struct rewrite_context *context,
114 const char *flagstring
117 int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
118 int mode = REWRITE_RECURSE;
119 int max_passes = info->li_max_passes_per_rule;
121 struct rewrite_rule *rule = NULL;
122 struct rewrite_subst *subst = NULL;
123 struct rewrite_action *action = NULL, *first_action = NULL;
127 assert( info != NULL );
128 assert( context != NULL );
129 assert( pattern != NULL );
130 assert( result != NULL );
133 * A null flagstring should be allowed
137 * Take care of substitution string
139 subst = rewrite_subst_compile( info, result );
140 if ( subst == NULL ) {
147 for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
153 case REWRITE_FLAG_HONORCASE: /* 'C' */
155 * Honor case (default is case insensitive)
157 flags &= ~REWRITE_REGEX_ICASE;
160 case REWRITE_FLAG_BASICREGEX: /* 'R' */
162 * Use POSIX Basic Regular Expression syntax
163 * instead of POSIX Extended Regular Expression
166 flags &= ~REWRITE_REGEX_EXTENDED;
170 * Execution mode flags
172 case REWRITE_FLAG_EXECONCE: /* ':' */
174 * Apply rule once only
176 mode &= ~REWRITE_RECURSE;
177 mode |= REWRITE_EXEC_ONCE;
181 * Special action flags
183 case REWRITE_FLAG_STOP: /* '@' */
185 * Bail out after applying rule
187 action = calloc( sizeof( struct rewrite_action ), 1 );
188 if ( action == NULL ) {
193 //mode &= ~REWRITE_RECURSE;
194 //mode |= REWRITE_EXEC_ONCE;
195 action->la_type = REWRITE_ACTION_STOP;
198 case REWRITE_FLAG_UNWILLING: /* '#' */
200 * Matching objs will be marked as gone!
202 action = calloc( sizeof( struct rewrite_action ), 1 );
203 if ( action == NULL ) {
208 mode &= ~REWRITE_RECURSE;
209 mode |= REWRITE_EXEC_ONCE;
210 action->la_type = REWRITE_ACTION_UNWILLING;
213 case REWRITE_FLAG_GOTO: /* 'G' */
215 * After applying rule, jump N rules
218 case REWRITE_FLAG_USER: { /* 'U' */
220 * After applying rule, return user-defined
226 if ( p[ 1 ] != '{' ) {
227 /* XXX Need to free stuff */
231 d = malloc( sizeof( int ) );
233 /* XXX Need to free stuff */
237 d[ 0 ] = strtol( &p[ 2 ], &next, 0 );
238 if ( next == NULL || next == &p[ 2 ] || next[0] != '}' ) {
239 /* XXX Need to free stuff */
243 action = calloc( sizeof( struct rewrite_action ), 1 );
244 if ( action == NULL ) {
249 case REWRITE_FLAG_GOTO:
250 action->la_type = REWRITE_ACTION_GOTO;
253 case REWRITE_FLAG_USER:
254 action->la_type = REWRITE_ACTION_USER;
261 action->la_args = (void *)d;
263 p = next; /* p is incremented by the for ... */
268 case REWRITE_FLAG_MAX_PASSES: { /* 'U' */
270 * Set the number of max passes per rule
274 if ( p[ 1 ] != '{' ) {
275 /* XXX Need to free stuff */
279 max_passes = strtol( &p[ 2 ], &next, 0 );
280 if ( next == NULL || next == &p[ 2 ] || next[0] != '}' ) {
281 /* XXX Need to free stuff */
285 if ( max_passes < 1 ) {
286 /* FIXME: nonsense ... */
290 p = next; /* p is incremented by the for ... */
295 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
299 action = calloc( sizeof( struct rewrite_action ), 1 );
300 if ( action == NULL ) {
305 action->la_type = REWRITE_ACTION_IGNORE_ERR;
313 * Unimplemented feature (complain only)
319 * Stupid way to append to a list ...
321 if ( action != NULL ) {
322 append_action( &first_action, action );
328 * Finally, rule allocation
330 rule = calloc( sizeof( struct rewrite_rule ), 1 );
331 if ( rule == NULL ) {
332 /* charray_free( res ); */
334 * XXX need to free the value subst stuff!
340 * REGEX compilation (luckily I don't need to take care of this ...)
342 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
343 /* charray_free( res ); */
345 *XXX need to free the value subst stuff!
352 * Just to remember them ...
354 rule->lr_pattern = strdup( pattern );
355 rule->lr_subststring = strdup( result );
356 rule->lr_flagstring = strdup( flagstring );
359 * Load compiled data into rule
361 rule->lr_subst = subst;
364 * Set various parameters
366 rule->lr_flags = flags; /* don't really need any longer ... */
367 rule->lr_mode = mode;
368 rule->lr_max_passes = max_passes;
369 rule->lr_action = first_action;
372 * Append rule at the end of the rewrite context
374 append_rule( context, rule );
376 return REWRITE_SUCCESS;
380 * Rewrites string according to rule; may return:
381 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
382 * STOP: fine, rule matched; stop processing following rules
383 * UNWILL: rule matched; force 'unwilling to perform'
387 struct rewrite_info *info,
388 struct rewrite_op *op,
389 struct rewrite_rule *rule,
394 size_t nmatch = REWRITE_MAX_MATCH;
395 regmatch_t match[ REWRITE_MAX_MATCH ];
397 int rc = REWRITE_SUCCESS;
401 struct berval val = { 0, NULL };
403 assert( info != NULL );
404 assert( op != NULL );
405 assert( rule != NULL );
406 assert( arg != NULL );
407 assert( result != NULL );
411 string = (char *)arg;
414 * In case recursive match is required (default)
418 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
419 " rule='%s' string='%s' [%s pass(es)]\n",
420 rule->lr_pattern, string, strcnt + 1 );
423 if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
424 if ( *result == NULL && strcnt > 0 ) {
430 * No match is OK; *result = NULL means no match
432 return REWRITE_REGEXEC_OK;
435 rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
438 *result = val.bv_val;
445 if ( rc != REWRITE_REGEXEC_OK ) {
449 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
450 && op->lo_num_passes < info->li_max_passes
451 && ++strcnt < rule->lr_max_passes ) {
457 return REWRITE_REGEXEC_OK;
461 rewrite_rule_destroy(
462 struct rewrite_rule **prule
465 struct rewrite_rule *rule;
466 struct rewrite_action *action;
473 if ( rule->lr_pattern ) {
474 free( rule->lr_pattern );
475 rule->lr_pattern = NULL;
478 if ( rule->lr_subststring ) {
479 free( rule->lr_subststring );
480 rule->lr_subststring = NULL;
483 if ( rule->lr_flagstring ) {
484 free( rule->lr_flagstring );
485 rule->lr_flagstring = NULL;
488 if ( rule->lr_subst ) {
489 rewrite_subst_destroy( &rule->lr_subst );
492 regfree( &rule->lr_regex );
494 for ( action = rule->lr_action; action; ) {
495 struct rewrite_action *curraction = action;
497 action = action->la_next;
498 destroy_action( &curraction );