9 #include "configfile.h"
14 #include <arpa/inet.h>
18 * like all glue code this file contains functions which
19 * are the external interface of lighttpd. The functions
20 * are used by the server itself and the plugins.
22 * The main-goal is to have a small library in the end
23 * which is linked against both and which will define
24 * the interface itself in the end.
29 /* handle global options */
31 /* parse config array */
32 int config_insert_values_internal(server
*srv
, array
*ca
, const config_values_t cv
[], config_scope_type_t scope
) {
36 for (i
= 0; cv
[i
].key
; i
++) {
38 if (NULL
== (du
= array_get_element(ca
, cv
[i
].key
))) {
44 if ((T_CONFIG_SCOPE_SERVER
== cv
[i
].scope
)
45 && (T_CONFIG_SCOPE_SERVER
!= scope
)) {
46 /* server scope options should only be set in server scope, not in conditionals */
47 log_error_write(srv
, __FILE__
, __LINE__
, "ss",
48 "DEPRECATED: don't set server options in conditionals, variable:",
54 if (du
->type
== TYPE_ARRAY
) {
56 data_array
*da
= (data_array
*)du
;
58 for (j
= 0; j
< da
->value
->used
; j
++) {
59 data_unset
*ds
= da
->value
->data
[j
];
60 if (ds
->type
== TYPE_STRING
) {
61 array_insert_unique(cv
[i
].destination
, ds
->copy(ds
));
63 log_error_write(srv
, __FILE__
, __LINE__
, "sssbsd",
64 "the value of an array can only be a string, variable:",
65 cv
[i
].key
, "[", ds
->key
, "], type:", ds
->type
);
71 log_error_write(srv
, __FILE__
, __LINE__
, "ss", cv
[i
].key
, "should have been a array of strings like ... = ( \"...\" )");
77 if (du
->type
== TYPE_STRING
) {
78 data_string
*ds
= (data_string
*)du
;
80 buffer_copy_buffer(cv
[i
].destination
, ds
->value
);
82 log_error_write(srv
, __FILE__
, __LINE__
, "ssss", cv
[i
].key
, "should have been a string like ... = \"...\"");
90 data_integer
*di
= (data_integer
*)du
;
92 *((unsigned short *)(cv
[i
].destination
)) = di
->value
;
96 data_string
*ds
= (data_string
*)du
;
98 /* If the value came from an environment variable, then it is a
99 * data_string, although it may contain a number in ASCII
100 * decimal format. We try to interpret the string as a decimal
101 * short before giving up, in order to support setting numeric
102 * values with environment variables (eg, port number).
104 if (ds
->value
->ptr
&& *ds
->value
->ptr
) {
106 long l
= strtol(ds
->value
->ptr
, &e
, 10);
107 if (e
!= ds
->value
->ptr
&& !*e
&& l
>=0 && l
<= 65535) {
108 *((unsigned short *)(cv
[i
].destination
)) = l
;
113 log_error_write(srv
, __FILE__
, __LINE__
, "ssb", "got a string but expected a short:", cv
[i
].key
, ds
->value
);
118 log_error_write(srv
, __FILE__
, __LINE__
, "ssds", "unexpected type for key:", cv
[i
].key
, du
->type
, "expected a short integer, range 0 ... 65535");
125 data_integer
*di
= (data_integer
*)du
;
127 *((unsigned int *)(cv
[i
].destination
)) = di
->value
;
131 data_string
*ds
= (data_string
*)du
;
133 if (ds
->value
->ptr
&& *ds
->value
->ptr
) {
135 long l
= strtol(ds
->value
->ptr
, &e
, 10);
136 if (e
!= ds
->value
->ptr
&& !*e
&& l
>= 0) {
137 *((unsigned int *)(cv
[i
].destination
)) = l
;
142 log_error_write(srv
, __FILE__
, __LINE__
, "ssb", "got a string but expected an integer:", cv
[i
].key
, ds
->value
);
147 log_error_write(srv
, __FILE__
, __LINE__
, "ssds", "unexpected type for key:", cv
[i
].key
, du
->type
, "expected an integer, range 0 ... 4294967295");
151 case T_CONFIG_BOOLEAN
:
152 if (du
->type
== TYPE_STRING
) {
153 data_string
*ds
= (data_string
*)du
;
155 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("enable"))) {
156 *((unsigned short *)(cv
[i
].destination
)) = 1;
157 } else if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("disable"))) {
158 *((unsigned short *)(cv
[i
].destination
)) = 0;
160 log_error_write(srv
, __FILE__
, __LINE__
, "ssbs", "ERROR: unexpected value for key:", cv
[i
].key
, ds
->value
, "(enable|disable)");
165 log_error_write(srv
, __FILE__
, __LINE__
, "ssss", "ERROR: unexpected type for key:", cv
[i
].key
, "(string)", "\"(enable|disable)\"");
173 case T_CONFIG_UNSUPPORTED
:
174 log_error_write(srv
, __FILE__
, __LINE__
, "ssss", "ERROR: found unsupported key:", cv
[i
].key
, "-", (char *)(cv
[i
].destination
));
176 srv
->config_unsupported
= 1;
179 case T_CONFIG_DEPRECATED
:
180 log_error_write(srv
, __FILE__
, __LINE__
, "ssss", "ERROR: found deprecated key:", cv
[i
].key
, "-", (char *)(cv
[i
].destination
));
182 srv
->config_deprecated
= 1;
191 int config_insert_values_global(server
*srv
, array
*ca
, const config_values_t cv
[], config_scope_type_t scope
) {
195 for (i
= 0; cv
[i
].key
; i
++) {
196 data_string
*touched
;
198 if (NULL
== (du
= array_get_element(ca
, cv
[i
].key
))) {
205 touched
= data_string_init();
207 buffer_copy_string_len(touched
->value
, CONST_STR_LEN(""));
208 buffer_copy_buffer(touched
->key
, du
->key
);
210 array_insert_unique(srv
->config_touched
, (data_unset
*)touched
);
213 return config_insert_values_internal(srv
, ca
, cv
, scope
);
216 static unsigned short sock_addr_get_port(sock_addr
*addr
) {
218 return ntohs(addr
->plain
.sa_family
? addr
->ipv6
.sin6_port
: addr
->ipv4
.sin_port
);
220 return ntohs(addr
->ipv4
.sin_port
);
224 static const char* cond_result_to_string(cond_result_t cond_result
) {
225 switch (cond_result
) {
226 case COND_RESULT_UNSET
: return "unset";
227 case COND_RESULT_SKIP
: return "skipped";
228 case COND_RESULT_FALSE
: return "false";
229 case COND_RESULT_TRUE
: return "true";
230 default: return "invalid cond_result_t";
234 static int config_addrstr_eq_remote_ip_mask(server
*srv
, const char *addrstr
, int nm_bits
, sock_addr
*rmt
) {
235 /* special-case 0 == nm_bits to mean "all bits of the address" in addrstr */
237 #ifdef HAVE_INET_PTON
238 if (1 == inet_pton(AF_INET
, addrstr
, &val
.ipv4
.sin_addr
))
240 if (INADDR_NONE
!= (val
.ipv4
.sin_addr
= inet_addr(addrstr
)))
246 log_error_write(srv
, __FILE__
, __LINE__
, "sd", "ERROR: ipv4 netmask too large:", nm_bits
);
249 nm
= htonl(~((1u << (32 - (0 != nm_bits
? nm_bits
: 32))) - 1));
251 if (rmt
->plain
.sa_family
== AF_INET
) {
252 return ((val
.ipv4
.sin_addr
.s_addr
& nm
) == (rmt
->ipv4
.sin_addr
.s_addr
& nm
));
254 } else if (rmt
->plain
.sa_family
== AF_INET6
255 && IN6_IS_ADDR_V4MAPPED(&rmt
->ipv6
.sin6_addr
)) {
257 in_addr_t x
= rmt
->ipv6
.sin6_addr
.s6_addr32
[3];
260 memcpy(&x
, rmt
->ipv6
.sin6_addr
.s6_addr
+12, sizeof(in_addr_t
));
262 return ((val
.ipv4
.sin_addr
.s_addr
& nm
) == (x
& nm
));
267 #if defined(HAVE_INET_PTON) && defined(HAVE_IPV6)
268 } else if (1 == inet_pton(AF_INET6
, addrstr
, &val
.ipv6
.sin6_addr
)) {
270 log_error_write(srv
, __FILE__
, __LINE__
, "sd", "ERROR: ipv6 netmask too large:", nm_bits
);
273 if (rmt
->plain
.sa_family
== AF_INET6
) {
274 uint8_t *a
= (uint8_t *)&val
.ipv6
.sin6_addr
.s6_addr
[0];
275 uint8_t *b
= (uint8_t *)&rmt
->ipv6
.sin6_addr
.s6_addr
[0];
278 match
= (nm_bits
>= 8)
280 : (*a
>> (8 - nm_bits
)) == (*b
>> (8 - nm_bits
));
281 } while (match
&& (nm_bits
-= 8) > 0);
283 } else if (rmt
->plain
.sa_family
== AF_INET
284 && IN6_IS_ADDR_V4MAPPED(&val
.ipv6
.sin6_addr
)) {
286 nm_bits
< 128 ? htonl(~(~0u >> (nm_bits
> 96 ? nm_bits
- 96 : 0))) : ~0u;
288 in_addr_t x
= val
.ipv6
.sin6_addr
.s6_addr32
[3];
291 memcpy(&x
, val
.ipv6
.sin6_addr
.s6_addr
+12, sizeof(in_addr_t
));
293 return ((x
& nm
) == (rmt
->ipv4
.sin_addr
.s_addr
& nm
));
299 log_error_write(srv
, __FILE__
, __LINE__
, "ss", "ERROR: ip addr is invalid:", addrstr
);
304 static int config_addrbuf_eq_remote_ip_mask(server
*srv
, buffer
*string
, char *nm_slash
, sock_addr
*rmt
) {
306 int nm_bits
= strtol(nm_slash
+ 1, &err
, 10);
307 size_t addrstrlen
= (size_t)(nm_slash
- string
->ptr
);
308 char addrstr
[64]; /*(larger than INET_ADDRSTRLEN and INET6_ADDRSTRLEN)*/
311 log_error_write(srv
, __FILE__
, __LINE__
, "sbs", "ERROR: non-digit found in netmask:", string
, err
);
316 if (*(nm_slash
+1) == '\0') {
317 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "ERROR: no number after / ", string
);
319 log_error_write(srv
, __FILE__
, __LINE__
, "sbs", "ERROR: invalid netmask <= 0:", string
, err
);
324 if (addrstrlen
>= sizeof(addrstr
)) {
325 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "ERROR: address string too long:", string
);
329 memcpy(addrstr
, string
->ptr
, addrstrlen
);
330 addrstr
[addrstrlen
] = '\0';
332 return config_addrstr_eq_remote_ip_mask(srv
, addrstr
, nm_bits
, rmt
);
335 static cond_result_t
config_check_cond_cached(server
*srv
, connection
*con
, data_config
*dc
);
337 static cond_result_t
config_check_cond_nocache(server
*srv
, connection
*con
, data_config
*dc
) {
339 server_socket
*srv_sock
= con
->srv_socket
;
340 cond_cache_t
*cache
= &con
->cond_cache
[dc
->context_ndx
];
342 /* check parent first */
343 if (dc
->parent
&& dc
->parent
->context_ndx
) {
345 * a nested conditional
347 * if the parent is not decided yet or false, we can't be true either
349 if (con
->conf
.log_condition_handling
) {
350 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "go parent", dc
->parent
->key
);
353 switch (config_check_cond_cached(srv
, con
, dc
->parent
)) {
354 case COND_RESULT_UNSET
:
356 return COND_RESULT_UNSET
;
357 case COND_RESULT_SKIP
:
358 case COND_RESULT_FALSE
:
359 /* failed precondition */
360 return COND_RESULT_SKIP
;
361 case COND_RESULT_TRUE
:
369 * a else branch; can only be executed if the previous branch
370 * was evaluated as "false" (not unset/skipped/true)
372 if (con
->conf
.log_condition_handling
) {
373 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "go prev", dc
->prev
->key
);
376 /* make sure prev is checked first */
377 switch (config_check_cond_cached(srv
, con
, dc
->prev
)) {
378 case COND_RESULT_UNSET
:
380 return COND_RESULT_UNSET
;
381 case COND_RESULT_SKIP
:
382 case COND_RESULT_TRUE
:
383 /* failed precondition */
384 return COND_RESULT_SKIP
;
385 case COND_RESULT_FALSE
:
391 if (!con
->conditional_is_valid
[dc
->comp
]) {
392 if (con
->conf
.log_condition_handling
) {
393 log_error_write(srv
, __FILE__
, __LINE__
, "dss",
396 "not available yet");
399 return COND_RESULT_UNSET
;
402 /* if we had a real result before and weren't cleared just return it */
403 switch (cache
->local_result
) {
404 case COND_RESULT_TRUE
:
405 case COND_RESULT_FALSE
:
406 return cache
->local_result
;
414 case COMP_HTTP_HOST
: {
415 char *ck_colon
= NULL
, *val_colon
= NULL
;
417 if (!buffer_string_is_empty(con
->uri
.authority
)) {
420 * append server-port to the HTTP_POST if necessary
423 l
= con
->uri
.authority
;
428 ck_colon
= strchr(dc
->string
->ptr
, ':');
429 val_colon
= strchr(l
->ptr
, ':');
431 if (NULL
!= ck_colon
&& NULL
== val_colon
) {
432 /* condition "host:port" but client send "host" */
433 buffer_copy_buffer(srv
->cond_check_buf
, l
);
434 buffer_append_string_len(srv
->cond_check_buf
, CONST_STR_LEN(":"));
435 buffer_append_int(srv
->cond_check_buf
, sock_addr_get_port(&(srv_sock
->addr
)));
436 l
= srv
->cond_check_buf
;
437 } else if (NULL
!= val_colon
&& NULL
== ck_colon
) {
438 /* condition "host" but client send "host:port" */
439 buffer_copy_string_len(srv
->cond_check_buf
, l
->ptr
, val_colon
- l
->ptr
);
440 l
= srv
->cond_check_buf
;
446 #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
447 } else if (!buffer_string_is_empty(con
->tlsext_server_name
)) {
448 l
= con
->tlsext_server_name
;
451 l
= srv
->empty_string
;
455 case COMP_HTTP_REMOTE_IP
: {
457 /* handle remoteip limitations
459 * "10.0.0.1" is provided for all comparisions
461 * only for == and != we support
466 if ((dc
->cond
== CONFIG_COND_EQ
||
467 dc
->cond
== CONFIG_COND_NE
) &&
468 (NULL
!= (nm_slash
= strchr(dc
->string
->ptr
, '/')))) {
469 switch (config_addrbuf_eq_remote_ip_mask(srv
, dc
->string
, nm_slash
, &con
->dst_addr
)) {
470 case 1: return (dc
->cond
== CONFIG_COND_EQ
) ? COND_RESULT_TRUE
: COND_RESULT_FALSE
;
471 case 0: return (dc
->cond
== CONFIG_COND_EQ
) ? COND_RESULT_FALSE
: COND_RESULT_TRUE
;
472 case -1: return COND_RESULT_FALSE
; /*(error parsing configfile entry)*/
475 l
= con
->dst_addr_buf
;
478 case COMP_HTTP_SCHEME
:
486 case COMP_HTTP_QUERY_STRING
:
490 case COMP_SERVER_SOCKET
:
491 l
= srv_sock
->srv_token
;
494 case COMP_HTTP_REFERER
: {
497 if (NULL
!= (ds
= (data_string
*)array_get_element(con
->request
.headers
, "Referer"))) {
500 l
= srv
->empty_string
;
504 case COMP_HTTP_COOKIE
: {
506 if (NULL
!= (ds
= (data_string
*)array_get_element(con
->request
.headers
, "Cookie"))) {
509 l
= srv
->empty_string
;
513 case COMP_HTTP_USER_AGENT
: {
515 if (NULL
!= (ds
= (data_string
*)array_get_element(con
->request
.headers
, "User-Agent"))) {
518 l
= srv
->empty_string
;
522 case COMP_HTTP_REQUEST_METHOD
: {
523 const char *method
= get_http_method_name(con
->request
.http_method
);
525 /* we only have the request method as const char but we need a buffer for comparing */
527 buffer_copy_string(srv
->tmp_buf
, method
);
533 case COMP_HTTP_LANGUAGE
: {
535 if (NULL
!= (ds
= (data_string
*)array_get_element(con
->request
.headers
, "Accept-Language"))) {
538 l
= srv
->empty_string
;
543 return COND_RESULT_FALSE
;
547 if (con
->conf
.log_condition_handling
) {
548 log_error_write(srv
, __FILE__
, __LINE__
, "bsbs", dc
->comp_key
,
549 "(", l
, ") compare to NULL");
551 return COND_RESULT_FALSE
;
554 if (con
->conf
.log_condition_handling
) {
555 log_error_write(srv
, __FILE__
, __LINE__
, "bsbsb", dc
->comp_key
,
556 "(", l
, ") compare to ", dc
->string
);
561 if (buffer_is_equal(l
, dc
->string
)) {
562 return (dc
->cond
== CONFIG_COND_EQ
) ? COND_RESULT_TRUE
: COND_RESULT_FALSE
;
564 return (dc
->cond
== CONFIG_COND_EQ
) ? COND_RESULT_FALSE
: COND_RESULT_TRUE
;
568 case CONFIG_COND_NOMATCH
:
569 case CONFIG_COND_MATCH
: {
573 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
575 n
= pcre_exec(dc
->regex
, dc
->regex_study
, CONST_BUF_LEN(l
), 0, 0,
576 cache
->matches
, elementsof(cache
->matches
));
578 cache
->patterncount
= n
;
580 cache
->comp_value
= l
;
581 return (dc
->cond
== CONFIG_COND_MATCH
) ? COND_RESULT_TRUE
: COND_RESULT_FALSE
;
583 /* cache is already cleared */
584 return (dc
->cond
== CONFIG_COND_MATCH
) ? COND_RESULT_FALSE
: COND_RESULT_TRUE
;
594 return COND_RESULT_FALSE
;
597 static cond_result_t
config_check_cond_cached(server
*srv
, connection
*con
, data_config
*dc
) {
598 cond_cache_t
*caches
= con
->cond_cache
;
600 if (COND_RESULT_UNSET
== caches
[dc
->context_ndx
].result
) {
601 caches
[dc
->context_ndx
].result
= config_check_cond_nocache(srv
, con
, dc
);
602 switch (caches
[dc
->context_ndx
].result
) {
603 case COND_RESULT_FALSE
:
604 case COND_RESULT_TRUE
:
605 /* remember result of local condition for a partial reset */
606 caches
[dc
->context_ndx
].local_result
= caches
[dc
->context_ndx
].result
;
612 if (con
->conf
.log_condition_handling
) {
613 log_error_write(srv
, __FILE__
, __LINE__
, "dss",
615 "(uncached) result:",
616 cond_result_to_string(caches
[dc
->context_ndx
].result
));
619 if (con
->conf
.log_condition_handling
) {
620 log_error_write(srv
, __FILE__
, __LINE__
, "dss",
623 cond_result_to_string(caches
[dc
->context_ndx
].result
));
626 return caches
[dc
->context_ndx
].result
;
629 /* if we reset the cache result for a node, we also need to clear all
630 * child nodes and else-branches*/
631 static void config_cond_clear_node(server
*srv
, connection
*con
, data_config
*dc
) {
632 /* if a node is "unset" all children are unset too */
633 if (con
->cond_cache
[dc
->context_ndx
].result
!= COND_RESULT_UNSET
) {
636 con
->cond_cache
[dc
->context_ndx
].patterncount
= 0;
637 con
->cond_cache
[dc
->context_ndx
].comp_value
= NULL
;
638 con
->cond_cache
[dc
->context_ndx
].result
= COND_RESULT_UNSET
;
640 for (i
= 0; i
< dc
->children
.used
; ++i
) {
641 data_config
*dc_child
= dc
->children
.data
[i
];
642 if (NULL
== dc_child
->prev
) {
643 /* only call for first node in if-else chain */
644 config_cond_clear_node(srv
, con
, dc_child
);
647 if (NULL
!= dc
->next
) config_cond_clear_node(srv
, con
, dc
->next
);
652 * reset the config-cache for a named item
654 * if the item is COND_LAST_ELEMENT we reset all items
656 void config_cond_cache_reset_item(server
*srv
, connection
*con
, comp_key_t item
) {
659 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
660 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
662 if (item
== dc
->comp
) {
663 /* clear local_result */
664 con
->cond_cache
[i
].local_result
= COND_RESULT_UNSET
;
665 /* clear result in subtree (including the node itself) */
666 config_cond_clear_node(srv
, con
, dc
);
672 * reset the config cache to its initial state at connection start
674 void config_cond_cache_reset(server
*srv
, connection
*con
) {
677 /* resetting all entries; no need to follow children as in config_cond_cache_reset_item */
678 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
679 con
->cond_cache
[i
].result
= COND_RESULT_UNSET
;
680 con
->cond_cache
[i
].local_result
= COND_RESULT_UNSET
;
681 con
->cond_cache
[i
].patterncount
= 0;
682 con
->cond_cache
[i
].comp_value
= NULL
;
685 for (i
= 0; i
< COMP_LAST_ELEMENT
; i
++) {
686 con
->conditional_is_valid
[i
] = 0;
690 int config_check_cond(server
*srv
, connection
*con
, data_config
*dc
) {
691 if (con
->conf
.log_condition_handling
) {
692 log_error_write(srv
, __FILE__
, __LINE__
, "s", "=== start of condition block ===");
694 return (config_check_cond_cached(srv
, con
, dc
) == COND_RESULT_TRUE
);
697 int config_append_cond_match_buffer(connection
*con
, data_config
*dc
, buffer
*buf
, int n
)
699 cond_cache_t
*cache
= &con
->cond_cache
[dc
->context_ndx
];
700 if (n
>= cache
->patterncount
) {
704 n
<<= 1; /* n *= 2 */
705 buffer_append_string_len(buf
,
706 cache
->comp_value
->ptr
+ cache
->matches
[n
],
707 cache
->matches
[n
+ 1] - cache
->matches
[n
]);