Coverage Report

Created: 2025-07-11 06:40

/src/httpd/server/util_expr_eval.c
Line
Count
Source (jump to first uncovered line)
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 "http_ssl.h"
27
#include "ap_provider.h"
28
#include "util_varbuf.h"
29
#include "util_expr_private.h"
30
#include "util_md5.h"
31
#include "util_varbuf.h"
32
33
#include "apr_lib.h"
34
#include "apr_fnmatch.h"
35
#include "apr_base64.h"
36
#include "apr_sha1.h"
37
#include "apr_version.h"
38
#include "apr_strings.h"
39
#include "apr_strmatch.h"
40
#if APR_VERSION_AT_LEAST(1,5,0)
41
#include "apr_escape.h"
42
#endif
43
44
#include <limits.h>     /* for INT_MAX */
45
46
/* we know core's module_index is 0 */
47
#undef APLOG_MODULE_INDEX
48
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
49
50
APR_HOOK_STRUCT(
51
    APR_HOOK_LINK(expr_lookup)
52
)
53
54
AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
55
                            (parms), DECLINED)
56
57
#define  LOG_MARK(info)  __FILE__, __LINE__, (info)->module_index
58
59
static int ap_expr_eval_cond(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node);
60
61
static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
62
                                            const ap_expr_t *info,
63
                                            const ap_expr_t *args);
64
static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx,
65
                                           unsigned int n);
66
static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
67
                                    ap_expr_var_func_t *func,
68
                                    const void *data);
69
70
typedef struct {
71
    int flags;
72
    const ap_expr_t *subst;
73
} ap_expr_regctx_t;
74
75
static const char *ap_expr_regexec(const char *subject,
76
                                   const ap_expr_t *reg,
77
                                   apr_array_header_t *list,
78
                                   ap_expr_eval_ctx_t *ctx);
79
80
static apr_array_header_t *ap_expr_list_make(ap_expr_eval_ctx_t *ctx,
81
                                             const ap_expr_t *node);
82
83
/* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
84
#ifdef AP_EXPR_DEBUG
85
static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
86
                           int loglevel, int indent);
87
#endif
88
89
/*
90
 * To reduce counting overhead, we only count calls to
91
 * ap_expr_eval_word() and ap_expr_eval_cond(). The max number of
92
 * stack frames is larger by some factor.
93
 */
94
0
#define AP_EXPR_MAX_RECURSION   20
95
static int inc_rec(ap_expr_eval_ctx_t *ctx)
96
0
{
97
0
    if (ctx->reclvl < AP_EXPR_MAX_RECURSION) {
98
0
        ctx->reclvl++;
99
0
        return 0;
100
0
    }
101
0
    *ctx->err = "Recursion limit reached";
102
    /* short circuit further evaluation */
103
0
    ctx->reclvl = INT_MAX;
104
0
    return 1;
105
0
}
106
107
static const char *ap_expr_list_pstrcat(apr_pool_t *p,
108
                                        const apr_array_header_t *list,
109
                                        const char *sep)
110
0
{
111
0
    if (list->nelts <= 0) {
112
0
        return NULL;
113
0
    }
114
0
    else if (list->nelts == 1) {
115
0
        return APR_ARRAY_IDX(list, 0, const char*);
116
0
    }
117
0
    else {
118
0
        struct ap_varbuf vb;
119
0
        int n = list->nelts - 1, i;
120
0
        apr_size_t slen = strlen(sep), vlen;
121
0
        const char *val;
122
123
0
        ap_varbuf_init(p, &vb, 0);
124
0
        for (i = 0; i < n; ++i) {
125
0
            val = APR_ARRAY_IDX(list, i, const char*);
126
0
            vlen = strlen(val);
127
0
            ap_varbuf_strmemcat(&vb, val, vlen);
128
0
            ap_varbuf_strmemcat(&vb, sep, slen);
129
0
        }
130
0
        val = APR_ARRAY_IDX(list, n, const char*);
131
0
        ap_varbuf_strmemcat(&vb, val, strlen(val));
132
133
0
        return vb.buf;
134
0
    }
135
0
}
136
137
static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
138
                                     const ap_expr_t *node)
139
0
{
140
0
    const char *result = "";
141
0
    if (inc_rec(ctx))
142
0
        return result;
143
0
    switch (node->node_op) {
144
0
    case op_Digit:
145
0
    case op_String:
146
0
        result = node->node_arg1;
147
0
        break;
148
0
    case op_Word:
149
0
        result = ap_expr_eval_word(ctx, node->node_arg1);
150
0
        break;
151
0
    case op_Bool:
152
0
        result = ap_expr_eval_cond(ctx, node->node_arg1) ? "true" : "false";
153
0
        break;
154
0
    case op_Var:
155
0
        result = ap_expr_eval_var(ctx, (ap_expr_var_func_t *)node->node_arg1,
156
0
                                  node->node_arg2);
157
0
        break;
158
0
    case op_Concat:
159
0
        if (((ap_expr_t *)node->node_arg2)->node_op != op_Concat &&
160
0
            ((ap_expr_t *)node->node_arg1)->node_op != op_Concat) {
161
0
            const char *s1 = ap_expr_eval_word(ctx, node->node_arg1);
162
0
            const char *s2 = ap_expr_eval_word(ctx, node->node_arg2);
163
0
            if (!*s1)
164
0
                result = s2;
165
0
            else if (!*s2)
166
0
                result = s1;
167
0
            else
168
0
                result = apr_pstrcat(ctx->p, s1, s2, NULL);
169
0
        }
170
0
        else if (((ap_expr_t *)node->node_arg1)->node_op == op_Concat) {
171
0
            const ap_expr_t *nodep = node;
172
0
            int n;
173
0
            int i = 1;
174
0
            struct iovec *vec;
175
0
            do {
176
0
                nodep = nodep->node_arg1;
177
0
                i++;
178
0
            } while (nodep->node_op == op_Concat);
179
0
            vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
180
0
            n = i;
181
0
            nodep = node;
182
0
            i--;
183
0
            do {
184
0
                vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
185
0
                                                            nodep->node_arg2);
186
0
                vec[i].iov_len = strlen(vec[i].iov_base);
187
0
                i--;
188
0
                nodep = nodep->node_arg1;
189
0
            } while (nodep->node_op == op_Concat);
190
0
            vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
191
0
            vec[i].iov_len = strlen(vec[i].iov_base);
192
0
            result = apr_pstrcatv(ctx->p, vec, n, NULL);
193
0
        }
194
0
        else {
195
0
            const ap_expr_t *nodep = node;
196
0
            int i = 1;
197
0
            struct iovec *vec;
198
0
            do {
199
0
                nodep = nodep->node_arg2;
200
0
                i++;
201
0
            } while (nodep->node_op == op_Concat);
202
0
            vec = apr_palloc(ctx->p, i * sizeof(struct iovec));
203
0
            nodep = node;
204
0
            i = 0;
205
0
            do {
206
0
                vec[i].iov_base = (void *)ap_expr_eval_word(ctx,
207
0
                                                            nodep->node_arg1);
208
0
                vec[i].iov_len = strlen(vec[i].iov_base);
209
0
                i++;
210
0
                nodep = nodep->node_arg2;
211
0
            } while (nodep->node_op == op_Concat);
212
0
            vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep);
213
0
            vec[i].iov_len = strlen(vec[i].iov_base);
214
0
            i++;
215
0
            result = apr_pstrcatv(ctx->p, vec, i, NULL);
216
0
        }
217
0
        break;
218
0
    case op_StringFuncCall: {
219
0
        const ap_expr_t *info = node->node_arg1;
220
0
        const ap_expr_t *args = node->node_arg2;
221
0
        result = ap_expr_eval_string_func(ctx, info, args);
222
0
        break;
223
0
    }
224
0
    case op_Join: {
225
0
        const char *sep;
226
0
        apr_array_header_t *list = ap_expr_list_make(ctx, node->node_arg1);
227
0
        sep = node->node_arg2 ? ap_expr_eval_word(ctx, node->node_arg2) : "";
228
0
        result = ap_expr_list_pstrcat(ctx->p, list, sep);
229
0
        break;
230
0
    }
231
0
    case op_Sub: {
232
0
        const ap_expr_t *reg = node->node_arg2;
233
0
        const char *subject = ap_expr_eval_word(ctx, node->node_arg1);
234
0
        result = ap_expr_regexec(subject, reg, NULL, ctx);
235
0
        break;
236
0
    }
237
0
    case op_Backref: {
238
0
        const unsigned int *np = node->node_arg1;
239
0
        result = ap_expr_eval_re_backref(ctx, *np);
240
0
        break;
241
0
    }
242
0
    default:
243
0
        *ctx->err = "Internal evaluation error: Unknown word expression node";
244
0
        break;
245
0
    }
246
0
    if (!result)
247
0
        result = "";
248
0
    ctx->reclvl--;
249
0
    return result;
250
0
}
251
252
static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
253
                                    ap_expr_var_func_t *func,
254
                                    const void *data)
255
0
{
256
0
    AP_DEBUG_ASSERT(func != NULL);
257
0
    AP_DEBUG_ASSERT(data != NULL);
258
0
    return (*func)(ctx, data);
259
0
}
260
261
static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx, unsigned int n)
262
0
{
263
0
    int len;
264
265
0
    if (!ctx->re_pmatch || !ctx->re_source || !*ctx->re_source
266
0
        || **ctx->re_source == '\0' || ctx->re_nmatch < n + 1)
267
0
        return "";
268
269
0
    len = ctx->re_pmatch[n].rm_eo - ctx->re_pmatch[n].rm_so;
270
0
    if (len == 0)
271
0
        return "";
272
273
0
    return apr_pstrndup(ctx->p, *ctx->re_source + ctx->re_pmatch[n].rm_so, len);
274
0
}
275
276
static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
277
                                            const ap_expr_t *info,
278
                                            const ap_expr_t *arg)
279
0
{
280
0
    const void *data = info->node_arg2;
281
282
0
    AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
283
0
    AP_DEBUG_ASSERT(info->node_arg1 != NULL);
284
0
    AP_DEBUG_ASSERT(data != NULL);
285
0
    if (arg->node_op == op_ListElement) {
286
        /* Evaluate the list elements and store them in apr_array_header. */
287
0
        ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
288
0
        apr_array_header_t *args = ap_expr_list_make(ctx, arg);
289
0
        return (*func)(ctx, data, args);
290
0
    }
291
0
    else {
292
0
        ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
293
0
        return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
294
0
    }
295
0
}
296
297
static int intstrcmp(const char *s1, const char *s2)
298
0
{
299
0
    apr_int64_t i1 = apr_atoi64(s1);
300
0
    apr_int64_t i2 = apr_atoi64(s2);
301
302
0
    if (i1 < i2)
303
0
        return -1;
304
0
    else if (i1 == i2)
305
0
        return 0;
306
0
    else
307
0
        return 1;
308
0
}
309
310
static const char *ap_expr_regexec(const char *subject,
311
                                   const ap_expr_t *reg,
312
                                   apr_array_header_t *list,
313
                                   ap_expr_eval_ctx_t *ctx)
