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; }
int rewrite_session( struct rewrite_info *info, const char *rewriteContext, const char *string, const void *cookie, char **result ) { struct rewrite_context *context; struct rewrite_op op = { 0, 0, NULL, NULL, NULL }; int rc; assert( info != NULL ); assert( rewriteContext != NULL ); assert( string != NULL ); assert( result != NULL ); /* * cookie can be null; means: don't care about session stuff */ *result = NULL; op.lo_cookie = cookie; /* * Engine not on means no failure, but explicit no rewriting */ if ( info->li_state != REWRITE_ON ) { rc = REWRITE_REGEXEC_OK; goto rc_return; } /* * Undefined context means no rewriting also * (conservative, are we sure it's what we want?) */ context = rewrite_context_find( info, rewriteContext ); if ( context == NULL ) { switch ( info->li_rewrite_mode ) { case REWRITE_MODE_ERR: rc = REWRITE_REGEXEC_ERR; goto rc_return; case REWRITE_MODE_OK: rc = REWRITE_REGEXEC_OK; goto rc_return; case REWRITE_MODE_COPY_INPUT: *result = strdup( string ); rc = ( *result != NULL ) ? REWRITE_REGEXEC_OK : REWRITE_REGEXEC_ERR; goto rc_return; case REWRITE_MODE_USE_DEFAULT: context = rewrite_context_find( info, REWRITE_DEFAULT_CONTEXT ); break; } } #if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ op.lo_string = strdup( string ); if ( op.lo_string == NULL ) { rc = REWRITE_REGEXEC_ERR; goto rc_return; } #endif /* * Applies rewrite context */ rc = rewrite_context_apply( info, &op, context, string, result ); assert( op.lo_depth == 0 ); #if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ free( op.lo_string ); #endif switch ( rc ) { /* * Success */ case REWRITE_REGEXEC_OK: case REWRITE_REGEXEC_STOP: /* * If rewrite succeeded return OK regardless of how * the successful rewriting was obtained! */ rc = REWRITE_REGEXEC_OK; break; /* * Internal or forced error, return = NULL; rc already OK. */ case REWRITE_REGEXEC_UNWILLING: case REWRITE_REGEXEC_ERR: if ( *result != NULL ) { if ( *result != string ) { free( *result ); } *result = NULL; } default: break; } rc_return:; if ( op.lo_vars ) { rewrite_var_delete( op.lo_vars ); } return rc; }
/* * Parses a config line and takes actions to fit content in rewrite structure; * lines handled are of the form: * * rewriteEngine {on|off} * rewriteMaxPasses numPasses [numPassesPerRule] * rewriteContext contextName [alias aliasedContextName] * rewriteRule pattern substPattern [ruleFlags] * rewriteMap mapType mapName [mapArgs] * rewriteParam paramName paramValue */ int rewrite_parse( struct rewrite_info *info, const char *fname, int lineno, int argc, char **argv ) { int rc = -1; assert( info != NULL ); assert( fname != NULL ); assert( argv != NULL ); assert( argc > 0 ); /* * Switch on the rewrite engine */ if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteEngine needs 'state'\n%s", fname, lineno, "" ); return -1; } else if ( argc > 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteEngine" " will be discarded\n%s", fname, lineno, "" ); } if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) { info->li_state = REWRITE_ON; } else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) { info->li_state = REWRITE_OFF; } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown 'state' in rewriteEngine;" " assuming 'on'\n%s", fname, lineno, "" ); info->li_state = REWRITE_ON; } rc = REWRITE_SUCCESS; /* * Alter max passes */ } else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteMaxPasses needs 'value'\n%s", fname, lineno, "" ); return -1; } if ( lutil_atoi( &info->li_max_passes, argv[ 1 ] ) != 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] unable to parse rewriteMaxPasses=\"%s\"\n", fname, lineno, argv[ 1 ] ); return -1; } if ( info->li_max_passes <= 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] negative or null rewriteMaxPasses\n", fname, lineno, 0 ); return -1; } if ( argc > 2 ) { if ( lutil_atoi( &info->li_max_passes_per_rule, argv[ 2 ] ) != 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] unable to parse rewriteMaxPassesPerRule=\"%s\"\n", fname, lineno, argv[ 2 ] ); return -1; } if ( info->li_max_passes_per_rule <= 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] negative or null rewriteMaxPassesPerRule\n", fname, lineno, 0 ); return -1; } } else { info->li_max_passes_per_rule = info->li_max_passes; } rc = REWRITE_SUCCESS; /* * Start a new rewrite context and set current context */ } else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteContext needs 'name'\n%s", fname, lineno, "" ); return -1; } /* * Checks for existence (lots of contexts should be * available by default ...) */ rewrite_int_curr_context = rewrite_context_find( info, argv[ 1 ] ); if ( rewrite_int_curr_context == NULL ) { rewrite_int_curr_context = rewrite_context_create( info, argv[ 1 ] ); } if ( rewrite_int_curr_context == NULL ) { return -1; } if ( argc > 2 ) { /* * A context can alias another (e.g., the `builtin' * contexts for backend operations, if not defined, * alias the `default' rewrite context (with the * notable exception of the searchResult context, * which can be undefined) */ if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) { struct rewrite_context *aliased; if ( argc == 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteContext" " needs 'name' after" " 'alias'\n%s", fname, lineno, "" ); return -1; } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in" " rewriteContext" " after aliased name" " will be" " discarded\n%s", fname, lineno, "" ); } aliased = rewrite_context_find( info, argv[ 3 ] ); if ( aliased == NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] aliased" " rewriteContext '%s'" " does not exists\n", fname, lineno, argv[ 3 ] ); return -1; } rewrite_int_curr_context->lc_alias = aliased; rewrite_int_curr_context = aliased; } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields" " in rewriteContext" " will be discarded\n%s", fname, lineno, "" ); } } rc = REWRITE_SUCCESS; /* * Compile a rule in current context */ } else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteRule needs 'pattern'" " 'subst' ['flags']\n%s", fname, lineno, "" ); return -1; } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteRule" " will be discarded\n%s", fname, lineno, "" ); } if ( rewrite_int_curr_context == NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteRule outside a" " context; will add to default\n%s", fname, lineno, "" ); rewrite_int_curr_context = rewrite_context_find( info, REWRITE_DEFAULT_CONTEXT ); /* * Default context MUST exist in a properly initialized * struct rewrite_info */ assert( rewrite_int_curr_context != NULL ); } rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ], argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) ); /* * Add a plugin map to the map tree */ } else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteMap needs at least 'type'" " and 'name' ['args']\n%s", fname, lineno, "" ); return -1; } rc = rewrite_parse_builtin_map( info, fname, lineno, argc, argv ); /* * Set the value of a global scope parameter */ } else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteParam needs 'name'" " and 'value'\n%s", fname, lineno, "" ); return -1; } rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] ); /* * Error */ } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown command '%s'\n", fname, lineno, "" ); return -1; } return rc; }