Coverage Report

Created: 2026-09-06 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httpd/server/util_expr_eval.c
Line
Count
Source
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
0
{
575
0
    return ap_run_expr_lookup(parms);
576
0
}
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
0
{
582
0
    ap_expr_parse_ctx_t ctx;
583
0
    int rc;
584
585
0
    memset(&ctx, 0, sizeof ctx);
586
0
    ctx.pool     = pool;
587
0
    ctx.ptemp    = ptemp;
588
0
    ctx.inputbuf = expr;
589
0
    ctx.inputlen = strlen(expr);
590
0
    ctx.inputptr = ctx.inputbuf;
591
0
    ctx.flags    = info->flags;
592
0
    ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_expr_lookup_default;
593
0
    ctx.at_start    = 1;
594
595
0
    rc = ap_expr_yylex_init(&ctx.scanner);
596
0
    if (rc)
597
0
        return "ap_expr_yylex_init error";
598
599
0
    ap_expr_yyset_extra(&ctx, ctx.scanner);
600
0
    rc = ap_expr_yyparse(&ctx);
601
0
    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
0
    if (ctx.error) {
608
0
        if (ctx.error2)
609
0
            return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
610
0
        else
611
0
            return ctx.error;
612
0
    }
613
0
    else if (ctx.error2) {
614
0
        return ctx.error2;
615
0
    }
616
617
0
    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
0
    info->root_node = ctx.expr;
626
627
0
    return NULL;
628
0
}
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
643
    /* Use restricted-contents ap_expr() parser in htaccess context. */
644
0
    if (cmd->pool == cmd->temp_pool) {
645
0
        info->flags |= AP_EXPR_FLAG_RESTRICTED_FILE_FUNC;
646
0
    }
647
648
0
    *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
649
650
0
    if (*err)
651
0
        return NULL;
652
653
0
    return info;
654
0
}
655
656
ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
657
                        ap_expr_parse_ctx_t *ctx)
658
0
{
659
0
    ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
660
0
    node->node_op   = op;
661
0
    node->node_arg1 = a1;
662
0
    node->node_arg2 = a2;
663
0
    return node;
664
0
}
665
666
ap_expr_t *ap_expr_concat_make(const void *a1, const void *a2,
667
                               ap_expr_parse_ctx_t *ctx)
668
0
{
669
0
    const ap_expr_t *node;
670
671
    /* Optimize out empty string(s) concatenation */
672
0
    if ((node = a1)
673
0
            && node->node_op == op_String
674
0
            && !*(const char *)node->node_arg1) {
675
0
        return (ap_expr_t *)a2;
676
0
    }
677
0
    if ((node = a2)
678
0
            && node->node_op == op_String
679
0
            && !*(const char *)node->node_arg1) {
680
0
        return (ap_expr_t *)a1;
681
0
    }
682
683
0
    return ap_expr_make(op_Concat, a1, a2, ctx);
684
0
}
685
686
ap_expr_t *ap_expr_regex_make(const char *pattern, const ap_expr_t *subst,
687
                              const char *flags, ap_expr_parse_ctx_t *ctx)
688
0
{
689
0
    ap_expr_t *node = NULL;
690
0
    ap_expr_regctx_t *regctx;
691
0
    ap_regex_t *regex;
692
693
0
    regctx = apr_pcalloc(ctx->pool, sizeof *regctx);
694
0
    regctx->subst = subst;
695
0
    if (flags) {
696
0
        for (; *flags; ++flags) {
697
0
            switch (*flags) {
698
0
            case 'i':
699
0
                regctx->flags |= AP_REG_ICASE;
700
0
                break;
701
0
            case 'm':
702
0
                regctx->flags |= AP_REG_NEWLINE;
703
0
                break;
704
0
            case 's':
705
0
                regctx->flags |= AP_REG_DOTALL;
706
0
                break;
707
0
            case 'g':
708
0
                regctx->flags |= AP_REG_MULTI;
709
0
                break;
710
0
            }
711
0
        }
712
0
    }
713
0
    regex = ap_pregcomp(ctx->pool, pattern, regctx->flags);
714
0
    if (!regex) {
715
0
        return NULL;
716
0
    }
717
718
0
    node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
719
0
    node->node_op   = op_Regex;
720
0
    node->node_arg1 = regex;
721
0
    node->node_arg2 = regctx;
722
0
    return node;
723
0
}
724
725
static ap_expr_t *ap_expr_info_make(int type, const char *name,
726
                                  ap_expr_parse_ctx_t *ctx,
727
                                  const ap_expr_t *arg)
728
0
{
729
0
    ap_expr_t *info = apr_palloc(ctx->pool, sizeof(ap_expr_t));
730
0
    ap_expr_lookup_parms parms;
731
0
    parms.type  = type;
732
0
    parms.flags = ctx->flags;
733
0
    parms.pool  = ctx->pool;
734
0
    parms.ptemp = ctx->ptemp;
735
0
    parms.name  = name;
736
0
    parms.func  = &info->node_arg1;
737
0
    parms.data  = &info->node_arg2;
738
0
    parms.err   = &ctx->error2;
739
0
    parms.arg   = NULL;
740
0
    if (arg) {
741
0
        switch(arg->node_op) {
742
0
            case op_String:
743
0
                parms.arg = arg->node_arg1;
744
0
                break;
745
0
            case op_ListElement:
746
                /* save the first literal/simple string argument */
747
0
                do {
748
0
                    const ap_expr_t *val = arg->node_arg1;
749
0
                    if (val && val->node_op == op_String) {
750
0
                        parms.arg = val->node_arg1;
751
0
                        break;
752
0
                    }
753
0
                    arg = arg->node_arg2;
754
0
                } while (arg != NULL);
755
0
                break;
756
0
            default:
757
0
                break;
758
0
        }
759
0
    }
760
0
    if (ctx->lookup_fn(&parms) != OK)
761
0
        return NULL;
762
0
    return info;
763
0
}
764
765
ap_expr_t *ap_expr_str_func_make(const char *name, const ap_expr_t *arg,
766
                               ap_expr_parse_ctx_t *ctx)
767
0
{
768
0
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx, arg);
769
0
    if (!info)
770
0
        return NULL;
771
772
0
    info->node_op = op_StringFuncInfo;
773
0
    return ap_expr_make(op_StringFuncCall, info, arg, ctx);
774
0
}
775
776
ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
777
                                ap_expr_parse_ctx_t *ctx)
778
0
{
779
0
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx, arg);
780
0
    if (!info)
781
0
        return NULL;
782
783
0
    info->node_op = op_ListFuncInfo;
784
0
    return ap_expr_make(op_ListFuncCall, info, arg, ctx);
785
0
}
786
787
ap_expr_t *ap_expr_unary_op_make(const char *name, const ap_expr_t *arg,
788
                               ap_expr_parse_ctx_t *ctx)
789
0
{
790
0
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx, arg);
791
0
    if (!info)
792
0
        return NULL;
793
794
0
    info->node_op = op_UnaryOpInfo;
795
0
    return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
796
0
}
797
798
ap_expr_t *ap_expr_binary_op_make(const char *name, const ap_expr_t *arg1,
799
                                const ap_expr_t *arg2, ap_expr_parse_ctx_t *ctx)
800
0
{
801
0
    ap_expr_t *args;
802
0
    ap_expr_t *info = ap_expr_info_make(AP_EXPR_FUNC_OP_BINARY, name, ctx,
803
0
                                        arg2);
804
0
    if (!info)
805
0
        return NULL;
806
807
0
    info->node_op = op_BinaryOpInfo;
808
0
    args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
809
0
    return ap_expr_make(op_BinaryOpCall, info, args, ctx);
810
0
}
811
812
813
ap_expr_t *ap_expr_var_make(const char *name, ap_expr_parse_ctx_t *ctx)
814
0
{
815
0
    ap_expr_t *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx, NULL);
816
0
    if (!node)
817
0
        return NULL;
818
819
0
    node->node_op = op_Var;
820
0
    return node;
821
0
}
822
823
ap_expr_t *ap_expr_backref_make(int num, ap_expr_parse_ctx_t *ctx)
824
0
{
825
0
    int *n = apr_pmemdup(ctx->pool, &num, sizeof(num));
826
0
    return ap_expr_make(op_Backref, n, NULL, ctx);
827
0
}
828
829
#ifdef AP_EXPR_DEBUG
830
831
#define MARK                        APLOG_MARK,loglevel,0,s
832
#define DUMP_E_E(op, e1, e2)                                                \
833
    do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2);      \
