2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2000-2005 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;
75 assert( paction != NULL );
76 assert( *paction != NULL );
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 action->la_type = REWRITE_ACTION_STOP;
196 case REWRITE_FLAG_UNWILLING: /* '#' */
198 * Matching objs will be marked as gone!
200 action = calloc( sizeof( struct rewrite_action ), 1 );
201 if ( action == NULL ) {
206 mode &= ~REWRITE_RECURSE;
207 mode |= REWRITE_EXEC_ONCE;
208 action->la_type = REWRITE_ACTION_UNWILLING;
211 case REWRITE_FLAG_GOTO: /* 'G' */
213 * After applying rule, jump N rules
216 case REWRITE_FLAG_USER: { /* 'U' */
218 * After applying rule, return user-defined
224 if ( p[ 1 ] != '{' ) {
225 /* XXX Need to free stuff */
229 d = malloc( sizeof( int ) );
231 /* XXX Need to free stuff */
235 d[ 0 ] = strtol( &p[ 2 ], &next, 0 );
236 if ( next == NULL || next == &p[ 2 ] || next[0] != '}' ) {
237 /* XXX Need to free stuff */
241 action = calloc( sizeof( struct rewrite_action ), 1 );
242 if ( action == NULL ) {
247 case REWRITE_FLAG_GOTO:
248 action->la_type = REWRITE_ACTION_GOTO;
251 case REWRITE_FLAG_USER:
252 action->la_type = REWRITE_ACTION_USER;
259 action->la_args = (void *)d;
261 p = next; /* p is incremented by the for ... */
266 case REWRITE_FLAG_MAX_PASSES: { /* 'U' */
268 * Set the number of max passes per rule
272 if ( p[ 1 ] != '{' ) {
273 /* XXX Need to free stuff */
277 max_passes = strtol( &p[ 2 ], &next, 0 );
278 if ( next == NULL || next == &p[ 2 ] || next[0] != '}' ) {
279 /* XXX Need to free stuff */
283 if ( max_passes < 1 ) {
284 /* FIXME: nonsense ... */
288 p = next; /* p is incremented by the for ... */
293 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
297 action = calloc( sizeof( struct rewrite_action ), 1 );
298 if ( action == NULL ) {
303 action->la_type = REWRITE_ACTION_IGNORE_ERR;
311 * Unimplemented feature (complain only)
317 * Stupid way to append to a list ...
319 if ( action != NULL ) {
320 append_action( &first_action, action );
326 * Finally, rule allocation
328 rule = calloc( sizeof( struct rewrite_rule ), 1 );
329 if ( rule == NULL ) {
330 /* charray_free( res ); */
332 * XXX need to free the value subst stuff!
338 * REGEX compilation (luckily I don't need to take care of this ...)
340 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
341 /* charray_free( res ); */
343 *XXX need to free the value subst stuff!
350 * Just to remember them ...
352 rule->lr_pattern = strdup( pattern );
353 rule->lr_subststring = strdup( result );
354 rule->lr_flagstring = strdup( flagstring );
357 * Load compiled data into rule
359 rule->lr_subst = subst;
362 * Set various parameters
364 rule->lr_flags = flags; /* don't really need any longer ... */
365 rule->lr_mode = mode;
366 rule->lr_max_passes = max_passes;
367 rule->lr_action = first_action;
370 * Append rule at the end of the rewrite context
372 append_rule( context, rule );
374 return REWRITE_SUCCESS;
378 * Rewrites string according to rule; may return:
379 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
380 * STOP: fine, rule matched; stop processing following rules
381 * UNWILL: rule matched; force 'unwilling to perform'
385 struct rewrite_info *info,
386 struct rewrite_op *op,
387 struct rewrite_rule *rule,
392 size_t nmatch = REWRITE_MAX_MATCH;
393 regmatch_t match[ REWRITE_MAX_MATCH ];
395 int rc = REWRITE_SUCCESS;
399 struct berval val = { 0, NULL };
401 assert( info != NULL );
402 assert( op != NULL );
403 assert( rule != NULL );
404 assert( arg != NULL );
405 assert( result != NULL );
409 string = (char *)arg;
412 * In case recursive match is required (default)
416 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
417 " rule='%s' string='%s' [%d pass(es)]\n",
418 rule->lr_pattern, string, strcnt + 1 );
422 rc = regexec( &rule->lr_regex, string, nmatch, match, 0 );
424 if ( *result == NULL && string != arg ) {
429 * No match is OK; *result = NULL means no match
431 return REWRITE_REGEXEC_OK;
434 rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
437 *result = val.bv_val;
439 if ( string != arg ) {
444 if ( rc != REWRITE_REGEXEC_OK ) {
448 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
449 && op->lo_num_passes < info->li_max_passes
450 && ++strcnt < rule->lr_max_passes ) {
456 return REWRITE_REGEXEC_OK;
460 rewrite_rule_destroy(
461 struct rewrite_rule **prule
464 struct rewrite_rule *rule;
465 struct rewrite_action *action;
467 assert( prule != NULL );
468 assert( *prule != NULL );
472 if ( rule->lr_pattern ) {
473 free( rule->lr_pattern );
474 rule->lr_pattern = NULL;
477 if ( rule->lr_subststring ) {
478 free( rule->lr_subststring );
479 rule->lr_subststring = NULL;
482 if ( rule->lr_flagstring ) {
483 free( rule->lr_flagstring );
484 rule->lr_flagstring = NULL;
487 if ( rule->lr_subst ) {
488 rewrite_subst_destroy( &rule->lr_subst );
491 regfree( &rule->lr_regex );
493 for ( action = rule->lr_action; action; ) {
494 struct rewrite_action *curraction = action;
496 action = action->la_next;
497 destroy_action( &curraction );