View | Details | Raw Unified | Return to bug 35256
Collapse All | Expand All

(-)server/util.c (+59 lines)
Lines 1589-1594 Link Here
1589
        return OK;
1589
        return OK;
1590
}
1590
}
1591
1591
1592
AP_DECLARE(int) ap_unescape_url_keepenc(char *url, char* enc)
1593
{
1594
    register int badesc, badpath;
1595
    char *x, *y;
1596
#ifdef CASE_BLIND_FILESYSTEM
1597
    int slash_allowed = enc && strchr(enc, '/') && strchr(enc,'\\');
1598
#else
1599
    int slash_allowed = enc && strchr(enc,'/');
1600
#endif
1601
1602
    badesc = 0;
1603
    badpath = 0;
1604
    /* Initial scan for first '%'. Don't bother writing values before
1605
     * seeing a '%' */
1606
    y = strchr(url, '%');
1607
    if (y == NULL) {
1608
        return OK;
1609
    }
1610
    for (x = y; *y; ++x, ++y) {
1611
        if (*y != '%') {
1612
            *x = *y;
1613
        }
1614
        else {
1615
            if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1616
                badesc = 1;
1617
                *x = '%';
1618
            }
1619
            else {
1620
                char decoded;
1621
                decoded = x2c(y + 1);
1622
                if (decoded == '\0') {
1623
                    badpath = 1;
1624
                }
1625
                if (enc && (strchr(enc,decoded) != 0)) {
1626
                    int j;
1627
                    for (j=0; j<3; ++j)
1628
                        *x++ = *y++;
1629
                }
1630
                else {
1631
                    *x = decoded;
1632
                    y += 2;
1633
                    if (!slash_allowed && IS_SLASH(*x))
1634
                        badpath = 1;
1635
                }
1636
            }
1637
        }
1638
    }
1639
    *x = '\0';
1640
    if (badesc) {
1641
        return HTTP_BAD_REQUEST;
1642
    }
1643
    else if (badpath) {
1644
        return HTTP_NOT_FOUND;
1645
    }
1646
    else {
1647
        return OK;
1648
    }
1649
}
1650
1592
AP_DECLARE(int) ap_unescape_url_keep2f(char *url)
1651
AP_DECLARE(int) ap_unescape_url_keep2f(char *url)
1593
{
1652
{
1594
    register int badesc, badpath;
1653
    register int badesc, badpath;
(-)server/core.c (+20 lines)
Lines 155-160 Link Here
155
    conf->enable_mmap = ENABLE_MMAP_UNSET;
155
    conf->enable_mmap = ENABLE_MMAP_UNSET;
156
    conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
156
    conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
157
    conf->allow_encoded_slashes = 0;
157
    conf->allow_encoded_slashes = 0;
158
    conf->allow_encoded_chars = 0;
158
159
159
    return (void *)conf;
160
    return (void *)conf;
160
}
161
}
Lines 412-417 Link Here
412
    }
413
    }
413
414
414
    conf->allow_encoded_slashes = new->allow_encoded_slashes;
415
    conf->allow_encoded_slashes = new->allow_encoded_slashes;
416
    /* No merging for now */
417
    if (new->allow_encoded_chars)
418
        conf->allow_encoded_chars = new->allow_encoded_chars;
415
419
416
    return (void*)conf;
420
    return (void*)conf;
417
}
421
}
Lines 2377-2382 Link Here
2377
    return NULL;
2381
    return NULL;
2378
}
2382
}
2379
2383
2384
static const char *set_allow_encchars(cmd_parms *cmd, void *d_,
2385
                                        const char *arg)
2386
{
2387
    core_dir_config *d = d_;
2388
    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2389
2390
    if (err != NULL) {
2391
        return err;
2392
    }
2393
    if (arg)
2394
        d->allow_encoded_chars = apr_pstrdup(cmd->pool, arg);
2395
    return NULL;
2396
}
2397
2380
static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
2398
static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
2381
                                        const char *arg)
2399
                                        const char *arg)
2382
{
2400
{
Lines 3340-3345 Link Here
3340
     "output filter name followed by one or more content-types"),
3358
     "output filter name followed by one or more content-types"),
3341
AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
3359
AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
3342
             "Allow URLs containing '/' encoded as '%2F'"),
3360
             "Allow URLs containing '/' encoded as '%2F'"),