834
         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);               \
835
         if (e2) expr_dump_tree(e2, s, loglevel, indent + 2);               \
836
    } while (0)
837
#define DUMP_S_E(op, s1, e1)                                                    \
838
    do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
839
         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);                   \
840
    } while (0)
841
#define DUMP_S_P(op, s1, p1)                                                \
842
    ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
843
#define DUMP_P_P(op, p1, p2)                                                \
844
    ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
845
#define DUMP_S_S(op, s1, s2)                                                       \
846
    ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
847
#define DUMP_P(op, p1)                                                      \
848
    ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
849
#define DUMP_IP(op, p1)                                                     \
850
    ap_log_error(MARK,"%*s%s: %d", indent, " ", op, *(int *)p1);
851
#define DUMP_S(op, s1)                                                      \
852
    ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
853
854
#define CASE_OP(op)                  case op: name = #op ; break;
855
856
static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
857
                           int loglevel, int indent)
858
{
859
    switch (e->node_op) {
860
    /* no arg */
861
    case op_NOP:
862
    case op_True:
863
    case op_False:
864
        {
865
            char *name;
866
            switch (e->node_op) {
867
            CASE_OP(op_NOP);
868
            CASE_OP(op_True);
869
            CASE_OP(op_False);
870
            default:
871
                ap_assert(0);
872
            }
873
            ap_log_error(MARK, "%*s%s", indent, " ", name);
874
        }
875
        break;
876
877
    /* arg1: string, arg2: expr */
878
    case op_UnaryOpCall:
879
    case op_BinaryOpCall:
880
    case op_BinaryOpArgs:
881
        {
882
            char *name;
883
            switch (e->node_op) {
884
            CASE_OP(op_BinaryOpCall);
885
            CASE_OP(op_UnaryOpCall);
886
            CASE_OP(op_BinaryOpArgs);
887
            default:
888
                ap_assert(0);
889
            }
890
            DUMP_S_E(name, e->node_arg1, e->node_arg2);
891
        }
892
        break;
893
894
    /* arg1: expr, arg2: expr */
895
    case op_Comp:
896
    case op_Not:
897
    case op_Or:
898
    case op_And:
899
    case op_EQ:
900
    case op_NE:
901
    case op_LT:
902
    case op_LE:
903
    case op_GT:
904
    case op_GE:
905
    case op_STR_EQ:
906
    case op_STR_NE:
907
    case op_STR_LT:
908
    case op_STR_LE:
909
    case op_STR_GT:
910
    case op_STR_GE:
911
    case op_IN:
912
    case op_REG:
913
    case op_NRE:
914
    case op_Word:
915
    case op_Bool:
916
    case op_Sub:
917
    case op_Join:
918
    case op_Split:
919
    case op_Concat:
920
    case op_StringFuncCall:
921
    case op_ListFuncCall:
922
    case op_ListElement:
923
        {
924
            char *name;
925
            switch (e->node_op) {
926
            CASE_OP(op_Comp);
927
            CASE_OP(op_Not);
928
            CASE_OP(op_Or);
929
            CASE_OP(op_And);
930
            CASE_OP(op_EQ);
931
            CASE_OP(op_NE);
932
            CASE_OP(op_LT);
933
            CASE_OP(op_LE);
934
            CASE_OP(op_GT);
935
            CASE_OP(op_GE);
936
            CASE_OP(op_STR_EQ);
937
            CASE_OP(op_STR_NE);
938
            CASE_OP(op_STR_LT);
939
            CASE_OP(op_STR_LE);
940
            CASE_OP(op_STR_GT);
941
            CASE_OP(op_STR_GE);
942
            CASE_OP(op_IN);
943
            CASE_OP(op_REG);
944
            CASE_OP(op_NRE);
945
            CASE_OP(op_Word);
946
            CASE_OP(op_Bool);
947
            CASE_OP(op_Sub);
948
            CASE_OP(op_Join);
949
            CASE_OP(op_Split);
950
            CASE_OP(op_Concat);
951
            CASE_OP(op_StringFuncCall);
952
            CASE_OP(op_ListFuncCall);
953
            CASE_OP(op_ListElement);
954
            default:
955
                ap_assert(0);
956
            }
957
            DUMP_E_E(name, e->node_arg1, e->node_arg2);
958
        }
959
        break;
960
    /* arg1: string */
961
    case op_Digit:
962
    case op_String:
963
        {
964
            char *name;
965
            switch (e->node_op) {
966
            CASE_OP(op_Digit);
967
            CASE_OP(op_String);
968
            default:
969
                ap_assert(0);
970
            }
971
            DUMP_S(name, e->node_arg1);
972
        }
973
        break;
974
    /* arg1: pointer, arg2: pointer */
975
    case op_Var:
976
    case op_StringFuncInfo:
977
    case op_UnaryOpInfo:
978
    case op_BinaryOpInfo:
979
    case op_ListFuncInfo:
980
        {
981
            char *name;
982
            switch (e->node_op) {
983
            CASE_OP(op_Var);
984
            CASE_OP(op_StringFuncInfo);
985
            CASE_OP(op_UnaryOpInfo);
986
            CASE_OP(op_BinaryOpInfo);
987
            CASE_OP(op_ListFuncInfo);
988
            default:
989
                ap_assert(0);
990
            }
991
            DUMP_P_P(name, e->node_arg1, e->node_arg2);
992
        }
993
        break;
994
    /* arg1: pointer */
995
    case op_Regex:
996
        DUMP_P("op_Regex", e->node_arg1);
997
        break;
998
    /* arg1: pointer to int */
999
    case op_Backref:
1000
        DUMP_IP("op_Backref", e->node_arg1);
1001
        break;
1002
    default:
1003
        ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
1004
        break;
1005
    }
1006
}
1007
#endif /* AP_EXPR_DEBUG */
1008
1009
0
#define expr_eval_log(ctx, level, ...) do { \
1010
0
    ap_expr_eval_ctx_t *x = (ctx); \
1011
0
    if (x->r) { \
1012
0
        ap_log_rerror(LOG_MARK(x->info), (level), 0, x->r, __VA_ARGS__); \
1013
0
    } \
1014
0
    else if (x->c) { \
1015
0
        ap_log_cerror(LOG_MARK(x->info), (level), 0, x->c, __VA_ARGS__); \
1016
0
    } \
1017
0
    else { \
1018
0
        ap_log_error(LOG_MARK(x->info), (level), 0, x->s, __VA_ARGS__); \
1019
0
    } \
1020
0
} while (0)
1021
1022
static int ap_expr_eval_unary_op(ap_expr_eval_ctx_t *ctx, const ap_expr_t *info,
1023
                                 const ap_expr_t *arg)
1024
0
{
1025
0
    ap_expr_op_unary_t *op_func = (ap_expr_op_unary_t *)info->node_arg1;
1026
0
    const void *data = info->node_arg2;
1027
1028
0
    AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
1029
0
    AP_DEBUG_ASSERT(op_func != NULL);
1030
0
    AP_DEBUG_ASSERT(data != NULL);
1031
0
    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
1032
0
}
1033
1034
static int ap_expr_eval_binary_op(ap_expr_eval_ctx_t *ctx,
1035
                                  const ap_expr_t *info,
1036
                                  const ap_expr_t *args)
1037
0
{
1038
0
    ap_expr_op_binary_t *op_func = (ap_expr_op_binary_t *)info->node_arg1;
1039
0
    const void *data = info->node_arg2;
1040
0
    const ap_expr_t *a1 = args->node_arg1;
1041
0
    const ap_expr_t *a2 = args->node_arg2;
1042
1043
0
    AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
1044
0
    AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
1045
0
    AP_DEBUG_ASSERT(op_func != NULL);
1046
0
    AP_DEBUG_ASSERT(data != NULL);
1047
0
    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
1048
0
                      ap_expr_eval_word(ctx, a2));
