1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*                      _             _
18 *  ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
19 */
20
21#include "httpd.h"
22#include "http_log.h"
23#include "http_core.h"
24#include "http_protocol.h"
25#include "http_request.h"
26#include "ap_provider.h"
27#include "util_expr_private.h"
28#include "util_md5.h"
29
30#include "apr_lib.h"
31#include "apr_fnmatch.h"
32#include "apr_base64.h"
33#include "apr_sha1.h"
34
35#include <limits.h>     /* for INT_MAX */
36
37/* we know core's module_index is 0 */
38#undef APLOG_MODULE_INDEX
39#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
40
41APR_HOOK_STRUCT(
42    APR_HOOK_LINK(expr_lookup)
43)
44
45AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
46                            (parms), DECLINED)
47
48#define  LOG_MARK(info)  __FILE__, __LINE__, (info)->module_index
49
50static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
51                                            const ap_expr_t *info,
52                                            const ap_expr_t *args);
53static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx,
54                                           unsigned int n);
55static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
56                                    ap_expr_var_func_t *func,
57                                    const void *data);
58
59/* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
60#ifdef AP_EXPR_DEBUG
61static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
62                           int loglevel, int indent);
63#endif
64
65/*
66 * To reduce counting overhead, we only count calls to
67 * ap_expr_eval_word() and ap_expr_eval(). The max number of
68 * stack frames is larger by some factor.
69 */
70#define AP_EXPR_MAX_RECURSION   20
71static int inc_rec(ap_expr_eval_ctx_t *ctx)
72{
73    if (ctx->reclvl < AP_EXPR_MAX_RECURSION) {
74        ctx->reclvl++;
75        return 0;
76    }
77    *ctx->err = "Recursion limit reached";
78    /* short circuit further evaluation */
79    ctx->reclvl = INT_MAX;
80    return 1;
81}
82
83static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
84                                     const ap_expr_t *node)
85{
86    const char *result = "";
87    if (inc_rec(ctx))
88        return result;
89    switch (node->node_op) {
90    case op_Digit:
91    case op_String:
92        result = node->node_arg1;
93        break;
94    case op_Var:
95        result = ap_expr_eval_var(ctx, (ap_expr_var_func_t *)node->node_arg1,
96                                  node->node_arg2);
97        break;
98    case op_Concat:
99        if (((ap_expr_t *)node->node_arg2)->node_op != op_Concat) {
100            const char *s1 = ap_expr_eval_word(ctx, node->node_arg1);
101            const char *s2 = ap_expr_eval_word(ctx, node->node_arg2);
102            if (!*s1)
103                result = s2;
104            else if (!*s2)
105                result = s1;
106            else
107                result = apr_pstrcat(ctx->p, s1, s2, NULL);
108        }
109        else {
110            const ap_expr_t *nodep = node;
111            int i = 1;
112            struct iovec *vec;
113            do {
114                nodep = nodep->node_arg2;
115                i++;
116            } while (nodep->node_op == op_Concat);
117            vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
118            nodep = node;
119            i = 0;
120            do {
121                vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
122                                                            nodep->node_arg1);
123                vec[i].iov_len = strlen(vec[i].iov_base);
124                i++;
125                nodep = nodep->node_arg2;
126            } while (nodep->node_op == op_Concat);
127            vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
128            vec[i].iov_len = strlen(vec[i].iov_base);
129            i++;
130            result = apr_pstrcatv(ctx->p, vec, i, NULL);
131        }
132        break;
133    case op_StringFuncCall: {
134        const ap_expr_t *info = node->node_arg1;
135        const ap_expr_t *args = node->node_arg2;
136        result = ap_expr_eval_string_func(ctx, info, args);
137        break;
138    }
139    case op_RegexBackref: {
140        const unsigned int *np = node->node_arg1;
141        result = ap_expr_eval_re_backref(ctx, *np);
142        break;
143    }
144    default:
145        *ctx->err = "Internal evaluation error: Unknown word expression node";
146        break;
147    }
148    if (!result)
149        result = "";
150    ctx->reclvl--;
151    return result;
152}
153
154static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
155                                    ap_expr_var_func_t *func,
156                                    const void *data)
157{
158    AP_DEBUG_ASSERT(func != NULL);
159    AP_DEBUG_ASSERT(data != NULL);
160    return (*func)(ctx, data);
161}
162
163static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx, unsigned int n)
164{
165    int len;
166
167    if (!ctx->re_pmatch || !ctx->re_source || *ctx->re_source == '\0' ||
168        ctx->re_nmatch < n + 1)
169        return "";
170
171    len = ctx->re_pmatch[n].rm_eo - ctx->re_pmatch[n].rm_so;
172    if (len == 0)
173        return "";
174
175    return apr_pstrndup(ctx->p, *ctx->re_source + ctx->re_pmatch[n].rm_so, len);
176}
177
178static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
179                                            const ap_expr_t *info,
180                                            const ap_expr_t *arg)
181{
182    ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
183    const void *data = info->node_arg2;
184
185    AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
186    AP_DEBUG_ASSERT(func != NULL);
187    AP_DEBUG_ASSERT(data != NULL);
188    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
189}
190
191static int intstrcmp(const char *s1, const char *s2)
192{
193    apr_int64_t i1 = apr_atoi64(s1);
194    apr_int64_t i2 = apr_atoi64(s2);
195
196    if (i1 < i2)
197        return -1;
198    else if (i1 == i2)
199        return 0;
200    else
201        return 1;
202}
203
204static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
205{
206    const ap_expr_t *e1 = node->node_arg1;
207    const ap_expr_t *e2 = node->node_arg2;
208    switch (node->node_op) {
209    case op_EQ:
210        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
211    case op_NE:
212        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
213    case op_LT:
214        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
215    case op_LE:
216        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
217    case op_GT:
218        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
219    case op_GE:
220        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
221    case op_STR_EQ:
222        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
223    case op_STR_NE:
224        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
225    case op_STR_LT:
226        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
227    case op_STR_LE:
228        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
229    case op_STR_GT:
230        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
231    case op_STR_GE:
232        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
233    case op_IN: {
234            const char *needle = ap_expr_eval_word(ctx, e1);
235            if (e2->node_op == op_ListElement) {
236                do {
237                    const ap_expr_t *val = e2->node_arg1;
238                    AP_DEBUG_ASSERT(e2->node_op == op_ListElement);
239                    if (strcmp(needle, ap_expr_eval_word(ctx, val)) == 0) {
240                        return 1;
241                        break;
242                    }
243                    e2 = e2->node_arg2;
244                } while (e2 != NULL);
245            }
246            else if (e2->node_op == op_ListFuncCall) {
247                const ap_expr_t *info = e2->node_arg1;
248                const ap_expr_t *arg = e2->node_arg2;
249                ap_expr_list_func_t *func = (ap_expr_list_func_t *)info->node_arg1;
250                apr_array_header_t *haystack;
251                int i = 0;
252                AP_DEBUG_ASSERT(func != NULL);
253                AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
254                haystack = (*func)(ctx, info->node_arg2, ap_expr_eval_word(ctx, arg));
255                if (haystack == NULL)
256                    return 0;
257                for (; i < haystack->nelts; i++) {
258                    if (strcmp(needle, APR_ARRAY_IDX(haystack,i,char *)) == 0)
259                        return 1;
260                }
261            }
262            return 0;
263        }
264    case op_REG:
265    case op_NRE: {
266            const char *word = ap_expr_eval_word(ctx, e1);
267            const ap_regex_t *regex = e2->node_arg1;
268            int result;
269
270            /*
271             * $0 ... $9 may contain stuff the user wants to keep. Therefore
272             * we only set them if there are capturing parens in the regex.
273             */
274            if (regex->re_nsub > 0) {
275                result = (0 == ap_regexec(regex, word, ctx->re_nmatch,
276                                          ctx->re_pmatch, 0));
277                *ctx->re_source = result ? word : NULL;
278            }
279            else {
280                result = (0 == ap_regexec(regex, word, 0, NULL, 0));
281            }
282
283            if (node->node_op == op_REG)
284                return result;
285            else
286                return !result;
287        }
288    default:
289        *ctx->err = "Internal evaluation error: Unknown comp expression node";
290        return -1;
291    }
292}
293
294/* combined string/int comparison for compatibility with ssl_expr */
295static int strcmplex(const char *str1, const char *str2)
296{
297    int i, n1, n2;
298
299    if (str1 == NULL)
300        return -1;
301    if (str2 == NULL)
302        return +1;
303    n1 = strlen(str1);
304    n2 = strlen(str2);
305    if (n1 > n2)
306        return 1;
307    if (n1 < n2)
308        return -1;
309    for (i = 0; i < n1; i++) {
310        if (str1[i] > str2[i])
311            return 1;
312        if (str1[i] < str2[i])
313            return -1;
314    }
315    return 0;
316}
317
318static int ssl_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
319{
320    const ap_expr_t *e1 = node->node_arg1;
321    const ap_expr_t *e2 = node->node_arg2;
322    switch (node->node_op) {
323    case op_EQ:
324    case op_STR_EQ:
325        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
326    case op_NE:
327    case op_STR_NE:
328        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
329    case op_LT:
330    case op_STR_LT:
331        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
332    case op_LE:
333    case op_STR_LE:
334        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
335    case op_GT:
336    case op_STR_GT:
337        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
338    case op_GE:
339    case op_STR_GE:
340        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
341    default:
342        return ap_expr_eval_comp(ctx, node);
343    }
344}
345
346AP_DECLARE_NONSTD(int) ap_expr_lookup_default(ap_expr_lookup_parms *parms)
347{
348    return ap_run_expr_lookup(parms);
349}
350
351AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
352                                       ap_expr_info_t *info, const char *expr,
353                                       ap_expr_lookup_fn_t *lookup_fn)
354{
355    ap_expr_parse_ctx_t ctx;
356    int rc;
357
358    ctx.pool     = pool;
359    ctx.ptemp    = ptemp;
360    ctx.inputbuf = expr;
361    ctx.inputlen = strlen(expr);
362    ctx.inputptr = ctx.inputbuf;
363    ctx.expr     = NULL;
364    ctx.error    = NULL;        /* generic bison error message (XXX: usually not very useful, should be axed) */
365    ctx.error2   = NULL;        /* additional error message */
366    ctx.flags    = info->flags;
367    ctx.scan_del    = '\0';
368    ctx.scan_buf[0] = '\0';
369    ctx.scan_ptr    = ctx.scan_buf;
370    ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_expr_lookup_default;
371    ctx.at_start    = 1;
372
373    ap_expr_yylex_init(&ctx.scanner);
374    ap_expr_yyset_extra(&ctx, ctx.scanner);
375    rc = ap_expr_yyparse(&ctx);
376    ap_expr_yylex_destroy(ctx.scanner);
377    if (ctx.error) {
378        if (ctx.error2)
379            return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
380        else
381            return ctx.error;
382    }
383    else if (ctx.error2) {
384        return ctx.error2;
385    }
386
387    if (rc) /* XXX can this happen? */
388        return "syntax error";
389
390#ifdef AP_EXPR_DEBUG
391    if (ctx.expr)
392        expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
393#endif
394
395    info->root_node = ctx.expr;
396
397    return NULL;
398}
399
400AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd_mi(const cmd_parms *cmd,
401                                                 const char *expr,
402                                                 unsigned int flags,
403                                                 const char **err,
404                                                 ap_expr_lookup_fn_t *lookup_fn,
405                                                 int module_index)
406{
407    ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
408    info->filename = cmd->directive->filename;
409    info->line_number = cmd->directive->line_num;
410    info->flags = flags;
411    info->module_index = module_index;
412    *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
413
414    if (*err)
415        return NULL;
416
417    return info;
418}
419
420ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
421                      ap_expr_parse_ctx_t *ctx)
422{
423    ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
424    node->node_op   = op;
425    node->node_arg1 = a1;
426    node->node_arg2 = a2;
427    return node;
428}
429
430static ap_expr_t *ap_expr_info_make(int type, const char *name,
431                                  ap_expr_parse_ctx_t *ctx,
432                                  const ap_expr_t *arg)
433{
434    ap_expr_t *info = apr_palloc(ctx->pool, sizeof(ap_expr_t));
435    ap_expr_lookup_parms parms;
436    parms.type  = type;
437    parms.flags = ctx->flags;
438    parms.pool  = ctx->pool;
439    parms.ptemp = ctx->ptemp;
440    parms.name  = name;
441    parms.func  = &info->node_arg1;
442    parms.data  = &info->node_arg2;
443    parms.err   = &ctx->error2;
444    parms.arg   = (arg && arg->node_op == op_String) ? arg->node_arg1 : NULL;
445    if (ctx->lookup_fn(&parms) != OK)
446        return NULL;
447    return info;
448}
449
450ap_expr_t *ap_expr_str_func_make(const char *name, const ap_expr_t *arg,
451                               ap_expr_parse_ctx_t *ctx)
452{
453    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx, arg);
454    if (!info)
455        return NULL;
456
457    info->node_op = op_StringFuncInfo;
458    return ap_expr_make(op_StringFuncCall, info, arg, ctx);
459}
460
461ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
462                                ap_expr_parse_ctx_t *ctx)
463{
464    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx, arg);
465    if (!info)
466        return NULL;
467
468    info->node_op = op_ListFuncInfo;
469    return ap_expr_make(op_ListFuncCall, info, arg, ctx);
470}
471
472ap_expr_t *ap_expr_unary_op_make(const char *name, const ap_expr_t *arg,
473                               ap_expr_parse_ctx_t *ctx)
474{
475    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx, arg);
476    if (!info)
477        return NULL;
478
479    info->node_op = op_UnaryOpInfo;
480    return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
481}
482
483ap_expr_t *ap_expr_binary_op_make(const char *name, const ap_expr_t *arg1,
484                                const ap_expr_t *arg2, ap_expr_parse_ctx_t *ctx)
485{
486    ap_expr_t *args;
487    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_BINARY, name, ctx,
488                                        arg2);
489    if (!info)
490        return NULL;
491
492    info->node_op = op_BinaryOpInfo;
493    args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
494    return ap_expr_make(op_BinaryOpCall, info, args, ctx);
495}
496
497
498ap_expr_t *ap_expr_var_make(const char *name, ap_expr_parse_ctx_t *ctx)
499{
500    ap_expr_t *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx, NULL);
501    if (!node)
502        return NULL;
503
504    node->node_op = op_Var;
505    return node;
506}
507
508#ifdef AP_EXPR_DEBUG
509
510#define MARK                        APLOG_MARK,loglevel,0,s
511#define DUMP_E_E(op, e1, e2)                                                \
512    do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2);      \
513         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);               \
514         if (e2) expr_dump_tree(e2, s, loglevel, indent + 2);               \
515    } while (0)
516#define DUMP_S_E(op, s1, e1)                                                    \
517    do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
518         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);                   \
519    } while (0)
520#define DUMP_S_P(op, s1, p1)                                                \
521    ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
522#define DUMP_P_P(op, p1, p2)                                                \
523    ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
524#define DUMP_S_S(op, s1, s2)                                                       \
525    ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
526#define DUMP_P(op, p1)                                                      \
527    ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
528#define DUMP_IP(op, p1)                                                     \
529    ap_log_error(MARK,"%*s%s: %d", indent, " ", op, *(int *)p1);
530#define DUMP_S(op, s1)                                                      \
531    ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
532
533#define CASE_OP(op)                  case op: name = #op ; break;
534
535static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
536                           int loglevel, int indent)
537{
538    switch (e->node_op) {
539    /* no arg */
540    case op_NOP:
541    case op_True:
542    case op_False:
543        {
544            char *name;
545            switch (e->node_op) {
546            CASE_OP(op_NOP);
547            CASE_OP(op_True);
548            CASE_OP(op_False);
549            default:
550                ap_assert(0);
551            }
552            ap_log_error(MARK, "%*s%s", indent, " ", name);
553        }
554        break;
555
556    /* arg1: string, arg2: expr */
557    case op_UnaryOpCall:
558    case op_BinaryOpCall:
559    case op_BinaryOpArgs:
560        {
561            char *name;
562            switch (e->node_op) {
563            CASE_OP(op_BinaryOpCall);
564            CASE_OP(op_UnaryOpCall);
565            CASE_OP(op_BinaryOpArgs);
566            default:
567                ap_assert(0);
568            }
569            DUMP_S_E(name, e->node_arg1, e->node_arg2);
570        }
571        break;
572
573    /* arg1: expr, arg2: expr */
574    case op_Comp:
575    case op_Not:
576    case op_Or:
577    case op_And:
578    case op_EQ:
579    case op_NE:
580    case op_LT:
581    case op_LE:
582    case op_GT:
583    case op_GE:
584    case op_STR_EQ:
585    case op_STR_NE:
586    case op_STR_LT:
587    case op_STR_LE:
588    case op_STR_GT:
589    case op_STR_GE:
590    case op_IN:
591    case op_REG:
592    case op_NRE:
593    case op_Concat:
594    case op_StringFuncCall:
595    case op_ListFuncCall:
596    case op_ListElement:
597        {
598            char *name;
599            switch (e->node_op) {
600            CASE_OP(op_Comp);
601            CASE_OP(op_Not);
602            CASE_OP(op_Or);
603            CASE_OP(op_And);
604            CASE_OP(op_EQ);
605            CASE_OP(op_NE);
606            CASE_OP(op_LT);
607            CASE_OP(op_LE);
608            CASE_OP(op_GT);
609            CASE_OP(op_GE);
610            CASE_OP(op_STR_EQ);
611            CASE_OP(op_STR_NE);
612            CASE_OP(op_STR_LT);
613            CASE_OP(op_STR_LE);
614            CASE_OP(op_STR_GT);
615            CASE_OP(op_STR_GE);
616            CASE_OP(op_IN);
617            CASE_OP(op_REG);
618            CASE_OP(op_NRE);
619            CASE_OP(op_Concat);
620            CASE_OP(op_StringFuncCall);
621            CASE_OP(op_ListFuncCall);
622            CASE_OP(op_ListElement);
623            default:
624                ap_assert(0);
625            }
626            DUMP_E_E(name, e->node_arg1, e->node_arg2);
627        }
628        break;
629    /* arg1: string */
630    case op_Digit:
631    case op_String:
632        {
633            char *name;
634            switch (e->node_op) {
635            CASE_OP(op_Digit);
636            CASE_OP(op_String);
637            default:
638                ap_assert(0);
639            }
640            DUMP_S(name, e->node_arg1);
641        }
642        break;
643    /* arg1: pointer, arg2: pointer */
644    case op_Var:
645    case op_StringFuncInfo:
646    case op_UnaryOpInfo:
647    case op_BinaryOpInfo:
648    case op_ListFuncInfo:
649        {
650            char *name;
651            switch (e->node_op) {
652            CASE_OP(op_Var);
653            CASE_OP(op_StringFuncInfo);
654            CASE_OP(op_UnaryOpInfo);
655            CASE_OP(op_BinaryOpInfo);
656            CASE_OP(op_ListFuncInfo);
657            default:
658                ap_assert(0);
659            }
660            DUMP_P_P(name, e->node_arg1, e->node_arg2);
661        }
662        break;
663    /* arg1: pointer */
664    case op_Regex:
665        DUMP_P("op_Regex", e->node_arg1);
666        break;
667    /* arg1: pointer to int */
668    case op_RegexBackref:
669        DUMP_IP("op_RegexBackref", e->node_arg1);
670        break;
671    default:
672        ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
673        break;
674    }
675}
676#endif /* AP_EXPR_DEBUG */
677
678static int ap_expr_eval_unary_op(ap_expr_eval_ctx_t *ctx, const ap_expr_t *info,
679                                 const ap_expr_t *arg)
680{
681    ap_expr_op_unary_t *op_func = (ap_expr_op_unary_t *)info->node_arg1;
682    const void *data = info->node_arg2;
683
684    AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
685    AP_DEBUG_ASSERT(op_func != NULL);
686    AP_DEBUG_ASSERT(data != NULL);
687    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
688}
689
690static int ap_expr_eval_binary_op(ap_expr_eval_ctx_t *ctx,
691                                  const ap_expr_t *info,
692                                  const ap_expr_t *args)
693{
694    ap_expr_op_binary_t *op_func = (ap_expr_op_binary_t *)info->node_arg1;
695    const void *data = info->node_arg2;
696    const ap_expr_t *a1 = args->node_arg1;
697    const ap_expr_t *a2 = args->node_arg2;
698
699    AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
700    AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
701    AP_DEBUG_ASSERT(op_func != NULL);
702    AP_DEBUG_ASSERT(data != NULL);
703    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
704                      ap_expr_eval_word(ctx, a2));
705}
706
707
708static int ap_expr_eval(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
709{
710    const ap_expr_t *e1 = node->node_arg1;
711    const ap_expr_t *e2 = node->node_arg2;
712    int result = FALSE;
713    if (inc_rec(ctx))
714        return result;
715    while (1) {
716        switch (node->node_op) {
717        case op_True:
718            result ^= TRUE;
719            goto out;
720        case op_False:
721            result ^= FALSE;
722            goto out;
723        case op_Not:
724            result = !result;
725            node = e1;
726            break;
727        case op_Or:
728            do {
729                if (e1->node_op == op_Not) {
730                    if (!ap_expr_eval(ctx, e1->node_arg1)) {
731                        result ^= TRUE;
732                        goto out;
733                    }
734                }
735                else {
736                    if (ap_expr_eval(ctx, e1)) {
737                        result ^= TRUE;
738                        goto out;
739                    }
740                }
741                node = node->node_arg2;
742                e1 = node->node_arg1;
743            } while (node->node_op == op_Or);
744            break;
745        case op_And:
746            do {
747                if (e1->node_op == op_Not) {
748                    if (ap_expr_eval(ctx, e1->node_arg1)) {
749                        result ^= FALSE;
750                        goto out;
751                    }
752                }
753                else {
754                    if (!ap_expr_eval(ctx, e1)) {
755                        result ^= FALSE;
756                        goto out;
757                    }
758                }
759                node = node->node_arg2;
760                e1 = node->node_arg1;
761            } while (node->node_op == op_And);
762            break;
763        case op_UnaryOpCall:
764            result ^= ap_expr_eval_unary_op(ctx, e1, e2);
765            goto out;
766        case op_BinaryOpCall:
767            result ^= ap_expr_eval_binary_op(ctx, e1, e2);
768            goto out;
769        case op_Comp:
770            if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
771                result ^= ssl_expr_eval_comp(ctx, e1);
772            else
773                result ^= ap_expr_eval_comp(ctx, e1);
774            goto out;
775        default:
776            *ctx->err = "Internal evaluation error: Unknown expression node";
777            goto out;
778        }
779        e1 = node->node_arg1;
780        e2 = node->node_arg2;
781    }
782out:
783    ctx->reclvl--;
784    return result;
785}
786
787AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info,
788                             const char **err)
789{
790    return ap_expr_exec_re(r, info, 0, NULL, NULL, err);
791}
792
793AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
794{
795    int rc;
796
797    AP_DEBUG_ASSERT(ctx->p != NULL);
798    /* XXX: allow r, c == NULL */
799    AP_DEBUG_ASSERT(ctx->r != NULL);
800    AP_DEBUG_ASSERT(ctx->c != NULL);
801    AP_DEBUG_ASSERT(ctx->s != NULL);
802    AP_DEBUG_ASSERT(ctx->err != NULL);
803    AP_DEBUG_ASSERT(ctx->info != NULL);
804    if (ctx->re_pmatch) {
805        AP_DEBUG_ASSERT(ctx->re_source != NULL);
806        AP_DEBUG_ASSERT(ctx->re_nmatch > 0);
807    }
808    ctx->reclvl = 0;
809
810    *ctx->err = NULL;
811    if (ctx->info->flags & AP_EXPR_FLAG_STRING_RESULT) {
812        *ctx->result_string = ap_expr_eval_word(ctx, ctx->info->root_node);
813        if (*ctx->err != NULL) {
814            ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
815                          "Evaluation of expression from %s:%d failed: %s",
816                          ctx->info->filename, ctx->info->line_number, *ctx->err);
817            return -1;
818        } else {
819            ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
820                          "Evaluation of string expression from %s:%d gave: %s",
821                          ctx->info->filename, ctx->info->line_number,
822                          *ctx->result_string);
823            return 1;
824        }
825    }
826    else {
827        rc = ap_expr_eval(ctx, ctx->info->root_node);
828        if (*ctx->err != NULL) {
829            ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
830                          "Evaluation of expression from %s:%d failed: %s",
831                          ctx->info->filename, ctx->info->line_number, *ctx->err);
832            return -1;
833        } else {
834            rc = rc ? 1 : 0;
835            ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE4, 0, ctx->r,
836                          "Evaluation of expression from %s:%d gave: %d",
837                          ctx->info->filename, ctx->info->line_number, rc);
838
839            if (ctx->vary_this && *ctx->vary_this)
840                apr_table_merge(ctx->r->headers_out, "Vary", *ctx->vary_this);
841
842            return rc;
843        }
844    }
845}
846
847AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info,
848                                apr_size_t nmatch, ap_regmatch_t *pmatch,
849                                const char **source, const char **err)
850{
851    ap_expr_eval_ctx_t ctx;
852    int dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
853    const char *tmp_source = NULL, *vary_this = NULL;
854    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
855
856    AP_DEBUG_ASSERT((info->flags & AP_EXPR_FLAG_STRING_RESULT) == 0);
857
858    ctx.r = r;
859    ctx.c = r->connection;
860    ctx.s = r->server;
861    ctx.p = r->pool;
862    ctx.err  = err;
863    ctx.info = info;
864    ctx.re_nmatch = nmatch;
865    ctx.re_pmatch = pmatch;
866    ctx.re_source = source;
867    ctx.vary_this = dont_vary ? NULL : &vary_this;
868    ctx.data = NULL;
869
870    if (!pmatch) {
871        ctx.re_nmatch = AP_MAX_REG_MATCH;
872        ctx.re_pmatch = tmp_pmatch;
873        ctx.re_source = &tmp_source;
874    }
875
876    return ap_expr_exec_ctx(&ctx);
877}
878
879AP_DECLARE(const char *) ap_expr_str_exec_re(request_rec *r,
880                                             const ap_expr_info_t *info,
881                                             apr_size_t nmatch,
882                                             ap_regmatch_t *pmatch,
883                                             const char **source,
884                                             const char **err)
885{
886    ap_expr_eval_ctx_t ctx;
887    int dont_vary, rc;
888    const char *tmp_source = NULL, *vary_this = NULL;
889    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
890    const char *result;
891
892    AP_DEBUG_ASSERT(info->flags & AP_EXPR_FLAG_STRING_RESULT);
893
894    if (info->root_node->node_op == op_String) {
895        /* short-cut for constant strings */
896        *err = NULL;
897        return (const char *)info->root_node->node_arg1;
898    }
899
900    dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
901
902    ctx.r = r;
903    ctx.c = r->connection;
904    ctx.s = r->server;
905    ctx.p = r->pool;
906    ctx.err  = err;
907    ctx.info = info;
908    ctx.re_nmatch = nmatch;
909    ctx.re_pmatch = pmatch;
910    ctx.re_source = source;
911    ctx.vary_this = dont_vary ? NULL : &vary_this;
912    ctx.data = NULL;
913    ctx.result_string = &result;
914
915    if (!pmatch) {
916        ctx.re_nmatch = AP_MAX_REG_MATCH;
917        ctx.re_pmatch = tmp_pmatch;
918        ctx.re_source = &tmp_source;
919    }
920
921    rc = ap_expr_exec_ctx(&ctx);
922    if (rc > 0)
923        return result;
924    else if (rc < 0)
925        return NULL;
926    else
927        ap_assert(0);
928    /* Not reached */
929    return NULL;
930}
931
932AP_DECLARE(const char *) ap_expr_str_exec(request_rec *r,
933                                          const ap_expr_info_t *info,
934                                          const char **err)
935{
936    return ap_expr_str_exec_re(r, info, 0, NULL, NULL, err);
937}
938
939
940static void add_vary(ap_expr_eval_ctx_t *ctx, const char *name)
941{
942    if (!ctx->vary_this)
943        return;
944
945    if (*ctx->vary_this) {
946        *ctx->vary_this = apr_pstrcat(ctx->p, *ctx->vary_this, ", ", name,
947                                      NULL);
948    }
949    else {
950        *ctx->vary_this = name;
951    }
952}
953
954static const char *req_table_func(ap_expr_eval_ctx_t *ctx, const void *data,
955                                  const char *arg)
956{
957    const char *name = (const char *)data;
958    apr_table_t *t;
959    if (!ctx->r)
960        return "";
961
962    if (name[2] == 's') {           /* resp */
963        /* Try r->headers_out first, fall back on err_headers_out. */
964        const char *v = apr_table_get(ctx->r->headers_out, arg);
965        if (v) {
966            return v;
967        }
968        t = ctx->r->err_headers_out;
969    }
970    else if (name[0] == 'n')        /* notes */
971        t = ctx->r->notes;
972    else if (name[3] == 'e')        /* reqenv */
973        t = ctx->r->subprocess_env;
974    else if (name[3] == '_')        /* req_novary */
975        t = ctx->r->headers_in;
976    else {                          /* req, http */
977        t = ctx->r->headers_in;
978        add_vary(ctx, arg);
979    }
980    return apr_table_get(t, arg);
981}
982
983static const char *env_func(ap_expr_eval_ctx_t *ctx, const void *data,
984                            const char *arg)
985{
986    const char *res;
987    /* this order is for ssl_expr compatibility */
988    if (ctx->r) {
989        if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
990            return res;
991        else if ((res = apr_table_get(ctx->r->subprocess_env, arg)) != NULL)
992            return res;
993    }
994    return getenv(arg);
995}
996
997static const char *osenv_func(ap_expr_eval_ctx_t *ctx, const void *data,
998                              const char *arg)
999{
1000    return getenv(arg);
1001}
1002
1003static const char *tolower_func(ap_expr_eval_ctx_t *ctx, const void *data,
1004                                const char *arg)
1005{
1006    char *result = apr_pstrdup(ctx->p, arg);
1007    ap_str_tolower(result);
1008    return result;
1009}
1010
1011static const char *toupper_func(ap_expr_eval_ctx_t *ctx, const void *data,
1012                                const char *arg)
1013{
1014    char *result = apr_pstrdup(ctx->p, arg);
1015    ap_str_toupper(result);
1016    return result;
1017}
1018
1019static const char *escape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1020                               const char *arg)
1021{
1022    return ap_escape_uri(ctx->p, arg);
1023}
1024
1025static const char *base64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1026                               const char *arg)
1027{
1028    return ap_pbase64encode(ctx->p, (char *)arg);
1029}
1030
1031static const char *unbase64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1032                               const char *arg)
1033{
1034    return ap_pbase64decode(ctx->p, arg);
1035}
1036
1037static const char *sha1_func(ap_expr_eval_ctx_t *ctx, const void *data,
1038                               const char *arg)
1039{
1040    apr_sha1_ctx_t context;
1041    apr_byte_t sha1[APR_SHA1_DIGESTSIZE];
1042    char *out;
1043
1044    out = apr_palloc(ctx->p, APR_SHA1_DIGESTSIZE*2+1);
1045
1046    apr_sha1_init(&context);
1047    apr_sha1_update(&context, arg, strlen(arg));
1048    apr_sha1_final(sha1, &context);
1049
1050    ap_bin2hex(sha1, APR_SHA1_DIGESTSIZE, out);
1051
1052    return out;
1053}
1054
1055static const char *md5_func(ap_expr_eval_ctx_t *ctx, const void *data,
1056                               const char *arg)
1057{
1058	return ap_md5(ctx->p, (const unsigned char *)arg);
1059}
1060
1061
1062#define MAX_FILE_SIZE 10*1024*1024
1063static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
1064                             char *arg)
1065{
1066    apr_file_t *fp;
1067    char *buf;
1068    apr_off_t offset;
1069    apr_size_t len;
1070    apr_finfo_t finfo;
1071
1072    if (apr_file_open(&fp, arg, APR_READ|APR_BUFFERED,
1073                      APR_OS_DEFAULT, ctx->p) != APR_SUCCESS) {
1074        *ctx->err = apr_psprintf(ctx->p, "Cannot open file %s", arg);
1075        return "";
1076    }
1077    apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
1078    if (finfo.size > MAX_FILE_SIZE) {
1079        *ctx->err = apr_psprintf(ctx->p, "File %s too large", arg);
1080        apr_file_close(fp);
1081        return "";
1082    }
1083    len = (apr_size_t)finfo.size;
1084    if (len == 0) {
1085        apr_file_close(fp);
1086        return "";
1087    }
1088    else {
1089        if ((buf = (char *)apr_palloc(ctx->p, sizeof(char)*(len+1))) == NULL) {
1090            *ctx->err = "Cannot allocate memory";
1091            apr_file_close(fp);
1092            return "";
1093        }
1094        offset = 0;
1095        apr_file_seek(fp, APR_SET, &offset);
1096        if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
1097            *ctx->err = apr_psprintf(ctx->p, "Cannot read from file %s", arg);
1098            apr_file_close(fp);
1099            return "";
1100        }
1101        buf[len] = '\0';
1102    }
1103    apr_file_close(fp);
1104    return buf;
1105}
1106
1107static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
1108                                  char *arg)
1109{
1110    apr_finfo_t sb;
1111    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1112        && sb.filetype == APR_REG && sb.size > 0)
1113        return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
1114    else
1115        return "0";
1116}
1117
1118static const char *unescape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1119                                 const char *arg)
1120{
1121    char *result = apr_pstrdup(ctx->p, arg);
1122    int ret = ap_unescape_url_keep2f(result, 0);
1123    if (ret == OK)
1124        return result;
1125    ap_log_rerror(LOG_MARK(ctx->info), APLOG_DEBUG, 0, ctx->r, APLOGNO(00538)
1126                  "%s %% escape in unescape('%s') at %s:%d",
1127                  ret == HTTP_BAD_REQUEST ? "Bad" : "Forbidden", arg,
1128                  ctx->info->filename, ctx->info->line_number);
1129    return "";
1130}
1131
1132static int op_nz(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1133{
1134    const char *name = (const char *)data;
1135    if (name[0] == 'z')
1136        return (arg[0] == '\0');
1137    else
1138        return (arg[0] != '\0');
1139}
1140
1141static int op_file_min(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1142{
1143    apr_finfo_t sb;
1144    const char *name = (const char *)data;
1145    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
1146        return FALSE;
1147    switch (name[0]) {
1148    case 'd':
1149        return (sb.filetype == APR_DIR);
1150    case 'e':
1151        return TRUE;
1152    case 'f':
1153        return (sb.filetype == APR_REG);
1154    case 's':
1155        return (sb.filetype == APR_REG && sb.size > 0);
1156    default:
1157        ap_assert(0);
1158    }
1159    return FALSE;
1160}
1161
1162static int op_file_link(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1163{
1164#if !defined(OS2)
1165    apr_finfo_t sb;
1166    if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1167        && sb.filetype == APR_LNK) {
1168        return TRUE;
1169    }
1170#endif
1171    return FALSE;
1172}
1173
1174static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1175{
1176    apr_finfo_t sb;
1177    if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1178        && (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
1179        return TRUE;
1180    }
1181    return FALSE;
1182}
1183
1184static int op_url_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1185{
1186    int rc = FALSE;
1187    request_rec  *rsub, *r = ctx->r;
1188    if (!r)
1189        return FALSE;
1190    /* avoid some infinite recursions */
1191    if (r->main && r->main->uri && r->uri && strcmp(r->main->uri, r->uri) == 0)
1192        return FALSE;
1193
1194    rsub = ap_sub_req_lookup_uri(arg, r, NULL);
1195    if (rsub->status < 400) {
1196            rc = TRUE;
1197    }
1198    ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
1199                  "Subrequest for -U %s at %s:%d gave status: %d",
1200                  arg, ctx->info->filename, ctx->info->line_number,
1201                  rsub->status);
1202    ap_destroy_sub_req(rsub);
1203    return rc;
1204}
1205
1206static int op_file_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1207{
1208    int rc = FALSE;
1209    apr_finfo_t sb;
1210    request_rec *rsub, *r = ctx->r;
1211    if (!r)
1212        return FALSE;
1213    rsub = ap_sub_req_lookup_file(arg, r, NULL);
1214    if (rsub->status < 300 &&
1215        /* double-check that file exists since default result is 200 */
1216        apr_stat(&sb, rsub->filename, APR_FINFO_MIN, ctx->p) == APR_SUCCESS) {
1217        rc = TRUE;
1218    }
1219    ap_log_rerror(LOG_MARK(ctx->info), APLOG_TRACE5, 0, r,
1220                  "Subrequest for -F %s at %s:%d gave status: %d",
1221                  arg, ctx->info->filename, ctx->info->line_number,
1222                  rsub->status);
1223    ap_destroy_sub_req(rsub);
1224    return rc;
1225}
1226
1227
1228APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
1229static APR_OPTIONAL_FN_TYPE(ssl_is_https) *is_https = NULL;
1230
1231static const char *conn_var_names[] = {
1232    "HTTPS",                    /*  0 */
1233    "IPV6",                     /*  1 */
1234    "CONN_LOG_ID",              /*  2 */
1235    "CONN_REMOTE_ADDR",         /*  3 */
1236    NULL
1237};
1238
1239static const char *conn_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1240{
1241    int index = ((const char **)data - conn_var_names);
1242    conn_rec *c = ctx->c;
1243    if (!c)
1244        return "";
1245
1246    switch (index) {
1247    case 0:
1248        if (is_https && is_https(c))
1249            return "on";
1250        else
1251            return "off";
1252    case 1:
1253#if APR_HAVE_IPV6
1254        {
1255            apr_sockaddr_t *addr = c->client_addr;
1256            if (addr->family == AF_INET6
1257                && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr))
1258                return "on";
1259            else
1260                return "off";
1261        }
1262#else
1263        return "off";
1264#endif
1265    case 2:
1266        return c->log_id;
1267    case 3:
1268        return c->client_ip;
1269    default:
1270        ap_assert(0);
1271        return NULL;
1272    }
1273}
1274
1275static const char *request_var_names[] = {
1276    "REQUEST_METHOD",           /*  0 */
1277    "REQUEST_SCHEME",           /*  1 */
1278    "REQUEST_URI",              /*  2 */
1279    "REQUEST_FILENAME",         /*  3 */
1280    "REMOTE_HOST",              /*  4 */
1281    "REMOTE_IDENT",             /*  5 */
1282    "REMOTE_USER",              /*  6 */
1283    "SERVER_ADMIN",             /*  7 */
1284    "SERVER_NAME",              /*  8 */
1285    "SERVER_PORT",              /*  9 */
1286    "SERVER_PROTOCOL",          /* 10 */
1287    "SCRIPT_FILENAME",          /* 11 */
1288    "PATH_INFO",                /* 12 */
1289    "QUERY_STRING",             /* 13 */
1290    "IS_SUBREQ",                /* 14 */
1291    "DOCUMENT_ROOT",            /* 15 */
1292    "AUTH_TYPE",                /* 16 */
1293    "THE_REQUEST",              /* 17 */
1294    "CONTENT_TYPE",             /* 18 */
1295    "HANDLER",                  /* 19 */
1296    "REQUEST_LOG_ID",           /* 20 */
1297    "SCRIPT_USER",              /* 21 */
1298    "SCRIPT_GROUP",             /* 22 */
1299    "DOCUMENT_URI",             /* 23 */
1300    "LAST_MODIFIED",            /* 24 */
1301    "CONTEXT_PREFIX",           /* 25 */
1302    "CONTEXT_DOCUMENT_ROOT",    /* 26 */
1303    "REQUEST_STATUS",           /* 27 */
1304    "REMOTE_ADDR",              /* 28 */
1305    NULL
1306};
1307
1308static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1309{
1310    int index = ((const char **)data - request_var_names);
1311    request_rec *r = ctx->r;
1312    if (!r)
1313        return "";
1314
1315    switch (index) {
1316    case 0:
1317        return r->method;
1318    case 1:
1319        return ap_http_scheme(r);
1320    case 2:
1321        return r->uri;
1322    case 3:
1323        return r->filename;
1324    case 4:
1325        return ap_get_remote_host(r->connection, r->per_dir_config,
1326                                  REMOTE_NAME, NULL);
1327    case 5:
1328        return ap_get_remote_logname(r);
1329    case 6:
1330        return r->user;
1331    case 7:
1332        return r->server->server_admin;
1333    case 8:
1334        return ap_get_server_name_for_url(r);
1335    case 9:
1336        return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
1337    case 10:
1338        return r->protocol;
1339    case 11:
1340        return r->filename;
1341    case 12:
1342        return r->path_info;
1343    case 13:
1344        return r->args;
1345    case 14:
1346        return (r->main != NULL ? "true" : "false");
1347    case 15:
1348        return ap_document_root(r);
1349    case 16:
1350        return r->ap_auth_type;
1351    case 17:
1352        return r->the_request;
1353    case 18:
1354        return r->content_type;
1355    case 19:
1356        return r->handler;
1357    case 20:
1358        return r->log_id;
1359    case 21:
1360        {
1361            char *result = "";
1362            if (r->finfo.valid & APR_FINFO_USER)
1363                apr_uid_name_get(&result, r->finfo.user, ctx->p);
1364            return result;
1365        }
1366    case 22:
1367        {
1368            char *result = "";
1369            if (r->finfo.valid & APR_FINFO_USER)
1370                apr_gid_name_get(&result, r->finfo.group, ctx->p);
1371            return result;
1372        }
1373    case 23:
1374        return r->uri;
1375    case 24:
1376        {
1377            apr_time_exp_t tm;
1378            apr_time_exp_lt(&tm, r->mtime);
1379            return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1380                                (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1381                                tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1382                                tm.tm_sec);
1383        }
1384    case 25:
1385        return ap_context_prefix(r);
1386    case 26:
1387        return ap_context_document_root(r);
1388    case 27:
1389        return r->status ? apr_psprintf(ctx->p, "%d", r->status) : "";
1390    case 28:
1391        return r->useragent_ip;
1392    default:
1393        ap_assert(0);
1394        return NULL;
1395    }
1396}
1397
1398static const char *req_header_var_names[] = {
1399    "HTTP_USER_AGENT",
1400    "HTTP_PROXY_CONNECTION",
1401    "HTTP_REFERER",
1402    "HTTP_COOKIE",
1403    "HTTP_FORWARDED",
1404    "HTTP_HOST",
1405    "HTTP_ACCEPT",
1406    NULL
1407};
1408
1409static const char *req_header_header_names[] = {
1410    "User-Agent",
1411    "Proxy-Connection",
1412    "Referer",
1413    "Cookie",
1414    "Forwarded",
1415    "Host",
1416    "Accept"
1417};
1418
1419static const char *req_header_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1420{
1421    const char **varname = (const char **)data;
1422    int index = (varname - req_header_var_names);
1423    const char *name;
1424
1425    AP_DEBUG_ASSERT(index < 6);
1426    if (!ctx->r)
1427        return "";
1428
1429    name = req_header_header_names[index];
1430    add_vary(ctx, name);
1431    return apr_table_get(ctx->r->headers_in, name);
1432}
1433
1434static const char *misc_var_names[] = {
1435    "TIME_YEAR",        /* 0 */
1436    "TIME_MON",         /* 1 */
1437    "TIME_DAY",         /* 2 */
1438    "TIME_HOUR",        /* 3 */
1439    "TIME_MIN",         /* 4 */
1440    "TIME_SEC",         /* 5 */
1441    "TIME_WDAY",        /* 6 */
1442    "TIME",             /* 7 */
1443    "SERVER_SOFTWARE",  /* 8 */
1444    "API_VERSION",      /* 9 */
1445    NULL
1446};
1447
1448static const char *misc_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1449{
1450    apr_time_exp_t tm;
1451    int index = ((const char **)data - misc_var_names);
1452    apr_time_exp_lt(&tm, apr_time_now());
1453
1454    switch (index) {
1455    case 0:
1456        return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
1457                            tm.tm_year % 100);
1458    case 1:
1459        return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
1460    case 2:
1461        return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
1462    case 3:
1463        return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
1464    case 4:
1465        return apr_psprintf(ctx->p, "%02d", tm.tm_min);
1466    case 5:
1467        return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
1468    case 6:
1469        return apr_psprintf(ctx->p, "%d", tm.tm_wday);
1470    case 7:
1471        return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1472                            (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1473                            tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1474                            tm.tm_sec);
1475    case 8:
1476        return ap_get_server_banner();
1477    case 9:
1478        return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER);
1479    default:
1480        ap_assert(0);
1481    }
1482
1483    return NULL;
1484}
1485
1486static int subnet_parse_arg(ap_expr_lookup_parms *parms)
1487{
1488    apr_ipsubnet_t *subnet;
1489    const char *addr = parms->arg;
1490    const char *mask;
1491    apr_status_t ret;
1492
1493    if (!parms->arg) {
1494        *parms->err = apr_psprintf(parms->ptemp,
1495                                   "-%s requires subnet/netmask as constant argument",
1496                                   parms->name);
1497        return !OK;
1498    }
1499
1500    mask = ap_strchr_c(addr, '/');
1501    if (mask) {
1502        addr = apr_pstrmemdup(parms->ptemp, addr, mask - addr);
1503        mask++;
1504    }
1505
1506    ret = apr_ipsubnet_create(&subnet, addr, mask, parms->pool);
1507    if (ret != APR_SUCCESS) {
1508        *parms->err = "parsing of subnet/netmask failed";
1509        return !OK;
1510    }
1511
1512    *parms->data = subnet;
1513    return OK;
1514}
1515
1516static int op_ipmatch(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1,
1517                const char *arg2)
1518{
1519    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
1520    apr_sockaddr_t *saddr;
1521
1522    AP_DEBUG_ASSERT(subnet != NULL);
1523
1524    /* maybe log an error if this goes wrong? */
1525    if (apr_sockaddr_info_get(&saddr, arg1, APR_UNSPEC, 0, 0, ctx->p) != APR_SUCCESS)
1526        return FALSE;
1527
1528    return apr_ipsubnet_test(subnet, saddr);
1529}
1530
1531static int op_R(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1)
1532{
1533    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
1534
1535    AP_DEBUG_ASSERT(subnet != NULL);
1536
1537    if (!ctx->r)
1538        return FALSE;
1539
1540    return apr_ipsubnet_test(subnet, ctx->r->useragent_addr);
1541}
1542
1543static int op_T(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1544{
1545    switch (arg[0]) {
1546    case '\0':
1547        return FALSE;
1548    case 'o':
1549    case 'O':
1550        return strcasecmp(arg, "off") == 0 ? FALSE : TRUE;
1551    case 'n':
1552    case 'N':
1553        return strcasecmp(arg, "no") == 0 ? FALSE : TRUE;
1554    case 'f':
1555    case 'F':
1556        return strcasecmp(arg, "false") == 0 ? FALSE : TRUE;
1557    case '0':
1558        return arg[1] == '\0' ? FALSE : TRUE;
1559    default:
1560        return TRUE;
1561    }
1562}
1563
1564static int op_fnmatch(ap_expr_eval_ctx_t *ctx, const void *data,
1565                      const char *arg1, const char *arg2)
1566{
1567    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_PATHNAME));
1568}
1569
1570static int op_strmatch(ap_expr_eval_ctx_t *ctx, const void *data,
1571                       const char *arg1, const char *arg2)
1572{
1573    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, 0));
1574}
1575
1576static int op_strcmatch(ap_expr_eval_ctx_t *ctx, const void *data,
1577                        const char *arg1, const char *arg2)
1578{
1579    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_CASE_BLIND));
1580}
1581
1582struct expr_provider_single {
1583    const void *func;
1584    const char *name;
1585    ap_expr_lookup_fn_t *arg_parsing_func;
1586    int restricted;
1587};
1588
1589struct expr_provider_multi {
1590    const void *func;
1591    const char **names;
1592};
1593
1594static const struct expr_provider_multi var_providers[] = {
1595    { misc_var_fn, misc_var_names },
1596    { req_header_var_fn, req_header_var_names },
1597    { request_var_fn, request_var_names },
1598    { conn_var_fn, conn_var_names },
1599    { NULL, NULL }
1600};
1601
1602static const struct expr_provider_single string_func_providers[] = {
1603    { osenv_func,           "osenv",          NULL, 0 },
1604    { env_func,             "env",            NULL, 0 },
1605    { req_table_func,       "resp",           NULL, 0 },
1606    { req_table_func,       "req",            NULL, 0 },
1607    /* 'http' as alias for 'req' for compatibility with ssl_expr */
1608    { req_table_func,       "http",           NULL, 0 },
1609    { req_table_func,       "note",           NULL, 0 },
1610    { req_table_func,       "reqenv",         NULL, 0 },
1611    { req_table_func,       "req_novary",     NULL, 0 },
1612    { tolower_func,         "tolower",        NULL, 0 },
1613    { toupper_func,         "toupper",        NULL, 0 },
1614    { escape_func,          "escape",         NULL, 0 },
1615    { unescape_func,        "unescape",       NULL, 0 },
1616    { file_func,            "file",           NULL, 1 },
1617    { filesize_func,        "filesize",       NULL, 1 },
1618    { base64_func,          "base64",         NULL, 0 },
1619    { unbase64_func,        "unbase64",       NULL, 0 },
1620    { sha1_func,            "sha1",           NULL, 0 },
1621    { md5_func,             "md5",            NULL, 0 },
1622    { NULL, NULL, NULL}
1623};
1624
1625static const struct expr_provider_single unary_op_providers[] = {
1626    { op_nz,        "n", NULL,             0 },
1627    { op_nz,        "z", NULL,             0 },
1628    { op_R,         "R", subnet_parse_arg, 0 },
1629    { op_T,         "T", NULL,             0 },
1630    { op_file_min,  "d", NULL,             1 },
1631    { op_file_min,  "e", NULL,             1 },
1632    { op_file_min,  "f", NULL,             1 },
1633    { op_file_min,  "s", NULL,             1 },
1634    { op_file_link, "L", NULL,             1 },
1635    { op_file_link, "h", NULL,             1 },
1636    { op_file_xbit, "x", NULL,             1 },
1637    { op_file_subr, "F", NULL,             0 },
1638    { op_url_subr,  "U", NULL,             0 },
1639    { op_url_subr,  "A", NULL,             0 },
1640    { NULL, NULL, NULL }
1641};
1642
1643static const struct expr_provider_single binary_op_providers[] = {
1644    { op_ipmatch,   "ipmatch",      subnet_parse_arg, 0 },
1645    { op_fnmatch,   "fnmatch",      NULL,             0 },
1646    { op_strmatch,  "strmatch",     NULL,             0 },
1647    { op_strcmatch, "strcmatch",    NULL,             0 },
1648    { NULL, NULL, NULL }
1649};
1650
1651static int core_expr_lookup(ap_expr_lookup_parms *parms)
1652{
1653    switch (parms->type) {
1654    case AP_EXPR_FUNC_VAR: {
1655            const struct expr_provider_multi *prov = var_providers;
1656            while (prov->func) {
1657                const char **name = prov->names;
1658                while (*name) {
1659                    if (strcasecmp(*name, parms->name) == 0) {
1660                        *parms->func = prov->func;
1661                        *parms->data = name;
1662                        return OK;
1663                    }
1664                    name++;
1665                }
1666                prov++;
1667            }
1668        }
1669        break;
1670    case AP_EXPR_FUNC_STRING:
1671    case AP_EXPR_FUNC_OP_UNARY:
1672    case AP_EXPR_FUNC_OP_BINARY: {
1673            const struct expr_provider_single *prov;
1674            switch (parms->type) {
1675            case AP_EXPR_FUNC_STRING:
1676                prov = string_func_providers;
1677                break;
1678            case AP_EXPR_FUNC_OP_UNARY:
1679                prov = unary_op_providers;
1680                break;
1681            case AP_EXPR_FUNC_OP_BINARY:
1682                prov = binary_op_providers;
1683                break;
1684            default:
1685                ap_assert(0);
1686            }
1687            while (prov->func) {
1688                int match;
1689                if (parms->type == AP_EXPR_FUNC_OP_UNARY)
1690                    match = !strcmp(prov->name, parms->name);
1691                else
1692                    match = !strcasecmp(prov->name, parms->name);
1693                if (match) {
1694                    if ((parms->flags & AP_EXPR_FLAG_RESTRICTED)
1695                        && prov->restricted) {
1696                        *parms->err =
1697                            apr_psprintf(parms->ptemp,
1698                                         "%s%s not available in restricted context",
1699                                         (parms->type == AP_EXPR_FUNC_STRING) ? "" : "-",
1700                                         prov->name);
1701                        return !OK;
1702                    }
1703                    *parms->func = prov->func;
1704                    if (prov->arg_parsing_func) {
1705                        return prov->arg_parsing_func(parms);
1706                    }
1707                    else {
1708                        *parms->data = prov->name;
1709                        return OK;
1710                    }
1711                }
1712                prov++;
1713            }
1714        }
1715        break;
1716    default:
1717        break;
1718    }
1719    return DECLINED;
1720}
1721
1722static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
1723{
1724    const char *type;
1725    const char *prefix = "";
1726
1727    switch (parms->type) {
1728    case AP_EXPR_FUNC_VAR:
1729        type = "Variable";
1730        break;
1731    case AP_EXPR_FUNC_STRING:
1732        type = "Function";
1733        break;
1734    case AP_EXPR_FUNC_LIST:
1735        type = "List-returning function";
1736        break;
1737    case AP_EXPR_FUNC_OP_UNARY:
1738        type = "Unary operator";
1739        break;
1740    case AP_EXPR_FUNC_OP_BINARY:
1741        type = "Binary operator";
1742        break;
1743    default:
1744        *parms->err = "Inavalid expression type in expr_lookup";
1745        return !OK;
1746    }
1747    if (   parms->type == AP_EXPR_FUNC_OP_UNARY
1748        || parms->type == AP_EXPR_FUNC_OP_BINARY) {
1749        prefix = "-";
1750    }
1751    *parms->err = apr_psprintf(parms->ptemp, "%s '%s%s' does not exist", type,
1752                               prefix, parms->name);
1753    return !OK;
1754}
1755
1756static int ap_expr_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1757                               apr_pool_t *ptemp, server_rec *s)
1758{
1759    is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
1760    apr_pool_cleanup_register(pconf, &is_https, ap_pool_cleanup_set_null,
1761                              apr_pool_cleanup_null);
1762    return OK;
1763}
1764
1765void ap_expr_init(apr_pool_t *p)
1766{
1767    ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
1768    ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
1769    ap_hook_post_config(ap_expr_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1770}
1771
1772