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 41APR_HOOK_STRUCT( 42 APR_HOOK_LINK(expr_lookup) 43) 44 45AP_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 50static 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); 53static const char *ap_expr_eval_re_backref(ap_expr_eval_ctx_t *ctx, 54 unsigned int n); 55static 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 61static 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 71static 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 83static 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 154static 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 163static 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 178static 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 191static 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 204static 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 */ 295static 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 318static 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 346AP_DECLARE_NONSTD(int) ap_expr_lookup_default(ap_expr_lookup_parms *parms) 347{ 348 return ap_run_expr_lookup(parms); 349} 350 351AP_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 400AP_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 420ap_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 430static 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 450ap_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 461ap_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 472ap_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 483ap_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 498ap_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 535static 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 678static 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 690static 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 708static 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 } 782out: 783 ctx->reclvl--; 784 return result; 785} 786 787AP_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 793AP_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 847AP_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 879AP_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 932AP_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 940static 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 954static 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 983static 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 997static const char *osenv_func(ap_expr_eval_ctx_t *ctx, const void *data, 998 const char *arg) 999{ 1000 return getenv(arg); 1001} 1002 1003static 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 1011static 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 1019static 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 1025static 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 1031static 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 1037static 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 1055static 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 1063static 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 1107static 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 1118static 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 1132static 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 1141static 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 1162static 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 1174static 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 1184static 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 1206static 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 1228APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); 1229static APR_OPTIONAL_FN_TYPE(ssl_is_https) *is_https = NULL; 1230 1231static 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 1239static 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 1275static 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 1308static 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 1398static 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 1409static const char *req_header_header_names[] = { 1410 "User-Agent", 1411 "Proxy-Connection", 1412 "Referer", 1413 "Cookie", 1414 "Forwarded", 1415 "Host", 1416 "Accept" 1417}; 1418 1419static 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 1434static 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 1448static 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 1486static 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 1516static 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 1531static 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 1543static 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 1564static 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 1570static 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 1576static 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 1582struct 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 1589struct expr_provider_multi { 1590 const void *func; 1591 const char **names; 1592}; 1593 1594static 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 1602static 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 1625static 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 1643static 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 1651static 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 1722static 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 1756static 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 1765void 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