1049
0
}
1050
1051
1052
static int ap_expr_eval_cond(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
1053
0
{
1054
0
    const ap_expr_t *e1 = node->node_arg1;
1055
0
    const ap_expr_t *e2 = node->node_arg2;
1056
0
    int result = FALSE;
1057
0
    if (inc_rec(ctx))
1058
0
        return result;
1059
0
    while (1) {
1060
0
        switch (node->node_op) {
1061
0
        case op_True:
1062
0
            result ^= TRUE;
1063
0
            goto out;
1064
0
        case op_False:
1065
0
            result ^= FALSE;
1066
0
            goto out;
1067
0
        case op_Not:
1068
0
            result = !result;
1069
0
            node = e1;
1070
0
            break;
1071
0
        case op_Or:
1072
0
            do {
1073
0
                if (e1->node_op == op_Not) {
1074
0
                    if (!ap_expr_eval_cond(ctx, e1->node_arg1)) {
1075
0
                        result ^= TRUE;
1076
0
                        goto out;
1077
0
                    }
1078
0
                }
1079
0
                else {
1080
0
                    if (ap_expr_eval_cond(ctx, e1)) {
1081
0
                        result ^= TRUE;
1082
0
                        goto out;
1083
0
                    }
1084
0
                }
1085
0
                node = node->node_arg2;
1086
0
                e1 = node->node_arg1;
1087
0
            } while (node->node_op == op_Or);
1088
0
            break;
1089
0
        case op_And:
1090
0
            do {
1091
0
                if (e1->node_op == op_Not) {
1092
0
                    if (ap_expr_eval_cond(ctx, e1->node_arg1)) {
1093
0
                        result ^= FALSE;
1094
0
                        goto out;
1095
0
                    }
1096
0
                }
1097
0
                else {
1098
0
                    if (!ap_expr_eval_cond(ctx, e1)) {
1099
0
                        result ^= FALSE;
1100
0
                        goto out;
1101
0
                    }
1102
0
                }
1103
0
                node = node->node_arg2;
1104
0
                e1 = node->node_arg1;
1105
0
            } while (node->node_op == op_And);
1106
0
            break;
1107
0
        case op_UnaryOpCall:
1108
0
            result ^= ap_expr_eval_unary_op(ctx, e1, e2);
1109
0
            goto out;
1110
0
        case op_BinaryOpCall:
1111
0
            result ^= ap_expr_eval_binary_op(ctx, e1, e2);
1112
0
            goto out;
1113
0
        case op_Comp:
1114
0
            if (ctx->info->flags & AP_EXPR_FLAG_SSL_EXPR_COMPAT)
1115
0
                result ^= ssl_expr_eval_comp(ctx, e1);
1116
0
            else
1117
0
                result ^= ap_expr_eval_comp(ctx, e1);
1118
0
            goto out;
1119
0
        default:
1120
0
            *ctx->err = "Internal evaluation error: Unknown expression node";
1121
0
            goto out;
1122
0
        }
1123
0
        e1 = node->node_arg1;
1124
0
        e2 = node->node_arg2;
1125
0
    }
1126
0
out:
1127
0
    ctx->reclvl--;
1128
0
    return result;
1129
0
}
1130
1131
AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info,
1132
                             const char **err)
1133
0
{
1134
0
    return ap_expr_exec_re(r, info, 0, NULL, NULL, err);
1135
0
}
1136
1137
AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
1138
0
{
1139
0
    int rc;
1140
1141
0
    AP_DEBUG_ASSERT(ctx->p != NULL);
1142
0
    AP_DEBUG_ASSERT(ctx->err != NULL);
1143
0
    AP_DEBUG_ASSERT(ctx->info != NULL);
1144
0
    if (ctx->re_pmatch) {
1145
0
        AP_DEBUG_ASSERT(ctx->re_source != NULL);
1146
0
        AP_DEBUG_ASSERT(ctx->re_nmatch > 0);
1147
0
    }
1148
0
    if (!ctx->s) {
1149
0
        if (ctx->r) {
1150
0
            ctx->s = ctx->r->server;
1151
0
        }
1152
0
        else if (ctx->c) {
1153
0
            ctx->s = ctx->c->base_server;
1154
0
        }
1155
0
    }
1156
0
    if (!ctx->c) {
1157
0
        if (ctx->r) {
1158
0
            ctx->c = ctx->r->connection;
1159
0
        }
1160
0
    }
1161
0
    AP_DEBUG_ASSERT(ctx->s != NULL);
1162
1163
0
    ctx->reclvl = 0;
1164
0
    *ctx->err = NULL;
1165
0
    if (ctx->info->flags & AP_EXPR_FLAG_STRING_RESULT) {
1166
0
        *ctx->result_string = ap_expr_eval_word(ctx, ctx->info->root_node);
1167
0
        if (*ctx->err != NULL) {
1168
0
            expr_eval_log(ctx, APLOG_ERR, APLOGNO(03298)
1169
0
                          "Evaluation of string expression from %s:%d failed: %s",
1170
0
                          ctx->info->filename, ctx->info->line_number, *ctx->err);
1171
0
            return -1;
1172
0
        } else {
1173
0
            expr_eval_log(ctx, APLOG_TRACE4,
1174
0
                          "Evaluation of string expression from %s:%d gave: %s",
1175
0
                          ctx->info->filename, ctx->info->line_number,
1176
0
                          *ctx->result_string);
1177
0
            return 1;
1178
0
        }
1179
0
    }
1180
0
    else {
1181
0
        rc = ap_expr_eval_cond(ctx, ctx->info->root_node);
1182
0
        if (*ctx->err != NULL) {
1183
0
            expr_eval_log(ctx, APLOG_ERR, APLOGNO(03299)
1184
0
                          "Evaluation of expression from %s:%d failed: %s",
1185
0
                          ctx->info->filename, ctx->info->line_number, *ctx->err);
1186
0
            return -1;
1187
0
        } else {
1188
0
            rc = rc ? 1 : 0;
1189
0
            expr_eval_log(ctx, APLOG_TRACE4,
1190
0
                          "Evaluation of expression from %s:%d gave: %d",
1191
0
                          ctx->info->filename, ctx->info->line_number, rc);
1192
1193
0
            if (ctx->r && ctx->vary_this && *ctx->vary_this)
1194
0
                apr_table_merge(ctx->r->headers_out, "Vary", *ctx->vary_this);
1195
1196
0
            return rc;
1197
0
        }
1198
0
    }
1199
0
}
1200
1201
AP_DECLARE(int) ap_expr_exec_re(request_rec *r, const ap_expr_info_t *info,
1202
                                apr_size_t nmatch, ap_regmatch_t *pmatch,
1203
                                const char **source, const char **err)
1204
0
{
1205
0
    ap_expr_eval_ctx_t ctx;
1206
0
    int dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
1207
0
    const char *tmp_source = NULL, *vary_this = NULL;
1208
0
    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
1209
1210
0
    AP_DEBUG_ASSERT((info->flags & AP_EXPR_FLAG_STRING_RESULT) == 0);
1211
1212
0
    ctx.r = r;
1213
0
    ctx.c = r->connection;
1214
0
    ctx.s = r->server;
1215
0
    ctx.p = r->pool;
1216
0
    ctx.err  = err;
1217
0
    ctx.info = info;
1218
0
    ctx.re_nmatch = nmatch;
1219
0
    ctx.re_pmatch = pmatch;
1220
0
    ctx.re_source = source;
1221
0
    ctx.vary_this = dont_vary ? NULL : &vary_this;
1222
0
    ctx.data = NULL;
1223
1224
0
    if (!pmatch) {
1225
0
        ctx.re_nmatch = AP_MAX_REG_MATCH;
1226
0
        ctx.re_pmatch = tmp_pmatch;
1227
0
        ctx.re_source = &tmp_source;
1228
0
    }
1229
1230
0
    return ap_expr_exec_ctx(&ctx);
1231
0
}
1232
1233
AP_DECLARE(const char *) ap_expr_str_exec_re(request_rec *r,
1234
                                             const ap_expr_info_t *info,
1235
                                             apr_size_t nmatch,
1236
                                             ap_regmatch_t *pmatch,
1237
                                             const char **source,
1238
                                             const char **err)
