Blame server/util_expr_eval.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/*                      _             _
Packit 90a5c9
 *  ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include "httpd.h"
Packit 90a5c9
#include "http_log.h"
Packit 90a5c9
#include "http_core.h"
Packit 90a5c9
#include "http_protocol.h"
Packit 90a5c9
#include "http_request.h"
Packit 90a5c9
#include "ap_provider.h"
Packit 90a5c9
#include "util_expr_private.h"
Packit 90a5c9
#include "util_md5.h"
Packit 90a5c9
Packit 90a5c9
#include "apr_lib.h"
Packit 90a5c9
#include "apr_fnmatch.h"
Packit 90a5c9
#include "apr_base64.h"
Packit 90a5c9
#include "apr_sha1.h"
Packit 90a5c9
Packit 90a5c9
#include <limits.h>     /* for INT_MAX */
Packit 90a5c9
Packit 90a5c9
/* we know core's module_index is 0 */
Packit 90a5c9
#undef APLOG_MODULE_INDEX
Packit 90a5c9
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
Packit 90a5c9
Packit 90a5c9
APR_HOOK_STRUCT(
Packit 90a5c9
    APR_HOOK_LINK(expr_lookup)
Packit 90a5c9
)
Packit 90a5c9
Packit 90a5c9
AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
Packit 90a5c9
                            (parms), DECLINED)
Packit 90a5c9
Packit 90a5c9
#define  LOG_MARK(info)  __FILE__, __LINE__, (info)->module_index
Packit 90a5c9
Packit 90a5c9
static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                            const ap_expr_t *info,
Packit 90a5c9
                                            const ap_expr_t *args);
Packit 90a5c9
static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                           unsigned int n);
Packit 90a5c9
static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                    ap_expr_var_func_t *func,
Packit 90a5c9
                                    const void *data);
Packit 90a5c9
Packit 90a5c9
/* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
Packit 90a5c9
#ifdef AP_EXPR_DEBUG
Packit 90a5c9
static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
Packit 90a5c9
                           int loglevel, int indent);
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * To reduce counting overhead, we only count calls to
Packit 90a5c9
 * ap_expr_eval_word() and ap_expr_eval(). The max number of
Packit 90a5c9
 * stack frames is larger by some factor.
Packit 90a5c9
 */
Packit 90a5c9
#define AP_EXPR_MAX_RECURSION   20
Packit 90a5c9
static int inc_rec(ap_expr_eval_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    if (ctx->reclvl < AP_EXPR_MAX_RECURSION) {
Packit 90a5c9
        ctx->reclvl++;
Packit 90a5c9
        return 0;
Packit 90a5c9
    }
Packit 90a5c9
    *ctx->err = "Recursion limit reached";
Packit 90a5c9
    /* short circuit further evaluation */
Packit 90a5c9
    ctx->reclvl = INT_MAX;
Packit 90a5c9
    return 1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                     const ap_expr_t *node)
Packit 90a5c9
{
Packit 90a5c9
    const char *result = "";
Packit 90a5c9
    if (inc_rec(ctx))
Packit 90a5c9
        return result;
Packit 90a5c9
    switch (node->node_op) {
Packit 90a5c9
    case op_Digit:
Packit 90a5c9
    case op_String:
Packit 90a5c9
        result = node->node_arg1;
Packit 90a5c9
        break;
Packit 90a5c9
    case op_Var:
Packit 90a5c9
        result = ap_expr_eval_var(ctx, (ap_expr_var_func_t *)node->node_arg1,
Packit 90a5c9
                                  node->node_arg2);
Packit 90a5c9
        break;
Packit 90a5c9
    case op_Concat:
Packit 90a5c9
        if (((ap_expr_t *)node->node_arg2)->node_op != op_Concat &&
Packit 90a5c9
            ((ap_expr_t *)node->node_arg1)->node_op != op_Concat) {
Packit 90a5c9
            const char *s1 = ap_expr_eval_word(ctx, node->node_arg1);
Packit 90a5c9
            const char *s2 = ap_expr_eval_word(ctx, node->node_arg2);
Packit 90a5c9
            if (!*s1)
Packit 90a5c9
                result = s2;
Packit 90a5c9
            else if (!*s2)
Packit 90a5c9
                result = s1;
Packit 90a5c9
            else
Packit 90a5c9
                result = apr_pstrcat(ctx->p, s1, s2, NULL);
Packit 90a5c9
        }
Packit 90a5c9
        else if (((ap_expr_t *)node->node_arg1)->node_op == op_Concat) {
Packit 90a5c9
            const ap_expr_t *nodep = node;
Packit 90a5c9
            int n;
Packit 90a5c9
            int i = 1;
Packit 90a5c9
            struct iovec *vec;
Packit 90a5c9
            do {
Packit 90a5c9
                nodep = nodep->node_arg1;
Packit 90a5c9
                i++;
Packit 90a5c9
            } while (nodep->node_op == op_Concat);
Packit 90a5c9
            vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
Packit 90a5c9
            n = i;
Packit 90a5c9
            nodep = node;
Packit 90a5c9
            i--;
Packit 90a5c9
            do {
Packit 90a5c9
                vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
Packit 90a5c9
                                                            nodep->node_arg2);
Packit 90a5c9
                vec[i].iov_len = strlen(vec[i].iov_base);
Packit 90a5c9
                i--;
Packit 90a5c9
                nodep = nodep->node_arg1;
Packit 90a5c9
            } while (nodep->node_op == op_Concat);
Packit 90a5c9
            vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
Packit 90a5c9
            vec[i].iov_len = strlen(vec[i].iov_base);
Packit 90a5c9
            result = apr_pstrcatv(ctx->p, vec, n, NULL);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            const ap_expr_t *nodep = node;
Packit 90a5c9
            int i = 1;
Packit 90a5c9
            struct iovec *vec;
Packit 90a5c9
            do {
Packit 90a5c9
                nodep = nodep->node_arg2;
Packit 90a5c9
                i++;
Packit 90a5c9
            } while (nodep->node_op == op_Concat);
Packit 90a5c9
            vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
Packit 90a5c9
            nodep = node;
Packit 90a5c9
            i = 0;
Packit 90a5c9
            do {
Packit 90a5c9
                vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
Packit 90a5c9
                                                            nodep->node_arg1);
Packit 90a5c9
                vec[i].iov_len = strlen(vec[i].iov_base);
Packit 90a5c9
                i++;
Packit 90a5c9
                nodep = nodep->node_arg2;
Packit 90a5c9
            } while (nodep->node_op == op_Concat);
Packit 90a5c9
            vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
Packit 90a5c9
            vec[i].iov_len = strlen(vec[i].iov_base);
Packit 90a5c9
            i++;
Packit 90a5c9
            result = apr_pstrcatv(ctx->p, vec, i, NULL);
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    case op_StringFuncCall: {
Packit 90a5c9
        const ap_expr_t *info = node->node_arg1;
Packit 90a5c9
        const ap_expr_t *args = node->node_arg2;
Packit 90a5c9
        result = ap_expr_eval_string_func(ctx, info, args);
Packit 90a5c9
        break;
Packit 90a5c9
    }
Packit 90a5c9
    case op_RegexBackref: {
Packit 90a5c9
        const unsigned int *np = node->node_arg1;
Packit 90a5c9
        result = ap_expr_eval_re_backref(ctx, *np);
Packit 90a5c9
        break;
Packit 90a5c9
    }
Packit 90a5c9
    default:
Packit 90a5c9
        *ctx->err = "Internal evaluation error: Unknown word expression node";
Packit 90a5c9
        break;
Packit 90a5c9
    }
Packit 90a5c9
    if (!result)
Packit 90a5c9
        result = "";
Packit 90a5c9
    ctx->reclvl--;
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                    ap_expr_var_func_t *func,
Packit 90a5c9
                                    const void *data)