314
0
{
315
0
    struct ap_varbuf vb;
316
0
    const char *val = subject;
317
0
    const ap_regex_t *regex = reg->node_arg1;
318
0
    const ap_expr_regctx_t *regctx = reg->node_arg2;
319
0
    ap_regmatch_t *pmatch = NULL, match0;
320
0
    apr_size_t nmatch = 0;
321
0
    const char *str = "";
322
0
    apr_size_t len = 0;
323
0
    int empty = 0, rv;
324
325
0
    ap_varbuf_init(ctx->p, &vb, 0);
326
0
    if (ctx->re_nmatch > 0) {
327
0
        nmatch = ctx->re_nmatch;
328
0
        pmatch = ctx->re_pmatch;
329
0
    }
330
0
    else if (regctx->subst) {
331
0
        nmatch = 1;
332
0
        pmatch = &match0;
333
0
    }
334
0
    do {
335
        /* If previous match was empty, we can't issue the exact same one or
336
         * we'd loop indefinitely.  So let's instead ask for an anchored and
337
         * non-empty match (i.e. something not empty at the start of the value)
338
         * and if nothing is found advance by one character below.
339
         */
340
0
        rv = ap_regexec(regex, val, nmatch, pmatch, 
341
0
                        empty ? AP_REG_ANCHORED | AP_REG_NOTEMPTY : 0);
342
0
        if (rv == 0) {
343
0
            int pos = pmatch[0].rm_so,
344
0
                end = pmatch[0].rm_eo;
345
0
            AP_DEBUG_ASSERT(pos >= 0 && pos <= end);
346
347
0
            if (regctx->subst) {
348
0
                *ctx->re_source = val;
349
0
                str = ap_expr_eval_word(ctx, regctx->subst);
350
0
                len = strlen(str);
351
0
            }
352
0
            if (list) {
353
0
                char *tmp = apr_palloc(ctx->p, pos + len + 1);
354
0
                memcpy(tmp, val, pos);
355
0
                memcpy(tmp + pos, str, len + 1);
356
0
                APR_ARRAY_PUSH(list, const char*) = tmp;
357
0
            }
358
0
            else {
359
0
                ap_varbuf_grow(&vb, pos + len + 1);
360
0
                ap_varbuf_strmemcat(&vb, val, pos);
361
0
                ap_varbuf_strmemcat(&vb, str, len);
362
0
                if (!(regctx->flags & AP_REG_MULTI)) {
363
                    /* Single substitution, preserve remaining data */
364
0
                    ap_varbuf_strmemcat(&vb, val + end, strlen(val) - end);
365
0
                    break;
366
0
                }
367
0
            }
368
            /* Note an empty match */
369
0
            empty = (end == 0);
370
0
            val += end;
371
0
        }
372
0
        else if (empty) {
373
            /* Skip this non-matching character (or full CRLF) and restart
374
             * another "normal" match (possibly empty) from there.
375
             */
376
0
            if (val[0] == '\r' && val[1] == '\n') {
377
0
                val += 2;
378
0
            }
379
0
            else {
380
0
                val++;
381
0
            }
382
0
            empty = 0;
383
0
        }
384
0
        else {
385
0
            if (list) {
386
0
                APR_ARRAY_PUSH(list, const char*) = val;
387
0
            }
388
0
            else if (vb.avail) {
389
0
                ap_varbuf_strmemcat(&vb, val, strlen(val));
390
0
            }
391
0
            else {
392
0
                return val;
393
0
            }
394
0
            break;
395
0
        }
396
0
    } while (*val);
397
398
0
    return vb.buf;
399
0
}
400
401
static apr_array_header_t *ap_expr_list_make(ap_expr_eval_ctx_t *ctx,
402
                                             const ap_expr_t *node)
403
0
{
404
0
    apr_array_header_t *list = NULL;
405
406
0
    if (node->node_op == op_Split) {
407
0
        const ap_expr_t *arg = node->node_arg1;
408
0
        const ap_expr_t *reg = node->node_arg2;
409
0
        const apr_array_header_t *source = ap_expr_list_make(ctx, arg);
410
0
        int i;
411
412
0
        list = apr_array_make(ctx->p, source->nelts, sizeof(const char*));
413
0
        for (i = 0; i < source->nelts; ++i) {
414
0
            const char *val = APR_ARRAY_IDX(source, i, const char*);
415
0
            (void)ap_expr_regexec(val, reg, list, ctx);
416
0
        }
417
0
    }
418
0
    else if (node->node_op == op_ListElement) {
419
0
        int n = 0;
420
0
        const ap_expr_t *elem;
421
0
        for (elem = node; elem; elem = elem->node_arg2) {
422
0
            AP_DEBUG_ASSERT(elem->node_op == op_ListElement);
423
0
            n++;
424
0
        }
425
426
0
        list = apr_array_make(ctx->p, n, sizeof(const char*));
427
0
        for (elem = node; elem; elem = elem->node_arg2) {
428
0
            APR_ARRAY_PUSH(list, const char*) =
429
0
                ap_expr_eval_word(ctx, elem->node_arg1);
430
0
        }
431
0
    }
432
0
    else if (node->node_op == op_ListFuncCall) {
433
0
        const ap_expr_t *info = node->node_arg1;
434
0
        ap_expr_list_func_t *func = info->node_arg1;
435
436
0
        AP_DEBUG_ASSERT(func != NULL);
437
0
        AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
438
0
        list = (*func)(ctx, info->node_arg2,
439
0
                       ap_expr_eval_word(ctx, node->node_arg2));
440
0
    }
441
0
    else {
442
0
        list = apr_array_make(ctx->p, 1, sizeof(const char*));
443
0
        APR_ARRAY_PUSH(list, const char*) = ap_expr_eval_word(ctx, node);
444
0
    }
445
446
0
    return list;
447
0
}
448
449
static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
450
0
{
451
0
    const ap_expr_t *e1 = node->node_arg1;
452
0
    const ap_expr_t *e2 = node->node_arg2;
453
0
    switch (node->node_op) {
454
0
    case op_EQ:
455
0
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
456
0
    case op_NE:
457
0
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
458
0
    case op_LT:
459
0
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
460
0
    case op_LE:
461
0
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
462
0
    case op_GT:
463
0
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
464
0
    case op_GE:
465
0
        return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
466
0
    case op_STR_EQ:
467
0
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
468
0
    case op_STR_NE:
469
0
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
470
0
    case op_STR_LT:
471
0
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
472
0
    case op_STR_LE:
473
0
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
474
0
    case op_STR_GT:
475
0
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
476
0
    case op_STR_GE:
477
0
        return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
478
0
    case op_IN: {
479
0
            int n;
480
0
            const char *needle, *subject;
481
0
            apr_array_header_t *haystack;
482
0
            haystack = ap_expr_list_make(ctx, e2);
483
0
            if (haystack) {
484
0
                needle = ap_expr_eval_word(ctx, e1);
485
0
                for (n = 0; n < haystack->nelts; ++n) {
486
0
                    subject = APR_ARRAY_IDX(haystack, n, const char*);
487
0
                    if (strcmp(needle, subject) == 0) {
488
0
                        return 1;
489
0
                    }
490
0
                }
491
0
            }
492
0
            return 0;
493
0
        }
494
0
    case op_REG:
495
0
    case op_NRE: {
496
0
            const char *word = ap_expr_eval_word(ctx, e1);
497
0
            const ap_regex_t *regex = e2->node_arg1;
498
0
            int result;
499
500
            /*
501
             * $0 ... $9 may contain stuff the user wants to keep. Therefore
502
             * we only set them if there are capturing parens in the regex.
503
             */
504
0
            if (regex->re_nsub > 0) {
505
0
                result = (0 == ap_regexec(regex, word, ctx->re_nmatch,
506
0
                                          ctx->re_pmatch, 0));
507
0
                *ctx->re_source = result ? word : NULL;
508
0
            }
509
0
            else {
510
0
                result = (0 == ap_regexec(regex, word, 0, NULL, 0));
511
0
            }
512
513
0
            return result ^ (node->node_op == op_NRE);
514
0
        }
515
0
    default:
516
0
        *ctx->err = "Internal evaluation error: Unknown comp expression node";
517
0
        return -1;
518
0
    }
519
0
}
520
521
/* combined string/int comparison for compatibility with ssl_expr */
522
static int strcmplex(const char *str1, const char *str2)
523
0
{
524
0
    apr_size_t i, n1, n2;
525
526
0
    if (str1 == NULL)
527
0
        return -1;
528
0
    if (str2 == NULL)
529
0
        return +1;
530
0
    n1 = strlen(str1);
531
0
    n2 = strlen(str2);
532
0
    if (n1 > n2)
533
0
        return 1;
534
0
    if (n1 < n2)
535
0
        return -1;
536
0
    for (i = 0; i < n1; i++) {
537
0
        if (str1[i] > str2[i])
538
0
            return 1;
539
0
        if (str1[i] < str2[i])
540
0
            return -1;
541
0
    }
542
0
    return 0;
543
0
}
544
545
static int ssl_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
546
0
{
547
0
    const ap_expr_t *e1 = node->node_arg1;
548
0
    const ap_expr_t *e2 = node->node_arg2;
549
0
    switch (node->node_op) {
550
0
    case op_EQ:
551
0
    case op_STR_EQ:
552
0
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
553
0
    case op_NE:
554
0
    case op_STR_NE:
555
0
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
556
0
    case op_LT:
557
0
    case op_STR_LT:
558
0
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
559
0
    case op_LE:
560
0
    case op_STR_LE:
561
0
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
562
0
    case op_GT:
563
0
    case op_STR_GT:
564
0
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
565
0
    case op_GE:
566
0
    case op_STR_GE:
567
0
        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
568
0
    default:
569
0
        return ap_expr_eval_comp(ctx, node);
570
0
    }
571
0
}
572
573
AP_DECLARE_NONSTD(int) ap_expr_lookup_default(ap_expr_lookup_parms *parms)
574
2.83k
{
575
2.83k
    return ap_run_expr_lookup(parms);
576
2.83k
}
577
578
AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
579
                                       ap_expr_info_t *info, const char *expr,
580
                                       ap_expr_lookup_fn_t *lookup_fn)