1239
0
{
1240
0
    ap_expr_eval_ctx_t ctx;
1241
0
    int dont_vary, rc;
1242
0
    const char *tmp_source, *vary_this;
1243
0
    ap_regmatch_t tmp_pmatch[AP_MAX_REG_MATCH];
1244
0
    const char *result;
1245
1246
0
    AP_DEBUG_ASSERT(info->flags & AP_EXPR_FLAG_STRING_RESULT);
1247
1248
0
    if (info->root_node->node_op == op_String) {
1249
        /* short-cut for constant strings */
1250
0
        *err = NULL;
1251
0
        return (const char *)info->root_node->node_arg1;
1252
0
    }
1253
1254
0
    tmp_source = NULL;
1255
0
    vary_this = NULL;
1256
1257
0
    dont_vary = (info->flags & AP_EXPR_FLAG_DONT_VARY);
1258
1259
0
    ctx.r = r;
1260
0
    ctx.c = r->connection;
1261
0
    ctx.s = r->server;
1262
0
    ctx.p = r->pool;
1263
0
    ctx.err  = err;
1264
0
    ctx.info = info;
1265
0
    ctx.re_nmatch = nmatch;
1266
0
    ctx.re_pmatch = pmatch;
1267
0
    ctx.re_source = source;
1268
0
    ctx.vary_this = dont_vary ? NULL : &vary_this;
1269
0
    ctx.data = NULL;
1270
0
    ctx.result_string = &result;
1271
1272
0
    if (!pmatch) {
1273
0
        ctx.re_nmatch = AP_MAX_REG_MATCH;
1274
0
        ctx.re_pmatch = tmp_pmatch;
1275
0
        ctx.re_source = &tmp_source;
1276
0
    }
1277
1278
0
    rc = ap_expr_exec_ctx(&ctx);
1279
0
    if (rc > 0)
1280
0
        return result;
1281
0
    else if (rc < 0)
1282
0
        return NULL;
1283
0
    else
1284
0
        ap_assert(0);
1285
    /* Not reached */
1286
0
    return NULL;
1287
0
}
1288
1289
AP_DECLARE(const char *) ap_expr_str_exec(request_rec *r,
1290
                                          const ap_expr_info_t *info,
1291
                                          const char **err)
1292
0
{
1293
0
    return ap_expr_str_exec_re(r, info, 0, NULL, NULL, err);
1294
0
}
1295
1296
1297
static void add_vary(ap_expr_eval_ctx_t *ctx, const char *name)
1298
0
{
1299
0
    if (!ctx->vary_this)
1300
0
        return;
1301
1302
0
    if (*ctx->vary_this) {
1303
0
        *ctx->vary_this = apr_pstrcat(ctx->p, *ctx->vary_this, ", ", name,
1304
0
                                      NULL);
1305
0
    }
1306
0
    else {
1307
0
        *ctx->vary_this = name;
1308
0
    }
1309
0
}
1310
1311
static const char *req_table_func(ap_expr_eval_ctx_t *ctx, const void *data,
1312
                                  const char *arg)
1313
0
{
1314
0
    const char *name = (const char *)data;
1315
0
    apr_table_t *t;
1316
0
    if (!ctx->r)
1317
0
        return "";
1318
1319
0
    if (name[2] == 's') {           /* resp */
1320
        /* Try r->headers_out first, fall back on err_headers_out. */
1321
0
        const char *v = apr_table_get(ctx->r->headers_out, arg);
1322
0
        if (v) {
1323
0
            return v;
1324
0
        }
1325
0
        t = ctx->r->err_headers_out;
1326
0
    }
1327
0
    else if (name[0] == 'n')        /* notes */
1328
0
        t = ctx->r->notes;
1329
0
    else if (name[3] == 'e')        /* reqenv */
1330
0
        t = ctx->r->subprocess_env;
1331
0
    else if (name[3] == '_')        /* req_novary */
1332
0
        t = ctx->r->headers_in;
1333
0
    else {                          /* req, http */
1334
0
        t = ctx->r->headers_in;
1335
        /* Skip the 'Vary: Host' header combination
1336
         * as indicated in rfc7231 section-7.1.4
1337
         */
1338
0
        if (strcasecmp(arg, "Host")){
1339
0
            add_vary(ctx, arg);
1340
0
        }
1341
0
    }
1342
0
    return apr_table_get(t, arg);
1343
0
}
1344
1345
static const char *env_func(ap_expr_eval_ctx_t *ctx, const void *data,
1346
                            const char *arg)
1347
0
{
1348
0
    const char *res;
1349
    /* this order is for ssl_expr compatibility */
1350
0
    if (ctx->r) {
1351
0
        if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
1352
0
            return res;
1353
0
        else if ((res = apr_table_get(ctx->r->subprocess_env, arg)) != NULL)
1354
0
            return res;
1355
0
    }
1356
0
    return getenv(arg);
1357
0
}
1358
1359
static const char *osenv_func(ap_expr_eval_ctx_t *ctx, const void *data,
1360
                              const char *arg)
1361
0
{
1362
0
    return getenv(arg);
1363
0
}
1364
1365
static const char *tolower_func(ap_expr_eval_ctx_t *ctx, const void *data,
1366
                                const char *arg)
1367
0
{
1368
0
    char *result = apr_pstrdup(ctx->p, arg);
1369
0
    ap_str_tolower(result);
1370
0
    return result;
1371
0
}
1372
1373
static const char *toupper_func(ap_expr_eval_ctx_t *ctx, const void *data,
1374
                                const char *arg)
1375
0
{
1376
0
    char *result = apr_pstrdup(ctx->p, arg);
1377
0
    ap_str_toupper(result);
1378
0
    return result;
1379
0
}
1380
1381
static const char *escape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1382
                               const char *arg)
1383
0
{
1384
0
    return ap_escape_uri(ctx->p, arg);
1385
0
}
1386
1387
static const char *base64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1388
                               const char *arg)
1389
0
{
1390
0
    return ap_pbase64encode(ctx->p, (char *)arg);
1391
0
}
1392
1393
static const char *unbase64_func(ap_expr_eval_ctx_t *ctx, const void *data,
1394
                               const char *arg)
1395
0
{
1396
0
    return ap_pbase64decode(ctx->p, arg);
1397
0
}
1398
1399
static const char *sha1_func(ap_expr_eval_ctx_t *ctx, const void *data,
1400
                               const char *arg)
1401
0
{
1402
0
    apr_sha1_ctx_t context;
1403
0
    apr_byte_t sha1[APR_SHA1_DIGESTSIZE];
1404
0
    char *out;
1405
1406
0
    out = apr_palloc(ctx->p, APR_SHA1_DIGESTSIZE*2+1);
1407
1408
0
    apr_sha1_init(&context);
1409
0
    apr_sha1_update(&context, arg, (unsigned int)strlen(arg));
1410
0
    apr_sha1_final(sha1, &context);
1411
1412
0
    ap_bin2hex(sha1, APR_SHA1_DIGESTSIZE, out);
1413
1414
0
    return out;
1415
0
}
1416
1417
static const char *md5_func(ap_expr_eval_ctx_t *ctx, const void *data,
1418
                               const char *arg)
1419
0
{
1420
0
    return ap_md5(ctx->p, (const unsigned char *)arg);
1421
0
}
1422
1423
#if APR_VERSION_AT_LEAST(1,6,0)
1424
static const char *ldap_func(ap_expr_eval_ctx_t *ctx, const void *data,
1425
                               const char *arg)
1426
0
{
1427
0
    return apr_pescape_ldap(ctx->p, arg, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_ALL);
1428
0
}
1429
#endif
1430
1431
static const char *escapehtml_func(ap_expr_eval_ctx_t *ctx, const void *data,
1432
                                   const char *arg)
1433
0
{
1434
0
    return ap_escape_html(ctx->p, arg);
1435
0
}
1436
1437
static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
1438
0
{
1439
0
    const char *original = parms->arg;
1440
0
    const apr_strmatch_pattern *pattern;
1441
1442
0
    if (!parms->arg) {
1443
0
        *parms->err = apr_psprintf(parms->ptemp, "replace() function needs an argument");
1444
0
        return !OK;
1445
0
    }
1446
1447
0
    pattern = apr_strmatch_precompile(parms->pool, original, 0);
1448
0
    *parms->data = pattern;
1449
0
    return OK;
1450
0
}
1451
1452
static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
1453
                               const apr_array_header_t *args)
1454
0
{
1455
0
    char *buff, *original, *replacement;
1456
0
    struct ap_varbuf vb;
1457
0
    apr_size_t repl_len, orig_len;
1458
0
    const char *repl;
1459
0
    apr_size_t bytes;
1460
0
    apr_size_t len;
1461
0
    const apr_strmatch_pattern *pattern = data;
1462
0
    if (args->nelts != 3) {
1463
0
        *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
1464
0
                                 "exactly 3 arguments, got %d", args->nelts);
1465
0
        return "";
1466
0
    }
