Ejemplo n.º 1
0
int
rewrite_rule_compile(
		struct rewrite_info *info,
		struct rewrite_context *context,
		const char *pattern,
		const char *result,
		const char *flagstring
)
{
	int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE;
	int mode = REWRITE_RECURSE;
	int max_passes = info->li_max_passes_per_rule;

	struct rewrite_rule *rule = NULL;
	struct rewrite_subst *subst = NULL;
	struct rewrite_action *action = NULL, *first_action = NULL;

	const char *p;

	assert( info != NULL );
	assert( context != NULL );
	assert( pattern != NULL );
	assert( result != NULL );

	/*
	 * A null flagstring should be allowed
	 */

	/*
	 * Take care of substitution string
	 */
	subst = rewrite_subst_compile( info, result );
	if ( subst == NULL ) {
		return REWRITE_ERR;
	}

	/*
	 * Take care of flags
	 */
	for ( p = flagstring; p[ 0 ] != '\0'; p++ ) {
		switch( p[ 0 ] ) {
			
		/*
		 * REGEX flags
		 */
		case REWRITE_FLAG_HONORCASE: 		/* 'C' */
			/*
			 * Honor case (default is case insensitive)
			 */
			flags &= ~REWRITE_REGEX_ICASE;
			break;
			
		case REWRITE_FLAG_BASICREGEX: 		/* 'R' */
			/*
			 * Use POSIX Basic Regular Expression syntax
			 * instead of POSIX Extended Regular Expression 
			 * syntax (default)
			 */
			flags &= ~REWRITE_REGEX_EXTENDED;
			break;
			
		/*
		 * Execution mode flags
		 */
		case REWRITE_FLAG_EXECONCE: 		/* ':' */
			/*
			 * Apply rule once only
			 */
			mode &= ~REWRITE_RECURSE;
			mode |= REWRITE_EXEC_ONCE;
			break;
		
		/*
		 * Special action flags
		 */
		case REWRITE_FLAG_STOP:	 		/* '@' */
			/*
			 * Bail out after applying rule
			 */
			action = calloc( sizeof( struct rewrite_action ), 1 );
			if ( action == NULL ) {
				goto fail;
			}

			action->la_type = REWRITE_ACTION_STOP;
			break;
			
		case REWRITE_FLAG_UNWILLING: 		/* '#' */
			/*
			 * Matching objs will be marked as gone!
			 */
			action = calloc( sizeof( struct rewrite_action ), 1 );
			if ( action == NULL ) {
				goto fail;
			}
			
			mode &= ~REWRITE_RECURSE;
			mode |= REWRITE_EXEC_ONCE;
			action->la_type = REWRITE_ACTION_UNWILLING;
			break;

		case REWRITE_FLAG_GOTO:				/* 'G' */
			/*
			 * After applying rule, jump N rules
			 */

		case REWRITE_FLAG_USER: {			/* 'U' */
			/*
			 * After applying rule, return user-defined
			 * error code
			 */
			char *next = NULL;
			int *d;
			
			if ( p[ 1 ] != '{' ) {
				goto fail;
			}

			d = malloc( sizeof( int ) );
			if ( d == NULL ) {
				goto fail;
			}

			d[ 0 ] = strtol( &p[ 2 ], &next, 0 );
			if ( next == &p[ 2 ] || next[0] != '}' ) {
				free( d );
				goto fail;
			}

			action = calloc( sizeof( struct rewrite_action ), 1 );
			if ( action == NULL ) {
				free( d );
				goto fail;
			}
			switch ( p[ 0 ] ) {
			case REWRITE_FLAG_GOTO:
				action->la_type = REWRITE_ACTION_GOTO;
				break;

			case REWRITE_FLAG_USER:
				action->la_type = REWRITE_ACTION_USER;
				break;

			default:
				assert(0);
			}

			action->la_args = (void *)d;

			p = next;	/* p is incremented by the for ... */
		
			break;
		}

		case REWRITE_FLAG_MAX_PASSES: {			/* 'U' */
			/*
			 * Set the number of max passes per rule
			 */
			char *next = NULL;
			
			if ( p[ 1 ] != '{' ) {
				goto fail;
			}

			max_passes = strtol( &p[ 2 ], &next, 0 );
			if ( next == &p[ 2 ] || next[0] != '}' ) {
				goto fail;
			}

			if ( max_passes < 1 ) {
				/* FIXME: nonsense ... */
				max_passes = 1;
			}

			p = next;	/* p is incremented by the for ... */
		
			break;
		}

		case REWRITE_FLAG_IGNORE_ERR:               /* 'I' */
			/*
			 * Ignore errors!
			 */
			action = calloc( sizeof( struct rewrite_action ), 1 );
			if ( action == NULL ) {
				goto fail;
			}
			
			action->la_type = REWRITE_ACTION_IGNORE_ERR;
			break;
			
		/*
		 * Other flags ...
		 */
		default:
			/*
			 * Unimplemented feature (complain only)
			 */
			break;
		}
		
		/*
		 * Stupid way to append to a list ...
		 */
		if ( action != NULL ) {
			append_action( &first_action, action );
			action = NULL;
		}
	}
	
	/*
	 * Finally, rule allocation
	 */
	rule = calloc( sizeof( struct rewrite_rule ), 1 );
	if ( rule == NULL ) {
		goto fail;
	}
	
	/*
	 * REGEX compilation (luckily I don't need to take care of this ...)
	 */
	if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) {
		goto fail;
	}
	
	/*
	 * Just to remember them ...
	 */
	rule->lr_pattern = strdup( pattern );
	rule->lr_subststring = strdup( result );
	rule->lr_flagstring = strdup( flagstring );
	if ( rule->lr_pattern == NULL
		|| rule->lr_subststring == NULL
		|| rule->lr_flagstring == NULL )
	{
		goto fail;
	}
	
	/*
	 * Load compiled data into rule
	 */
	rule->lr_subst = subst;

	/*
	 * Set various parameters
	 */
	rule->lr_flags = flags;		/* don't really need any longer ... */
	rule->lr_mode = mode;
	rule->lr_max_passes = max_passes;
	rule->lr_action = first_action;
	
	/*
	 * Append rule at the end of the rewrite context
	 */
	append_rule( context, rule );

	return REWRITE_SUCCESS;

