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