Ejemplo n.º 1
0
/*
 * Compiles a substitution pattern
 */
struct rewrite_subst *
rewrite_subst_compile(
		struct rewrite_info *info,
		const char *str
)
{
	size_t subs_len;
	struct berval *subs = NULL, *tmps;
	struct rewrite_submatch *submatch = NULL;

	struct rewrite_subst *s = NULL;

	char *result, *begin, *p;
	int nsub = 0, l;

	assert( info != NULL );
	assert( str != NULL );

	result = strdup( str );
	if ( result == NULL ) {
		return NULL;
	}

	/*
	 * Take care of substitution string
	 */
	for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {

		/*
		 * Keep only single escapes '%'
		 */
		if (  !IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) {
			continue;
		} 

		if (  IS_REWRITE_SUBMATCH_ESCAPE( p[ 1 ] ) ) {
			/* Pull &p[1] over p, including the trailing '\0' */
			AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) );
			continue;
		}

		tmps = ( struct berval * )realloc( subs,
				sizeof( struct berval )*( nsub + 1 ) );
		if ( tmps == NULL ) {
			goto cleanup;
		}
		subs = tmps;
		
		/*
		 * I think an `if l > 0' at runtime is better outside than
		 * inside a function call ...
		 */
		l = p - begin;
		if ( l > 0 ) {
			subs_len += l;
			subs[ nsub ].bv_len = l;
			subs[ nsub ].bv_val = malloc( l + 1 );
			if ( subs[ nsub ].bv_val == NULL ) {
				goto cleanup;
			}
			AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
			subs[ nsub ].bv_val[ l ] = '\0';
		} else {
			subs[ nsub ].bv_val = NULL;
			subs[ nsub ].bv_len = 0;
		}
		
		/*
		 * Substitution pattern
		 */
		if ( isdigit( (unsigned char) p[ 1 ] ) ) {
			struct rewrite_submatch *tmpsm;
			int d = p[ 1 ] - '0';

			/*
			 * Add a new value substitution scheme
			 */

			tmpsm = ( struct rewrite_submatch * )realloc( submatch,
					sizeof( struct rewrite_submatch )*( nsub + 1 ) );
			if ( tmpsm == NULL ) {
				goto cleanup;
			}
			submatch = tmpsm;
			submatch[ nsub ].ls_submatch = d;

			/*
			 * If there is no argument, use default
			 * (substitute substring as is)
			 */
			if ( p[ 2 ] != '{' ) {
				submatch[ nsub ].ls_type = 
					REWRITE_SUBMATCH_ASIS;
				submatch[ nsub ].ls_map = NULL;
				begin = ++p + 1;

			} else {
				struct rewrite_map *map;

				submatch[ nsub ].ls_type =
					REWRITE_SUBMATCH_XMAP;

				map = rewrite_xmap_parse( info,
						p + 3, (const char **)&begin );
				if ( map == NULL ) {
					goto cleanup;
				}
				submatch[ nsub ].ls_map = map;
				p = begin - 1;
			}

		/*
		 * Map with args ...
		 */
		} else if ( p[ 1 ] == '{' ) {
			struct rewrite_map *map;
			struct rewrite_submatch *tmpsm;

			map = rewrite_map_parse( info, p + 2,
					(const char **)&begin );
			if ( map == NULL ) {
				goto cleanup;
			}
			p = begin - 1;

			/*
			 * Add a new value substitution scheme
			 */
			tmpsm = ( struct rewrite_submatch * )realloc( submatch,
					sizeof( struct rewrite_submatch )*( nsub + 1 ) );
			if ( tmpsm == NULL ) {
				goto cleanup;
			}
			submatch = tmpsm;
			submatch[ nsub ].ls_type =
				REWRITE_SUBMATCH_MAP_W_ARG;
			submatch[ nsub ].ls_map = map;

		/*
		 * Escape '%' ...
		 */
		} else if ( p[ 1 ] == '%' ) {
			AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) );
			continue;

		} else {
			goto cleanup;
		}

		nsub++;
	}
	
	/*
	 * Last part of string
	 */
	tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) );
	if ( tmps == NULL ) {
		/*
		 * XXX need to free the value subst stuff!
		 */
		free( subs );
		goto cleanup;
	}
	subs = tmps;
	l = p - begin;
	if ( l > 0 ) {
		subs_len += l;
		subs[ nsub ].bv_len = l;
		subs[ nsub ].bv_val = malloc( l + 1 );
		if ( subs[ nsub ].bv_val == NULL ) {
			free( subs );
			goto cleanup;
		}
		AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
		subs[ nsub ].bv_val[ l ] = '\0';
	} else {
		subs[ nsub ].bv_val = NULL;
		subs[ nsub ].bv_len = 0;
	}

	s = calloc( sizeof( struct rewrite_subst ), 1 );
	if ( s == NULL ) {
		goto cleanup;
	}

	s->lt_subs_len = subs_len;
        s->lt_subs = subs;
        s->lt_num_submatch = nsub;
        s->lt_submatch = submatch;

cleanup:;
	free( result );

	return s;
}
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;
}