581
1.37k
{
582
1.37k
    ap_expr_parse_ctx_t ctx;
583
1.37k
    int rc;
584
585
1.37k
    memset(&ctx, 0, sizeof ctx);
586
1.37k
    ctx.pool     = pool;
587
1.37k
    ctx.ptemp    = ptemp;
588
1.37k
    ctx.inputbuf = expr;
589
1.37k
    ctx.inputlen = strlen(expr);
590
1.37k
    ctx.inputptr = ctx.inputbuf;
591
1.37k
    ctx.flags    = info->flags;
592
1.37k
    ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_expr_lookup_default;
593
1.37k
    ctx.at_start    = 1;
594
595
1.37k
    rc = ap_expr_yylex_init(&ctx.scanner);
596
1.37k
    if (rc)
597
0
        return "ap_expr_yylex_init error";
598
599
1.37k
    ap_expr_yyset_extra(&ctx, ctx.scanner);
600
1.37k
    rc = ap_expr_yyparse(&ctx);
601
1.37k
    ap_expr_yylex_destroy(ctx.scanner);
602
603
    /* ctx.error: the generic bison error message
604
     *            (XXX: usually not very useful, should be axed)
605
     * ctx.error2: an additional error message
606
     */
607
1.37k
    if (ctx.error) {
608
166
        if (ctx.error2)
609
25
            return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
610
141
        else
611
141
            return ctx.error;
612
166
    }
613
1.20k
    else if (ctx.error2) {
614
69
        return ctx.error2;
615
69
    }
616
617
1.13k
    if (rc) /* XXX can this happen? */
618
0
        return "syntax error";
619
620
#ifdef AP_EXPR_DEBUG
621
    if (ctx.expr)
622
        expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
623
#endif
624
625
1.13k
    info->root_node = ctx.expr;
626
627
1.13k
    return NULL;
628
1.13k
}
629
630
AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd_mi(const cmd_parms *cmd,
631
                                                 const char *expr,
632
                                                 unsigned int flags,
633
                                                 const char **err,
634
                                                 ap_expr_lookup_fn_t *lookup_fn,
635
                                                 int module_index)
636
0
{
637
0
    ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
638
0
    info->filename = cmd->directive->filename;
639
0
    info->line_number = cmd->directive->line_num;
640
0
    info->flags = flags;
641
0
    info->module_index = module_index;
642
0
    *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
643
644
0
    if (*err)
645
0
        return NULL;
646
647
0
    return info;
648
0
}
649
650
ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
651
                        ap_expr_parse_ctx_t *ctx)
652
87.5k
{
653
87.5k
    ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
654
87.5k
    node->node_op   = op;
655
87.5k
    node->node_arg1 = a1;
656
87.5k
    node->node_arg2 = a2;
657
87.5k
    return node;
658
87.5k
}
659
660
ap_expr_t *ap_expr_concat_make(const void *a1, const void *a2,
661
                               ap_expr_parse_ctx_t *ctx)
662
26.9k
{
663
26.9k
    const ap_expr_t *node;
664
665
    /* Optimize out empty string(s) concatenation */
666
26.9k
    if ((node = a1)
667
26.9k
            && node->node_op == op_String
668
26.9k
            && !*(const char *)node->node_arg1) {
669
0
        return (ap_expr_t *)a2;
670
0
    }
671
26.9k
    if ((node = a2)
672
26.9k
            && node->node_op == op_String
673
26.9k
            && !*(const char *)node->node_arg1) {
674
227
        return (ap_expr_t *)a1;
675
227
    }
676
677
26.7k
    return ap_expr_make(op_Concat, a1, a2, ctx);
678
26.9k
}
679
680
ap_expr_t *ap_expr_regex_make(const char *pattern, const ap_expr_t *subst,
681
                              const char *flags, ap_expr_parse_ctx_t *ctx)
682
5.99k
{
683
5.99k
    ap_expr_t *node = NULL;
684
5.99k
    ap_expr_regctx_t *regctx;
685
5.99k
    ap_regex_t *regex;
686
687
5.99k
    regctx = apr_pcalloc(ctx->pool, sizeof *regctx);
688
5.99k
    regctx->subst = subst;
689
5.99k
    if (flags) {
690
6.61k
        for (; *flags; ++flags) {
691
626
            switch (*flags) {
692
495
            case 'i':
693
495
                regctx->flags |= AP_REG_ICASE;
694
495
                break;
695
129
            case 'm':
696
129
                regctx->flags |= AP_REG_NEWLINE;
697
129
                break;
698
0
            case 's':
699
0
                regctx->flags |= AP_REG_DOTALL;
700
0
                break;
701
2
            case 'g':
702
2
                regctx->flags |= AP_REG_MULTI;
703
2
                break;
704
626
            }
705
626
        }
706
5.99k
    }
707
5.99k
    regex = ap_pregcomp(ctx->pool, pattern, regctx->flags);
708
5.99k
    if (!regex) {
709
1
        return NULL;
710
1
    }
711
712
5.98k
    node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
713
5.98k
    node->node_op   = op_Regex;
714
5.98k
    node->node_arg1 = regex;
715
5.98k
    node->node_arg2 = regctx;
716
5.98k
    return node;
717
5.99k
}
718
719
static ap_expr_t *ap_expr_info_make(int type, const char *name,
720
                                  ap_expr_parse_ctx_t *ctx,
721
                                  const ap_expr_t *arg)
722
2.83k
{
723
2.83k
    ap_expr_t *info = apr_palloc(ctx->pool, sizeof(ap_expr_t));
724
2.83k
    ap_expr_lookup_parms parms;
725
2.83k
    parms.type  = type;
726
2.83k
    parms.flags = ctx->flags;
727
2.83k
    parms.pool  = ctx->pool;
728
2.83k
    parms.ptemp = ctx->ptemp;
729
2.83k
    parms.name  = name;
730
2.83k
    parms.func  = &info->node_arg1;
731
2.83k
    parms.data  = &info->node_arg2;
732
2.83k
    parms.err   = &ctx->error2;
733
2.83k
    parms.arg   = NULL;
734
2.83k
    if (arg) {
735
2.29k
        switch(arg->node_op) {
736
293
            case op_String:
737
293
                parms.arg = arg->node_arg1;
738
293
                break;
739
170
            case op_ListElement:
740
                /* save the first literal/simple string argument */
741
342
                do {
742
342
                    const ap_expr_t *val = arg->node_arg1;
743
342
                    if (val && val->node_op == op_String) {
744
0
                        parms.arg = val->node_arg1;
745
0
                        break;
746
0
                    }
747
342
                    arg = arg->node_arg2;
748
342
                } while (arg != NULL);
749
0
                break;
750
1.82k
            default:
751
1.82k
                break;
752
2.29k
        }
753
2.29k
    }
754
2.83k
    if (ctx->lookup_fn(&parms) != OK)
755
2.83k
        return NULL;
756
0
    return info;
757
2.83k
}
758
759
ap_expr_t *ap_expr_str_func_make(const char *name, const ap_expr_t *arg,
760
                               ap_expr_parse_ctx_t *ctx)
761
958
{
762
958
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx, arg);
763
958
    if (!info)
764
958
        return NULL;
765
766
0
    info->node_op = op_StringFuncInfo;
767
0
    return ap_expr_make(op_StringFuncCall, info, arg, ctx);
768
958
}
769
770
ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
771
                                ap_expr_parse_ctx_t *ctx)
772
1.32k
{
773
1.32k
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx, arg);
774
1.32k
    if (!info)
775
1.32k
        return NULL;
776
777
0
    info->node_op = op_ListFuncInfo;
778
0
    return ap_expr_make(op_ListFuncCall, info, arg, ctx);
779
1.32k
}
780
781
ap_expr_t *ap_expr_unary_op_make(const char *name, const ap_expr_t *arg,
782
                               ap_expr_parse_ctx_t *ctx)
783
282
{
784
282
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx, arg);
785
282
    if (!info)
786
282
        return NULL;
787
788
0
    info->node_op = op_UnaryOpInfo;
789
0
    return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
790
282
}
791
792
ap_expr_t *ap_expr_binary_op_make(const char *name, const ap_expr_t *arg1,
793
                                const ap_expr_t *arg2, ap_expr_parse_ctx_t *ctx)
794
269
{
795
269
    ap_expr_t *args;
796
269
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_BINARY, name, ctx,
797
269
                                        arg2);
798
269
    if (!info)
799
269
        return NULL;
800
801
0
    info->node_op = op_BinaryOpInfo;
802
0
    args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
803
0
    return ap_expr_make(op_BinaryOpCall, info, args, ctx);
804
269
}
805
806
807
ap_expr_t *ap_expr_var_make(const char *name, ap_expr_parse_ctx_t *ctx)
808
0
{
809
0
    ap_expr_t *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx, NULL);
810
0
    if (!node)
811
0
        return NULL;
812
813
0
    node->node_op = op_Var;
814
0
    return node;
815
0
}
816
817
ap_expr_t *ap_expr_backref_make(int num, ap_expr_parse_ctx_t *ctx)
818
13.9k
{
819
13.9k
    int *n = apr_pmemdup(ctx->pool, &num, sizeof(num));
820
13.9k
    return ap_expr_make(op_Backref, n, NULL, ctx);
821
13.9k
}
822
823
#ifdef AP_EXPR_DEBUG
824
825
#define MARK                        APLOG_MARK,loglevel,0,s
826
#define DUMP_E_E(op, e1, e2)                                                \
827
    do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2);      \
828
         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);               \
829
         if (e2) expr_dump_tree(e2, s, loglevel, indent + 2);               \
830
    } while (0)
831
#define DUMP_S_E(op, s1, e1)                                                    \
832
    do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
833
         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);                   \
834
    } while (0)
835
#define DUMP_S_P(op, s1, p1)                                                \
836
    ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
837
#define DUMP_P_P(op, p1, p2)                                                \
838
    ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
839
#define DUMP_S_S(op, s1, s2)                                                       \
840
    ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
841
#define DUMP_P(op, p1)                                                      \
842
    ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
843
#define DUMP_IP(op, p1)                                                     \
844
    ap_log_error(MARK,"%*s%s: %d", indent, " ", op, *(int *)p1);
845
#define DUMP_S(op, s1)                                                      \
846
    ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
847
848
#define CASE_OP(op)                  case op: name = #op ; break;
849
850
static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
851
                           int loglevel, int indent)