1467
1468
0
    buff = APR_ARRAY_IDX(args, 0, char *);
1469
0
    original = APR_ARRAY_IDX(args, 1, char *);
1470
0
    replacement = APR_ARRAY_IDX(args, 2, char *);
1471
0
    repl_len = strlen(replacement);
1472
0
    orig_len = strlen(original);
1473
0
    bytes = strlen(buff);
1474
1475
0
    ap_varbuf_init(ctx->p, &vb, 0);
1476
0
    vb.strlen = 0;
1477
    
1478
0
    while ((repl = apr_strmatch(pattern, buff, bytes))) {
1479
0
        len = (apr_size_t) (repl - buff);
1480
0
        ap_varbuf_strmemcat(&vb, buff, len);
1481
0
        ap_varbuf_strmemcat(&vb, replacement, repl_len);
1482
1483
0
        len += orig_len;
1484
0
        bytes -= len;
1485
0
        buff += len;
1486
0
    }
1487
1488
0
    return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
1489
0
}
1490
1491
0
#define MAX_FILE_SIZE 10*1024*1024
1492
static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
1493
                             char *arg)
1494
0
{
1495
0
    apr_file_t *fp;
1496
0
    char *buf;
1497
0
    apr_off_t offset;
1498
0
    apr_size_t len;
1499
0
    apr_finfo_t finfo;
1500
1501
0
    if (apr_file_open(&fp, arg, APR_READ|APR_BUFFERED,
1502
0
                      APR_OS_DEFAULT, ctx->p) != APR_SUCCESS) {
1503
0
        *ctx->err = apr_psprintf(ctx->p, "Cannot open file %s", arg);
1504
0
        return "";
1505
0
    }
1506
0
    apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
1507
0
    if (finfo.size > MAX_FILE_SIZE) {
1508
0
        *ctx->err = apr_psprintf(ctx->p, "File %s too large", arg);
1509
0
        apr_file_close(fp);
1510
0
        return "";
1511
0
    }
1512
0
    len = (apr_size_t)finfo.size;
1513
0
    if (len == 0) {
1514
0
        apr_file_close(fp);
1515
0
        return "";
1516
0
    }
1517
0
    else {
1518
0
        if ((buf = (char *)apr_palloc(ctx->p, sizeof(char)*(len+1))) == NULL) {
1519
0
            *ctx->err = "Cannot allocate memory";
1520
0
            apr_file_close(fp);
1521
0
            return "";
1522
0
        }
1523
0
        offset = 0;
1524
0
        apr_file_seek(fp, APR_SET, &offset);
1525
0
        if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
1526
0
            *ctx->err = apr_psprintf(ctx->p, "Cannot read from file %s", arg);
1527
0
            apr_file_close(fp);
1528
0
            return "";
1529
0
        }
1530
0
        buf[len] = '\0';
1531
0
    }
1532
0
    apr_file_close(fp);
1533
0
    return buf;
1534
0
}
1535
1536
static apr_status_t stat_check(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1537
0
{
1538
0
    apr_status_t rv = APR_SUCCESS;
1539
0
    if (APR_SUCCESS != (rv = ap_stat_check(arg, ctx->p))) {
1540
0
        *ctx->err = apr_psprintf(ctx->p, "stat of %s not allowed", arg);
1541
0
    }
1542
0
    return rv;
1543
0
}
1544
static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
1545
                                  char *arg)
1546
0
{
1547
0
    apr_finfo_t sb;
1548
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1549
0
        return "";
1550
0
    }
1551
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1552
0
        && sb.filetype == APR_REG && sb.size > 0)
1553
0
        return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
1554
0
    else
1555
0
        return "0";
1556
0
}
1557
1558
static const char *filemod_func(ap_expr_eval_ctx_t *ctx, const void *data,
1559
                                  char *arg)
1560
0
{
1561
0
    apr_finfo_t sb;
1562
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1563
0
        return "";
1564
0
    }
1565
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
1566
0
        && sb.filetype == APR_REG && sb.mtime > 0)
1567
0
        return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, (apr_off_t)sb.mtime);
1568
0
    else
1569
0
        return "0";
1570
0
}
1571
1572
1573
static const char *unescape_func(ap_expr_eval_ctx_t *ctx, const void *data,
1574
                                 const char *arg)
1575
0
{
1576
0
    char *result = apr_pstrdup(ctx->p, arg);
1577
0
    int ret = ap_unescape_url_keep2f(result, 0);
1578
0
    if (ret == OK)
1579
0
        return result;
1580
0
    expr_eval_log(ctx, APLOG_DEBUG, APLOGNO(00538)
1581
0
                  "%s %% escape in unescape('%s') at %s:%d",
1582
0
                  ret == HTTP_BAD_REQUEST ? "Bad" : "Forbidden", arg,
1583
0
                  ctx->info->filename, ctx->info->line_number);
1584
0
    return "";
1585
0
}
1586
1587
static int op_nz(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1588
0
{
1589
0
    const char *name = (const char *)data;
1590
0
    if (name[0] == 'z')
1591
0
        return (arg[0] == '\0');
1592
0
    else
1593
0
        return (arg[0] != '\0');
1594
0
}
1595
1596
static int op_file_min(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1597
0
{
1598
0
    apr_finfo_t sb;
1599
0
    const char *name = (const char *)data;
1600
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1601
0
        return FALSE;
1602
0
    }
1603
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
1604
0
        return FALSE;
1605
0
    switch (name[0]) {
1606
0
    case 'd':
1607
0
        return (sb.filetype == APR_DIR);
1608
0
    case 'e':
1609
0
        return TRUE;
1610
0
    case 'f':
1611
0
        return (sb.filetype == APR_REG);
1612
0
    case 's':
1613
0
        return (sb.filetype == APR_REG && sb.size > 0);
1614
0
    default:
1615
0
        ap_assert(0);
1616
0
    }
1617
0
    return FALSE;
1618
0
}
1619
1620
static int op_file_link(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1621
0
{
1622
0
#if !defined(OS2)
1623
0
    apr_finfo_t sb;
1624
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1625
0
        return FALSE;
1626
0
    }
1627
0
    if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1628
0
        && sb.filetype == APR_LNK) {
1629
0
        return TRUE;
1630
0
    }
1631
0
#endif
1632
0
    return FALSE;
1633
0
}
1634
1635
static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1636
0
{
1637
0
    apr_finfo_t sb;
1638
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1639
0
        return FALSE;
1640
0
    }
1641
0
    if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
1642
0
        && (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
1643
0
        return TRUE;
1644
0
    }
1645
0
    return FALSE;
