2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2000-2003 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 *base,
54 struct rewrite_action *action
57 struct rewrite_action *a;
59 assert( base != NULL );
60 assert( action != NULL );
62 for ( a = base; a->la_next != NULL; a = a->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 int *pi = (int *)action->la_args;
102 * In case of error it returns NULL and does not free all the memory
103 * it allocated; as this is a once only phase, and an error at this stage
104 * would require the server to stop, there is no need to be paranoid
105 * about memory allocation
108 rewrite_rule_compile(
109 struct rewrite_info *info,
110 struct rewrite_context *context,
113 const char *flagstring
116 int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
117 int mode = REWRITE_RECURSE;
119 struct rewrite_rule *rule = NULL;
120 struct rewrite_subst *subst = NULL;
121 struct rewrite_action *action = NULL, *first_action = NULL;
125 assert( info != NULL );
126 assert( context != NULL );
127 assert( pattern != NULL );
128 assert( result != NULL );
131 * A null flagstring should be allowed
135 * Take care of substitution string
137 subst = rewrite_subst_compile( info, result );
138 if ( subst == NULL ) {
145 for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
151 case REWRITE_FLAG_HONORCASE: /* 'C' */
153 * Honor case (default is case insensitive)
155 flags &= ~REWRITE_REGEX_ICASE;
158 case REWRITE_FLAG_BASICREGEX: /* 'R' */
160 * Use POSIX Basic Regular Expression syntax
161 * instead of POSIX Extended Regular Expression
164 flags &= ~REWRITE_REGEX_EXTENDED;
168 * Execution mode flags
170 case REWRITE_FLAG_EXECONCE: /* ':' */
172 * Apply rule once only
174 mode &= ~REWRITE_RECURSE;
175 mode |= REWRITE_EXEC_ONCE;
179 * Special action flags
181 case REWRITE_FLAG_STOP: /* '@' */
183 * Bail out after applying rule
185 action = calloc( sizeof( struct rewrite_action ), 1 );
186 if ( action == NULL ) {
191 mode &= ~REWRITE_RECURSE;
192 mode |= REWRITE_EXEC_ONCE;
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
220 if ( p[ 1 ] != '{' ) {
221 /* XXX Need to free stuff */
225 q = strchr( p + 2, '}' );
227 /* XXX Need to free stuff */
232 if ( l >= sizeof( buf ) ) {
233 /* XXX Need to free stuff */
236 AC_MEMCPY( buf, p + 2, l );
239 d = malloc( sizeof( int ) );
241 /* XXX Need to free stuff */
244 d[ 0 ] = atoi( buf );
246 action = calloc( sizeof( struct rewrite_action ), 1 );
247 if ( action == NULL ) {
251 action->la_type = REWRITE_ACTION_GOTO;
252 action->la_args = (void *)d;
254 p = q; /* p is incremented by the for ... */
259 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
263 action = calloc( sizeof( struct rewrite_action ), 1 );
264 if ( action == NULL ) {
269 action->la_type = REWRITE_ACTION_IGNORE_ERR;
277 * Unimplemented feature (complain only)
283 * Stupid way to append to a list ...
285 if ( action != NULL ) {
286 if ( first_action == NULL ) {
287 first_action = action;
289 append_action( first_action, action );
296 * Finally, rule allocation
298 rule = calloc( sizeof( struct rewrite_rule ), 1 );
299 if ( rule == NULL ) {
300 /* charray_free( res ); */
302 * XXX need to free the value subst stuff!
308 * REGEX compilation (luckily I don't need to take care of this ...)
310 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
311 /* charray_free( res ); */
313 *XXX need to free the value subst stuff!
320 * Just to remember them ...
322 rule->lr_pattern = strdup( pattern );
323 rule->lr_subststring = strdup( result );
324 rule->lr_flagstring = strdup( flagstring );
327 * Load compiled data into rule
329 rule->lr_subst = subst;
332 * Set various parameters
334 rule->lr_flags = flags; /* don't really need any longer ... */
335 rule->lr_mode = mode;
336 rule->lr_action = first_action;
339 * Append rule at the end of the rewrite context
341 append_rule( context, rule );
343 return REWRITE_SUCCESS;
347 * Rewrites string according to rule; may return:
348 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
349 * STOP: fine, rule matched; stop processing following rules
350 * UNWILL: rule matched; force 'unwilling to perform'
354 struct rewrite_info *info,
355 struct rewrite_op *op,
356 struct rewrite_rule *rule,
361 size_t nmatch = REWRITE_MAX_MATCH;
362 regmatch_t match[ REWRITE_MAX_MATCH ];
364 int rc = REWRITE_SUCCESS;
368 struct berval val = { 0, NULL };
370 assert( info != NULL );
371 assert( op != NULL );
372 assert( rule != NULL );
373 assert( arg != NULL );
374 assert( result != NULL );
378 string = (char *)arg;
381 * In case recursive match is required (default)
385 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
386 " rule='%s' string='%s'\n",
387 rule->lr_pattern, string, 0 );
390 if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
391 if ( *result == NULL && strcnt > 0 ) {
397 * No match is OK; *result = NULL means no match
399 return REWRITE_REGEXEC_OK;
402 rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
405 *result = val.bv_val;
412 if ( rc != REWRITE_REGEXEC_OK ) {
416 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
417 && op->lo_num_passes <= info->li_max_passes ) {
424 return REWRITE_REGEXEC_OK;
428 rewrite_rule_destroy(
429 struct rewrite_rule **prule
432 struct rewrite_rule *rule;
433 struct rewrite_action *action;
440 if ( rule->lr_pattern ) {
441 free( rule->lr_pattern );
442 rule->lr_pattern = NULL;
445 if ( rule->lr_subststring ) {
446 free( rule->lr_subststring );
447 rule->lr_subststring = NULL;
450 if ( rule->lr_flagstring ) {
451 free( rule->lr_flagstring );
452 rule->lr_flagstring = NULL;
455 if ( rule->lr_subst ) {
456 rewrite_subst_destroy( &rule->lr_subst );
459 regfree( &rule->lr_regex );
461 for ( action = rule->lr_action; action; ) {
462 struct rewrite_action *curraction = action;
464 action = action->la_next;
465 destroy_action( &curraction );