fail:
	if ( rule ) {
		if ( rule->lr_pattern ) free( rule->lr_pattern );
		if ( rule->lr_subststring ) free( rule->lr_subststring );
		if ( rule->lr_flagstring ) free( rule->lr_flagstring );
		free( rule );
	}
	destroy_actions( first_action );
	free( subst );
	return REWRITE_ERR;
}
Ejemplo n.º 2
0
struct rewrite_map *
rewrite_map_parse(
		struct rewrite_info *info,
		const char *string,
		const char **currpos
)
{
	struct rewrite_map *map = NULL;
	struct rewrite_subst *subst = NULL;
	char *s, *begin = NULL, *end;
	const char *p;
	int l, cnt, mtx = 0, rc = 0;

	assert( info != NULL );
	assert( string != NULL );
	assert( currpos != NULL );

	*currpos = NULL;

	/*
	 * Go to the end of the map invocation (the right closing brace)
	 */
	for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) {
		if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) {
			/*
			 * '%' marks the beginning of a new map
			 */
			if ( p[ 1 ] == '{' ) {
				cnt++;
			/*
			 * '%' followed by a digit may mark the beginning
			 * of an old map
			 */
			} else if ( isdigit( (unsigned char) p[ 1 ] ) && p[ 2 ] == '{' ) {
				cnt++;
				p++;
			}

			if ( p[ 1 ] != '\0' ) {
				p++;
			}

		} else if ( p[ 0 ] == '}' ) {
			cnt--;
		}
	}
	if ( cnt != 0 ) {
		return NULL;
	}
	*currpos = p;
	
	/*
	 * Copy the map invocation
	 */
	l = p - string - 1;
	s = calloc( sizeof( char ), l + 1 );
	if ( s == NULL ) {
		return NULL;
	}
	AC_MEMCPY( s, string, l );
	s[ l ] = 0;

	/*
	 * Isolate the map name (except for variable deref)
	 */
	switch ( s[ 0 ] ) {
	case REWRITE_OPERATOR_VARIABLE_GET:
	case REWRITE_OPERATOR_PARAM_GET:
		break;

	default:
		begin = strchr( s, '(' );
		if ( begin == NULL ) {
			rc = -1;
			goto cleanup;
		}
		begin[ 0 ] = '\0';
		begin++;
		break;
	}

	/*
	 * Check for special map types
	 */
	p = s;
	switch ( p[ 0 ] ) {
	case REWRITE_OPERATOR_SUBCONTEXT:
	case REWRITE_OPERATOR_COMMAND:
	case REWRITE_OPERATOR_VARIABLE_SET:
	case REWRITE_OPERATOR_VARIABLE_GET:
	case REWRITE_OPERATOR_PARAM_GET:
		p++;
		break;
	}

	/*
	 * Variable set and get may be repeated to indicate session-wide
	 * instead of operation-wide variables
	 */
	switch ( p[ 0 ] ) {
        case REWRITE_OPERATOR_VARIABLE_SET:
	case REWRITE_OPERATOR_VARIABLE_GET:
		p++;
		break;
	}

	/*
	 * Variable get token can be appended to variable set to mean store
	 * AND rewrite
	 */
	if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
		p++;
	}
	
	/*
	 * Check the syntax of the variable name
	 */
	if ( !isalpha( (unsigned char) p[ 0 ] ) ) {
		rc = -1;
		goto cleanup;
	}
	for ( p++; p[ 0 ] != '\0'; p++ ) {
		if ( !isalnum( (unsigned char) p[ 0 ] ) ) {
			rc = -1;
			goto cleanup;
		}
	}

	/*
	 * Isolate the argument of the map (except for variable deref)
	 */
	switch ( s[ 0 ] ) {
	case REWRITE_OPERATOR_VARIABLE_GET:
	case REWRITE_OPERATOR_PARAM_GET:
		break;

	default:
		end = strrchr( begin, ')' );
		if ( end == NULL ) {
			rc = -1;
			goto cleanup;
		}
		end[ 0 ] = '\0';

		/*
	 	 * Compile the substitution pattern of the map argument
	 	 */
		subst = rewrite_subst_compile( info, begin );
		if ( subst == NULL ) {
			rc = -1;
			goto cleanup;
		}
		break;
	}

	/*
	 * Create the map
	 */
	map = calloc( sizeof( struct rewrite_map ), 1 );
	if ( map == NULL ) {
		rc = -1;
		goto cleanup;
	}
	memset( map, 0, sizeof( struct rewrite_map ) );
	