852
{
853
    switch (e->node_op) {
854
    /* no arg */
855
    case op_NOP:
856
    case op_True:
857
    case op_False:
858
        {
859
            char *name;
860
            switch (e->node_op) {
861
            CASE_OP(op_NOP);
862
            CASE_OP(op_True);
863
            CASE_OP(op_False);
864
            default:
865
                ap_assert(0);
866
            }
867
            ap_log_error(MARK, "%*s%s", indent, " ", name);
868
        }
869
        break;
870
871
    /* arg1: string, arg2: expr */
872
    case op_UnaryOpCall:
873
    case op_BinaryOpCall:
874
    case op_BinaryOpArgs:
875
        {
876
            char *name;
877
            switch (e->node_op) {
878
            CASE_OP(op_BinaryOpCall);
879
            CASE_OP(op_UnaryOpCall);
880
            CASE_OP(op_BinaryOpArgs);
881
            default:
882
                ap_assert(0);
883
            }
884
            DUMP_S_E(name, e->node_arg1, e->node_arg2);
885
        }
886
        break;
887
888
    /* arg1: expr, arg2: expr */
889
    case op_Comp:
890
    case op_Not:
891
    case op_Or:
892
    case op_And:
893
    case op_EQ:
894
    case op_NE:
895
    case op_LT:
896
    case op_LE:
897
    case op_GT:
898
    case op_GE:
899
    case op_STR_EQ:
900
    case op_STR_NE:
901
    case op_STR_LT:
902
    case op_STR_LE:
903
    case op_STR_GT:
904
    case op_STR_GE:
905
    case op_IN:
906
    case op_REG:
907
    case op_NRE:
908
    case op_Word:
909
    case op_Bool:
910
    case op_Sub:
911
    case op_Join:
912
    case op_Split:
913
    case op_Concat:
914
    case op_StringFuncCall:
915
    case op_ListFuncCall:
916
    case op_ListElement:
917
        {
918
            char *name;
919
            switch (e->node_op) {
920
            CASE_OP(op_Comp);
921
            CASE_OP(op_Not);
922
            CASE_OP(op_Or);
923
            CASE_OP(op_And);
924
            CASE_OP(op_EQ);
925
            CASE_OP(op_NE);
926
            CASE_OP(op_LT);
927
            CASE_OP(op_LE);
928
            CASE_OP(op_GT);
929
            CASE_OP(op_GE);
930
            CASE_OP(op_STR_EQ);
931
            CASE_OP(op_STR_NE);
932
            CASE_OP(op_STR_LT);
933
            CASE_OP(op_STR_LE);
934
            CASE_OP(op_STR_GT);
935
            CASE_OP(op_STR_GE);
936
            CASE_OP(op_IN);
937
            CASE_OP(op_REG);
938
            CASE_OP(op_NRE);
939
            CASE_OP(op_Word);
940
            CASE_OP(op_Bool);
941
            CASE_OP(op_Sub);
942
            CASE_OP(op_Join);
943
            CASE_OP(op_Split);
944
            CASE_OP(op_Concat);
945
            CASE_OP(op_StringFuncCall);
946
            CASE_OP(op_ListFuncCall);
947
            CASE_OP(op_ListElement);
948
            default:
949
                ap_assert(0);
950
            }
951
            DUMP_E_E(name, e->node_arg1, e->node_arg2);
952
        }
953
        break;
954
    /* arg1: string */
955
    case op_Digit:
956
    case op_String:
957
        {
958
            char *name;
959
            switch (e->node_op) {
960
            CASE_OP(op_Digit);
961
            CASE_OP(op_String);
962
            default:
963
                ap_assert(0);
964
            }
965
            DUMP_S(name, e->node_arg1);
966
        }
967
        break;
968
    /* arg1: pointer, arg2: pointer */
969
    case op_Var:
970
    case op_StringFuncInfo:
971
    case op_UnaryOpInfo:
972
    case op_BinaryOpInfo:
973
    case op_ListFuncInfo:
974
        {
975
            char *name;
976
            switch (e->node_op) {
977
            CASE_OP(op_Var);
978
            CASE_OP(op_StringFuncInfo);
979
            CASE_OP(op_UnaryOpInfo);
980
            CASE_OP(op_BinaryOpInfo);
981
            CASE_OP(op_ListFuncInfo);
982
            default:
983
                ap_assert(0);
984
            }
985
            DUMP_P_P(name, e->node_arg1, e->node_arg2);
986
        }
987
        break;
988
    /* arg1: pointer */
989
    case op_Regex:
990
        DUMP_P("op_Regex", e->node_arg1);
991
        break;
992
    /* arg1: pointer to int */
993
    case op_Backref:
994
        DUMP_IP("op_Backref", e->node_arg1);
995
        break;
996
    default:
997
        ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
998
        break;
999
    }
1000
}
1001
#endif /* AP_EXPR_DEBUG */
1002
1003
0
#define expr_eval_log(ctx, level, ...) do { \
1004
0
    ap_expr_eval_ctx_t *x = (ctx); \
1005
0
    if (x->r) { \
1006
0
        ap_log_rerror(LOG_MARK(x->info), (level), 0, x->r, __VA_ARGS__); \
1007
0
    } \
1008
0
    else if (x->c) { \
1009
0
        ap_log_cerror(LOG_MARK(x->info), (level), 0, x->c, __VA_ARGS__); \
1010
0
    } \
1011
0
    else { \
1012
0
        ap_log_error(LOG_MARK(x->info), (level), 0, x->s, __VA_ARGS__); \
1013
0
    } \
1014
0
} while (0)
1015
1016
static int ap_expr_eval_unary_op(ap_expr_eval_ctx_t *ctx, const ap_expr_t *info,
1017
                                 const ap_expr_t *arg)
1018
0
{
1019
0
    ap_expr_op_unary_t *op_func = (ap_expr_op_unary_t *)info->node_arg1;
1020
0
    const void *data = info->node_arg2;
1021
1022
0
    AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
1023
0
    AP_DEBUG_ASSERT(op_func != NULL);
1024
0
    AP_DEBUG_ASSERT(data != NULL);
1025
0
    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
1026
0
}
1027
1028
static int ap_expr_eval_binary_op(ap_expr_eval_ctx_t *ctx,
1029
                                  const ap_expr_t *info,
1030
                                  const ap_expr_t *args)
1031
0
{
1032
0
    ap_expr_op_binary_t *op_func = (ap_expr_op_binary_t *)info->node_arg1;
1033
0
    const void *data = info->node_arg2;
1034
0
    const ap_expr_t *a1 = args->node_arg1;
1035
0
    const ap_expr_t *a2 = args->node_arg2;
1036
1037
0
    AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
1038
0
    AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
1039
0
    AP_DEBUG_ASSERT(op_func != NULL);
1040
0
    AP_DEBUG_ASSERT(data != NULL);
1041
0
    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
1042
0
                      ap_expr_eval_word(ctx, a2));
1043
0
}
1044
1045
1046
static int ap_expr_eval_cond(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
1047
0
{
1048
0
    const ap_expr_t *e1 = node->node_arg1;
1049
0
    const ap_expr_t *e2 = node->node_arg2;
1050
0
    int result = FALSE;
1051
0
    if (inc_rec(ctx))
1052
0
        return result;
1053
0
    while (1) {
1054
0
        switch (node->node_op) {
1055
0
        case op_True:
1056
0
            result ^= TRUE;
1057
0
            goto out;
1058
0
        case op_False:
1059
0
            result ^= FALSE;
1060
0
            goto out;
1061
0
        case op_Not:
1062
0
            result = !result;
1063
0
            node = e1;
1064
0
            break;
1065
0
        case op_Or:
1066
0
            do {
1067
0
                if (e1->node_op == op_Not) {
1068
0
                    if (!ap_expr_eval_cond(ctx, e1->node_arg1)) {
1069
0
                        result ^= TRUE;
1070
0
                        goto out;
1071
0
                    }
1072
0
                }
1073
0
                else {
1074
0
                    if (ap_expr_eval_cond(ctx, e1)) {
1075
0
                        result ^= TRUE;
1076
0
                        goto out;
1077
0
                    }
1078
0
                }
1079
0
                node = node->node_arg2;
1080
0
                e1 = node->node_arg1;
1081
0
            } while (node->node_op == op_Or);
1082
0
            break;
1083
0
        case op_And:
1084
0
            do {
1085
0
                if (e1->node_op == op_Not) {
1086
0
                    if (ap_expr_eval_cond(ctx, e1->node_arg1)) {
1087
0
                        result ^= FALSE;
1088
0
                        goto out;
1089
0
                    }
1090
0
                }
1091
0
                else {
1092
0
                    if (!ap_expr_eval_cond(ctx, e1)) {
1093
0
                        result ^= FALSE;
1094
0
                        goto out;
1095
0
                    }
1096
0
                }
1097
0
                node = node->node_arg2;
1098
0
                e1 = node->node_arg1;
1099
0
            } while (node->node_op == op_And);
1100
0
            break;
1101
0
        case op_UnaryOpCall:
1102
0
            result ^= ap_expr_eval_unary_op(ctx, e1, e2);
1103
0
            goto out;
1104
0
        case op_BinaryOpCall:
1105
0
            result ^= ap_expr_eval_binary_op(ctx, e1, e2);
1106
0
            goto out;
1107
0
        case op_Comp:
1108
0
            if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
1109
0
                result ^= ssl_expr_eval_comp(ctx, e1);
1110
0
            else
1111
0
                result ^= ap_expr_eval_comp(ctx, e1);
1112
0
            goto out;
1113
0
        default:
1114
0
            *ctx->err = "Internal evaluation error: Unknown expression node";
1115
0
            goto out;
1116
0
        }
1117
0
        e1 = node->node_arg1;
1118
0
        e2 = node->node_arg2;
1119
0
    }
1120
0
out:
1121
0
    ctx->reclvl--;
1122
0
    return result;
1123
0
}
1124
1125
AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info,
1126
                             const char **err)
1127
0
{
1128
0
    return ap_expr_exec_re(r, info, 0, NULL, NULL, err);
1129
0
}
1130
1131
AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
1132
0
{
1133
0
    int rc;
1134
1135
0
    AP_DEBUG_ASSERT(ctx->p != NULL);
1136
0
    AP_DEBUG_ASSERT(ctx->err != NULL);
1137
0
    AP_DEBUG_ASSERT(ctx->info != NULL);
1138
0
    if (ctx->re_pmatch) {
1139
0
        AP_DEBUG_ASSERT(ctx->re_source != NULL);
1140
0
        AP_DEBUG_ASSERT(ctx->re_nmatch > 0);
1141
0
    }
1142
0
    if (!ctx->s) {
1143
0
        if (ctx->r) {
1144
0
            ctx->s = ctx->r->server;
1145
0
        }
1146
0
        else if (ctx->c) {
1147
0
            ctx->s = ctx->c->base_server;
1148
0
        }
1149
0
    }
1150
0
    if (!ctx->c) {
1151
0
        if (ctx->r) {
1152
0
            ctx->c = ctx->r->connection;
1153
0
        }
1154
0
    }
1155
0
    AP_DEBUG_ASSERT(ctx->s != NULL);
1156
1157
0
    ctx->reclvl = 0;
1158
0
    *ctx->err = NULL;
1159
0
    if (ctx->info->flags & AP_EXPR_FLAG_STRING_RESULT) {
1160
0
        *ctx->result_string = ap_expr_eval_word(ctx, ctx->info->root_node);
1161
0
        if (*ctx->err != NULL) {
1162
0
            expr_eval_log(ctx, APLOG_ERR, APLOGNO(03298)
1163
0
                          "Evaluation of string expression from %s:%d failed: %s",
1164
0
                          ctx->info->filename, ctx->info->line_number, *ctx->err);
1165
0
            return -1;
1166
0
        } else {
1167
0
            expr_eval_log(ctx, APLOG_TRACE4,
1168
0
                          "Evaluation of string expression from %s:%d gave: %s",
1169
0
                          ctx->info->filename, ctx->info->line_number,
1170
0
                          *ctx->result_string);
1171
0
            return 1;
1172
0
        }
1173
0
    }
1174
0
    else {
1175
0
        rc = ap_expr_eval_cond(ctx, ctx->info->root_node);
1176
0
        if (*ctx->err != NULL) {
1177
0
            expr_eval_log(ctx, APLOG_ERR, APLOGNO(03299)
1178
0
                          "Evaluation of expression from %s:%d failed: %s",
1179
0
                          ctx->info->filename, ctx->info->line_number, *ctx->err);
1180
0
            return -1;
1181
0
        } else {
1182
0
            rc = rc ? 1 : 0;
1183
0
            expr_eval_log(ctx, APLOG_TRACE4,
1184
0
                          "Evaluation of expression from %s:%d gave: %d",
1185
0
                          ctx->info->filename, ctx->info->line_number, rc);
1186
1187
0
            if (ctx->r && ctx->vary_this && *ctx->vary_this)
1188
0
                apr_table_merge(ctx->r->headers_out, "Vary", *ctx->vary_this);
1189
1190
0
            return rc;
1191
0
        }
1192
0
    }
1193
0
}
1194
1195
AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info,
1196
                                apr_size_t nmatch, ap_regmatch_t *pmatch,