1646
0
}
1647
1648
static int op_url_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1649
0
{
1650
0
    int rc = FALSE;
1651
0
    request_rec  *rsub, *r = ctx->r;
1652
0
    if (!r)
1653
0
        return FALSE;
1654
    /* avoid some infinite recursions */
1655
0
    if (r->main && r->main->uri && r->uri && strcmp(r->main->uri, r->uri) == 0)
1656
0
        return FALSE;
1657
1658
0
    rsub = ap_sub_req_lookup_uri(arg, r, NULL);
1659
0
    if (rsub->status < HTTP_BAD_REQUEST) {
1660
0
            rc = TRUE;
1661
0
    }
1662
0
    expr_eval_log(ctx, APLOG_TRACE5,
1663
0
                  "Subrequest for -U %s at %s:%d gave status: %d",
1664
0
                  arg, ctx->info->filename, ctx->info->line_number,
1665
0
                  rsub->status);
1666
0
    ap_destroy_sub_req(rsub);
1667
0
    return rc;
1668
0
}
1669
1670
static int op_file_subr(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
1671
0
{
1672
0
    int rc = FALSE;
1673
0
    apr_finfo_t sb;
1674
0
    request_rec *rsub, *r = ctx->r;
1675
0
    if (!r)
1676
0
        return FALSE;
1677
0
    if (APR_SUCCESS != stat_check(ctx, data, arg)) {
1678
0
        return FALSE;
1679
0
    }
1680
0
    rsub = ap_sub_req_lookup_file(arg, r, NULL);
1681
0
    if (rsub->status < HTTP_MULTIPLE_CHOICES &&
1682
        /* double-check that file exists since default result is 200 */
1683
0
        apr_stat(&sb, rsub->filename, APR_FINFO_MIN, ctx->p) == APR_SUCCESS) {
1684
0
        rc = TRUE;
1685
0
    }
1686
0
    expr_eval_log(ctx, APLOG_TRACE5,
1687
0
                  "Subrequest for -F %s at %s:%d gave status: %d",
1688
0
                  arg, ctx->info->filename, ctx->info->line_number,
1689
0
                  rsub->status);
1690
0
    ap_destroy_sub_req(rsub);
1691
0
    return rc;
1692
0
}
1693
1694
1695
APR_DECLARE_OPTIONAL_FN(int, http2_is_h2, (conn_rec *));
1696
static APR_OPTIONAL_FN_TYPE(http2_is_h2) *is_http2 = NULL;
1697
1698
static const char *const conn_var_names[] = {
1699
    "HTTPS",                    /*  0 */
1700
    "IPV6",                     /*  1 */
1701
    "CONN_LOG_ID",              /*  2 */
1702
    "CONN_REMOTE_ADDR",         /*  3 */
1703
    "HTTP2",                    /*  4 */
1704
    NULL
1705
};
1706
1707
static const char *conn_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1708
0
{
1709
0
    int index = ((const char **)data - conn_var_names);
1710
0
    conn_rec *c = ctx->c;
1711
0
    if (!c)
1712
0
        return "";
1713
1714
0
    switch (index) {
1715
0
    case 0:
1716
0
        if (ap_ssl_conn_is_ssl(c))
1717
0
            return "on";
1718
0
        else
1719
0
            return "off";
1720
0
    case 1:
1721
0
#if APR_HAVE_IPV6
1722
0
        {
1723
0
            apr_sockaddr_t *addr = c->client_addr;
1724
0
            if (addr->family == AF_INET6
1725
0
                && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr))
1726
0
                return "on";
1727
0
            else
1728
0
                return "off";
1729
0
        }
1730
#else
1731
        return "off";
1732
#endif
1733
0
    case 2:
1734
0
        return c->log_id;
1735
0
    case 3:
1736
0
        return c->client_ip;
1737
0
    case 4:
1738
0
        if (is_http2 && is_http2(c))
1739
0
            return "on";
1740
0
        else
1741
0
            return "off";
1742
0
    default:
1743
0
        ap_assert(0);
1744
0
        return NULL;
1745
0
    }
1746
0
}
1747
1748
static const char *const request_var_names[] = {
1749
    "REQUEST_METHOD",           /*  0 */
1750
    "REQUEST_SCHEME",           /*  1 */
1751
    "REQUEST_URI",              /*  2 */
1752
    "REQUEST_FILENAME",         /*  3 */
1753
    "REMOTE_HOST",              /*  4 */
1754
    "REMOTE_IDENT",             /*  5 */
1755
    "REMOTE_USER",              /*  6 */
1756
    "SERVER_ADMIN",             /*  7 */
1757
    "SERVER_NAME",              /*  8 */
1758
    "SERVER_PORT",              /*  9 */
1759
    "SERVER_PROTOCOL",          /* 10 */
1760
    "SCRIPT_FILENAME",          /* 11 */
1761
    "PATH_INFO",                /* 12 */
1762
    "QUERY_STRING",             /* 13 */
1763
    "IS_SUBREQ",                /* 14 */
1764
    "DOCUMENT_ROOT",            /* 15 */
1765
    "AUTH_TYPE",                /* 16 */
1766
    "THE_REQUEST",              /* 17 */
1767
    "CONTENT_TYPE",             /* 18 */
1768
    "HANDLER",                  /* 19 */
1769
    "REQUEST_LOG_ID",           /* 20 */
1770
    "SCRIPT_USER",              /* 21 */
1771
    "SCRIPT_GROUP",             /* 22 */
1772
    "DOCUMENT_URI",             /* 23 */
1773
    "LAST_MODIFIED",            /* 24 */
1774
    "CONTEXT_PREFIX",           /* 25 */
1775
    "CONTEXT_DOCUMENT_ROOT",    /* 26 */
1776
    "REQUEST_STATUS",           /* 27 */
1777
    "REMOTE_ADDR",              /* 28 */
1778
    "SERVER_PROTOCOL_VERSION",  /* 29 */
1779
    "SERVER_PROTOCOL_VERSION_MAJOR",  /* 30 */
1780
    "SERVER_PROTOCOL_VERSION_MINOR",  /* 31 */
1781
    "REMOTE_PORT",                    /* 32 */
1782
    NULL
1783
};
1784
1785
static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1786
0
{
1787
0
    int index = ((const char **)data - request_var_names);
1788
0
    request_rec *r = ctx->r;
1789
0
    if (!r)
1790
0
        return "";
1791
1792
0
    switch (index) {
1793
0
    case 0:
1794
0
        return r->method;
1795
0
    case 1:
1796
0
        return ap_http_scheme(r);
1797
0
    case 2:
1798
0
        return r->uri;
1799
0
    case 3:
1800
0
        return r->filename;
1801
0
    case 4:
1802
0
        return ap_get_useragent_host(r, REMOTE_NAME, NULL);
1803
0
    case 5:
1804
0
        return ap_get_remote_logname(r);
1805
0
    case 6:
1806
0
        return r->user;
1807
0
    case 7:
1808
0
        return r->server->server_admin;
1809
0
    case 8:
1810
0
        return ap_get_server_name_for_url(r);
1811
0
    case 9:
1812
0
        return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
1813
0
    case 10:
1814
0
        return r->protocol;
1815
0
    case 11:
1816
0
        return r->filename;
1817
0
    case 12:
1818
0
        return r->path_info;
1819
0
    case 13:
1820
0
        return r->args;
1821
0
    case 14:
1822
0
        return (r->main != NULL ? "true" : "false");
1823
0
    case 15:
1824
0
        return ap_document_root(r);
1825
0
    case 16:
1826
0
        return r->ap_auth_type;
1827
0
    case 17:
1828
0
        return r->the_request;
1829
0
    case 18:
1830
0
        return r->content_type;
1831
0
    case 19:
1832
0
        return r->handler;
1833
0
    case 20:
1834
0
        return r->log_id;
1835
0
    case 21:
1836
0
        {
1837
0
            char *result = "";
1838
0
            if (r->finfo.valid & APR_FINFO_USER)
1839
0
                apr_uid_name_get(&result, r->finfo.user, ctx->p);
1840
0
            return result;
1841
0
        }
1842
0
    case 22:
1843
0
        {
1844
0
            char *result = "";
1845
0
            if (r->finfo.valid & APR_FINFO_USER)
1846
0
                apr_gid_name_get(&result, r->finfo.group, ctx->p);
1847
0
            return result;
1848
0
        }
1849
0
    case 23:
1850
0
        {
1851
0
            const char *uri = apr_table_get(r->subprocess_env, "DOCUMENT_URI");
1852
0
            return uri ? uri : r->uri;
1853
0
        }
1854
0
    case 24:
1855
0
        {
1856
0
            apr_time_exp_t tm;
1857
0
            apr_time_exp_lt(&tm, r->mtime);
1858
0
            return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1859
0
                                (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1860
0
                                tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1861
0
                                tm.tm_sec);
1862
0
        }
1863
0
    case 25:
1864
0
        return ap_context_prefix(r);
1865
0
    case 26:
1866
0
        return ap_context_document_root(r);
1867
0
    case 27:
1868
0
        return r->status ? apr_psprintf(ctx->p, "%d", r->status) : "";
1869
0
    case 28:
1870
0
        return r->useragent_ip;
1871
0
    case 29:
1872
0
        switch (r->proto_num) {
1873
0
        case 1001:  return "1001";   /* 1.1 */
1874
0
        case 1000:  return "1000";   /* 1.0 */
1875
0
        case 9:     return "9";      /* 0.9 */
1876
0
        }
1877
0
        return apr_psprintf(ctx->p, "%d", r->proto_num);
1878
0
    case 30:
1879
0
        switch (HTTP_VERSION_MAJOR(r->proto_num)) {
1880
0
        case 0:     return "0";
1881
0
        case 1:     return "1";
1882
0
        }
1883
0
        return apr_psprintf(ctx->p, "%d", HTTP_VERSION_MAJOR(r->proto_num));
1884
0
    case 31:
1885
0
        switch (HTTP_VERSION_MINOR(r->proto_num)) {
1886
0
        case 0:     return "0";
1887
0
        case 1:     return "1";
1888
0
        case 9:     return "9";
1889
0
        }
1890
0
        return apr_psprintf(ctx->p, "%d", HTTP_VERSION_MINOR(r->proto_num));
1891
0
    case 32:
1892
0
        return apr_psprintf(ctx->p, "%u", ctx->c->client_addr->port);
1893
0
    default:
1894
0
        ap_assert(0);
1895
0
        return NULL;
1896
0
    }
1897
0
}
1898
1899
static const char *const req_header_var_names[] = {
1900
    "HTTP_USER_AGENT",       /* 0 */
1901
    "HTTP_PROXY_CONNECTION", /* 1 */
1902
    "HTTP_REFERER",          /* 2 */
1903
    "HTTP_COOKIE",           /* 3 */
1904
    "HTTP_FORWARDED",        /* 4 */
1905
    "HTTP_HOST",             /* 5 */
1906
    "HTTP_ACCEPT",           /* 6 */
1907
    NULL
1908
};
1909
1910
static const char *const req_header_header_names[] = {
1911
    "User-Agent",
1912
    "Proxy-Connection",
1913
    "Referer",
1914
    "Cookie",
1915
    "Forwarded",
1916
    "Host",
1917
    "Accept"
1918
};
1919
1920
static const char *req_header_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1921
0
{
1922
0
    const char **const varname = (const char **)data;
1923
0
    int index = (varname - req_header_var_names);
1924
0
    const char *name;
1925
1926
0
    AP_DEBUG_ASSERT(index < 7);
1927
0
    if (!ctx->r)
1928
0
        return "";
1929
1930
0
    name = req_header_header_names[index];
1931
    /* Skip the 'Vary: Host' header combination
1932
     * as indicated in rfc7231 section-7.1.4
1933
     */
1934
0
    if (strcasecmp(name, "Host")){
1935
0
        add_vary(ctx, name);
1936
0
    }
1937
0
    return apr_table_get(ctx->r->headers_in, name);
1938
0
}
1939
1940
static const char *const misc_var_names[] = {
1941
    "TIME_YEAR",        /* 0 */
1942
    "TIME_MON",         /* 1 */
1943
    "TIME_DAY",         /* 2 */
1944
    "TIME_HOUR",        /* 3 */
1945
    "TIME_MIN",         /* 4 */
1946
    "TIME_SEC",         /* 5 */
1947
    "TIME_WDAY",        /* 6 */
1948
    "TIME",             /* 7 */
1949
    "SERVER_SOFTWARE",  /* 8 */
1950
    "API_VERSION",      /* 9 */
1951
    NULL
1952
};
1953
1954
static const char *misc_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
1955
0
{
1956
0
    apr_time_exp_t tm;
1957
0
    int index = ((const char **)data - misc_var_names);
1958
0
    apr_time_exp_lt(&tm, apr_time_now());
1959
1960
0
    switch (index) {
1961
0
    case 0:
1962
0
        return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
1963
0
                            tm.tm_year % 100);
1964
0
    case 1:
1965
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
1966
0
    case 2:
1967
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
1968
0
    case 3:
1969
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
1970
0
    case 4:
1971
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_min);
1972
0
    case 5:
1973
0
        return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
1974
0
    case 6:
1975
0
        return apr_psprintf(ctx->p, "%d", tm.tm_wday);
1976
0
    case 7:
1977
0
        return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
1978
0
                            (tm.tm_year / 100) + 19, (tm.tm_year % 100),
1979
0
                            tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
1980
0
                            tm.tm_sec);
1981
0
    case 8:
1982
0
        return ap_get_server_banner();
1983
0
    case 9:
1984
0
        return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER_MAJOR);
1985
0
    default:
1986
0
        ap_assert(0);
1987
0
    }
1988
1989
0
    return NULL;
1990
0
}
1991
1992
static int subnet_parse_arg(ap_expr_lookup_parms *parms)
1993
0
{
1994
0
    apr_ipsubnet_t *subnet;
1995
0
    const char *addr = parms->arg;
1996
0
    const char *mask;
1997
0
    apr_status_t ret;
1998
1999
0
    if (!parms->arg) {
2000
0
        *parms->err = apr_psprintf(parms->ptemp,
2001
0
                                   "-%s requires subnet/netmask as constant argument",
2002
0
                                   parms->name);
2003
0
        return !OK;
2004
0
    }
2005
2006
0
    mask = ap_strchr_c(addr, '/');
2007
0
    if (mask) {
2008
0
        addr = apr_pstrmemdup(parms->ptemp, addr, mask - addr);
2009
0
        mask++;
2010
0
    }
2011
2012
0
    ret = apr_ipsubnet_create(&subnet, addr, mask, parms->pool);
2013
0
    if (ret != APR_SUCCESS) {
2014
0
        *parms->err = "parsing of subnet/netmask failed";
2015
0
        return !OK;
2016
0
    }
2017
2018
0
    *parms->data = subnet;
2019
0
    return OK;
2020
0
}
2021
2022
static int op_ipmatch(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1,
2023
                const char *arg2)
2024
0
{
2025
0
    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
2026
0
    apr_sockaddr_t *saddr;
2027
2028
0
    AP_DEBUG_ASSERT(subnet != NULL);
2029
2030
    /* maybe log an error if this goes wrong? */
2031
0
    if (apr_sockaddr_info_get(&saddr, arg1, APR_UNSPEC, 0, 0, ctx->p) != APR_SUCCESS)
2032
0
        return FALSE;
2033
2034
0
    return apr_ipsubnet_test(subnet, saddr);
2035
0
}
2036
2037
static int op_R(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg1)
2038
0
{
2039
0
    apr_ipsubnet_t *subnet = (apr_ipsubnet_t *)data;
2040
2041
0
    AP_DEBUG_ASSERT(subnet != NULL);
2042
2043
0
    if (!ctx->r)
2044
0
        return FALSE;
2045
2046
0
    return apr_ipsubnet_test(subnet, ctx->r->useragent_addr);
2047
0
}
2048
2049
static int op_T(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
2050
0
{
2051
0
    switch (arg[0]) {
2052
0
    case '\0':
2053
0
        return FALSE;
2054
0
    case 'o':
2055
0
    case 'O':
2056
0
        return strcasecmp(arg, "off") == 0 ? FALSE : TRUE;
2057
0
    case 'n':
2058
0
    case 'N':
2059
0
        return strcasecmp(arg, "no") == 0 ? FALSE : TRUE;
2060
0
    case 'f':
2061
0
    case 'F':
2062
0
        return strcasecmp(arg, "false") == 0 ? FALSE : TRUE;
2063
0
    case '0':
2064
0
        return arg[1] == '\0' ? FALSE : TRUE;
2065
0
    default:
2066
0
        return TRUE;
2067
0
    }
2068
0
}
2069
2070
static int op_fnmatch(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, APR_FNM_PATHNAME));
2074
0
}
2075
2076
static int op_strmatch(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, 0));
2080
0
}
2081
2082
static int op_strcmatch(ap_expr_eval_ctx_t *ctx, const void *data,
2083
                        const char *arg1, const char *arg2)