3361
AP_INIT_TAKE1("AllowEncodedChars", set_allow_encchars, NULL, RSRC_CONF,
3362
             "Allow URLs containing encoded chars to pass through"),
3343
3363
3344
/*
3364
/*
3345
 * These are default configuration directives that mpms can/should
3365
 * These are default configuration directives that mpms can/should
(-)server/request.c (-14 / +18 lines)
Lines 94-99 Link Here
94
    }
94
    }
95
}
95
}
96
96
97
static char* merge_escapes(int encoded_slashes, char* encoded_chars,
98
        apr_pool_t *p) {
99
    char* echars = encoded_slashes ? "\\/" : 0;
100
    if (encoded_chars) {
101
        echars = echars ?
102
            apr_pstrcat(p, echars, encoded_chars) : encoded_chars;
103
    }
104
    return echars;
105
}
106
97
/* This is the master logic for processing requests.  Do NOT duplicate
107
/* This is the master logic for processing requests.  Do NOT duplicate
98
 * this logic elsewhere, or the security model will be broken by future
108
 * this logic elsewhere, or the security model will be broken by future
99
 * API changes.  Each phase must be individually optimized to pick up
109
 * API changes.  Each phase must be individually optimized to pick up
Lines 106-127 Link Here
106
116
107
    /* Ignore embedded %2F's in path for proxy requests */
117
    /* Ignore embedded %2F's in path for proxy requests */
108
    if (!r->proxyreq && r->parsed_uri.path) {
118
    if (!r->proxyreq && r->parsed_uri.path) {
109
        core_dir_config *d;
119
        core_dir_config *d = ap_get_module_config(r->per_dir_config, &core_module);
110
        d = ap_get_module_config(r->per_dir_config, &core_module);
120
        char* echars = merge_escapes(d->allow_encoded_slashes,
111
        if (d->allow_encoded_slashes) {
121
                d->allow_encoded_chars, r->pool);
112
            access_status = ap_unescape_url_keep2f(r->parsed_uri.path);
122
        access_status = ap_unescape_url_keepenc(r->parsed_uri.path, echars);
113
        }
114
        else {
115
            access_status = ap_unescape_url(r->parsed_uri.path);
116
        }
117
        if (access_status) {
123
        if (access_status) {
118
            if (access_status == HTTP_NOT_FOUND) {
124
            if (access_status == HTTP_NOT_FOUND) {
119
                if (! d->allow_encoded_slashes) {
125
                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
120
                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
126
                      "found illegal chars %%2f (encoded '/') or \\0 in URI "
121
                                  "found %%2f (encoded '/') in URI "
127
                      "(decoded='%s'), returning 404",
122
                                  "(decoded='%s'), returning 404",
128
                      r->parsed_uri.path);
123
                                  r->parsed_uri.path);
124
                }
125
            }
129
            }
126
            return access_status;
130
            return access_status;
127
        }
131
        }
(-)include/httpd.h (+8 lines)
Lines 1438-1443 Link Here
1438
AP_DECLARE(int) ap_unescape_url_keep2f(char *url);
1438
AP_DECLARE(int) ap_unescape_url_keep2f(char *url);
1439
1439
1440
/**
1440
/**
1441
 * Unescape a URL, but leaving specified chars escaped
1442
 * @param url The url to unescape
1443
 * @param enc The chars to keep 
1444
 * @return 0 on success, non-zero otherwise
1445
 */
1446
AP_DECLARE(int) ap_unescape_url_keepenc(char *url, char *enc);
1447
1448
/**
1441
 * Convert all double slashes to single slashes
1449
 * Convert all double slashes to single slashes
1442
 * @param name The string to convert
1450
 * @param name The string to convert
1443
 */
1451
 */
(-)include/http_core.h (+3 lines)
Lines 540-545 Link Here
540
#define USE_CANONICAL_PHYS_PORT_ON    (1)
540
#define USE_CANONICAL_PHYS_PORT_ON    (1)
541
#define USE_CANONICAL_PHYS_PORT_UNSET (2)
541
#define USE_CANONICAL_PHYS_PORT_UNSET (2)
542
    unsigned use_canonical_phys_port : 2;
542
    unsigned use_canonical_phys_port : 2;
543
    
544
    char *allow_encoded_chars; /* Allow URLs containing given encoded chars 
545
                                  to pass through */
543
546
544
} core_dir_config;
547
} core_dir_config;
545
548

Return to bug 35256