1197
                                const char **source, const char **err)
1198
0
{
1199
0
    ap_expr_eval_ctx_t ctx;
1200
0
    int dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
1201
0
    const char *tmp_source = NULL, *vary_this = NULL;
1202
0
    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
1203
1204
0
    AP_DEBUG_ASSERT((info->flags & AP_EXPR_FLAG_STRING_RESULT) == 0);
1205
1206
0
    ctx.r = r;
1207
0
    ctx.c = r->connection;
1208
0
    ctx.s = r->server;
1209
0
    ctx.p = r->pool;
1210
0
    ctx.err  = err;
1211
0
    ctx.info = info;
1212
0
    ctx.re_nmatch = nmatch;
1213
0
    ctx.re_pmatch = pmatch;
1214
0
    ctx.re_source = source;
1215
0
    ctx.vary_this = dont_vary ? NULL : &vary_this;
1216
0
    ctx.data = NULL;
1217
1218
0
    if (!pmatch) {
1219
0
        ctx.re_nmatch = AP_MAX_REG_MATCH;
1220
0
        ctx.re_pmatch = tmp_pmatch;
1221
0
        ctx.re_source = &tmp_source;
1222
0
    }
1223
1224
0
    return ap_expr_exec_ctx(&ctx);
1225
0
}
1226
1227
AP_DECLARE(const char *) ap_expr_str_exec_re(request_rec *r,
1228
                                             const ap_expr_info_t *info,
1229
                                             apr_size_t nmatch,
1230
                                             ap_regmatch_t *pmatch,
1231
                                             const char **source,
1232
                                             const char **err)
1233
0
{
1234
0
    ap_expr_eval_ctx_t ctx;
1235
0
    int dont_vary, rc;
1236
0
    const char *tmp_source, *vary_this;
1237
0
    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
1238
0
    const char *result;
1239
1240
0
    AP_DEBUG_ASSERT(info->flags & AP_EXPR_FLAG_STRING_RESULT);
1241
1242
0
    if (info->root_node->node_op == op_String) {
1243
        /* short-cut for constant strings */
1244
0
        *err = NULL;
1245
0
        return (const char *)info->root_node->node_arg1;
1246
0
    }
1247
1248
0
    tmp_source = NULL;
1249
0
    vary_this = NULL;
1250
1251
0
    dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
1252
1253
0
    ctx.r = r;
1254
0
    ctx.c = r->connection;
1255
0
    ctx.s = r->server;
1256
0
    ctx.p = r->pool;
1257
0
    ctx.err  = err;
1258
0
    ctx.info = info;
1259
0
    ctx.re_nmatch = nmatch;
1260
0
    ctx.re_pmatch = pmatch;
1261
0
    ctx.re_source = source;
1262
0
    ctx.vary_this = dont_vary ? NULL : &vary_this;
1263
0
    ctx.data = NULL;
1264
0
    ctx.result_string = &result;
1265
1266
0
    if (!pmatch) {
1267
0
        ctx.re_nmatch = AP_MAX_REG_MATCH;
1268
0
        ctx.re_pmatch = tmp_pmatch;
1269
0
        ctx.re_source = &tmp_source;
1270
0
    }
1271
1272
0
    rc = ap_expr_exec_ctx(&ctx);
1273
0
    if (rc > 0)
1274
0
        return result;
1275
0
    else if (rc < 0)
1276
0
        return NULL;
1277
0
    else
1278
0
        ap_assert(0);
1279
    /* Not reached */
1280
0
    return NULL;
1281
0
}
1282
1283
AP_DECLARE(const char *) ap_expr_str_exec(request_rec *r,
1284
                                          const ap_expr_info_t *info,
1285
                                          const char **err)
1286
0
{
1287
0
    return ap_expr_str_exec_re(r, info, 0, NULL, NULL, err);
1288
0
}
1289
1290
1291
static void add_vary(ap_expr_eval_ctx_t *ctx, const char *name)
1292
0
{
1293
0
    if (!ctx->vary_this)
1294
0
        return;
1295
1296
0
    if (*ctx->vary_this) {
1297
0
        *ctx->vary_this = apr_pstrcat(ctx->p, *ctx->vary_this, ", ", name,
1298
0
                                      NULL);
1299
0
    }
1300
0
    else {
1301
0
        *ctx->vary_this = name;
1302
0
    }
1303
0
}
1304
1305
static const char *req_table_func(ap_expr_eval_ctx_t *ctx, const void *data,
1306
                                  const char *arg)
1307
0
{
1308
0
    const char *name = (const char *)data;
1309
0
    apr_table_t *t;
1310
0
    if (!ctx->r)
1311
0
        return "";
1312
1313
0
    if (name[2] == 's') {           /* resp */
1314
        /* Try r->headers_out first, fall back on err_headers_out. */
1315
0
        const char *v = apr_table_get(ctx->r->headers_out, arg);
1316
0
        if (v) {
1317
0
            return v;
1318
0
        }
1319
0
        t = ctx->r->err_headers_out;
1320
0
    }
1321
0
    else if (name[0] == 'n')        /* notes */
1322
0
        t = ctx->r->notes;
1323
0
    else if (name[3] == 'e')        /* reqenv */
1324
0
        t = ctx->r->subprocess_env;
1325
0
    else if (name[3] == '_')        /* req_novary */
1326
0
        t = ctx->r->headers_in;
1327
0
    else {                          /* req, http */
1328
0
        t = ctx->r->headers_in;
1329
        /* Skip the 'Vary: Host' header combination
1330
         * as indicated in rfc7231 section-7.1.4
1331
         */
1332
0
        if (strcasecmp(arg, "Host")){
1333
0
            add_vary(ctx, arg);
1334
0
        }
1335
0
    }
1336
0
    return apr_table_get(t, arg);
1337
0
}
1338
1339
static const char *env_func(ap_expr_eval_ctx_t *ctx, const void *data,
1340
                            const char *arg)
1341
0
{
1342
0
    const char *res;
1343
    /* this order is for ssl_expr compatibility */
1344
0
    if (ctx->r) {
1345
0
        if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
1346
0
            return res;
1347
0
        else if ((res = apr_table_get(ctx->r->subprocess_env, arg)) != NULL)
1348
0
            return res;
1349
0
    }
1350
0
    return getenv(arg);
1351
0
}
1352
1353
static const char *osenv_func(ap_expr_eval_ctx_t *ctx, const void *data,
1354
                              const char *arg)
1355
0
{
1356
0
    return getenv(arg);
1357
0
}
1358
1359
static const char *tolower_func(ap_expr_eval_ctx_t *ctx, const void *data,
1360
                                const char *arg)
1361
0
{
1362
0
    char *result = apr_pstrdup(ctx->p, arg);
1363
0
    ap_str_tolower(result);
1364
0
    return result;
1365
0
}
1366
1367
static const char *toupper_func(ap_expr_eval_ctx_t *ctx, const void *data,
1368
                                const char *arg)
1369
0
{
1370
0
    char *result = apr_pstrdup(ctx->p, arg);
1371
0
    ap_str_toupper(result);
1372
0
    return result;
1373
0
}
1374
1375
static const char *escape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1376
                               const char *arg)
1377
0
{
1378
0
    return ap_escape_uri(ctx->p, arg);
1379
0
}
1380
1381
static const char *base64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1382
                               const char *arg)
1383
0
{
1384
0
    return ap_pbase64encode(ctx->p, (char *)arg);
1385
0
}
1386
1387
static const char *unbase64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1388
                               const char *arg)
1389
0
{
1390
0
    return ap_pbase64decode(ctx->p, arg);
1391
0
}
1392
1393
static const char *sha1_func(ap_expr_eval_ctx_t *ctx, const void *data,
1394
                               const char *arg)
1395
0
{
1396
0
    apr_sha1_ctx_t context;
1397
0
    apr_byte_t sha1[APR_SHA1_DIGESTSIZE];
1398
0
    char *out;
1399
1400
0
    out = apr_palloc(ctx->p, APR_SHA1_DIGESTSIZE*2+1);
1401
1402
0
    apr_sha1_init(&context);
1403
0
    apr_sha1_update(&context, arg, (unsigned int)strlen(arg));
1404
0
    apr_sha1_final(sha1, &context);
1405
1406
0
    ap_bin2hex(sha1, APR_SHA1_DIGESTSIZE, out);
1407
1408
0
    return out;
1409
0
}
1410
1411
static const char *md5_func(ap_expr_eval_ctx_t *ctx, const void *data,
1412
                               const char *arg)
1413
0
{
1414
0
    return ap_md5(ctx->p, (const unsigned char *)arg);
1415
0
}
1416
1417
#if APR_VERSION_AT_LEAST(1,6,0)
1418
static const char *ldap_func(ap_expr_eval_ctx_t *ctx, const void *data,
1419
                               const char *arg)
1420
0
{
1421
0
    return apr_pescape_ldap(ctx->p, arg, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_ALL);
1422
0
}
1423
#endif
1424
1425
static const char *escapehtml_func(ap_expr_eval_ctx_t *ctx, const void *data,
1426
                                   const char *arg)
1427
0
{
1428
0
    return ap_escape_html(ctx->p, arg);
1429
0
}
1430
1431
static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
1432
0
{
1433
0
    const char *original = parms->arg;
1434
0
    const apr_strmatch_pattern *pattern;
1435
1436
0
    if (!parms->arg) {
1437
0
        *parms->err = apr_psprintf(parms->ptemp, "replace() function needs an argument");
1438
0
        return !OK;
1439
0
    }
1440
1441
0
    pattern = apr_strmatch_precompile(parms->pool, original, 0);
1442
0
    *parms->data = pattern;
1443
0
    return OK;
1444
0
}
1445
1446
static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
1447
                               const apr_array_header_t *args)
