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