perform all the expansions on the input string * putting the result into a new string * * for security reasons this expansion must be performed in a * single pass, otherwise an attacker can arrange for the result * of an earlier expansion to include expansion specifiers that * are interpreted by a later expansion, producing results that * were not intended by the administrator. * * unsafe
| 2427 | * to -1 and remains so if no qmark is found. |
| 2428 | */ |
| 2429 | static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry, |
| 2430 | int *unsafe_qmark) |
| 2431 | { |
| 2432 | #define EXPAND_SPECIALS "\\$%" |
| 2433 | result_list *result, *current; |
| 2434 | result_list sresult[SMALL_EXPANSION]; |
| 2435 | unsigned spc = 0; |
| 2436 | apr_size_t span, inputlen, outlen; |
| 2437 | char *p, *c; |
| 2438 | apr_pool_t *pool = ctx->r->pool; |
| 2439 | |
| 2440 | inputlen = strlen(input); |
| 2441 | if (!unsafe_qmark) { |
| 2442 | span = strcspn(input, EXPAND_SPECIALS); |
| 2443 | } |
| 2444 | else { |
| 2445 | span = strcspn(input, EXPAND_SPECIALS "?"); |
| 2446 | if (input[span] == '?') { |
| 2447 | /* this qmark is not from an expansion thus safe */ |
| 2448 | *unsafe_qmark = 0; |
| 2449 | |
| 2450 | /* keep tracking only if interested in the last qmark */ |
| 2451 | if (!entry || !(entry->flags & RULEFLAG_QSLAST)) { |
| 2452 | unsafe_qmark = NULL; |
| 2453 | } |
| 2454 | |
| 2455 | /* find the next real special char, any (last) qmark up to |
| 2456 | * there is safe too |
| 2457 | */ |
| 2458 | span += strcspn(input + span, EXPAND_SPECIALS); |
| 2459 | } |
| 2460 | } |
| 2461 | |
| 2462 | /* fast path (no specials) */ |
| 2463 | if (span >= inputlen) { |
| 2464 | return apr_pstrmemdup(pool, input, inputlen); |
| 2465 | } |
| 2466 | |
| 2467 | /* well, actually something to do */ |
| 2468 | result = current = &(sresult[spc++]); |
| 2469 | |
| 2470 | p = input + span; |
| 2471 | current->next = NULL; |
| 2472 | current->string = input; |
| 2473 | current->len = span; |
| 2474 | outlen = span; |
| 2475 | |
| 2476 | /* loop for specials */ |
| 2477 | do { |
| 2478 | int expanded = 0; |
| 2479 | |
| 2480 | /* prepare next entry */ |
| 2481 | if (current->len) { |
| 2482 | current->next = (spc < SMALL_EXPANSION) |
| 2483 | ? &(sresult[spc++]) |
| 2484 | : (result_list *)apr_palloc(pool, |
| 2485 | sizeof(result_list)); |
| 2486 | current = current->next; |
no test coverage detected