/* * Substitutes a portion of rewritten string according to substitution * pattern using submatches */ int rewrite_subst_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_subst *subst, const char *string, const regmatch_t *match, struct berval *val ) { struct berval *submatch = NULL; char *res = NULL; int n = 0, l, cl; int rc = REWRITE_REGEXEC_OK; assert( info != NULL ); assert( op != NULL ); assert( subst != NULL ); assert( string != NULL ); assert( match != NULL ); assert( val != NULL ); assert( val->bv_val == NULL ); val->bv_val = NULL; val->bv_len = 0; /* * Prepare room for submatch expansion */ if ( subst->lt_num_submatch > 0 ) { submatch = calloc( sizeof( struct berval ), subst->lt_num_submatch ); if ( submatch == NULL ) { return REWRITE_REGEXEC_ERR; } } /* * Resolve submatches (simple subst, map expansion and so). */ for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) { struct berval key = { 0, NULL }; submatch[ n ].bv_val = NULL; /* * Get key */ switch ( subst->lt_submatch[ n ].ls_type ) { case REWRITE_SUBMATCH_ASIS: case REWRITE_SUBMATCH_XMAP: rc = submatch_copy( &subst->lt_submatch[ n ], string, match, &key ); if ( rc != REWRITE_SUCCESS ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } break; case REWRITE_SUBMATCH_MAP_W_ARG: switch ( subst->lt_submatch[ n ].ls_map->lm_type ) { case REWRITE_MAP_GET_OP_VAR: case REWRITE_MAP_GET_SESN_VAR: case REWRITE_MAP_GET_PARAM: rc = REWRITE_SUCCESS; break; default: rc = rewrite_subst_apply( info, op, subst->lt_submatch[ n ].ls_map->lm_subst, string, match, &key); } if ( rc != REWRITE_SUCCESS ) { goto cleanup; } break; default: Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 ); rc = REWRITE_ERR; break; } if ( rc != REWRITE_SUCCESS ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } /* * Resolve key */ switch ( subst->lt_submatch[ n ].ls_type ) { case REWRITE_SUBMATCH_ASIS: submatch[ n ] = key; rc = REWRITE_SUCCESS; break; case REWRITE_SUBMATCH_XMAP: rc = rewrite_xmap_apply( info, op, subst->lt_submatch[ n ].ls_map, &key, &submatch[ n ] ); free( key.bv_val ); key.bv_val = NULL; break; case REWRITE_SUBMATCH_MAP_W_ARG: rc = rewrite_map_apply( info, op, subst->lt_submatch[ n ].ls_map, &key, &submatch[ n ] ); free( key.bv_val ); key.bv_val = NULL; break; default: /* * When implemented, this might return the * exit status of a rewrite context, * which may include a stop, or an * unwilling to perform */ rc = REWRITE_ERR; break; } if ( rc != REWRITE_SUCCESS ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } /* * Increment the length of the resulting string */ l += submatch[ n ].bv_len; } /* * Alloc result buffer */ l += subst->lt_subs_len; res = malloc( l + 1 ); if ( res == NULL ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } /* * Apply submatches (possibly resolved thru maps) */ for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) { if ( subst->lt_subs[ n ].bv_val != NULL ) { AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, subst->lt_subs[ n ].bv_len ); cl += subst->lt_subs[ n ].bv_len; } AC_MEMCPY( res + cl, submatch[ n ].bv_val, submatch[ n ].bv_len ); cl += submatch[ n ].bv_len; } if ( subst->lt_subs[ n ].bv_val != NULL ) { AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, subst->lt_subs[ n ].bv_len ); cl += subst->lt_subs[ n ].bv_len; } res[ cl ] = '\0'; val->bv_val = res; val->bv_len = l; cleanup:; if ( submatch ) { for ( ; --n >= 0; ) { if ( submatch[ n ].bv_val ) { free( submatch[ n ].bv_val ); } } free( submatch ); } return rc; }
/* * Rewrites string according to rule; may return: * OK: fine; if *result != NULL rule matched and rewrite succeeded. * STOP: fine, rule matched; stop processing following rules * UNWILL: rule matched; force 'unwilling to perform' */ int rewrite_rule_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_rule *rule, const char *arg, char **result ) { size_t nmatch = REWRITE_MAX_MATCH; regmatch_t match[ REWRITE_MAX_MATCH ]; int rc = REWRITE_SUCCESS; char *string; int strcnt = 0; struct berval val = { 0, NULL }; assert( info != NULL ); assert( op != NULL ); assert( rule != NULL ); assert( arg != NULL ); assert( result != NULL ); *result = NULL; string = (char *)arg; /* * In case recursive match is required (default) */ recurse:; Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply" " rule='%s' string='%s' [%d pass(es)]\n", rule->lr_pattern, string, strcnt + 1 ); op->lo_num_passes++; rc = regexec( &rule->lr_regex, string, nmatch, match, 0 ); if ( rc != 0 ) { if ( *result == NULL && string != arg ) { free( string ); } /* * No match is OK; *result = NULL means no match */ return REWRITE_REGEXEC_OK; } rc = rewrite_subst_apply( info, op, rule->lr_subst, string, match, &val ); *result = val.bv_val; val.bv_val = NULL; if ( string != arg ) { free( string ); string = NULL; } if ( rc != REWRITE_REGEXEC_OK ) { return rc; } if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE && op->lo_num_passes < info->li_max_passes && ++strcnt < rule->lr_max_passes ) { string = *result; goto recurse; } return REWRITE_REGEXEC_OK; }