to be returned in r->status */
} rule_return_type;
+typedef enum {
+ COND_RC_NOMATCH = 0, /* the cond didn't match */
+ COND_RC_MATCH = 1, /* the cond matched */
+ COND_RC_STATUS_SET = 3 /* The condition eval set a final r->status */
+} cond_return_type;
+
typedef struct {
char *input; /* Input string of RewriteCond */
char *pattern; /* the RegExp pattern string */
/*
* Apply a single rewriteCond
*/
-static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx, apr_pool_t *pool)
+static cond_return_type apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx, apr_pool_t *pool)
{
char *input = NULL;
apr_finfo_t sb;
request_rec *rsub, *r = ctx->r;
ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
- int rc = 0;
+ int rc = COND_RC_NOMATCH;
int basis;
if (p->ptype != CONDPAT_AP_EXPR)
switch (p->ptype) {
case CONDPAT_FILE_EXISTS:
+ if (APR_SUCCESS != ap_stat_check(input, r->pool)) {
+ r->status = HTTP_FORBIDDEN;
+ rewritelog(r, 4, ctx->perdir, "RewriteCond: refusing to stat input='%s'", input);
+ return COND_RC_STATUS_SET;
+ }
if ( apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
&& sb.filetype == APR_REG) {
- rc = 1;
+ rc = COND_RC_MATCH;
}
break;
case CONDPAT_FILE_SIZE:
+ if (APR_SUCCESS != ap_stat_check(input, r->pool)) {
+ r->status = HTTP_FORBIDDEN;
+ rewritelog(r, 4, ctx->perdir, "RewriteCond: refusing to stat input='%s'", input);
+ return COND_RC_STATUS_SET;
+ }
if ( apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
&& sb.filetype == APR_REG && sb.size > 0) {
- rc = 1;
+ rc = COND_RC_MATCH;
}
break;
case CONDPAT_FILE_LINK:
+ if (APR_SUCCESS != ap_stat_check(input, r->pool)) {
+ r->status = HTTP_FORBIDDEN;
+ rewritelog(r, 4, ctx->perdir, "RewriteCond: refusing to stat input='%s'", input);
+ return COND_RC_STATUS_SET;
+ }
#if !defined(OS2)
if ( apr_stat(&sb, input, APR_FINFO_MIN | APR_FINFO_LINK,
r->pool) == APR_SUCCESS
&& sb.filetype == APR_LNK) {
- rc = 1;
+ rc = COND_RC_MATCH;
}
#endif
break;
case CONDPAT_FILE_DIR:
+ if (APR_SUCCESS != ap_stat_check(input, r->pool)) {
+ r->status = HTTP_FORBIDDEN;
+ rewritelog(r, 4, ctx->perdir, "RewriteCond: refusing to stat input='%s'", input);
+ return COND_RC_STATUS_SET;
+ }
if ( apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
&& sb.filetype == APR_DIR) {
- rc = 1;
+ rc = COND_RC_MATCH;
}
break;
case CONDPAT_FILE_XBIT:
+ if (APR_SUCCESS != ap_stat_check(input, r->pool)) {
+ r->status = HTTP_FORBIDDEN;
+ rewritelog(r, 4, ctx->perdir, "RewriteCond: refusing to stat input='%s'", input);
+ return COND_RC_STATUS_SET;
+ }
if ( apr_stat(&sb, input, APR_FINFO_PROT, r->pool) == APR_SUCCESS
&& (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
- rc = 1;
+ rc = COND_RC_MATCH;
}
break;
if (*input && subreq_ok(r)) {
rsub = ap_sub_req_lookup_uri(input, r, NULL);
if (rsub->status < 400) {
- rc = 1;
+ rc = COND_RC_MATCH;
}
rewritelog(r, 5, NULL, "RewriteCond URI (-U check: "
"path=%s -> status=%d", input, rsub->status);
case CONDPAT_LU_FILE:
if (*input && subreq_ok(r)) {
+ if (APR_SUCCESS != ap_stat_check(input, r->pool)) {
+ r->status = HTTP_FORBIDDEN;
+ rewritelog(r, 4, ctx->perdir, "RewriteCond: refusing to stat input='%s'", input);
+ return COND_RC_STATUS_SET;
+ }
rsub = ap_sub_req_lookup_file(input, r, NULL);
if (rsub->status < 300 &&
/* double-check that file exists since default result is 200 */
apr_stat(&sb, rsub->filename, APR_FINFO_MIN,
r->pool) == APR_SUCCESS) {
- rc = 1;
+ rc = COND_RC_MATCH;
}
rewritelog(r, 5, NULL, "RewriteCond file (-F check: path=%s "
"-> file=%s status=%d", input, rsub->filename,
basis = 1;
test_str_g:
if (p->flags & CONDFLAG_NOCASE) {
- rc = (strcasecmp(input, p->pattern) >= basis) ? 1 : 0;
+ rc = (strcasecmp(input, p->pattern) >= basis) ? COND_RC_MATCH : COND_RC_NOMATCH;
}
else {
- rc = (compare_lexicography(input, p->pattern) >= basis) ? 1 : 0;
+ rc = (compare_lexicography(input, p->pattern) >= basis) ? COND_RC_MATCH : COND_RC_NOMATCH;
}
break;
basis = -1;
test_str_l:
if (p->flags & CONDFLAG_NOCASE) {
- rc = (strcasecmp(input, p->pattern) <= basis) ? 1 : 0;
+ rc = (strcasecmp(input, p->pattern) <= basis) ? COND_RC_MATCH : COND_RC_NOMATCH;
}
else {
- rc = (compare_lexicography(input, p->pattern) <= basis) ? 1 : 0;
+ rc = (compare_lexicography(input, p->pattern) <= basis) ? COND_RC_MATCH : COND_RC_NOMATCH;
}
break;
rewritelog(r, 1, ctx->perdir,
"RewriteCond: expr='%s' evaluation failed: %s",
p->pattern - p->pskip, err);
- rc = 0;
+ rc = COND_RC_NOMATCH;
+ }
+ else {
+ rc = COND_RC_MATCH;
}
/* update briRC backref info */
if (rc && !(p->flags & CONDFLAG_NOTMATCH)) {
break;
}
- if (p->flags & CONDFLAG_NOTMATCH) {
+ if (p->flags & CONDFLAG_NOTMATCH && rc <= COND_RC_MATCH) {
rc = !rc;
}
rewritecond_entry *c = &conds[i];
rc = apply_rewrite_cond(c, ctx, ctx->temp_pool ? ctx->temp_pool : r->pool);
+
+ /* Error while evaluating cond, r->status set */
+ if (COND_RC_STATUS_SET == rc) {
+ return RULE_RC_STATUS_SET;
+ }
+
/*
* Reset vary_this if the novary flag is set for this condition.
*/
}
static apr_status_t core_dirwalk_stat(apr_finfo_t *finfo, request_rec *r,
- apr_int32_t wanted)
+ apr_int32_t wanted)
{
- return apr_stat(finfo, r->filename, wanted, r->pool);
+ apr_status_t rv = ap_stat_check(r->filename, r->pool);
+ if (rv == APR_SUCCESS) {
+ rv = apr_stat(finfo, r->filename, wanted, r->pool);
+ }
+ return rv;
}
static void core_dump_config(apr_pool_t *p, server_rec *s)
*s++ = '/';
ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
- "ap_filepath_merge: check converted path %s allowed %d",
+ "check_unc: check converted path %s allowed %d",
teststring,
sconf->unc_list ? sconf->unc_list->nelts : 0);
!ap_cstr_casecmp(uri.hostinfo, configured_unc))) {
rv = APR_SUCCESS;
ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
- "ap_filepath_merge: match %s %s",
+ "check_unc: match %s %s",
uri.hostinfo, configured_unc);
break;
}
else {
ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
- "ap_filepath_merge: no match %s %s", uri.hostinfo,
+ "check_unc: no match %s %s", uri.hostinfo,
configured_unc);
}
}
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(10504)
- "ap_filepath_merge: UNC path %s not allowed by UNCList", teststring);
+ "check_unc: UNC path %s not allowed by UNCList", teststring);
}
return rv;
#endif
}
+#ifdef WIN32
+AP_DECLARE(apr_status_t) ap_stat_check(const char *path, apr_pool_t *p)
+{
+ return check_unc(path, p);
+}
+#else
+AP_DECLARE(apr_status_t) ap_stat_check(const char *path, apr_pool_t *p)
+{
+ return APR_SUCCESS;
+}
+#endif
static void register_hooks(apr_pool_t *p)
{
return buf;
}
+static apr_status_t stat_check(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
+{
+ apr_status_t rv = APR_SUCCESS;
+ if (APR_SUCCESS != (rv = ap_stat_check(arg, ctx->p))) {
+ *ctx->err = apr_psprintf(ctx->p, "stat of %s not allowed", arg);
+ }
+ return rv;
+}
static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
char *arg)
{
apr_finfo_t sb;
+ if (APR_SUCCESS != stat_check(ctx, data, arg)) {
+ return "";
+ }
if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
&& sb.filetype == APR_REG && sb.size > 0)
return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
char *arg)
{
apr_finfo_t sb;
+ if (APR_SUCCESS != stat_check(ctx, data, arg)) {
+ return "";
+ }
if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
&& sb.filetype == APR_REG && sb.mtime > 0)
return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, (apr_off_t)sb.mtime);
{
apr_finfo_t sb;
const char *name = (const char *)data;
+ if (APR_SUCCESS != stat_check(ctx, data, arg)) {
+ return FALSE;
+ }
if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
return FALSE;
switch (name[0]) {
{
#if !defined(OS2)
apr_finfo_t sb;
+ if (APR_SUCCESS != stat_check(ctx, data, arg)) {
+ return FALSE;
+ }
if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
&& sb.filetype == APR_LNK) {
return TRUE;
static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
{
apr_finfo_t sb;
+ if (APR_SUCCESS != stat_check(ctx, data, arg)) {
+ return FALSE;
+ }
if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
&& (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
return TRUE;
request_rec *rsub, *r = ctx->r;
if (!r)
return FALSE;
+ if (APR_SUCCESS != stat_check(ctx, data, arg)) {
+ return FALSE;
+ }
rsub = ap_sub_req_lookup_file(arg, r, NULL);
if (rsub->status < 300 &&
/* double-check that file exists since default result is 200 */