1448
0
{
1449
0
    char *buff, *original, *replacement;
1450
0
    struct ap_varbuf vb;
1451
0
    apr_size_t repl_len, orig_len;
1452
0
    const char *repl;
1453
0
    apr_size_t bytes;
1454
0
    apr_size_t len;
1455
0
    const apr_strmatch_pattern *pattern = data;
1456
0
    if (args->nelts != 3) {
1457
0
        *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
1458
0
                                 "exactly 3 arguments, got %d", args->nelts);
1459
0
        return "";
1460
0
    }
1461
1462
0
    buff = APR_ARRAY_IDX(args, 0, char *);
1463
0
    original = APR_ARRAY_IDX(args, 1, char *);
1464
0
    replacement = APR_ARRAY_IDX(args, 2, char *);
1465
0
    repl_len = strlen(replacement);
1466
0
    orig_len = strlen(original);
1467
0
    bytes = strlen(buff);
1468
1469
0
    ap_varbuf_init(ctx->p, &vb, 0);
1470
0
    vb.strlen = 0;
1471
    
1472
0
    while ((repl = apr_strmatch(pattern, buff, bytes))) {
1473
0
        len = (apr_size_t) (repl - buff);
1474
0
        ap_varbuf_strmemcat(&vb, buff, len);
1475
0
        ap_varbuf_strmemcat(&vb, replacement, repl_len);
1476
1477
0
        len += orig_len;
1478
0
        bytes -= len;
1479
0
        buff += len;
1480
0
    }
1481
1482
0
    return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
1483
0
}
1484
1485
0
#define MAX_FILE_SIZE 10*1024*1024
1486
static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
1487
                             char *arg)
1488
0
{
1489
0
    apr_file_t *fp;
1490
0
    char *buf;
1491
0
    apr_off_t offset;
1492
0
    apr_size_t len;
1493
0
    apr_finfo_t finfo;
1494
1495
0
    if (apr_file_open(&fp, arg, APR_READ|APR_BUFFERED,
1496
0
                      APR_OS_DEFAULT, ctx->p) != APR_SUCCESS) {
1497
0
        *ctx->err = apr_psprintf(ctx->p, "Cannot open file %s", arg);
1498
0
        return "";
1499
0
    }
1500
0
    apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
1501
0
    if (finfo.size > MAX_FILE_SIZE) {
1502
0
        *ctx->err = apr_psprintf(ctx->p, "File %s too large", arg);
1503
0
        apr_file_close(fp);
1504
0
        return "";
1505
0
    }
1506
0
    len = (apr_size_t)finfo.size;
1507
0
    if (len == 0) {
1508
0
        apr_file_close(fp);
1509
0
        return "";
1510
0
    }
1511
0
    else {
1512
0
        if ((buf = (char *)apr_palloc(ctx->p, sizeof(char)*(len+1))) == NULL) {
1513
0
            *ctx->err = "Cannot allocate memory";
1514
0
            apr_file_close(fp);
1515
0
            return "";
1516
0
        }
1517
0
        offset = 0;
1518
0
        apr_file_seek(fp, APR_SET, &offset);
1519
0
        if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
1520
0
            *ctx->err = apr_psprintf(ctx->p, "Cannot read from file %s", arg);
1521
0
            apr_file_close(fp);
1522
0
            return "";
1523
0
        }
1524
0
        buf[len] = '\0';
1525
0
    }
1526
0
    apr_file_close(fp);
1527
0
    return buf;
1528
0
}
1529
1530
static apr_status_t stat_check(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1531
0
{
1532
0
    apr_status_t rv = APR_SUCCESS;
1533
0
    if (APR_SUCCESS != (rv = ap_stat_check(arg, ctx->p))) {
1534
0
        *ctx->err = apr_psprintf(ctx->p, "stat of %s not allowed", arg);
1535
0
    }
1536
0
    return rv;
1537
0
}
1538
static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
1539
                                  char *arg)
1540
0
{
1541
0
    apr_finfo_t sb;
1542
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1543
0
        return "";
1544
0
    }
1545
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1546
0
        && sb.filetype == APR_REG && sb.size > 0)
1547
0
        return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
1548
0
    else
1549
0
        return "0";
1550
0
}
1551
1552
static const char *filemod_func(ap_expr_eval_ctx_t *ctx, const void *data,
1553
                                  char *arg)
1554
0
{
1555
0
    apr_finfo_t sb;
1556
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1557
0
        return "";
1558
0
    }
1559
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1560
0
        && sb.filetype == APR_REG && sb.mtime > 0)
1561
0
        return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, (apr_off_t)sb.mtime);
1562
0
    else
1563
0
        return "0";
1564
0
}
1565
1566
1567
static const char *unescape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1568
                                 const char *arg)
1569
0
{
1570
0
    char *result = apr_pstrdup(ctx->p, arg);
1571
0
    int ret = ap_unescape_url_keep2f(result, 0);
1572
0
    if (ret == OK)
1573
0
        return result;
1574
0
    expr_eval_log(ctx, APLOG_DEBUG, APLOGNO(00538)
1575
0
                  "%s %% escape in unescape('%s') at %s:%d",
1576
0
                  ret == HTTP_BAD_REQUEST ? "Bad" : "Forbidden", arg,
1577
0
                  ctx->info->filename, ctx->info->line_number);
1578
0
    return "";
1579
0
}
1580
1581
static int op_nz(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1582
0
{
1583
0
    const char *name = (const char *)data;
1584
0
    if (name[0] == 'z')
1585
0
        return (arg[0] == '\0');
1586
0
    else
1587
0
        return (arg[0] != '\0');
1588
0
}
1589
1590
static int op_file_min(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1591
0
{
1592
0
    apr_finfo_t sb;
1593
0
    const char *name = (const char *)data;
1594
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1595
0
        return FALSE;
1596
0
    }
1597
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
1598
0
        return FALSE;
1599
0
    switch (name[0]) {
1600
0
    case 'd':
1601
0
        return (sb.filetype == APR_DIR);
1602
0
    case 'e':
1603
0
        return TRUE;
1604
0
    case 'f':
1605
0
        return (sb.filetype == APR_REG);
1606
0
    case 's':
1607
0
        return (sb.filetype == APR_REG && sb.size > 0);
1608
0
    default:
1609
0
        ap_assert(0);
1610
0
    }
1611
0
    return FALSE;
1612
0
}
1613
1614
static int op_file_link(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1615
0
{
1616
0
#if !defined(OS2)
1617
0
    apr_finfo_t sb;
1618
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1619
0
        return FALSE;
1620
0
    }
1621
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1622
0
        && sb.filetype == APR_LNK) {
1623
0
        return TRUE;
1624
0
    }
1625
0
#endif
1626
0
    return FALSE;
1627
0
}
1628
1629
static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1630
0
{
1631
0
    apr_finfo_t sb;
1632
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1633
0
        return FALSE;
1634
0
    }
1635
0
    if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1636
0
        && (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
1637
0
        return TRUE;
1638
0
    }
1639
0
    return FALSE;
1640
0
}
1641
1642
static int op_url_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1643
0
{
1644
0
    int rc = FALSE;
1645
0
    request_rec  *rsub, *r = ctx->r;
1646
0
    if (!r)
1647
0
        return FALSE;
1648
    /* avoid some infinite recursions */
1649
0
    if (r->main && r->main->uri && r->uri && strcmp(r->main->uri, r->uri) == 0)
1650
0
        return FALSE;
1651
1652
0
    rsub = ap_sub_req_lookup_uri(arg, r, NULL);
1653
0
    if (rsub->status < 400) {
1654
0
            rc = TRUE;
1655
0
    }
1656
0
    expr_eval_log(ctx, APLOG_TRACE5,
1657
0
                  "Subrequest for -U %s at %s:%d gave status: %d",
1658
0
                  arg, ctx->info->filename, ctx->info->line_number,
1659
0
                  rsub->status);
1660
0
    ap_destroy_sub_req(rsub);
1661
0
    return rc;
1662
0
}
1663
1664
static int op_file_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1665
0
{
1666
0
    int rc = FALSE;
1667
0
    apr_finfo_t sb;
1668
0
    request_rec *rsub, *r = ctx->r;
1669
0
    if (!r)
1670
0
        return FALSE;
1671
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1672
0
        return FALSE;
1673
0
    }
1674
0
    rsub = ap_sub_req_lookup_file(arg, r, NULL);
1675
0
    if (rsub->status < 300 &&
1676
        /* double-check that file exists since default result is 200 */
1677
0
        apr_stat(&sb, rsub->filename, APR_FINFO_MIN, ctx->p) == APR_SUCCESS) {
1678
0
        rc = TRUE;
1679
0
    }
1680
0
    expr_eval_log(ctx, APLOG_TRACE5,
1681
0
                  "Subrequest for -F %s at %s:%d gave status: %d",
1682
0
                  arg, ctx->info->filename, ctx->info->line_number,
1683
0
                  rsub->status);
1684
0
    ap_destroy_sub_req(rsub);
1685
0
    return rc;
1686
0
}
1687
1688
1689
APR_DECLARE_OPTIONAL_FN(int, http2_is_h2, (conn_rec *));
1690
static APR_OPTIONAL_FN_TYPE(http2_is_h2) *is_http2 = NULL;
1691
1692
static const char *const conn_var_names[] = {
1693
    "HTTPS",                    /*  0 */
1694
    "IPV6",                     /*  1 */
1695
    "CONN_LOG_ID",              /*  2 */
1696
    "CONN_REMOTE_ADDR",         /*  3 */
1697
    "HTTP2",                    /*  4 */
1698
    NULL
1699
};
1700
1701
static const char *conn_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1702
0
{
1703
0
    int index = ((const char **)data - conn_var_names);
1704
0
    conn_rec *c = ctx->c;
1705
0
    if (!c)
1706
0
        return "";
1707
1708
0
    switch (index) {
1709
0
    case 0:
1710
0
        if (ap_ssl_conn_is_ssl(c))
1711
0
            return "on";
1712
0
        else
1713
0
            return "off";
1714
0
    case 1:
1715
0
#if APR_HAVE_IPV6
1716
0
        {
1717
0
            apr_sockaddr_t *addr = c->client_addr;
1718
0
            if (addr->family == AF_INET6
1719
0
                && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr))
1720
0
                return "on";
1721
0
            else
1722
0
                return "off";
1723
0
        }
1724
#else
1725
        return "off";
1726
#endif
1727
0
    case 2:
1728
0
        return c->log_id;
1729
0
    case 3:
1730
0
        return c->client_ip;
1731
0
    case 4:
1732
0
        if (is_http2 && is_http2(c))
1733
0
            return "on";
1734
0
        else
1735
0
            return "off";
1736
0
    default:
1737
0
        ap_assert(0);
1738
0
        return NULL;
1739
0
    }