2084
0
{
2085
0
    return (APR_SUCCESS == apr_fnmatch(arg2, arg1, APR_FNM_CASE_BLIND));
2086
0
}
2087
2088
0
#define RESTRICTED_FILE_TEST 0x01
2089
0
#define RESTRICTED_FILE_FUNC 0x02
2090
0
#define RESTRICTED_ALL      (RESTRICTED_FILE_TEST | RESTRICTED_FILE_FUNC)
2091
2092
struct expr_provider_single {
2093
    const void *func;
2094
    const char *name;
2095
    ap_expr_lookup_fn_t *arg_parsing_func;
2096
    unsigned int restricted;
2097
};
2098
2099
struct expr_provider_multi {
2100
    const void *func;
2101
    const char *const *names;
2102
};
2103
2104
static const struct expr_provider_multi var_providers[] = {
2105
    { misc_var_fn, misc_var_names },
2106
    { req_header_var_fn, req_header_var_names },
2107
    { request_var_fn, request_var_names },
2108
    { conn_var_fn, conn_var_names },
2109
    { NULL, NULL }
2110
};
2111
2112
static const struct expr_provider_single string_func_providers[] = {
2113
    { osenv_func,           "osenv",          NULL, 0 },
2114
    { env_func,             "env",            NULL, 0 },
2115
    { req_table_func,       "resp",           NULL, 0 },
2116
    { req_table_func,       "req",            NULL, 0 },
2117
    /* 'http' as alias for 'req' for compatibility with ssl_expr */
2118
    { req_table_func,       "http",           NULL, 0 },
2119
    { req_table_func,       "note",           NULL, 0 },
2120
    { req_table_func,       "reqenv",         NULL, 0 },
2121
    { req_table_func,       "req_novary",     NULL, 0 },
2122
    { tolower_func,         "tolower",        NULL, 0 },
2123
    { toupper_func,         "toupper",        NULL, 0 },
2124
    { escape_func,          "escape",         NULL, 0 },
2125
    { unescape_func,        "unescape",       NULL, 0 },
2126
    { file_func,            "file",           NULL, RESTRICTED_FILE_FUNC },
2127
    { filesize_func,        "filesize",       NULL, RESTRICTED_FILE_FUNC },
2128
    { filemod_func,         "filemod",        NULL, RESTRICTED_FILE_FUNC },
2129
    { base64_func,          "base64",         NULL, 0 },
2130
    { unbase64_func,        "unbase64",       NULL, 0 },
2131
    { sha1_func,            "sha1",           NULL, 0 },
2132
    { md5_func,             "md5",            NULL, 0 },
2133
#if APR_VERSION_AT_LEAST(1,6,0)
2134
    { ldap_func,            "ldap",           NULL, 0 },
2135
#endif
2136
    { replace_func,         "replace",        replace_func_parse_arg, 0 },
2137
    { escapehtml_func,      "escapehtml",     NULL, 0 },
2138
    { NULL, NULL, NULL}
2139
};
2140
2141
static const struct expr_provider_single unary_op_providers[] = {
2142
    { op_nz,        "n", NULL,             0 },
2143
    { op_nz,        "z", NULL,             0 },
2144
    { op_R,         "R", subnet_parse_arg, 0 },
2145
    { op_T,         "T", NULL,             0 },
2146
    { op_file_min,  "d", NULL,             RESTRICTED_FILE_TEST },
2147
    { op_file_min,  "e", NULL,             RESTRICTED_FILE_TEST },
2148
    { op_file_min,  "f", NULL,             RESTRICTED_FILE_TEST },
2149
    { op_file_min,  "s", NULL,             RESTRICTED_FILE_TEST },
2150
    { op_file_link, "L", NULL,             RESTRICTED_FILE_TEST },
2151
    { op_file_link, "h", NULL,             RESTRICTED_FILE_TEST },
2152
    { op_file_xbit, "x", NULL,             RESTRICTED_FILE_TEST },
2153
    { op_file_subr, "F", NULL,             0 },
2154
    { op_url_subr,  "U", NULL,             0 },
2155
    { op_url_subr,  "A", NULL,             0 },
2156
    { NULL, NULL, NULL }
2157
};
2158
2159
static const struct expr_provider_single binary_op_providers[] = {
2160
    { op_ipmatch,   "ipmatch",      subnet_parse_arg, 0 },
2161
    { op_fnmatch,   "fnmatch",      NULL,             0 },
2162
    { op_strmatch,  "strmatch",     NULL,             0 },
2163
    { op_strcmatch, "strcmatch",    NULL,             0 },
2164
    { NULL, NULL, NULL }
2165
};
2166
2167
static int core_expr_lookup(ap_expr_lookup_parms *parms)
2168
0
{
2169
0
    switch (parms->type) {
2170
0
    case AP_EXPR_FUNC_VAR: {
2171
0
            const struct expr_provider_multi *prov = var_providers;
2172
0
            while (prov->func) {
2173
0
                const char *const *name = prov->names;
2174
0
                while (*name) {
2175
0
                    if (ap_cstr_casecmp(*name, parms->name) == 0) {
2176
0
                        *parms->func = prov->func;
2177
0
                        *parms->data = name;
2178
0
                        return OK;
2179
0
                    }
2180
0
                    name++;
2181
0
                }
2182
0
                prov++;
2183
0
            }
2184
0
        }
2185
0
        break;
2186
0
    case AP_EXPR_FUNC_STRING:
2187
0
    case AP_EXPR_FUNC_OP_UNARY:
2188
0
    case AP_EXPR_FUNC_OP_BINARY: {
2189
0
            const struct expr_provider_single *prov = NULL;
2190
0
            switch (parms->type) {
2191
0
            case AP_EXPR_FUNC_STRING:
2192
0
                prov = string_func_providers;
2193
0
                break;
2194
0
            case AP_EXPR_FUNC_OP_UNARY:
2195
0
                prov = unary_op_providers;
2196
0
                break;
2197
0
            case AP_EXPR_FUNC_OP_BINARY:
2198
0
                prov = binary_op_providers;
2199
0
                break;
2200
0
            default:
2201
0
                ap_assert(0);
2202
0
            }
2203
0
            while (prov && prov->func) {
2204
0
                int match;
2205
0
                if (parms->type == AP_EXPR_FUNC_OP_UNARY)
2206
0
                    match = !strcmp(prov->name, parms->name);
2207
0
                else
2208
0
                    match = !ap_cstr_casecmp(prov->name, parms->name);
2209
0
                if (match) {
2210
0
                    if (((parms->flags & AP_EXPR_FLAG_RESTRICTED)
2211
0
                         && (prov->restricted & RESTRICTED_ALL))
2212
0
                        || ((parms->flags & AP_EXPR_FLAG_RESTRICTED_FILE_FUNC)
2213
0
                            && (prov->restricted & RESTRICTED_FILE_FUNC))) {
2214
0
                        *parms->err =
2215
0
                            apr_psprintf(parms->ptemp,
2216
0
                                         "%s%s not available in restricted context",
2217
0
                                         (parms->type == AP_EXPR_FUNC_STRING) ? "" : "-",
2218
0
                                         prov->name);
2219
0
                        return !OK;
2220
0
                    }
2221
0
                    *parms->func = prov->func;
2222
0
                    if (prov->arg_parsing_func) {
2223
0
                        return prov->arg_parsing_func(parms);
2224
0
                    }
2225
0
                    else {
2226
0
                        *parms->data = prov->name;
2227
0
                        return OK;
2228
0
                    }
2229
0
                }
2230
0
                prov++;
2231
0
            }
2232
0
        }
2233
0
        break;
2234
0
    default:
2235
0
        break;
2236
0
    }
2237
0
    return DECLINED;
2238
0
}
2239
2240
static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
2241
0
{
2242
0
    const char *type;
2243
0
    const char *prefix = "";
2244
2245
0
    switch (parms->type) {
2246
0
    case AP_EXPR_FUNC_VAR:
2247
0
        type = "Variable";
2248
0
        break;
2249
0
    case AP_EXPR_FUNC_STRING:
2250
0
        type = "Function";
2251
0
        break;
2252
0
    case AP_EXPR_FUNC_LIST:
2253
0
        type = "List-returning function";
2254
0
        break;
2255
0
    case AP_EXPR_FUNC_OP_UNARY:
2256
0
        type = "Unary operator";
2257
0
        break;
2258
0
    case AP_EXPR_FUNC_OP_BINARY:
2259
0
        type = "Binary operator";
2260
0
        break;
2261
0
    default:
2262
0
        *parms->err = "Invalid expression type in expr_lookup";
2263
0
        return !OK;
2264
0
    }
2265
0
    if (   parms->type == AP_EXPR_FUNC_OP_UNARY
2266
0
        || parms->type == AP_EXPR_FUNC_OP_BINARY) {
2267
0
        prefix = "-";
2268
0
    }
2269
0
    *parms->err = apr_psprintf(parms->ptemp, "%s '%s%s' does not exist", type,
2270
0
                               prefix, parms->name);
2271
0
    return !OK;
2272
0
}
2273
2274
static int ap_expr_post_config(apr_pool_t *pconf, apr_pool_t *plog,
2275
                               apr_pool_t *ptemp, server_rec *s)
2276
0
{
2277
0
    is_http2 = APR_RETRIEVE_OPTIONAL_FN(http2_is_h2);
2278
0
    return OK;
2279
0
}
2280
2281
void ap_expr_init(apr_pool_t *p)
2282
0
{
2283
0
    ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
2284
0
    ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
2285
0
    ap_hook_post_config(ap_expr_post_config, NULL, NULL, APR_HOOK_MIDDLE);
2286
0
}
2287