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 **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;
120 struct rewrite_rule *rule = NULL;
121 struct rewrite_subst *subst = NULL;
122 struct rewrite_action *action = NULL, *first_action = NULL;
126 assert( info != NULL );
127 assert( context != NULL );
128 assert( pattern != NULL );
129 assert( result != NULL );
132 * A null flagstring should be allowed
136 * Take care of substitution string
138 subst = rewrite_subst_compile( info, result );
139 if ( subst == NULL ) {
146 for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
152 case REWRITE_FLAG_HONORCASE: /* 'C' */
154 * Honor case (default is case insensitive)
156 flags &= ~REWRITE_REGEX_ICASE;
159 case REWRITE_FLAG_BASICREGEX: /* 'R' */
161 * Use POSIX Basic Regular Expression syntax
162 * instead of POSIX Extended Regular Expression
165 flags &= ~REWRITE_REGEX_EXTENDED;
169 * Execution mode flags
171 case REWRITE_FLAG_EXECONCE: /* ':' */
173 * Apply rule once only
175 mode &= ~REWRITE_RECURSE;
176 mode |= REWRITE_EXEC_ONCE;
180 * Special action flags
182 case REWRITE_FLAG_STOP: /* '@' */
184 * Bail out after applying rule
186 action = calloc( sizeof( struct rewrite_action ), 1 );
187 if ( action == NULL ) {
192 mode &= ~REWRITE_RECURSE;
193 mode |= REWRITE_EXEC_ONCE;
194 action->la_type = REWRITE_ACTION_STOP;
197 case REWRITE_FLAG_UNWILLING: /* '#' */
199 * Matching objs will be marked as gone!
201 action = calloc( sizeof( struct rewrite_action ), 1 );
202 if ( action == NULL ) {
207 mode &= ~REWRITE_RECURSE;
208 mode |= REWRITE_EXEC_ONCE;
209 action->la_type = REWRITE_ACTION_UNWILLING;
212 case REWRITE_FLAG_GOTO: /* 'G' */
214 * After applying rule, jump N rules
217 case REWRITE_FLAG_USER: { /* 'U' */
219 * After applying rule, return user-defined
226 if ( p[ 1 ] != '{' ) {
227 /* XXX Need to free stuff */
231 q = strchr( p + 2, '}' );
233 /* XXX Need to free stuff */
238 if ( l >= sizeof( buf ) ) {
239 /* XXX Need to free stuff */
242 AC_MEMCPY( buf, p + 2, l );
245 d = malloc( sizeof( int ) );
247 /* XXX Need to free stuff */
250 d[ 0 ] = atoi( buf );
252 action = calloc( sizeof( struct rewrite_action ), 1 );
253 if ( action == NULL ) {
258 case REWRITE_FLAG_GOTO:
259 action->la_type = REWRITE_ACTION_GOTO;
262 case REWRITE_FLAG_USER:
263 action->la_type = REWRITE_ACTION_USER;
270 action->la_args = (void *)d;
272 p = q; /* p is incremented by the for ... */
277 case REWRITE_FLAG_IGNORE_ERR: /* 'I' */
281 action = calloc( sizeof( struct rewrite_action ), 1 );
282 if ( action == NULL ) {
287 action->la_type = REWRITE_ACTION_IGNORE_ERR;
295 * Unimplemented feature (complain only)
301 * Stupid way to append to a list ...
303 if ( action != NULL ) {
304 append_action( &first_action, action );
310 * Finally, rule allocation
312 rule = calloc( sizeof( struct rewrite_rule ), 1 );
313 if ( rule == NULL ) {
314 /* charray_free( res ); */
316 * XXX need to free the value subst stuff!
322 * REGEX compilation (luckily I don't need to take care of this ...)
324 if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
325 /* charray_free( res ); */
327 *XXX need to free the value subst stuff!
334 * Just to remember them ...
336 rule->lr_pattern = strdup( pattern );
337 rule->lr_subststring = strdup( result );
338 rule->lr_flagstring = strdup( flagstring );
341 * Load compiled data into rule
343 rule->lr_subst = subst;
346 * Set various parameters
348 rule->lr_flags = flags; /* don't really need any longer ... */
349 rule->lr_mode = mode;
350 rule->lr_action = first_action;
353 * Append rule at the end of the rewrite context
355 append_rule( context, rule );
357 return REWRITE_SUCCESS;
361 * Rewrites string according to rule; may return:
362 * OK: fine; if *result != NULL rule matched and rewrite succeeded.
363 * STOP: fine, rule matched; stop processing following rules
364 * UNWILL: rule matched; force 'unwilling to perform'
368 struct rewrite_info *info,
369 struct rewrite_op *op,
370 struct rewrite_rule *rule,
375 size_t nmatch = REWRITE_MAX_MATCH;
376 regmatch_t match[ REWRITE_MAX_MATCH ];
378 int rc = REWRITE_SUCCESS;
382 struct berval val = { 0, NULL };
384 assert( info != NULL );
385 assert( op != NULL );
386 assert( rule != NULL );
387 assert( arg != NULL );
388 assert( result != NULL );
392 string = (char *)arg;
395 * In case recursive match is required (default)
399 Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply"
400 " rule='%s' string='%s'\n",
401 rule->lr_pattern, string, 0 );
404 if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) {
405 if ( *result == NULL && strcnt > 0 ) {
411 * No match is OK; *result = NULL means no match
413 return REWRITE_REGEXEC_OK;
416 rc = rewrite_subst_apply( info, op, rule->lr_subst, string,
419 *result = val.bv_val;
426 if ( rc != REWRITE_REGEXEC_OK ) {
430 if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE
431 && op->lo_num_passes <= info->li_max_passes ) {
438 return REWRITE_REGEXEC_OK;
442 rewrite_rule_destroy(
443 struct rewrite_rule **prule
446 struct rewrite_rule *rule;
447 struct rewrite_action *action;
454 if ( rule->lr_pattern ) {
455 free( rule->lr_pattern );
456 rule->lr_pattern = NULL;
459 if ( rule->lr_subststring ) {
460 free( rule->lr_subststring );
461 rule->lr_subststring = NULL;
464 if ( rule->lr_flagstring ) {
465 free( rule->lr_flagstring );
466 rule->lr_flagstring = NULL;
469 if ( rule->lr_subst ) {
470 rewrite_subst_destroy( &rule->lr_subst );
473 regfree( &rule->lr_regex );
475 for ( action = rule->lr_action; action; ) {
476 struct rewrite_action *curraction = action;
478 action = action->la_next;
479 destroy_action( &curraction );