1740
0
}
1741
1742
static const char *const request_var_names[] = {
1743
    "REQUEST_METHOD",           /*  0 */
1744
    "REQUEST_SCHEME",           /*  1 */
1745
    "REQUEST_URI",              /*  2 */
1746
    "REQUEST_FILENAME",         /*  3 */
1747
    "REMOTE_HOST",              /*  4 */
1748
    "REMOTE_IDENT",             /*  5 */
1749
    "REMOTE_USER",              /*  6 */
1750
    "SERVER_ADMIN",             /*  7 */
1751
    "SERVER_NAME",              /*  8 */
1752
    "SERVER_PORT",              /*  9 */
1753
    "SERVER_PROTOCOL",          /* 10 */
1754
    "SCRIPT_FILENAME",          /* 11 */
1755
    "PATH_INFO",                /* 12 */
1756
    "QUERY_STRING",             /* 13 */
1757
    "IS_SUBREQ",                /* 14 */
1758
    "DOCUMENT_ROOT",            /* 15 */
1759
    "AUTH_TYPE",                /* 16 */
1760
    "THE_REQUEST",              /* 17 */
1761
    "CONTENT_TYPE",             /* 18 */
1762
    "HANDLER",                  /* 19 */
1763
    "REQUEST_LOG_ID",           /* 20 */
1764
    "SCRIPT_USER",              /* 21 */
1765
    "SCRIPT_GROUP",             /* 22 */
1766
    "DOCUMENT_URI",             /* 23 */
1767
    "LAST_MODIFIED",            /* 24 */
1768
    "CONTEXT_PREFIX",           /* 25 */
1769
    "CONTEXT_DOCUMENT_ROOT",    /* 26 */
1770
    "REQUEST_STATUS",           /* 27 */
1771
    "REMOTE_ADDR",              /* 28 */
1772
    "SERVER_PROTOCOL_VERSION",  /* 29 */
1773
    "SERVER_PROTOCOL_VERSION_MAJOR",  /* 30 */
1774
    "SERVER_PROTOCOL_VERSION_MINOR",  /* 31 */
1775
    "REMOTE_PORT",                    /* 32 */
1776
    NULL
1777
};
1778
1779
static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1780
0
{
1781
0
    int index = ((const char **)data - request_var_names);
1782
0
    request_rec *r = ctx->r;
1783
0
    if (!r)
1784
0
        return "";
1785
1786
0
    switch (index) {
1787
0
    case 0:
1788
0
        return r->method;
1789
0
    case 1:
1790
0
        return ap_http_scheme(r);
1791
0
    case 2:
1792
0
        return r->uri;
1793
0
    case 3:
1794
0
        return r->filename;
1795
0
    case 4:
1796
0
        return ap_get_useragent_host(r, REMOTE_NAME, NULL);
1797
0
    case 5:
1798
0
        return ap_get_remote_logname(r);
1799
0
    case 6:
1800
0
        return r->user;
1801
0
    case 7:
1802
0
        return r->server->server_admin;
1803
0
    case 8:
1804
0
        return ap_get_server_name_for_url(r);
1805
0
    case 9:
1806
0
        return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
1807
0
    case 10:
1808
0
        return r->protocol;
1809
0
    case 11:
1810
0
        return r->filename;
1811
0
    case 12:
1812
0
        return r->path_info;
1813
0
    case 13:
1814
0
        return r->args;
1815
0
    case 14:
1816
0
        return (r->main != NULL ? "true" : "false");
1817
0
    case 15:
1818
0
        return ap_document_root(r);
1819
0
    case 16:
1820
0
        return r->ap_auth_type;
1821
0
    case 17:
1822
0
        return r->the_request;
1823
0
    case 18:
1824
0
        return r->content_type;
1825
0
    case 19:
1826
0
        return r->handler;
1827
0
    case 20:
1828
0
        return r->log_id;
1829
0
    case 21:
1830
0
        {
1831
0
            char *result = "";
1832
0
            if (r->finfo.valid & APR_FINFO_USER)
1833
0
                apr_uid_name_get(&result, r->finfo.user, ctx->p);
1834
0
            return result;
1835
0
        }
1836
0
    case 22:
1837
0
        {
1838
0
            char *result = "";
1839
0
            if (r->finfo.valid & APR_FINFO_USER)
1840
0
                apr_gid_name_get(&result, r->finfo.group, ctx->p);
1841
0
            return result;
1842
0
        }
1843
0
    case 23:
1844
0
        {
1845
0
            const char *uri = apr_table_get(r->subprocess_env, "DOCUMENT_URI");
1846
0
            return uri ? uri : r->uri;
1847
0
        }
1848
0
    case 24:
1849
0
        {
1850
0
            apr_time_exp_t tm;
1851
0
            apr_time_exp_lt(&tm, r->mtime);
1852
0
            return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1853
0
                                (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1854
0
                                tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1855
0
                                tm.tm_sec);
1856
0
        }
1857
0
    case 25:
1858
0
        return ap_context_prefix(r);
1859
0
    case 26:
1860
0
        return ap_context_document_root(r);
1861
0
    case 27:
1862
0
        return r->status ? apr_psprintf(ctx->p, "%d", r->status) : "";
1863
0
    case 28:
1864
0
        return r->useragent_ip;
1865
0
    case 29:
1866
0
        switch (r->proto_num) {
1867
0
        case 1001:  return "1001";   /* 1.1 */
1868
0
        case 1000:  return "1000";   /* 1.0 */
1869
0
        case 9:     return "9";      /* 0.9 */
1870
0
        }
1871
0
        return apr_psprintf(ctx->p, "%d", r->proto_num);
1872
0
    case 30:
1873
0
        switch (HTTP_VERSION_MAJOR(r->proto_num)) {
1874
0
        case 0:     return "0";
1875
0
        case 1:     return "1";
1876
0
        }
1877
0
        return apr_psprintf(ctx->p, "%d", HTTP_VERSION_MAJOR(r->proto_num));
1878
0
    case 31:
1879
0
        switch (HTTP_VERSION_MINOR(r->proto_num)) {
1880
0
        case 0:     return "0";
1881
0
        case 1:     return "1";
1882
0
        case 9:     return "9";
1883
0
        }
1884
0
        return apr_psprintf(ctx->p, "%d", HTTP_VERSION_MINOR(r->proto_num));
1885
0
    case 32:
1886
0
        return apr_psprintf(ctx->p, "%u", ctx->c->client_addr->port);
1887
0
    default:
1888
0
        ap_assert(0);
1889
0
        return NULL;
1890
0
    }
1891
0
}
1892
1893
static const char *const req_header_var_names[] = {
1894
    "HTTP_USER_AGENT",       /* 0 */
1895
    "HTTP_PROXY_CONNECTION", /* 1 */
1896
    "HTTP_REFERER",          /* 2 */
1897
    "HTTP_COOKIE",           /* 3 */
1898
    "HTTP_FORWARDED",        /* 4 */
1899
    "HTTP_HOST",             /* 5 */
1900
    "HTTP_ACCEPT",           /* 6 */
1901
    NULL
1902
};
1903
1904
static const char *const req_header_header_names[] = {
1905
    "User-Agent",
1906
    "Proxy-Connection",
1907
    "Referer",
1908
    "Cookie",
1909
    "Forwarded",
1910
    "Host",
1911
    "Accept"
1912
};
1913
1914
static const char *req_header_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1915
0
{
1916
0
    const char **const varname = (const char **)data;
1917
0
    int index = (varname - req_header_var_names);
1918
0
    const char *name;
1919
1920
0
    AP_DEBUG_ASSERT(index < 7);
1921
0
    if (!ctx->r)
1922
0
        return "";
1923
1924
0
    name = req_header_header_names[index];
1925
    /* Skip the 'Vary: Host' header combination
1926
     * as indicated in rfc7231 section-7.1.4
1927
     */
1928
0
    if (strcasecmp(name, "Host")){
1929
0
        add_vary(ctx, name);
1930
0
    }
1931
0
    return apr_table_get(ctx->r->headers_in, name);
1932
0
}
1933
1934
static const char *const misc_var_names[] = {
1935
    "TIME_YEAR",        /* 0 */
1936
    "TIME_MON",         /* 1 */
1937
    "TIME_DAY",         /* 2 */
1938
    "TIME_HOUR",        /* 3 */
1939
    "TIME_MIN",         /* 4 */
1940
    "TIME_SEC",         /* 5 */
1941
    "TIME_WDAY",        /* 6 */
1942
    "TIME",             /* 7 */
1943
    "SERVER_SOFTWARE",  /* 8 */
1944
    "API_VERSION",      /* 9 */
1945
    NULL
1946
};
1947
1948
static const char *misc_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1949
0
{
1950
0
    apr_time_exp_t tm;
1951
0
    int index = ((const char **)data - misc_var_names);
1952
0
    apr_time_exp_lt(&tm, apr_time_now());
1953
1954
0
    switch (index) {
1955
0
    case 0:
1956
0
        return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
1957
0
                            tm.tm_year % 100);
1958
0
    case 1:
1959
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
1960
0
    case 2:
1961
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
1962
0
    case 3:
1963
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
1964
0
    case 4:
1965
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_min);
1966
0
    case 5:
1967
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
1968
0
    case 6:
1969
0
        return apr_psprintf(ctx->p, "%d", tm.tm_wday);
1970
0
    case 7:
1971
0
        return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1972
0
                            (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1973
0
                            tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1974
0
                            tm.tm_sec);
1975
0
    case 8:
1976
0
        return ap_get_server_banner();
1977
0
    case 9:
1978
0
        return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER_MAJOR);
1979
0
    default:
1980
0
        ap_assert(0);
1981
0
    }
1982
1983
0
    return NULL;
1984
0
}
1985
1986
static int subnet_parse_arg(ap_expr_lookup_parms *parms)
1987
0
{
1988
0
    apr_ipsubnet_t *subnet;
1989
0
    const char *addr = parms->arg;
1990
0
    const char *mask;
1991
0
    apr_status_t ret;
1992
1993
0
    if (!parms->arg) {
1994
0
        *parms->err = apr_psprintf(parms->ptemp,
1995
0
                                   "-%s requires subnet/netmask as constant argument",
1996
0
                                   parms->name);
1997
0
        return !OK;
1998
0
    }
1999
2000
0
    mask = ap_strchr_c(addr, '/');
2001
0
    if (mask) {
2002
0
        addr = apr_pstrmemdup(parms->ptemp, addr, mask - addr);
2003
0
        mask++;
2004
0
    }
2005
2006
0
    ret = apr_ipsubnet_create(&subnet, addr, mask, parms->pool);
2007
0
    if (ret != APR_SUCCESS) {
2008
0
        *parms->err = "parsing of subnet/netmask failed";
2009
0
        return !OK;
2010
0
    }
2011
2012
0
    *parms->data = subnet;
2013
0
    return OK;
2014
0
}
2015
2016
static int op_ipmatch(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1,
2017
                const char *arg2)