Packit 90a5c9
{
Packit 90a5c9
    AP_DEBUG_ASSERT(func != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(data != NULL);
Packit 90a5c9
    return (*func)(ctx, data);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx, unsigned int n)
Packit 90a5c9
{
Packit 90a5c9
    int len;
Packit 90a5c9
Packit 90a5c9
    if (!ctx->re_pmatch || !ctx->re_source || !*ctx->re_source
Packit 90a5c9
        || **ctx->re_source == '\0' || ctx->re_nmatch < n + 1)
Packit 90a5c9
        return "";
Packit 90a5c9
Packit 90a5c9
    len = ctx->re_pmatch[n].rm_eo - ctx->re_pmatch[n].rm_so;
Packit 90a5c9
    if (len == 0)
Packit 90a5c9
        return "";
Packit 90a5c9
Packit 90a5c9
    return apr_pstrndup(ctx->p, *ctx->re_source + ctx->re_pmatch[n].rm_so, len);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                            const ap_expr_t *info,
Packit 90a5c9
                                            const ap_expr_t *arg)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
Packit 90a5c9
    const void *data = info->node_arg2;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
Packit 90a5c9
    AP_DEBUG_ASSERT(func != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(data != NULL);
Packit 90a5c9
    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int intstrcmp(const char *s1, const char *s2)
Packit 90a5c9
{
Packit 90a5c9
    apr_int64_t i1 = apr_atoi64(s1);
Packit 90a5c9
    apr_int64_t i2 = apr_atoi64(s2);
Packit 90a5c9
Packit 90a5c9
    if (i1 < i2)
Packit 90a5c9
        return -1;
Packit 90a5c9
    else if (i1 == i2)
Packit 90a5c9
        return 0;
Packit 90a5c9
    else
Packit 90a5c9
        return 1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
Packit 90a5c9
{
Packit 90a5c9
    const ap_expr_t *e1 = node->node_arg1;
Packit 90a5c9
    const ap_expr_t *e2 = node->node_arg2;
Packit 90a5c9
    switch (node->node_op) {
Packit 90a5c9
    case op_EQ:
Packit 90a5c9
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
Packit 90a5c9
    case op_NE:
Packit 90a5c9
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
Packit 90a5c9
    case op_LT:
Packit 90a5c9
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
Packit 90a5c9
    case op_LE:
Packit 90a5c9
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
Packit 90a5c9
    case op_GT:
Packit 90a5c9
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
Packit 90a5c9
    case op_GE:
Packit 90a5c9
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
Packit 90a5c9
    case op_STR_EQ:
Packit 90a5c9
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
Packit 90a5c9
    case op_STR_NE:
Packit 90a5c9
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
Packit 90a5c9
    case op_STR_LT:
Packit 90a5c9
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
Packit 90a5c9
    case op_STR_LE:
Packit 90a5c9
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
Packit 90a5c9
    case op_STR_GT:
Packit 90a5c9
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
Packit 90a5c9
    case op_STR_GE:
Packit 90a5c9
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
Packit 90a5c9
    case op_IN: {
Packit 90a5c9
            const char *needle = ap_expr_eval_word(ctx, e1);
Packit 90a5c9
            if (e2->node_op == op_ListElement) {
Packit 90a5c9
                do {
Packit 90a5c9
                    const ap_expr_t *val = e2->node_arg1;
Packit 90a5c9
                    AP_DEBUG_ASSERT(e2->node_op == op_ListElement);
Packit 90a5c9
                    if (strcmp(needle, ap_expr_eval_word(ctx, val)) == 0)
Packit 90a5c9
                        return 1;
Packit 90a5c9
                    e2 = e2->node_arg2;
Packit 90a5c9
                } while (e2 != NULL);
Packit 90a5c9
            }
Packit 90a5c9
            else if (e2->node_op == op_ListFuncCall) {
Packit 90a5c9
                const ap_expr_t *info = e2->node_arg1;
Packit 90a5c9
                const ap_expr_t *arg = e2->node_arg2;
Packit 90a5c9
                ap_expr_list_func_t *func = (ap_expr_list_func_t *)info->node_arg1;
Packit 90a5c9
                apr_array_header_t *haystack;
Packit 90a5c9
Packit 90a5c9
                AP_DEBUG_ASSERT(func != NULL);
Packit 90a5c9
                AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
Packit 90a5c9
                haystack = (*func)(ctx, info->node_arg2, ap_expr_eval_word(ctx, arg));
Packit 90a5c9
                if (haystack == NULL) {
Packit 90a5c9
                    return 0;
Packit 90a5c9
                }
Packit 90a5c9
                if (ap_array_str_contains(haystack, needle)) {
Packit 90a5c9
                    return 1;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            return 0;
Packit 90a5c9
        }
Packit 90a5c9
    case op_REG:
Packit 90a5c9
    case op_NRE: {
Packit 90a5c9
            const char *word = ap_expr_eval_word(ctx, e1);
Packit 90a5c9
            const ap_regex_t *regex = e2->node_arg1;
Packit 90a5c9
            int result;
Packit 90a5c9
Packit 90a5c9
            /*
Packit 90a5c9
             * $0 ... $9 may contain stuff the user wants to keep. Therefore
Packit 90a5c9
             * we only set them if there are capturing parens in the regex.
Packit 90a5c9
             */
Packit 90a5c9
            if (regex->re_nsub > 0) {
Packit 90a5c9
                result = (0 == ap_regexec(regex, word, ctx->re_nmatch,
Packit 90a5c9
                                          ctx->re_pmatch, 0));
Packit 90a5c9
                *ctx->re_source = result ? word : NULL;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                result = (0 == ap_regexec(regex, word, 0, NULL, 0));
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            if (node->node_op == op_REG)
Packit 90a5c9
                return result;
Packit 90a5c9
            else
Packit 90a5c9
                return !result;
Packit 90a5c9
        }
Packit 90a5c9
    default:
Packit 90a5c9
        *ctx->err = "Internal evaluation error: Unknown comp expression node";
Packit 90a5c9
        return -1;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* combined string/int comparison for compatibility with ssl_expr */
Packit 90a5c9
static int strcmplex(const char *str1, const char *str2)
Packit 90a5c9
{
Packit 90a5c9
    int i, n1, n2;
Packit 90a5c9
Packit 90a5c9
    if (str1 == NULL)
Packit 90a5c9
        return -1;
Packit 90a5c9
    if (str2 == NULL)
Packit 90a5c9
        return +1;
Packit 90a5c9
    n1 = strlen(str1);
Packit 90a5c9
    n2 = strlen(str2);
Packit 90a5c9
    if (n1 > n2)
Packit 90a5c9
        return 1;
Packit 90a5c9
    if (n1 < n2)
Packit 90a5c9
        return -1;
Packit 90a5c9
    for (i = 0; i < n1; i++) {
Packit 90a5c9
        if (str1[i] > str2[i])
Packit 90a5c9
            return 1;
Packit 90a5c9
        if (str1[i] < str2[i])
Packit 90a5c9
            return -1;
Packit 90a5c9
    }
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int ssl_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
Packit 90a5c9
{
Packit 90a5c9
    const ap_expr_t *e1 = node->node_arg1;
Packit 90a5c9
    const ap_expr_t *e2 = node->node_arg2;
Packit 90a5c9
    switch (node->node_op) {
Packit 90a5c9
    case op_EQ:
Packit 90a5c9
    case op_STR_EQ:
Packit 90a5c9
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
Packit 90a5c9
    case op_NE:
Packit 90a5c9
    case op_STR_NE:
Packit 90a5c9
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
Packit 90a5c9
    case op_LT:
Packit 90a5c9
    case op_STR_LT:
Packit 90a5c9
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
Packit 90a5c9
    case op_LE:
Packit 90a5c9
    case op_STR_LE:
Packit 90a5c9
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
Packit 90a5c9
    case op_GT:
Packit 90a5c9
    case op_STR_GT:
Packit 90a5c9
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
Packit 90a5c9
    case op_GE:
Packit 90a5c9
    case op_STR_GE:
Packit 90a5c9
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
Packit 90a5c9
    default:
Packit 90a5c9
        return ap_expr_eval_comp(ctx, node);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE_NONSTD(int) ap_expr_lookup_default(ap_expr_lookup_parms *parms)
Packit 90a5c9
{
Packit 90a5c9
    return ap_run_expr_lookup(parms);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
Packit 90a5c9
                                       ap_expr_info_t *info, const char *expr,
Packit 90a5c9
                                       ap_expr_lookup_fn_t *lookup_fn)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_parse_ctx_t ctx;
Packit 90a5c9
    int rc;
Packit 90a5c9
Packit 90a5c9
    ctx.pool     = pool;
Packit 90a5c9
    ctx.ptemp    = ptemp;
Packit 90a5c9
    ctx.inputbuf = expr;
Packit 90a5c9
    ctx.inputlen = strlen(expr);
Packit 90a5c9
    ctx.inputptr = ctx.inputbuf;
Packit 90a5c9
    ctx.expr     = NULL;
Packit 90a5c9
    ctx.error    = NULL;        /* generic bison error message (XXX: usually not very useful, should be axed) */
Packit 90a5c9
    ctx.error2   = NULL;        /* additional error message */
Packit 90a5c9
    ctx.flags    = info->flags;
Packit 90a5c9
    ctx.scan_del    = '\0';
Packit 90a5c9
    ctx.scan_buf[0] = '\0';
Packit 90a5c9
    ctx.scan_ptr    = ctx.scan_buf;
Packit 90a5c9
    ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_expr_lookup_default;
Packit 90a5c9
    ctx.at_start    = 1;
Packit 90a5c9
Packit 90a5c9
    ap_expr_yylex_init(&ctx.scanner);
Packit 90a5c9
    ap_expr_yyset_extra(&ctx, ctx.scanner);
Packit 90a5c9
    rc = ap_expr_yyparse(&ctx;;
Packit 90a5c9
    ap_expr_yylex_destroy(ctx.scanner);
Packit 90a5c9
    if (ctx.error) {
Packit 90a5c9
        if (ctx.error2)
Packit 90a5c9
            return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
Packit 90a5c9
        else
Packit 90a5c9
            return ctx.error;
Packit 90a5c9
    }
Packit 90a5c9
    else if (ctx.error2) {
Packit 90a5c9
        return ctx.error2;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (rc) /* XXX can this happen? */
Packit 90a5c9
        return "syntax error";
Packit 90a5c9
Packit 90a5c9
#ifdef AP_EXPR_DEBUG
Packit 90a5c9
    if (ctx.expr)
Packit 90a5c9
        expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    info->root_node = ctx.expr;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd_mi(const cmd_parms *cmd,
Packit 90a5c9
                                                 const char *expr,
Packit 90a5c9
                                                 unsigned int flags,
Packit 90a5c9
                                                 const char **err,
Packit 90a5c9
                                                 ap_expr_lookup_fn_t *lookup_fn,
Packit 90a5c9
                                                 int module_index)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
Packit 90a5c9
    info->filename = cmd->directive->filename;
Packit 90a5c9
    info->line_number = cmd->directive->line_num;
Packit 90a5c9
    info->flags = flags;
Packit 90a5c9
    info->module_index = module_index;
Packit 90a5c9
    *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
Packit 90a5c9
Packit 90a5c9
    if (*err)
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    return info;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
Packit 90a5c9
                      ap_expr_parse_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
Packit 90a5c9
    node->node_op   = op;
Packit 90a5c9
    node->node_arg1 = a1;
Packit 90a5c9
    node->node_arg2 = a2;
Packit 90a5c9
    return node;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static ap_expr_t *ap_expr_info_make(int type, const char *name,
Packit 90a5c9
                                  ap_expr_parse_ctx_t *ctx,
Packit 90a5c9
                                  const ap_expr_t *arg)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_t *info = apr_palloc(ctx->pool, sizeof(ap_expr_t));
Packit 90a5c9
    ap_expr_lookup_parms parms;
Packit 90a5c9
    parms.type  = type;
Packit 90a5c9
    parms.flags = ctx->flags;
Packit 90a5c9
    parms.pool  = ctx->pool;
Packit 90a5c9
    parms.ptemp = ctx->ptemp;
Packit 90a5c9
    parms.name  = name;
Packit 90a5c9
    parms.func  = &info->node_arg1;
Packit 90a5c9
    parms.data  = &info->node_arg2;
Packit 90a5c9
    parms.err   = &ctx->error2;
Packit 90a5c9
    parms.arg   = (arg && arg->node_op == op_String) ? arg->node_arg1 : NULL;
Packit 90a5c9
    if (ctx->lookup_fn(&parms) != OK)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    return info;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
ap_expr_t *ap_expr_str_func_make(const char *name, const ap_expr_t *arg,
Packit 90a5c9
                               ap_expr_parse_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx, arg);
Packit 90a5c9
    if (!info)
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    info->node_op = op_StringFuncInfo;
Packit 90a5c9
    return ap_expr_make(op_StringFuncCall, info, arg, ctx);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
Packit 90a5c9
                                ap_expr_parse_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx, arg);
Packit 90a5c9
    if (!info)
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    info->node_op = op_ListFuncInfo;
Packit 90a5c9
    return ap_expr_make(op_ListFuncCall, info, arg, ctx);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
ap_expr_t *ap_expr_unary_op_make(const char *name, const ap_expr_t *arg,
Packit 90a5c9
                               ap_expr_parse_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx, arg);
Packit 90a5c9
    if (!info)
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    info->node_op = op_UnaryOpInfo;
Packit 90a5c9
    return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
ap_expr_t *ap_expr_binary_op_make(const char *name, const ap_expr_t *arg1,
Packit 90a5c9
                                const ap_expr_t *arg2, ap_expr_parse_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_t *args;
Packit 90a5c9
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_BINARY, name, ctx,
Packit 90a5c9
                                        arg2);
Packit 90a5c9
    if (!info)
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    info->node_op = op_BinaryOpInfo;
Packit 90a5c9
    args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
Packit 90a5c9
    return ap_expr_make(op_BinaryOpCall, info, args, ctx);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
ap_expr_t *ap_expr_var_make(const char *name, ap_expr_parse_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_t *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx, NULL);
Packit 90a5c9
    if (!node)
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    node->node_op = op_Var;
Packit 90a5c9
    return node;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#ifdef AP_EXPR_DEBUG
Packit 90a5c9
Packit 90a5c9
#define MARK                        APLOG_MARK,loglevel,0,s
Packit 90a5c9
#define DUMP_E_E(op, e1, e2)                                                \
Packit 90a5c9
    do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2);      \
Packit 90a5c9
         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);               \
Packit 90a5c9
         if (e2) expr_dump_tree(e2, s, loglevel, indent + 2);               \
Packit 90a5c9
    } while (0)
Packit 90a5c9
#define DUMP_S_E(op, s1, e1)                                                    \
Packit 90a5c9
    do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
Packit 90a5c9
         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);                   \
Packit 90a5c9
    } while (0)
Packit 90a5c9
#define DUMP_S_P(op, s1, p1)                                                \
Packit 90a5c9
    ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
Packit 90a5c9
#define DUMP_P_P(op, p1, p2)                                                \
Packit 90a5c9
    ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
Packit 90a5c9
#define DUMP_S_S(op, s1, s2)                                                       \
Packit 90a5c9
    ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
Packit 90a5c9
#define DUMP_P(op, p1)                                                      \
Packit 90a5c9
    ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
Packit 90a5c9
#define DUMP_IP(op, p1)                                                     \
Packit 90a5c9
    ap_log_error(MARK,"%*s%s: %d", indent, " ", op, *(int *)p1);
Packit 90a5c9
#define DUMP_S(op, s1)                                                      \
Packit 90a5c9
    ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
Packit 90a5c9
Packit 90a5c9
#define CASE_OP(op)                  case op: name = #op ; break;
Packit 90a5c9
Packit 90a5c9
static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
Packit 90a5c9
                           int loglevel, int indent)
Packit 90a5c9
{
Packit 90a5c9
    switch (e->node_op) {
Packit 90a5c9
    /* no arg */
Packit 90a5c9
    case op_NOP:
Packit 90a5c9
    case op_True:
Packit 90a5c9
    case op_False:
Packit 90a5c9
        {
Packit 90a5c9
            char *name;
Packit 90a5c9
            switch (e->node_op) {
Packit 90a5c9
            CASE_OP(op_NOP);
Packit 90a5c9
            CASE_OP(op_True);
Packit 90a5c9
            CASE_OP(op_False);
Packit 90a5c9
            default:
Packit 90a5c9
                ap_assert(0);
Packit 90a5c9
            }
Packit 90a5c9
            ap_log_error(MARK, "%*s%s", indent, " ", name);
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
Packit 90a5c9
    /* arg1: string, arg2: expr */
Packit 90a5c9
    case op_UnaryOpCall:
Packit 90a5c9
    case op_BinaryOpCall:
Packit 90a5c9
    case op_BinaryOpArgs:
Packit 90a5c9
        {
Packit 90a5c9
            char *name;
Packit 90a5c9
            switch (e->node_op) {
Packit 90a5c9
            CASE_OP(op_BinaryOpCall);
Packit 90a5c9
            CASE_OP(op_UnaryOpCall);
Packit 90a5c9
            CASE_OP(op_BinaryOpArgs);
Packit 90a5c9
            default:
Packit 90a5c9
                ap_assert(0);
Packit 90a5c9
            }
Packit 90a5c9
            DUMP_S_E(name, e->node_arg1, e->node_arg2);
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
Packit 90a5c9
    /* arg1: expr, arg2: expr */
Packit 90a5c9
    case op_Comp:
Packit 90a5c9
    case op_Not:
Packit 90a5c9
    case op_Or:
Packit 90a5c9
    case op_And:
Packit 90a5c9
    case op_EQ:
Packit 90a5c9
    case op_NE:
Packit 90a5c9
    case op_LT:
Packit 90a5c9
    case op_LE:
Packit 90a5c9
    case op_GT:
Packit 90a5c9
    case op_GE:
Packit 90a5c9
    case op_STR_EQ:
Packit 90a5c9
    case op_STR_NE:
Packit 90a5c9
    case op_STR_LT:
Packit 90a5c9
    case op_STR_LE:
Packit 90a5c9
    case op_STR_GT:
Packit 90a5c9
    case op_STR_GE:
Packit 90a5c9
    case op_IN:
Packit 90a5c9
    case op_REG:
Packit 90a5c9
    case op_NRE:
Packit 90a5c9
    case op_Concat:
Packit 90a5c9
    case op_StringFuncCall:
Packit 90a5c9
    case op_ListFuncCall:
Packit 90a5c9
    case op_ListElement:
Packit 90a5c9
        {
Packit 90a5c9
            char *name;
Packit 90a5c9
            switch (e->node_op) {
Packit 90a5c9
            CASE_OP(op_Comp);
Packit 90a5c9
            CASE_OP(op_Not);
Packit 90a5c9
            CASE_OP(op_Or);
Packit 90a5c9
            CASE_OP(op_And);
Packit 90a5c9
            CASE_OP(op_EQ);
Packit 90a5c9
            CASE_OP(op_NE);
Packit 90a5c9
            CASE_OP(op_LT);
Packit 90a5c9
            CASE_OP(op_LE);
Packit 90a5c9
            CASE_OP(op_GT);
Packit 90a5c9
            CASE_OP(op_GE);
Packit 90a5c9
            CASE_OP(op_STR_EQ);
Packit 90a5c9
            CASE_OP(op_STR_NE);
Packit 90a5c9
            CASE_OP(op_STR_LT);
Packit 90a5c9
            CASE_OP(op_STR_LE);
Packit 90a5c9
            CASE_OP(op_STR_GT);
Packit 90a5c9
            CASE_OP(op_STR_GE);
Packit 90a5c9
            CASE_OP(op_IN);
Packit 90a5c9
            CASE_OP(op_REG);
Packit 90a5c9
            CASE_OP(op_NRE);
Packit 90a5c9
            CASE_OP(op_Concat);
Packit 90a5c9
            CASE_OP(op_StringFuncCall);
Packit 90a5c9
            CASE_OP(op_ListFuncCall);
Packit 90a5c9
            CASE_OP(op_ListElement);
Packit 90a5c9
            default:
Packit 90a5c9
                ap_assert(0);
Packit 90a5c9
            }
Packit 90a5c9
            DUMP_E_E(name, e->node_arg1, e->node_arg2);
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    /* arg1: string */
Packit 90a5c9
    case op_Digit:
Packit 90a5c9
    case op_String:
Packit 90a5c9
        {
Packit 90a5c9
            char *name;
Packit 90a5c9
            switch (e->node_op) {
Packit 90a5c9
            CASE_OP(op_Digit);
Packit 90a5c9
            CASE_OP(op_String);
Packit 90a5c9
            default:
Packit 90a5c9
                ap_assert(0);
Packit 90a5c9
            }
Packit 90a5c9
            DUMP_S(name, e->node_arg1);
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    /* arg1: pointer, arg2: pointer */
Packit 90a5c9
    case op_Var:
Packit 90a5c9
    case op_StringFuncInfo:
Packit 90a5c9
    case op_UnaryOpInfo:
Packit 90a5c9
    case op_BinaryOpInfo:
Packit 90a5c9
    case op_ListFuncInfo:
Packit 90a5c9
        {
Packit 90a5c9
            char *name;
Packit 90a5c9
            switch (e->node_op) {
Packit 90a5c9
            CASE_OP(op_Var);
Packit 90a5c9
            CASE_OP(op_StringFuncInfo);
Packit 90a5c9
            CASE_OP(op_UnaryOpInfo);
Packit 90a5c9
            CASE_OP(op_BinaryOpInfo);
Packit 90a5c9
            CASE_OP(op_ListFuncInfo);
Packit 90a5c9
            default:
Packit 90a5c9
                ap_assert(0);
Packit 90a5c9
            }
Packit 90a5c9
            DUMP_P_P(name, e->node_arg1, e->node_arg2);
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    /* arg1: pointer */
Packit 90a5c9
    case op_Regex:
Packit 90a5c9
        DUMP_P("op_Regex", e->node_arg1);
Packit 90a5c9
        break;
Packit 90a5c9
    /* arg1: pointer to int */
Packit 90a5c9
    case op_RegexBackref:
Packit 90a5c9
        DUMP_IP("op_RegexBackref", e->node_arg1);
Packit 90a5c9
        break;
Packit 90a5c9
    default:
Packit 90a5c9
        ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
Packit 90a5c9
        break;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
#endif /* AP_EXPR_DEBUG */
Packit 90a5c9
Packit 90a5c9
static int ap_expr_eval_unary_op(ap_expr_eval_ctx_t *ctx, const ap_expr_t *info,
Packit 90a5c9
                                 const ap_expr_t *arg)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_op_unary_t *op_func = (ap_expr_op_unary_t *)info->node_arg1;
Packit 90a5c9
    const void *data = info->node_arg2;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
Packit 90a5c9
    AP_DEBUG_ASSERT(op_func != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(data != NULL);
Packit 90a5c9
    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int ap_expr_eval_binary_op(ap_expr_eval_ctx_t *ctx,
Packit 90a5c9
                                  const ap_expr_t *info,
Packit 90a5c9
                                  const ap_expr_t *args)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_op_binary_t *op_func = (ap_expr_op_binary_t *)info->node_arg1;
Packit 90a5c9
    const void *data = info->node_arg2;
Packit 90a5c9
    const ap_expr_t *a1 = args->node_arg1;
Packit 90a5c9
    const ap_expr_t *a2 = args->node_arg2;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
Packit 90a5c9
    AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
Packit 90a5c9
    AP_DEBUG_ASSERT(op_func != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(data != NULL);
Packit 90a5c9
    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
Packit 90a5c9
                      ap_expr_eval_word(ctx, a2));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static int ap_expr_eval(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
Packit 90a5c9
{
Packit 90a5c9
    const ap_expr_t *e1 = node->node_arg1;
Packit 90a5c9
    const ap_expr_t *e2 = node->node_arg2;
Packit 90a5c9
    int result = FALSE;
Packit 90a5c9
    if (inc_rec(ctx))
Packit 90a5c9
        return result;
Packit 90a5c9
    while (1) {
Packit 90a5c9
        switch (node->node_op) {
Packit 90a5c9
        case op_True:
Packit 90a5c9
            result ^= TRUE;
Packit 90a5c9
            goto out;
Packit 90a5c9
        case op_False:
Packit 90a5c9
            result ^= FALSE;
Packit 90a5c9
            goto out;
Packit 90a5c9
        case op_Not:
Packit 90a5c9
            result = !result;
Packit 90a5c9
            node = e1;
Packit 90a5c9
            break;
Packit 90a5c9
        case op_Or:
Packit 90a5c9
            do {
Packit 90a5c9
                if (e1->node_op == op_Not) {
Packit 90a5c9
                    if (!ap_expr_eval(ctx, e1->node_arg1)) {
Packit 90a5c9
                        result ^= TRUE;
Packit 90a5c9
                        goto out;
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    if (ap_expr_eval(ctx, e1)) {
Packit 90a5c9
                        result ^= TRUE;
Packit 90a5c9
                        goto out;
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                node = node->node_arg2;
Packit 90a5c9
                e1 = node->node_arg1;
Packit 90a5c9
            } while (node->node_op == op_Or);
Packit 90a5c9
            break;
Packit 90a5c9
        case op_And:
Packit 90a5c9
            do {
Packit 90a5c9
                if (e1->node_op == op_Not) {
Packit 90a5c9
                    if (ap_expr_eval(ctx, e1->node_arg1)) {
Packit 90a5c9
                        result ^= FALSE;
Packit 90a5c9
                        goto out;
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    if (!ap_expr_eval(ctx, e1)) {
Packit 90a5c9
                        result ^= FALSE;
Packit 90a5c9
                        goto out;
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                node = node->node_arg2;
Packit 90a5c9
                e1 = node->node_arg1;
Packit 90a5c9
            } while (node->node_op == op_And);
Packit 90a5c9
            break;
Packit 90a5c9
        case op_UnaryOpCall:
Packit 90a5c9
            result ^= ap_expr_eval_unary_op(ctx, e1, e2);
Packit 90a5c9
            goto out;
Packit 90a5c9
        case op_BinaryOpCall:
Packit 90a5c9
            result ^= ap_expr_eval_binary_op(ctx, e1, e2);
Packit 90a5c9
            goto out;
Packit 90a5c9
        case op_Comp:
Packit 90a5c9
            if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
Packit 90a5c9
                result ^= ssl_expr_eval_comp(ctx, e1);
Packit 90a5c9
            else
Packit 90a5c9
                result ^= ap_expr_eval_comp(ctx, e1);
Packit 90a5c9
            goto out;
Packit 90a5c9
        default:
Packit 90a5c9
            *ctx->err = "Internal evaluation error: Unknown expression node";
Packit 90a5c9
            goto out;
Packit 90a5c9
        }
Packit 90a5c9
        e1 = node->node_arg1;
Packit 90a5c9
        e2 = node->node_arg2;
Packit 90a5c9
    }
Packit 90a5c9
out:
Packit 90a5c9
    ctx->reclvl--;
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info,
Packit 90a5c9
                             const char **err)
Packit 90a5c9
{
Packit 90a5c9
    return ap_expr_exec_re(r, info, 0, NULL, NULL, err);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
Packit 90a5c9
{
Packit 90a5c9
    int rc;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(ctx->p != NULL);
Packit 90a5c9
    /* XXX: allow r, c == NULL */
Packit 90a5c9
    AP_DEBUG_ASSERT(ctx->r != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(ctx->c != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(ctx->s != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(ctx->err != NULL);
Packit 90a5c9
    AP_DEBUG_ASSERT(ctx->info != NULL);
Packit 90a5c9
    if (ctx->re_pmatch) {
Packit 90a5c9
        AP_DEBUG_ASSERT(ctx->re_source != NULL);
Packit 90a5c9
        AP_DEBUG_ASSERT(ctx->re_nmatch > 0);
Packit 90a5c9
    }
Packit 90a5c9
    ctx->reclvl = 0;
Packit 90a5c9
Packit 90a5c9
    *ctx->err = NULL;
Packit 90a5c9
    if (ctx->info->flags & AP_EXPR_FLAG_STRING_RESULT) {
Packit 90a5c9
        *ctx->result_string = ap_expr_eval_word(ctx, ctx->info->root_node);
Packit 90a5c9
        if (*ctx->err != NULL) {
Packit 90a5c9
            ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
Packit 90a5c9
                          "Evaluation of expression from %s:%d failed: %s",
Packit 90a5c9
                          ctx->info->filename, ctx->info->line_number, *ctx->err);
Packit 90a5c9
            return -1;
Packit 90a5c9
        } else {
Packit 90a5c9
            ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
Packit 90a5c9
                          "Evaluation of string expression from %s:%d gave: %s",
Packit 90a5c9
                          ctx->info->filename, ctx->info->line_number,
Packit 90a5c9
                          *ctx->result_string);
Packit 90a5c9
            return 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        rc = ap_expr_eval(ctx, ctx->info->root_node);
Packit 90a5c9
        if (*ctx->err != NULL) {
Packit 90a5c9
            ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
Packit 90a5c9
                          "Evaluation of expression from %s:%d failed: %s",
Packit 90a5c9
                          ctx->info->filename, ctx->info->line_number, *ctx->err);
Packit 90a5c9
            return -1;
Packit 90a5c9
        } else {
Packit 90a5c9
            rc = rc ? 1 : 0;
Packit 90a5c9
            ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
Packit 90a5c9
                          "Evaluation of expression from %s:%d gave: %d",
Packit 90a5c9
                          ctx->info->filename, ctx->info->line_number, rc);
Packit 90a5c9
Packit 90a5c9
            if (ctx->vary_this && *ctx->vary_this)
Packit 90a5c9
                apr_table_merge(ctx->r->headers_out, "Vary", *ctx->vary_this);
Packit 90a5c9
Packit 90a5c9
            return rc;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info,
Packit 90a5c9
                                apr_size_t nmatch, ap_regmatch_t *pmatch,
Packit 90a5c9
                                const char **source, const char **err)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_eval_ctx_t ctx;
Packit 90a5c9
    int dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
Packit 90a5c9
    const char *tmp_source = NULL, *vary_this = NULL;
Packit 90a5c9
    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT((info->flags & AP_EXPR_FLAG_STRING_RESULT) == 0);
Packit 90a5c9
Packit 90a5c9
    ctx.r = r;
Packit 90a5c9
    ctx.c = r->connection;
Packit 90a5c9
    ctx.s = r->server;
Packit 90a5c9
    ctx.p = r->pool;
Packit 90a5c9
    ctx.err  = err;
Packit 90a5c9
    ctx.info = info;
Packit 90a5c9
    ctx.re_nmatch = nmatch;
Packit 90a5c9
    ctx.re_pmatch = pmatch;
Packit 90a5c9
    ctx.re_source = source;
Packit 90a5c9
    ctx.vary_this = dont_vary ? NULL : &vary_this;
Packit 90a5c9
    ctx.data = NULL;
Packit 90a5c9
Packit 90a5c9
    if (!pmatch) {
Packit 90a5c9
        ctx.re_nmatch = AP_MAX_REG_MATCH;
Packit 90a5c9
        ctx.re_pmatch = tmp_pmatch;
Packit 90a5c9
        ctx.re_source = &tmp_source;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return ap_expr_exec_ctx(&ctx;;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(const char *) ap_expr_str_exec_re(request_rec *r,
Packit 90a5c9
                                             const ap_expr_info_t *info,
Packit 90a5c9
                                             apr_size_t nmatch,
Packit 90a5c9
                                             ap_regmatch_t *pmatch,
Packit 90a5c9
                                             const char **source,
Packit 90a5c9
                                             const char **err)
Packit 90a5c9
{
Packit 90a5c9
    ap_expr_eval_ctx_t ctx;
Packit 90a5c9
    int dont_vary, rc;
Packit 90a5c9
    const char *tmp_source, *vary_this;
Packit 90a5c9
    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
Packit 90a5c9
    const char *result;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(info->flags & AP_EXPR_FLAG_STRING_RESULT);
Packit 90a5c9
Packit 90a5c9
    if (info->root_node->node_op == op_String) {
Packit 90a5c9
        /* short-cut for constant strings */
Packit 90a5c9
        *err = NULL;
Packit 90a5c9
        return (const char *)info->root_node->node_arg1;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    tmp_source = NULL;
Packit 90a5c9
    vary_this = NULL;
Packit 90a5c9
Packit 90a5c9
    dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
Packit 90a5c9
Packit 90a5c9
    ctx.r = r;
Packit 90a5c9
    ctx.c = r->connection;
Packit 90a5c9
    ctx.s = r->server;
Packit 90a5c9
    ctx.p = r->pool;
Packit 90a5c9
    ctx.err  = err;
Packit 90a5c9
    ctx.info = info;
Packit 90a5c9
    ctx.re_nmatch = nmatch;
Packit 90a5c9
    ctx.re_pmatch = pmatch;
Packit 90a5c9
    ctx.re_source = source;
Packit 90a5c9
    ctx.vary_this = dont_vary ? NULL : &vary_this;
Packit 90a5c9
    ctx.data = NULL;
Packit 90a5c9
    ctx.result_string = &result;
Packit 90a5c9
Packit 90a5c9
    if (!pmatch) {
Packit 90a5c9
        ctx.re_nmatch = AP_MAX_REG_MATCH;
Packit 90a5c9
        ctx.re_pmatch = tmp_pmatch;
Packit 90a5c9
        ctx.re_source = &tmp_source;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    rc = ap_expr_exec_ctx(&ctx;;
Packit 90a5c9
    if (rc > 0)
Packit 90a5c9
        return result;
Packit 90a5c9
    else if (rc < 0)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    else
Packit 90a5c9
        ap_assert(0);
Packit 90a5c9
    /* Not reached */
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(const char *) ap_expr_str_exec(request_rec *r,
Packit 90a5c9
                                          const ap_expr_info_t *info,
Packit 90a5c9
                                          const char **err)
Packit 90a5c9
{
Packit 90a5c9
    return ap_expr_str_exec_re(r, info, 0, NULL, NULL, err);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static void add_vary(ap_expr_eval_ctx_t *ctx, const char *name)
Packit 90a5c9
{
Packit 90a5c9
    if (!ctx->vary_this)
Packit 90a5c9
        return;
Packit 90a5c9
Packit 90a5c9
    if (*ctx->vary_this) {
Packit 90a5c9
        *ctx->vary_this = apr_pstrcat(ctx->p, *ctx->vary_this, ", ", name,
Packit 90a5c9
                                      NULL);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        *ctx->vary_this = name;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *req_table_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                                  const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    const char *name = (const char *)data;
Packit 90a5c9
    apr_table_t *t;
Packit 90a5c9
    if (!ctx->r)
Packit 90a5c9
        return "";
Packit 90a5c9
Packit 90a5c9
    if (name[2] == 's') {           /* resp */
Packit 90a5c9
        /* Try r->headers_out first, fall back on err_headers_out. */
Packit 90a5c9
        const char *v = apr_table_get(ctx->r->headers_out, arg);
Packit 90a5c9
        if (v) {
Packit 90a5c9
            return v;
Packit 90a5c9
        }
Packit 90a5c9
        t = ctx->r->err_headers_out;
Packit 90a5c9
    }
Packit 90a5c9
    else if (name[0] == 'n')        /* notes */
Packit 90a5c9
        t = ctx->r->notes;
Packit 90a5c9
    else if (name[3] == 'e')        /* reqenv */
Packit 90a5c9
        t = ctx->r->subprocess_env;
Packit 90a5c9
    else if (name[3] == '_')        /* req_novary */
Packit 90a5c9
        t = ctx->r->headers_in;
Packit 90a5c9
    else {                          /* req, http */
Packit 90a5c9
        t = ctx->r->headers_in;
Packit 90a5c9
        /* Skip the 'Vary: Host' header combination
Packit 90a5c9
         * as indicated in rfc7231 section-7.1.4
Packit 90a5c9
         */
Packit 90a5c9
        if (strcasecmp(arg, "Host")){
Packit 90a5c9
            add_vary(ctx, arg);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return apr_table_get(t, arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *env_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                            const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    const char *res;
Packit 90a5c9
    /* this order is for ssl_expr compatibility */
Packit 90a5c9
    if (ctx->r) {
Packit 90a5c9
        if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
Packit 90a5c9
            return res;
Packit 90a5c9
        else if ((res = apr_table_get(ctx->r->subprocess_env, arg)) != NULL)
Packit 90a5c9
            return res;
Packit 90a5c9
    }
Packit 90a5c9
    return getenv(arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *osenv_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                              const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    return getenv(arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *tolower_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                                const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    char *result = apr_pstrdup(ctx->p, arg);
Packit 90a5c9
    ap_str_tolower(result);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *toupper_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                                const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    char *result = apr_pstrdup(ctx->p, arg);
Packit 90a5c9
    ap_str_toupper(result);
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *escape_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                               const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    return ap_escape_uri(ctx->p, arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *base64_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                               const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    return ap_pbase64encode(ctx->p, (char *)arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *unbase64_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                               const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    return ap_pbase64decode(ctx->p, arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *sha1_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                               const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    apr_sha1_ctx_t context;
Packit 90a5c9
    apr_byte_t sha1[APR_SHA1_DIGESTSIZE];
Packit 90a5c9
    char *out;
Packit 90a5c9
Packit 90a5c9
    out = apr_palloc(ctx->p, APR_SHA1_DIGESTSIZE*2+1);
Packit 90a5c9
Packit 90a5c9
    apr_sha1_init(&context);
Packit 90a5c9
    apr_sha1_update(&context, arg, strlen(arg));
Packit 90a5c9
    apr_sha1_final(sha1, &context);
Packit 90a5c9
Packit 90a5c9
    ap_bin2hex(sha1, APR_SHA1_DIGESTSIZE, out);
Packit 90a5c9
Packit 90a5c9
    return out;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *md5_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                               const char *arg)
Packit 90a5c9
{
Packit 90a5c9
	return ap_md5(ctx->p, (const unsigned char *)arg);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
#define MAX_FILE_SIZE 10*1024*1024
Packit 90a5c9
static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                             char *arg)
Packit 90a5c9
{
Packit 90a5c9
    apr_file_t *fp;
Packit 90a5c9
    char *buf;
Packit 90a5c9
    apr_off_t offset;
Packit 90a5c9
    apr_size_t len;
Packit 90a5c9
    apr_finfo_t finfo;
Packit 90a5c9
Packit 90a5c9
    if (apr_file_open(&fp, arg, APR_READ|APR_BUFFERED,
Packit 90a5c9
                      APR_OS_DEFAULT, ctx->p) != APR_SUCCESS) {
Packit 90a5c9
        *ctx->err = apr_psprintf(ctx->p, "Cannot open file %s", arg);
Packit 90a5c9
        return "";
Packit 90a5c9
    }
Packit 90a5c9
    apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
Packit 90a5c9
    if (finfo.size > MAX_FILE_SIZE) {
Packit 90a5c9
        *ctx->err = apr_psprintf(ctx->p, "File %s too large", arg);
Packit 90a5c9
        apr_file_close(fp);
Packit 90a5c9
        return "";
Packit 90a5c9
    }
Packit 90a5c9
    len = (apr_size_t)finfo.size;
Packit 90a5c9
    if (len == 0) {
Packit 90a5c9
        apr_file_close(fp);
Packit 90a5c9
        return "";
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        if ((buf = (char *)apr_palloc(ctx->p, sizeof(char)*(len+1))) == NULL) {
Packit 90a5c9
            *ctx->err = "Cannot allocate memory";
Packit 90a5c9
            apr_file_close(fp);
Packit 90a5c9
            return "";
Packit 90a5c9
        }
Packit 90a5c9
        offset = 0;
Packit 90a5c9
        apr_file_seek(fp, APR_SET, &offset);
Packit 90a5c9
        if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
Packit 90a5c9
            *ctx->err = apr_psprintf(ctx->p, "Cannot read from file %s", arg);
Packit 90a5c9
            apr_file_close(fp);
Packit 90a5c9
            return "";
Packit 90a5c9
        }
Packit 90a5c9
        buf[len] = '\0';
Packit 90a5c9
    }
Packit 90a5c9
    apr_file_close(fp);
Packit 90a5c9
    return buf;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                                  char *arg)
Packit 90a5c9
{
Packit 90a5c9
    apr_finfo_t sb;
Packit 90a5c9
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
Packit 90a5c9
        && sb.filetype == APR_REG && sb.size > 0)
Packit 90a5c9
        return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
Packit 90a5c9
    else
Packit 90a5c9
        return "0";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *unescape_func(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                                 const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    char *result = apr_pstrdup(ctx->p, arg);
Packit 90a5c9
    int ret = ap_unescape_url_keep2f(result, 0);
Packit 90a5c9
    if (ret == OK)
Packit 90a5c9
        return result;
Packit 90a5c9
    ap_log_rerror(LOG_MARK(ctx->info), APLOG_DEBUG, 0, ctx->r, APLOGNO(00538)
Packit 90a5c9
                  "%s %% escape in unescape('%s') at %s:%d",
Packit 90a5c9
                  ret == HTTP_BAD_REQUEST ? "Bad" : "Forbidden", arg,
Packit 90a5c9
                  ctx->info->filename, ctx->info->line_number);
Packit 90a5c9
    return "";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_nz(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    const char *name = (const char *)data;
Packit 90a5c9
    if (name[0] == 'z')
Packit 90a5c9
        return (arg[0] == '\0');
Packit 90a5c9
    else
Packit 90a5c9
        return (arg[0] != '\0');
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_file_min(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    apr_finfo_t sb;
Packit 90a5c9
    const char *name = (const char *)data;
Packit 90a5c9
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
Packit 90a5c9
        return FALSE;
Packit 90a5c9
    switch (name[0]) {
Packit 90a5c9
    case 'd':
Packit 90a5c9
        return (sb.filetype == APR_DIR);
Packit 90a5c9
    case 'e':
Packit 90a5c9
        return TRUE;
Packit 90a5c9
    case 'f':
Packit 90a5c9
        return (sb.filetype == APR_REG);
Packit 90a5c9
    case 's':
Packit 90a5c9
        return (sb.filetype == APR_REG && sb.size > 0);
Packit 90a5c9
    default:
Packit 90a5c9
        ap_assert(0);
Packit 90a5c9
    }
Packit 90a5c9
    return FALSE;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_file_link(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
#if !defined(OS2)
Packit 90a5c9
    apr_finfo_t sb;
Packit 90a5c9
    if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
Packit 90a5c9
        && sb.filetype == APR_LNK) {
Packit 90a5c9
        return TRUE;
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
    return FALSE;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    apr_finfo_t sb;
Packit 90a5c9
    if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
Packit 90a5c9
        && (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
Packit 90a5c9
        return TRUE;
Packit 90a5c9
    }
Packit 90a5c9
    return FALSE;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_url_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    int rc = FALSE;
Packit 90a5c9
    request_rec  *rsub, *r = ctx->r;
Packit 90a5c9
    if (!r)
Packit 90a5c9
        return FALSE;
Packit 90a5c9
    /* avoid some infinite recursions */
Packit 90a5c9
    if (r->main && r->main->uri && r->uri && strcmp(r->main->uri, r->uri) == 0)
Packit 90a5c9
        return FALSE;
Packit 90a5c9
Packit 90a5c9
    rsub = ap_sub_req_lookup_uri(arg, r, NULL);
Packit 90a5c9
    if (rsub->status < 400) {
Packit 90a5c9
            rc = TRUE;
Packit 90a5c9
    }
Packit 90a5c9
    ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
Packit 90a5c9
                  "Subrequest for -U %s at %s:%d gave status: %d",
Packit 90a5c9
                  arg, ctx->info->filename, ctx->info->line_number,
Packit 90a5c9
                  rsub->status);
Packit 90a5c9
    ap_destroy_sub_req(rsub);
Packit 90a5c9
    return rc;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_file_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    int rc = FALSE;
Packit 90a5c9
    apr_finfo_t sb;
Packit 90a5c9
    request_rec *rsub, *r = ctx->r;
Packit 90a5c9
    if (!r)
Packit 90a5c9
        return FALSE;
Packit 90a5c9
    rsub = ap_sub_req_lookup_file(arg, r, NULL);
Packit 90a5c9
    if (rsub->status < 300 &&
Packit 90a5c9
        /* double-check that file exists since default result is 200 */
Packit 90a5c9
        apr_stat(&sb, rsub->filename, APR_FINFO_MIN, ctx->p) == APR_SUCCESS) {
Packit 90a5c9
        rc = TRUE;
Packit 90a5c9
    }
Packit 90a5c9
    ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
Packit 90a5c9
                  "Subrequest for -F %s at %s:%d gave status: %d",
Packit 90a5c9
                  arg, ctx->info->filename, ctx->info->line_number,
Packit 90a5c9
                  rsub->status);
Packit 90a5c9
    ap_destroy_sub_req(rsub);
Packit 90a5c9
    return rc;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(ssl_is_https) *is_https = NULL;
Packit 90a5c9
Packit 90a5c9
APR_DECLARE_OPTIONAL_FN(int, http2_is_h2, (conn_rec *));
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(http2_is_h2) *is_http2 = NULL;
Packit 90a5c9
Packit 90a5c9
static const char *conn_var_names[] = {
Packit 90a5c9
    "HTTPS",                    /*  0 */
Packit 90a5c9
    "IPV6",                     /*  1 */
Packit 90a5c9
    "CONN_LOG_ID",              /*  2 */
Packit 90a5c9
    "CONN_REMOTE_ADDR",         /*  3 */
Packit 90a5c9
    "HTTP2",                    /*  4 */
Packit 90a5c9
    NULL
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const char *conn_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
Packit 90a5c9
{
Packit 90a5c9
    int index = ((const char **)data - conn_var_names);
Packit 90a5c9
    conn_rec *c = ctx->c;
Packit 90a5c9
    if (!c)
Packit 90a5c9
        return "";
Packit 90a5c9
Packit 90a5c9
    switch (index) {
Packit 90a5c9
    case 0:
Packit 90a5c9
        if (is_https && is_https(c))
Packit 90a5c9
            return "on";
Packit 90a5c9
        else
Packit 90a5c9
            return "off";
Packit 90a5c9
    case 1:
Packit 90a5c9
#if APR_HAVE_IPV6
Packit 90a5c9
        {
Packit 90a5c9
            apr_sockaddr_t *addr = c->client_addr;
Packit 90a5c9
            if (addr->family == AF_INET6
Packit 90a5c9
                && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr))
Packit 90a5c9
                return "on";
Packit 90a5c9
            else
Packit 90a5c9
                return "off";
Packit 90a5c9
        }
Packit 90a5c9
#else
Packit 90a5c9
        return "off";
Packit 90a5c9
#endif
Packit 90a5c9
    case 2:
Packit 90a5c9
        return c->log_id;
Packit 90a5c9
    case 3:
Packit 90a5c9
        return c->client_ip;
Packit 90a5c9
    case 4:
Packit 90a5c9
        if (is_http2 && is_http2(c))
Packit 90a5c9
            return "on";
Packit 90a5c9
        else
Packit 90a5c9
            return "off";
Packit 90a5c9
    default:
Packit 90a5c9
        ap_assert(0);
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *request_var_names[] = {
Packit 90a5c9
    "REQUEST_METHOD",           /*  0 */
Packit 90a5c9
    "REQUEST_SCHEME",           /*  1 */
Packit 90a5c9
    "REQUEST_URI",              /*  2 */
Packit 90a5c9
    "REQUEST_FILENAME",         /*  3 */
Packit 90a5c9
    "REMOTE_HOST",              /*  4 */
Packit 90a5c9
    "REMOTE_IDENT",             /*  5 */
Packit 90a5c9
    "REMOTE_USER",              /*  6 */
Packit 90a5c9
    "SERVER_ADMIN",             /*  7 */
Packit 90a5c9
    "SERVER_NAME",              /*  8 */
Packit 90a5c9
    "SERVER_PORT",              /*  9 */
Packit 90a5c9
    "SERVER_PROTOCOL",          /* 10 */
Packit 90a5c9
    "SCRIPT_FILENAME",          /* 11 */
Packit 90a5c9
    "PATH_INFO",                /* 12 */
Packit 90a5c9
    "QUERY_STRING",             /* 13 */
Packit 90a5c9
    "IS_SUBREQ",                /* 14 */
Packit 90a5c9
    "DOCUMENT_ROOT",            /* 15 */
Packit 90a5c9
    "AUTH_TYPE",                /* 16 */
Packit 90a5c9
    "THE_REQUEST",              /* 17 */
Packit 90a5c9
    "CONTENT_TYPE",             /* 18 */
Packit 90a5c9
    "HANDLER",                  /* 19 */
Packit 90a5c9
    "REQUEST_LOG_ID",           /* 20 */
Packit 90a5c9
    "SCRIPT_USER",              /* 21 */
Packit 90a5c9
    "SCRIPT_GROUP",             /* 22 */
Packit 90a5c9
    "DOCUMENT_URI",             /* 23 */
Packit 90a5c9
    "LAST_MODIFIED",            /* 24 */
Packit 90a5c9
    "CONTEXT_PREFIX",           /* 25 */
Packit 90a5c9
    "CONTEXT_DOCUMENT_ROOT",    /* 26 */
Packit 90a5c9
    "REQUEST_STATUS",           /* 27 */
Packit 90a5c9
    "REMOTE_ADDR",              /* 28 */
Packit 90a5c9
    "REMOTE_PORT",              /* 29 */
Packit 90a5c9
    NULL
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
Packit 90a5c9
{
Packit 90a5c9
    int index = ((const char **)data - request_var_names);
Packit 90a5c9
    request_rec *r = ctx->r;
Packit 90a5c9
    if (!r)
Packit 90a5c9
        return "";
Packit 90a5c9
Packit 90a5c9
    switch (index) {
Packit 90a5c9
    case 0:
Packit 90a5c9
        return r->method;
Packit 90a5c9
    case 1:
Packit 90a5c9
        return ap_http_scheme(r);
Packit 90a5c9
    case 2:
Packit 90a5c9
        return r->uri;
Packit 90a5c9
    case 3:
Packit 90a5c9
        return r->filename;
Packit 90a5c9
    case 4:
Packit 90a5c9
        return ap_get_useragent_host(r, REMOTE_NAME, NULL);
Packit 90a5c9
    case 5:
Packit 90a5c9
        return ap_get_remote_logname(r);
Packit 90a5c9
    case 6:
Packit 90a5c9
        return r->user;
Packit 90a5c9
    case 7:
Packit 90a5c9
        return r->server->server_admin;
Packit 90a5c9
    case 8:
Packit 90a5c9
        return ap_get_server_name_for_url(r);
Packit 90a5c9
    case 9:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
Packit 90a5c9
    case 10:
Packit 90a5c9
        return r->protocol;
Packit 90a5c9
    case 11:
Packit 90a5c9
        return r->filename;
Packit 90a5c9
    case 12:
Packit 90a5c9
        return r->path_info;
Packit 90a5c9
    case 13:
Packit 90a5c9
        return r->args;
Packit 90a5c9
    case 14:
Packit 90a5c9
        return (r->main != NULL ? "true" : "false");
Packit 90a5c9
    case 15:
Packit 90a5c9
        return ap_document_root(r);
Packit 90a5c9
    case 16:
Packit 90a5c9
        return r->ap_auth_type;
Packit 90a5c9
    case 17:
Packit 90a5c9
        return r->the_request;
Packit 90a5c9
    case 18:
Packit 90a5c9
        return r->content_type;
Packit 90a5c9
    case 19:
Packit 90a5c9
        return r->handler;
Packit 90a5c9
    case 20:
Packit 90a5c9
        return r->log_id;
Packit 90a5c9
    case 21:
Packit 90a5c9
        {
Packit 90a5c9
            char *result = "";
Packit 90a5c9
            if (r->finfo.valid & APR_FINFO_USER)
Packit 90a5c9
                apr_uid_name_get(&result, r->finfo.user, ctx->p);
Packit 90a5c9
            return result;
Packit 90a5c9
        }
Packit 90a5c9
    case 22:
Packit 90a5c9
        {
Packit 90a5c9
            char *result = "";
Packit 90a5c9
            if (r->finfo.valid & APR_FINFO_USER)
Packit 90a5c9
                apr_gid_name_get(&result, r->finfo.group, ctx->p);
Packit 90a5c9
            return result;
Packit 90a5c9
        }
Packit 90a5c9
    case 23:
Packit 90a5c9
        {
Packit 90a5c9
            const char *uri = apr_table_get(r->subprocess_env, "DOCUMENT_URI");
Packit 90a5c9
            return uri ? uri : r->uri;
Packit 90a5c9
        }
Packit 90a5c9
    case 24:
Packit 90a5c9
        {
Packit 90a5c9
            apr_time_exp_t tm;
Packit 90a5c9
            apr_time_exp_lt(&tm, r->mtime);
Packit 90a5c9
            return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
Packit 90a5c9
                                (tm.tm_year / 100) + 19, (tm.tm_year % 100),
Packit 90a5c9
                                tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
Packit 90a5c9
                                tm.tm_sec);
Packit 90a5c9
        }
Packit 90a5c9
    case 25:
Packit 90a5c9
        return ap_context_prefix(r);
Packit 90a5c9
    case 26:
Packit 90a5c9
        return ap_context_document_root(r);
Packit 90a5c9
    case 27:
Packit 90a5c9
        return r->status ? apr_psprintf(ctx->p, "%d", r->status) : "";
Packit 90a5c9
    case 28:
Packit 90a5c9
        return r->useragent_ip;
Packit 90a5c9
    case 29:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%u", ctx->c->client_addr->port);
Packit 90a5c9
    default:
Packit 90a5c9
        ap_assert(0);
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *req_header_var_names[] = {
Packit 90a5c9
    "HTTP_USER_AGENT",       /* 0 */
Packit 90a5c9
    "HTTP_PROXY_CONNECTION", /* 1 */
Packit 90a5c9
    "HTTP_REFERER",          /* 2 */
Packit 90a5c9
    "HTTP_COOKIE",           /* 3 */
Packit 90a5c9
    "HTTP_FORWARDED",        /* 4 */
Packit 90a5c9
    "HTTP_HOST",             /* 5 */
Packit 90a5c9
    "HTTP_ACCEPT",           /* 6 */
Packit 90a5c9
    NULL
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const char *req_header_header_names[] = {
Packit 90a5c9
    "User-Agent",
Packit 90a5c9
    "Proxy-Connection",
Packit 90a5c9
    "Referer",
Packit 90a5c9
    "Cookie",
Packit 90a5c9
    "Forwarded",
Packit 90a5c9
    "Host",
Packit 90a5c9
    "Accept"
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const char *req_header_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
Packit 90a5c9
{
Packit 90a5c9
    const char **varname = (const char **)data;
Packit 90a5c9
    int index = (varname - req_header_var_names);
Packit 90a5c9
    const char *name;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(index < 7);
Packit 90a5c9
    if (!ctx->r)
Packit 90a5c9
        return "";
Packit 90a5c9
Packit 90a5c9
    name = req_header_header_names[index];
Packit 90a5c9
    /* Skip the 'Vary: Host' header combination
Packit 90a5c9
     * as indicated in rfc7231 section-7.1.4
Packit 90a5c9
     */
Packit 90a5c9
    if (strcasecmp(name, "Host")){
Packit 90a5c9
        add_vary(ctx, name);
Packit 90a5c9
    }
Packit 90a5c9
    return apr_table_get(ctx->r->headers_in, name);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *misc_var_names[] = {
Packit 90a5c9
    "TIME_YEAR",        /* 0 */
Packit 90a5c9
    "TIME_MON",         /* 1 */
Packit 90a5c9
    "TIME_DAY",         /* 2 */
Packit 90a5c9
    "TIME_HOUR",        /* 3 */
Packit 90a5c9
    "TIME_MIN",         /* 4 */
Packit 90a5c9
    "TIME_SEC",         /* 5 */
Packit 90a5c9
    "TIME_WDAY",        /* 6 */
Packit 90a5c9
    "TIME",             /* 7 */
Packit 90a5c9
    "SERVER_SOFTWARE",  /* 8 */
Packit 90a5c9
    "API_VERSION",      /* 9 */
Packit 90a5c9
    NULL
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const char *misc_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
Packit 90a5c9
{
Packit 90a5c9
    apr_time_exp_t tm;
Packit 90a5c9
    int index = ((const char **)data - misc_var_names);
Packit 90a5c9
    apr_time_exp_lt(&tm, apr_time_now());
Packit 90a5c9
Packit 90a5c9
    switch (index) {
Packit 90a5c9
    case 0:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
Packit 90a5c9
                            tm.tm_year % 100);
Packit 90a5c9
    case 1:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
Packit 90a5c9
    case 2:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
Packit 90a5c9
    case 3:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
Packit 90a5c9
    case 4:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%02d", tm.tm_min);
Packit 90a5c9
    case 5:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
Packit 90a5c9
    case 6:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%d", tm.tm_wday);
Packit 90a5c9
    case 7:
Packit 90a5c9
        return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
Packit 90a5c9
                            (tm.tm_year / 100) + 19, (tm.tm_year % 100),
Packit 90a5c9
                            tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
Packit 90a5c9
                            tm.tm_sec);
Packit 90a5c9
    case 8:
Packit 90a5c9
        return ap_get_server_banner();
Packit 90a5c9
    case 9:
Packit 90a5c9
        return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER_MAJOR);
Packit 90a5c9
    default:
Packit 90a5c9
        ap_assert(0);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int subnet_parse_arg(ap_expr_lookup_parms *parms)
Packit 90a5c9
{
Packit 90a5c9
    apr_ipsubnet_t *subnet;
Packit 90a5c9
    const char *addr = parms->arg;
Packit 90a5c9
    const char *mask;
Packit 90a5c9
    apr_status_t ret;
Packit 90a5c9
Packit 90a5c9
    if (!parms->arg) {
Packit 90a5c9
        *parms->err = apr_psprintf(parms->ptemp,
Packit 90a5c9
                                   "-%s requires subnet/netmask as constant argument",
Packit 90a5c9
                                   parms->name);
Packit 90a5c9
        return !OK;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    mask = ap_strchr_c(addr, '/');
Packit 90a5c9
    if (mask) {
Packit 90a5c9
        addr = apr_pstrmemdup(parms->ptemp, addr, mask - addr);
Packit 90a5c9
        mask++;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ret = apr_ipsubnet_create(&subnet, addr, mask, parms->pool);
Packit 90a5c9
    if (ret != APR_SUCCESS) {
Packit 90a5c9
        *parms->err = "parsing of subnet/netmask failed";
Packit 90a5c9
        return !OK;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    *parms->data = subnet;
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_ipmatch(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1,
Packit 90a5c9
                const char *arg2)
Packit 90a5c9
{
Packit 90a5c9
    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
Packit 90a5c9
    apr_sockaddr_t *saddr;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(subnet != NULL);
Packit 90a5c9
Packit 90a5c9
    /* maybe log an error if this goes wrong? */
Packit 90a5c9
    if (apr_sockaddr_info_get(&saddr, arg1, APR_UNSPEC, 0, 0, ctx->p) != APR_SUCCESS)
Packit 90a5c9
        return FALSE;
Packit 90a5c9
Packit 90a5c9
    return apr_ipsubnet_test(subnet, saddr);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_R(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1)
Packit 90a5c9
{
Packit 90a5c9
    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(subnet != NULL);
Packit 90a5c9
Packit 90a5c9
    if (!ctx->r)
Packit 90a5c9
        return FALSE;
Packit 90a5c9
Packit 90a5c9
    return apr_ipsubnet_test(subnet, ctx->r->useragent_addr);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_T(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    switch (arg[0]) {
Packit 90a5c9
    case '\0':
Packit 90a5c9
        return FALSE;
Packit 90a5c9
    case 'o':
Packit 90a5c9
    case 'O':
Packit 90a5c9
        return strcasecmp(arg, "off") == 0 ? FALSE : TRUE;
Packit 90a5c9
    case 'n':
Packit 90a5c9
    case 'N':
Packit 90a5c9
        return strcasecmp(arg, "no") == 0 ? FALSE : TRUE;
Packit 90a5c9
    case 'f':
Packit 90a5c9
    case 'F':
Packit 90a5c9
        return strcasecmp(arg, "false") == 0 ? FALSE : TRUE;
Packit 90a5c9
    case '0':
Packit 90a5c9
        return arg[1] == '\0' ? FALSE : TRUE;
Packit 90a5c9
    default:
Packit 90a5c9
        return TRUE;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_fnmatch(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                      const char *arg1, const char *arg2)
Packit 90a5c9
{
Packit 90a5c9
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_PATHNAME));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_strmatch(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                       const char *arg1, const char *arg2)
Packit 90a5c9
{
Packit 90a5c9
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, 0));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int op_strcmatch(ap_expr_eval_ctx_t *ctx, const void *data,
Packit 90a5c9
                        const char *arg1, const char *arg2)
Packit 90a5c9
{
Packit 90a5c9
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_CASE_BLIND));
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
struct expr_provider_single {
Packit 90a5c9
    const void *func;
Packit 90a5c9
    const char *name;
Packit 90a5c9
    ap_expr_lookup_fn_t *arg_parsing_func;
Packit 90a5c9
    int restricted;
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
struct expr_provider_multi {
Packit 90a5c9
    const void *func;
Packit 90a5c9
    const char **names;
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const struct expr_provider_multi var_providers[] = {
Packit 90a5c9
    { misc_var_fn, misc_var_names },
Packit 90a5c9
    { req_header_var_fn, req_header_var_names },
Packit 90a5c9
    { request_var_fn, request_var_names },
Packit 90a5c9
    { conn_var_fn, conn_var_names },
Packit 90a5c9
    { NULL, NULL }
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const struct expr_provider_single string_func_providers[] = {
Packit 90a5c9
    { osenv_func,           "osenv",          NULL, 0 },
Packit 90a5c9
    { env_func,             "env",            NULL, 0 },
Packit 90a5c9
    { req_table_func,       "resp",           NULL, 0 },
Packit 90a5c9
    { req_table_func,       "req",            NULL, 0 },
Packit 90a5c9
    /* 'http' as alias for 'req' for compatibility with ssl_expr */
Packit 90a5c9
    { req_table_func,       "http",           NULL, 0 },
Packit 90a5c9
    { req_table_func,       "note",           NULL, 0 },
Packit 90a5c9
    { req_table_func,       "reqenv",         NULL, 0 },
Packit 90a5c9
    { req_table_func,       "req_novary",     NULL, 0 },
Packit 90a5c9
    { tolower_func,         "tolower",        NULL, 0 },
Packit 90a5c9
    { toupper_func,         "toupper",        NULL, 0 },
Packit 90a5c9
    { escape_func,          "escape",         NULL, 0 },
Packit 90a5c9
    { unescape_func,        "unescape",       NULL, 0 },
Packit 90a5c9
    { file_func,            "file",           NULL, 1 },
Packit 90a5c9
    { filesize_func,        "filesize",       NULL, 1 },
Packit 90a5c9
    { base64_func,          "base64",         NULL, 0 },
Packit 90a5c9
    { unbase64_func,        "unbase64",       NULL, 0 },
Packit 90a5c9
    { sha1_func,            "sha1",           NULL, 0 },
Packit 90a5c9
    { md5_func,             "md5",            NULL, 0 },
Packit 90a5c9
    { NULL, NULL, NULL}
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const struct expr_provider_single unary_op_providers[] = {
Packit 90a5c9
    { op_nz,        "n", NULL,             0 },
Packit 90a5c9
    { op_nz,        "z", NULL,             0 },
Packit 90a5c9
    { op_R,         "R", subnet_parse_arg, 0 },
Packit 90a5c9
    { op_T,         "T", NULL,             0 },
Packit 90a5c9
    { op_file_min,  "d", NULL,             1 },
Packit 90a5c9
    { op_file_min,  "e", NULL,             1 },
Packit 90a5c9
    { op_file_min,  "f", NULL,             1 },
Packit 90a5c9
    { op_file_min,  "s", NULL,             1 },
Packit 90a5c9
    { op_file_link, "L", NULL,             1 },
Packit 90a5c9
    { op_file_link, "h", NULL,             1 },
Packit 90a5c9
    { op_file_xbit, "x", NULL,             1 },
Packit 90a5c9
    { op_file_subr, "F", NULL,             0 },
Packit 90a5c9
    { op_url_subr,  "U", NULL,             0 },
Packit 90a5c9
    { op_url_subr,  "A", NULL,             0 },
Packit 90a5c9
    { NULL, NULL, NULL }
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const struct expr_provider_single binary_op_providers[] = {
Packit 90a5c9
    { op_ipmatch,   "ipmatch",      subnet_parse_arg, 0 },
Packit 90a5c9
    { op_fnmatch,   "fnmatch",      NULL,             0 },
Packit 90a5c9
    { op_strmatch,  "strmatch",     NULL,             0 },
Packit 90a5c9
    { op_strcmatch, "strcmatch",    NULL,             0 },
Packit 90a5c9
    { NULL, NULL, NULL }
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static int core_expr_lookup(ap_expr_lookup_parms *parms)
Packit 90a5c9
{
Packit 90a5c9
    switch (parms->type) {
Packit 90a5c9
    case AP_EXPR_FUNC_VAR: {
Packit 90a5c9
            const struct expr_provider_multi *prov = var_providers;
Packit 90a5c9
            while (prov->func) {
Packit 90a5c9
                const char **name = prov->names;
Packit 90a5c9
                while (*name) {
Packit 90a5c9
                    if (strcasecmp(*name, parms->name) == 0) {
Packit 90a5c9
                        *parms->func = prov->func;
Packit 90a5c9
                        *parms->data = name;
Packit 90a5c9
                        return OK;
Packit 90a5c9
                    }
Packit 90a5c9
                    name++;
Packit 90a5c9
                }
Packit 90a5c9
                prov++;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    case AP_EXPR_FUNC_STRING:
Packit 90a5c9
    case AP_EXPR_FUNC_OP_UNARY:
Packit 90a5c9
    case AP_EXPR_FUNC_OP_BINARY: {
Packit 90a5c9
            const struct expr_provider_single *prov = NULL;
Packit 90a5c9
            switch (parms->type) {
Packit 90a5c9
            case AP_EXPR_FUNC_STRING:
Packit 90a5c9
                prov = string_func_providers;
Packit 90a5c9
                break;
Packit 90a5c9
            case AP_EXPR_FUNC_OP_UNARY:
Packit 90a5c9
                prov = unary_op_providers;
Packit 90a5c9
                break;
Packit 90a5c9
            case AP_EXPR_FUNC_OP_BINARY:
Packit 90a5c9
                prov = binary_op_providers;
Packit 90a5c9
                break;
Packit 90a5c9
            default:
Packit 90a5c9
                ap_assert(0);
Packit 90a5c9
            }
Packit 90a5c9
            while (prov && prov->func) {
Packit 90a5c9
                int match;
Packit 90a5c9
                if (parms->type == AP_EXPR_FUNC_OP_UNARY)
Packit 90a5c9
                    match = !strcmp(prov->name, parms->name);
Packit 90a5c9
                else
Packit 90a5c9
                    match = !strcasecmp(prov->name, parms->name);
Packit 90a5c9
                if (match) {
Packit 90a5c9
                    if ((parms->flags & AP_EXPR_FLAG_RESTRICTED)
Packit 90a5c9
                        && prov->restricted) {
Packit 90a5c9
                        *parms->err =
Packit 90a5c9
                            apr_psprintf(parms->ptemp,
Packit 90a5c9
                                         "%s%s not available in restricted context",
Packit 90a5c9
                                         (parms->type == AP_EXPR_FUNC_STRING) ? "" : "-",
Packit 90a5c9
                                         prov->name);
Packit 90a5c9
                        return !OK;
Packit 90a5c9
                    }
Packit 90a5c9
                    *parms->func = prov->func;
Packit 90a5c9
                    if (prov->arg_parsing_func) {
Packit 90a5c9
                        return prov->arg_parsing_func(parms);
Packit 90a5c9
                    }
Packit 90a5c9
                    else {
Packit 90a5c9
                        *parms->data = prov->name;
Packit 90a5c9
                        return OK;
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                prov++;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    default:
Packit 90a5c9
        break;
Packit 90a5c9
    }
Packit 90a5c9
    return DECLINED;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
Packit 90a5c9
{
Packit 90a5c9
    const char *type;
Packit 90a5c9
    const char *prefix = "";
Packit 90a5c9
Packit 90a5c9
    switch (parms->type) {
Packit 90a5c9
    case AP_EXPR_FUNC_VAR:
Packit 90a5c9
        type = "Variable";
Packit 90a5c9
        break;
Packit 90a5c9
    case AP_EXPR_FUNC_STRING:
Packit 90a5c9
        type = "Function";
Packit 90a5c9
        break;
Packit 90a5c9
    case AP_EXPR_FUNC_LIST:
Packit 90a5c9
        type = "List-returning function";
Packit 90a5c9
        break;
Packit 90a5c9
    case AP_EXPR_FUNC_OP_UNARY:
Packit 90a5c9
        type = "Unary operator";
Packit 90a5c9
        break;
Packit 90a5c9
    case AP_EXPR_FUNC_OP_BINARY:
Packit 90a5c9
        type = "Binary operator";
Packit 90a5c9
        break;
Packit 90a5c9
    default:
Packit 90a5c9
        *parms->err = "Inavalid expression type in expr_lookup";
Packit 90a5c9
        return !OK;
Packit 90a5c9
    }
Packit 90a5c9
    if (   parms->type == AP_EXPR_FUNC_OP_UNARY
Packit 90a5c9
        || parms->type == AP_EXPR_FUNC_OP_BINARY) {
Packit 90a5c9
        prefix = "-";
Packit 90a5c9
    }
Packit 90a5c9
    *parms->err = apr_psprintf(parms->ptemp, "%s '%s%s' does not exist", type,
Packit 90a5c9
                               prefix, parms->name);
Packit 90a5c9
    return !OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int ap_expr_post_config(apr_pool_t *pconf, apr_pool_t *plog,
Packit 90a5c9
                               apr_pool_t *ptemp, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
Packit 90a5c9
    is_http2 = APR_RETRIEVE_OPTIONAL_FN(http2_is_h2);
Packit 90a5c9
    apr_pool_cleanup_register(pconf, &is_https, ap_pool_cleanup_set_null,
Packit 90a5c9
                              apr_pool_cleanup_null);
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void ap_expr_init(apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
    ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
Packit 90a5c9
    ap_hook_post_config(ap_expr_post_config, NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
}
Packit 90a5c9