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