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