2018
0
{
2019
0
    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
2020
0
    apr_sockaddr_t *saddr;
2021
2022
0
    AP_DEBUG_ASSERT(subnet != NULL);
2023
2024
    /* maybe log an error if this goes wrong? */
2025
0
    if (apr_sockaddr_info_get(&saddr, arg1, APR_UNSPEC, 0, 0, ctx->p) != APR_SUCCESS)
2026
0
        return FALSE;
2027
2028
0
    return apr_ipsubnet_test(subnet, saddr);
2029
0
}
2030
2031
static int op_R(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1)
2032
0
{
2033
0
    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
2034
2035
0
    AP_DEBUG_ASSERT(subnet != NULL);
2036
2037
0
    if (!ctx->r)
2038
0
        return FALSE;
2039
2040
0
    return apr_ipsubnet_test(subnet, ctx->r->useragent_addr);
2041
0
}
2042
2043
static int op_T(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
2044
0
{
2045
0
    switch (arg[0]) {
2046
0
    case '\0':
2047
0
        return FALSE;
2048
0
    case 'o':
2049
0
    case 'O':
2050
0
        return strcasecmp(arg, "off") == 0 ? FALSE : TRUE;
2051
0
    case 'n':
2052
0
    case 'N':
2053
0
        return strcasecmp(arg, "no") == 0 ? FALSE : TRUE;
2054
0
    case 'f':
2055
0
    case 'F':
2056
0
        return strcasecmp(arg, "false") == 0 ? FALSE : TRUE;
2057
0
    case '0':
2058
0
        return arg[1] == '\0' ? FALSE : TRUE;
2059
0
    default:
2060
0
        return TRUE;
2061
0
    }
2062
0
}
2063
2064
static int op_fnmatch(ap_expr_eval_ctx_t *ctx, const void *data,
2065
                      const char *arg1, const char *arg2)
2066
0
{
2067
0
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_PATHNAME));
2068
0
}
2069
2070
static int op_strmatch(ap_expr_eval_ctx_t *ctx, const void *data,
2071
                       const char *arg1, const char *arg2)
2072
0
{
2073
0
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, 0));
2074
0
}
2075
2076
static int op_strcmatch(ap_expr_eval_ctx_t *ctx, const void *data,
2077
                        const char *arg1, const char *arg2)
2078
0
{
2079
0
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_CASE_BLIND));
2080
0
}
2081
2082
struct expr_provider_single {
2083
    const void *func;
2084
    const char *name;
2085
    ap_expr_lookup_fn_t *arg_parsing_func;
2086
    int restricted;
2087
};
2088
2089
struct expr_provider_multi {
2090
    const void *func;
2091
    const char *const *names;
2092
};
2093
2094
static const struct expr_provider_multi var_providers[] = {
2095
    { misc_var_fn, misc_var_names },
2096
    { req_header_var_fn, req_header_var_names },
2097
    { request_var_fn, request_var_names },
2098
    { conn_var_fn, conn_var_names },
2099
    { NULL, NULL }
2100
};
2101
2102
static const struct expr_provider_single string_func_providers[] = {
2103
    { osenv_func,           "osenv",          NULL, 0 },
2104
    { env_func,             "env",            NULL, 0 },
2105
    { req_table_func,       "resp",           NULL, 0 },
2106
    { req_table_func,       "req",            NULL, 0 },
2107
    /* 'http' as alias for 'req' for compatibility with ssl_expr */
2108
    { req_table_func,       "http",           NULL, 0 },
2109
    { req_table_func,       "note",           NULL, 0 },
2110
    { req_table_func,       "reqenv",         NULL, 0 },
2111
    { req_table_func,       "req_novary",     NULL, 0 },
2112
    { tolower_func,         "tolower",        NULL, 0 },
2113
    { toupper_func,         "toupper",        NULL, 0 },
2114
    { escape_func,          "escape",         NULL, 0 },
2115
    { unescape_func,        "unescape",       NULL, 0 },
2116
    { file_func,            "file",           NULL, 1 },
2117
    { filesize_func,        "filesize",       NULL, 1 },
2118
    { filemod_func,         "filemod",        NULL, 1 },
2119
    { base64_func,          "base64",         NULL, 0 },
2120
    { unbase64_func,        "unbase64",       NULL, 0 },
2121
    { sha1_func,            "sha1",           NULL, 0 },
2122
    { md5_func,             "md5",            NULL, 0 },
2123
#if APR_VERSION_AT_LEAST(1,6,0)
2124
    { ldap_func,            "ldap",           NULL, 0 },
2125
#endif
2126
    { replace_func,         "replace",        replace_func_parse_arg, 0 },
2127
    { escapehtml_func,      "escapehtml",     NULL, 0 },
2128
    { NULL, NULL, NULL}
2129
};
2130
2131
static const struct expr_provider_single unary_op_providers[] = {
2132
    { op_nz,        "n", NULL,             0 },
2133
    { op_nz,        "z", NULL,             0 },
2134
    { op_R,         "R", subnet_parse_arg, 0 },
2135
    { op_T,         "T", NULL,             0 },
2136
    { op_file_min,  "d", NULL,             1 },
2137
    { op_file_min,  "e", NULL,             1 },
2138
    { op_file_min,  "f", NULL,             1 },
2139
    { op_file_min,  "s", NULL,             1 },
2140
    { op_file_link, "L", NULL,             1 },
2141
    { op_file_link, "h", NULL,             1 },
2142
    { op_file_xbit, "x", NULL,             1 },
2143
    { op_file_subr, "F", NULL,             0 },
2144
    { op_url_subr,  "U", NULL,             0 },
2145
    { op_url_subr,  "A", NULL,             0 },
2146
    { NULL, NULL, NULL }
2147
};
2148
2149
static const struct expr_provider_single binary_op_providers[] = {
2150
    { op_ipmatch,   "ipmatch",      subnet_parse_arg, 0 },
2151
    { op_fnmatch,   "fnmatch",      NULL,             0 },
2152
    { op_strmatch,  "strmatch",     NULL,             0 },
2153
    { op_strcmatch, "strcmatch",    NULL,             0 },
2154
    { NULL, NULL, NULL }
2155
};
2156
2157
static int core_expr_lookup(ap_expr_lookup_parms *parms)
2158
0
{
2159
0
    switch (parms->type) {
2160
0
    case AP_EXPR_FUNC_VAR: {
2161
0
            const struct expr_provider_multi *prov = var_providers;
2162
0
            while (prov->func) {
2163
0
                const char *const *name = prov->names;
2164
0
                while (*name) {
2165
0
                    if (ap_cstr_casecmp(*name, parms->name) == 0) {
2166
0
                        *parms->func = prov->func;
2167
0
                        *parms->data = name;
2168
0
                        return OK;
2169
0
                    }
2170
0
                    name++;
2171
0
                }
2172
0
                prov++;
2173
0
            }
2174
0
        }
2175
0
        break;
2176
0
    case AP_EXPR_FUNC_STRING:
2177
0
    case AP_EXPR_FUNC_OP_UNARY:
2178
0
    case AP_EXPR_FUNC_OP_BINARY: {
2179
0
            const struct expr_provider_single *prov = NULL;
2180
0
            switch (parms->type) {
2181
0
            case AP_EXPR_FUNC_STRING:
2182
0
                prov = string_func_providers;
2183
0
                break;
2184
0
            case AP_EXPR_FUNC_OP_UNARY:
2185
0
                prov = unary_op_providers;
2186
0
                break;
2187
0
            case AP_EXPR_FUNC_OP_BINARY:
2188
0
                prov = binary_op_providers;
2189
0
                break;
2190
0
            default:
2191
0
                ap_assert(0);
2192
0
            }
2193
0
            while (prov && prov->func) {
2194
0
                int match;
2195
0
                if (parms->type == AP_EXPR_FUNC_OP_UNARY)
2196
0
                    match = !strcmp(prov->name, parms->name);
2197
0
                else
2198
0
                    match = !ap_cstr_casecmp(prov->name, parms->name);
2199
0
                if (match) {
2200
0
                    if ((parms->flags & AP_EXPR_FLAG_RESTRICTED)
2201
0
                        && prov->restricted) {
2202
0
                        *parms->err =
2203
0
                            apr_psprintf(parms->ptemp,
2204
0
                                         "%s%s not available in restricted context",
2205
0
                                         (parms->type == AP_EXPR_FUNC_STRING) ? "" : "-",
2206
0
                                         prov->name);
2207
0
                        return !OK;
2208
0
                    }
2209
0
                    *parms->func = prov->func;
2210
0
                    if (prov->arg_parsing_func) {
2211
0
                        return prov->arg_parsing_func(parms);
2212
0
                    }
2213
0
                    else {
2214
0
                        *parms->data = prov->name;
2215
0
                        return OK;
2216
0
                    }
2217
0
                }
2218
0
                prov++;
2219
0
            }
2220
0
        }
2221
0
        break;
2222
0
    default:
2223
0
        break;
2224
0
    }
2225
0
    return DECLINED;
2226
0
}
2227
2228
static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
2229
0
{
2230
0
    const char *type;
2231
0
    const char *prefix = "";
2232
2233
0
    switch (parms->type) {
2234
0
    case AP_EXPR_FUNC_VAR:
2235
0
        type = "Variable";
2236
0
        break;
2237
0
    case AP_EXPR_FUNC_STRING:
2238
0
        type = "Function";
2239
0
        break;
2240
0
    case AP_EXPR_FUNC_LIST:
2241
0
        type = "List-returning function";
2242
0
        break;
2243
0
    case AP_EXPR_FUNC_OP_UNARY:
2244
0
        type = "Unary operator";
2245
0
        break;
2246
0
    case AP_EXPR_FUNC_OP_BINARY:
2247
0
        type = "Binary operator";
2248
0
        break;
2249
0
    default:
2250
0
        *parms->err = "Invalid expression type in expr_lookup";
2251
0
        return !OK;
2252
0
    }
2253
0
    if (   parms->type == AP_EXPR_FUNC_OP_UNARY
2254
0
        || parms->type == AP_EXPR_FUNC_OP_BINARY) {
2255
0
        prefix = "-";
2256
0
    }
2257
0
    *parms->err = apr_psprintf(parms->ptemp, "%s '%s%s' does not exist", type,
2258
0
                               prefix, parms->name);
2259
0
    return !OK;
2260
0
}
2261
2262
static int ap_expr_post_config(apr_pool_t *pconf, apr_pool_t *plog,
2263
                               apr_pool_t *ptemp, server_rec *s)
2264
0
{
2265
0
    is_http2 = APR_RETRIEVE_OPTIONAL_FN(http2_is_h2);
2266
0
    return OK;
2267
0
}
2268
2269
void ap_expr_init(apr_pool_t *p)
2270
0
{
2271
0
    ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
2272
0
    ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
2273
0
    ap_hook_post_config(ap_expr_post_config, NULL, NULL, APR_HOOK_MIDDLE);
2274
0
}
2275