#ifdef USE_REWRITE_LDAP_PVT_THREADS
        if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
		rc = -1;
		goto cleanup;
	}
	++mtx;
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
			
	/*
	 * No subst for variable deref
	 */
	switch ( s[ 0 ] ) {
	case REWRITE_OPERATOR_VARIABLE_GET:
	case REWRITE_OPERATOR_PARAM_GET:
		break;

	default:
		map->lm_subst = subst;
		break;
	}

	/*
	 * Parses special map types
	 */
	switch ( s[ 0 ] ) {
	
	/*
	 * Subcontext
	 */
	case REWRITE_OPERATOR_SUBCONTEXT:		/* '>' */

		/*
		 * Fetch the rewrite context
		 * it MUST have been defined previously
		 */
		map->lm_type = REWRITE_MAP_SUBCONTEXT;
		map->lm_name = strdup( s + 1 );
		if ( map->lm_name == NULL ) {
			rc = -1;
			goto cleanup;
		}
		map->lm_data = rewrite_context_find( info, s + 1 );
		if ( map->lm_data == NULL ) {
			rc = -1;
			goto cleanup;
		}
		break;

	/*
	 * External command (not implemented yet)
	 */
	case REWRITE_OPERATOR_COMMAND:		/* '|' */
		rc = -1;
		goto cleanup;
	
	/*
	 * Variable set
	 */
	case REWRITE_OPERATOR_VARIABLE_SET:	/* '&' */
		if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) {
			if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
				map->lm_type = REWRITE_MAP_SETW_SESN_VAR;
				map->lm_name = strdup( s + 3 );
			} else {
				map->lm_type = REWRITE_MAP_SET_SESN_VAR;
				map->lm_name = strdup( s + 2 );
			}
		} else {
			if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
				map->lm_type = REWRITE_MAP_SETW_OP_VAR;
				map->lm_name = strdup( s + 2 );
			} else {
				map->lm_type = REWRITE_MAP_SET_OP_VAR;
				map->lm_name = strdup( s + 1 );
			}
		}
		if ( map->lm_name == NULL ) {
			rc = -1;
			goto cleanup;
		}
		break;
	
	/*
	 * Variable dereference
	 */
	case REWRITE_OPERATOR_VARIABLE_GET:	/* '*' */
		if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
			map->lm_type = REWRITE_MAP_GET_SESN_VAR;
			map->lm_name = strdup( s + 2 );
		} else {
			map->lm_type = REWRITE_MAP_GET_OP_VAR;
			map->lm_name = strdup( s + 1 );
		}
		if ( map->lm_name == NULL ) {
			rc = -1;
			goto cleanup;
		}
		break;
	
	/*
	 * Parameter
	 */
	case REWRITE_OPERATOR_PARAM_GET:		/* '$' */
		map->lm_type = REWRITE_MAP_GET_PARAM;
		map->lm_name = strdup( s + 1 );
		if ( map->lm_name == NULL ) {
			rc = -1;
			goto cleanup;
		}
		break;
	
	/*
	 * Built-in map
	 */
	default:
		map->lm_type = REWRITE_MAP_BUILTIN;
		map->lm_name = strdup( s );
		if ( map->lm_name == NULL ) {
			rc = -1;
			goto cleanup;
		}
		map->lm_data = rewrite_builtin_map_find( info, s );
		if ( map->lm_data == NULL ) {
			rc = -1;
			goto cleanup;
		}
		break;

	}

cleanup:
	free( s );
	if ( rc ) {
		if ( subst != NULL ) {
			free( subst );
		}
		if ( map ) {
#ifdef USE_REWRITE_LDAP_PVT_THREADS
		        if ( mtx ) {
				ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
			}
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

			if ( map->lm_name ) {
				free( map->lm_name );
				map->lm_name = NULL;
			}
			free( map );
			map = NULL;
		}
	}

	return map;
}