[core] fix config merge of array lists
[lighttpd.git] / src / configfile-glue.c
blob1982f37cbc0908a19cc31e4d688d4ae96fdff5e4
1 #include "first.h"
3 #include "base.h"
4 #include "buffer.h"
5 #include "array.h"
6 #include "log.h"
7 #include "plugin.h"
9 #include "configfile.h"
11 #include <string.h>
12 #include <stdlib.h>
13 #ifndef _WIN32
14 #include <arpa/inet.h>
15 #endif
17 /**
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) {
33 size_t i;
34 data_unset *du;
36 for (i = 0; cv[i].key; i++) {
38 if (NULL == (du = array_get_element(ca, cv[i].key))) {
39 /* no found */
41 continue;
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:",
49 cv[i].key);
52 switch (cv[i].type) {
53 case T_CONFIG_ARRAY:
54 if (du->type == TYPE_ARRAY) {
55 size_t j;
56 data_array *da = (data_array *)du;
58 for (j = 0; j < da->value->used; j++) {
59 if (da->value->data[j]->type == TYPE_STRING) {
60 data_string *ds = data_string_init();
62 buffer_copy_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
63 if (!((data_string *)(da->value->data[j]))->is_index_key) {
64 /* the id's were generated automaticly, as we copy now we might have to renumber them
65 * this is used to prepend server.modules by mod_indexfile as it has to be loaded
66 * before mod_fastcgi and friends */
67 buffer_copy_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
70 array_insert_unique(cv[i].destination, (data_unset *)ds);
71 } else {
72 log_error_write(srv, __FILE__, __LINE__, "sssbsd",
73 "the value of an array can only be a string, variable:",
74 cv[i].key, "[", da->value->data[j]->key, "], type:", da->value->data[j]->type);
76 return -1;
79 } else {
80 log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
82 return -1;
84 break;
85 case T_CONFIG_STRING:
86 if (du->type == TYPE_STRING) {
87 data_string *ds = (data_string *)du;
89 buffer_copy_buffer(cv[i].destination, ds->value);
90 } else {
91 log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
93 return -1;
95 break;
96 case T_CONFIG_SHORT:
97 switch(du->type) {
98 case TYPE_INTEGER: {
99 data_integer *di = (data_integer *)du;
101 *((unsigned short *)(cv[i].destination)) = di->value;
102 break;
104 case TYPE_STRING: {
105 data_string *ds = (data_string *)du;
107 /* If the value came from an environment variable, then it is a
108 * data_string, although it may contain a number in ASCII
109 * decimal format. We try to interpret the string as a decimal
110 * short before giving up, in order to support setting numeric
111 * values with environment variables (eg, port number).
113 if (ds->value->ptr && *ds->value->ptr) {
114 char *e;
115 long l = strtol(ds->value->ptr, &e, 10);
116 if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
117 *((unsigned short *)(cv[i].destination)) = l;
118 break;
122 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
124 return -1;
126 default:
127 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
128 return -1;
130 break;
131 case T_CONFIG_INT:
132 switch(du->type) {
133 case TYPE_INTEGER: {
134 data_integer *di = (data_integer *)du;
136 *((unsigned int *)(cv[i].destination)) = di->value;
137 break;
139 case TYPE_STRING: {
140 data_string *ds = (data_string *)du;
142 if (ds->value->ptr && *ds->value->ptr) {
143 char *e;
144 long l = strtol(ds->value->ptr, &e, 10);
145 if (e != ds->value->ptr && !*e && l >= 0) {
146 *((unsigned int *)(cv[i].destination)) = l;
147 break;
151 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);
153 return -1;
155 default:
156 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
157 return -1;
159 break;
160 case T_CONFIG_BOOLEAN:
161 if (du->type == TYPE_STRING) {
162 data_string *ds = (data_string *)du;
164 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
165 *((unsigned short *)(cv[i].destination)) = 1;
166 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
167 *((unsigned short *)(cv[i].destination)) = 0;
168 } else {
169 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
171 return -1;
173 } else {
174 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
176 return -1;
178 break;
179 case T_CONFIG_LOCAL:
180 case T_CONFIG_UNSET:
181 break;
182 case T_CONFIG_UNSUPPORTED:
183 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
185 srv->config_unsupported = 1;
187 break;
188 case T_CONFIG_DEPRECATED:
189 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
191 srv->config_deprecated = 1;
193 break;
197 return 0;
200 int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
201 size_t i;
202 data_unset *du;
204 for (i = 0; cv[i].key; i++) {
205 data_string *touched;
207 if (NULL == (du = array_get_element(ca, cv[i].key))) {
208 /* no found */
210 continue;
213 /* touched */
214 touched = data_string_init();
216 buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
217 buffer_copy_buffer(touched->key, du->key);
219 array_insert_unique(srv->config_touched, (data_unset *)touched);
222 return config_insert_values_internal(srv, ca, cv, scope);
225 static unsigned short sock_addr_get_port(sock_addr *addr) {
226 #ifdef HAVE_IPV6
227 return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
228 #else
229 return ntohs(addr->ipv4.sin_port);
230 #endif
233 static const char* cond_result_to_string(cond_result_t cond_result) {
234 switch (cond_result) {
235 case COND_RESULT_UNSET: return "unset";
236 case COND_RESULT_SKIP: return "skipped";
237 case COND_RESULT_FALSE: return "false";
238 case COND_RESULT_TRUE: return "true";
239 default: return "invalid cond_result_t";
243 static int config_addrstr_eq_remote_ip_mask(server *srv, const char *addrstr, int nm_bits, sock_addr *rmt) {
244 /* special-case 0 == nm_bits to mean "all bits of the address" in addrstr */
245 sock_addr val;
246 #ifdef HAVE_INET_PTON
247 if (1 == inet_pton(AF_INET, addrstr, &val.ipv4.sin_addr))
248 #else
249 if (INADDR_NONE != (val.ipv4.sin_addr = inet_addr(addrstr)))
250 #endif
252 /* build netmask */
253 uint32_t nm;
254 if (nm_bits > 32) {
255 log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv4 netmask too large:", nm_bits);
256 return -1;
258 nm = htonl(~((1u << (32 - (0 != nm_bits ? nm_bits : 32))) - 1));
260 if (rmt->plain.sa_family == AF_INET) {
261 return ((val.ipv4.sin_addr.s_addr & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
262 #ifdef HAVE_IPV6
263 } else if (rmt->plain.sa_family == AF_INET6
264 && IN6_IS_ADDR_V4MAPPED(&rmt->ipv6.sin6_addr)) {
265 in_addr_t x = *(in_addr_t *)(rmt->ipv6.sin6_addr.s6_addr+12);
266 return ((val.ipv4.sin_addr.s_addr & nm) == (x & nm));
267 #endif
268 } else {
269 return 0;
271 #if defined(HAVE_INET_PTON) && defined(HAVE_IPV6)
272 } else if (1 == inet_pton(AF_INET6, addrstr, &val.ipv6.sin6_addr)) {
273 if (nm_bits > 128) {
274 log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv6 netmask too large:", nm_bits);
275 return -1;
277 if (rmt->plain.sa_family == AF_INET6) {
278 uint8_t *a = (uint8_t *)&val.ipv6.sin6_addr.s6_addr[0];
279 uint8_t *b = (uint8_t *)&rmt->ipv6.sin6_addr.s6_addr[0];
280 int match;
281 do {
282 match = (nm_bits >= 8)
283 ? *a++ == *b++
284 : (*a >> (8 - nm_bits)) == (*b >> (8 - nm_bits));
285 } while (match && (nm_bits -= 8) > 0);
286 return match;
287 } else if (rmt->plain.sa_family == AF_INET
288 && IN6_IS_ADDR_V4MAPPED(&val.ipv6.sin6_addr)) {
289 in_addr_t x = *(in_addr_t *)(val.ipv6.sin6_addr.s6_addr+12);
290 uint32_t nm =
291 htonl(~((1u << (32 - (0 != nm_bits ? (nm_bits > 96 ? nm_bits - 96 : 0) : 32))) - 1));
292 return ((x & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
293 } else {
294 return 0;
296 #endif
297 } else {
298 log_error_write(srv, __FILE__, __LINE__, "ss", "ERROR: ip addr is invalid:", addrstr);
299 return -1;
303 static int config_addrbuf_eq_remote_ip_mask(server *srv, buffer *string, char *nm_slash, sock_addr *rmt) {
304 char *err;
305 int nm_bits = strtol(nm_slash + 1, &err, 10);
306 size_t addrstrlen = (size_t)(nm_slash - string->ptr);
307 char addrstr[64]; /*(larger than INET_ADDRSTRLEN and INET6_ADDRSTRLEN)*/
309 if (*err) {
310 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", string, err);
311 return -1;
314 if (nm_bits <= 0) {
315 if (*(nm_slash+1) == '\0') {
316 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", string);
317 } else {
318 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask <= 0:", string, err);
320 return -1;
323 if (addrstrlen >= sizeof(addrstr)) {
324 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: address string too long:", string);
325 return -1;
328 memcpy(addrstr, string->ptr, addrstrlen);
329 addrstr[addrstrlen] = '\0';
331 return config_addrstr_eq_remote_ip_mask(srv, addrstr, nm_bits, rmt);
334 static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
336 static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
337 buffer *l;
338 server_socket *srv_sock = con->srv_socket;
339 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
341 /* check parent first */
342 if (dc->parent && dc->parent->context_ndx) {
344 * a nested conditional
346 * if the parent is not decided yet or false, we can't be true either
348 if (con->conf.log_condition_handling) {
349 log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
352 switch (config_check_cond_cached(srv, con, dc->parent)) {
353 case COND_RESULT_UNSET:
354 /* decide later */
355 return COND_RESULT_UNSET;
356 case COND_RESULT_SKIP:
357 case COND_RESULT_FALSE:
358 /* failed precondition */
359 return COND_RESULT_SKIP;
360 case COND_RESULT_TRUE:
361 /* proceed */
362 break;
366 if (dc->prev) {
368 * a else branch; can only be executed if the previous branch
369 * was evaluated as "false" (not unset/skipped/true)
371 if (con->conf.log_condition_handling) {
372 log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key);
375 /* make sure prev is checked first */
376 switch (config_check_cond_cached(srv, con, dc->prev)) {
377 case COND_RESULT_UNSET:
378 /* decide later */
379 return COND_RESULT_UNSET;
380 case COND_RESULT_SKIP:
381 case COND_RESULT_TRUE:
382 /* failed precondition */
383 return COND_RESULT_SKIP;
384 case COND_RESULT_FALSE:
385 /* proceed */
386 break;
390 if (!con->conditional_is_valid[dc->comp]) {
391 if (con->conf.log_condition_handling) {
392 log_error_write(srv, __FILE__, __LINE__, "dss",
393 dc->comp,
394 dc->key->ptr,
395 "not available yet");
398 return COND_RESULT_UNSET;
401 /* if we had a real result before and weren't cleared just return it */
402 switch (cache->local_result) {
403 case COND_RESULT_TRUE:
404 case COND_RESULT_FALSE:
405 return cache->local_result;
406 default:
407 break;
410 /* pass the rules */
412 switch (dc->comp) {
413 case COMP_HTTP_HOST: {
414 char *ck_colon = NULL, *val_colon = NULL;
416 if (!buffer_string_is_empty(con->uri.authority)) {
419 * append server-port to the HTTP_POST if necessary
422 l = con->uri.authority;
424 switch(dc->cond) {
425 case CONFIG_COND_NE:
426 case CONFIG_COND_EQ:
427 ck_colon = strchr(dc->string->ptr, ':');
428 val_colon = strchr(l->ptr, ':');
430 if (NULL != ck_colon && NULL == val_colon) {
431 /* condition "host:port" but client send "host" */
432 buffer_copy_buffer(srv->cond_check_buf, l);
433 buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
434 buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
435 l = srv->cond_check_buf;
436 } else if (NULL != val_colon && NULL == ck_colon) {
437 /* condition "host" but client send "host:port" */
438 buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
439 l = srv->cond_check_buf;
441 break;
442 default:
443 break;
445 #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
446 } else if (!buffer_string_is_empty(con->tlsext_server_name)) {
447 l = con->tlsext_server_name;
448 #endif
449 } else {
450 l = srv->empty_string;
452 break;
454 case COMP_HTTP_REMOTE_IP: {
455 char *nm_slash;
456 /* handle remoteip limitations
458 * "10.0.0.1" is provided for all comparisions
460 * only for == and != we support
462 * "10.0.0.1/24"
465 if ((dc->cond == CONFIG_COND_EQ ||
466 dc->cond == CONFIG_COND_NE) &&
467 (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
468 switch (config_addrbuf_eq_remote_ip_mask(srv, dc->string, nm_slash, &con->dst_addr)) {
469 case 1: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
470 case 0: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
471 case -1: return COND_RESULT_FALSE; /*(error parsing configfile entry)*/
474 l = con->dst_addr_buf;
475 break;
477 case COMP_HTTP_SCHEME:
478 l = con->uri.scheme;
479 break;
481 case COMP_HTTP_URL:
482 l = con->uri.path;
483 break;
485 case COMP_HTTP_QUERY_STRING:
486 l = con->uri.query;
487 break;
489 case COMP_SERVER_SOCKET:
490 l = srv_sock->srv_token;
491 break;
493 case COMP_HTTP_REFERER: {
494 data_string *ds;
496 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
497 l = ds->value;
498 } else {
499 l = srv->empty_string;
501 break;
503 case COMP_HTTP_COOKIE: {
504 data_string *ds;
505 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
506 l = ds->value;
507 } else {
508 l = srv->empty_string;
510 break;
512 case COMP_HTTP_USER_AGENT: {
513 data_string *ds;
514 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
515 l = ds->value;
516 } else {
517 l = srv->empty_string;
519 break;
521 case COMP_HTTP_REQUEST_METHOD: {
522 const char *method = get_http_method_name(con->request.http_method);
524 /* we only have the request method as const char but we need a buffer for comparing */
526 buffer_copy_string(srv->tmp_buf, method);
528 l = srv->tmp_buf;
530 break;
532 case COMP_HTTP_LANGUAGE: {
533 data_string *ds;
534 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) {
535 l = ds->value;
536 } else {
537 l = srv->empty_string;
539 break;
541 default:
542 return COND_RESULT_FALSE;
545 if (NULL == l) {
546 if (con->conf.log_condition_handling) {
547 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
548 "(", l, ") compare to NULL");
550 return COND_RESULT_FALSE;
553 if (con->conf.log_condition_handling) {
554 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
555 "(", l, ") compare to ", dc->string);
557 switch(dc->cond) {
558 case CONFIG_COND_NE:
559 case CONFIG_COND_EQ:
560 if (buffer_is_equal(l, dc->string)) {
561 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
562 } else {
563 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
565 break;
566 #ifdef HAVE_PCRE_H
567 case CONFIG_COND_NOMATCH:
568 case CONFIG_COND_MATCH: {
569 int n;
571 #ifndef elementsof
572 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
573 #endif
574 n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0,
575 cache->matches, elementsof(cache->matches));
577 cache->patterncount = n;
578 if (n > 0) {
579 cache->comp_value = l;
580 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
581 } else {
582 /* cache is already cleared */
583 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
585 break;
587 #endif
588 default:
589 /* no way */
590 break;
593 return COND_RESULT_FALSE;
596 static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
597 cond_cache_t *caches = con->cond_cache;
599 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
600 caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc);
601 switch (caches[dc->context_ndx].result) {
602 case COND_RESULT_FALSE:
603 case COND_RESULT_TRUE:
604 /* remember result of local condition for a partial reset */
605 caches[dc->context_ndx].local_result = caches[dc->context_ndx].result;
606 break;
607 default:
608 break;
611 if (con->conf.log_condition_handling) {
612 log_error_write(srv, __FILE__, __LINE__, "dss",
613 dc->context_ndx,
614 "(uncached) result:",
615 cond_result_to_string(caches[dc->context_ndx].result));
617 } else {
618 if (con->conf.log_condition_handling) {
619 log_error_write(srv, __FILE__, __LINE__, "dss",
620 dc->context_ndx,
621 "(cached) result:",
622 cond_result_to_string(caches[dc->context_ndx].result));
625 return caches[dc->context_ndx].result;
628 /* if we reset the cache result for a node, we also need to clear all
629 * child nodes and else-branches*/
630 static void config_cond_clear_node(server *srv, connection *con, data_config *dc) {
631 /* if a node is "unset" all children are unset too */
632 if (con->cond_cache[dc->context_ndx].result != COND_RESULT_UNSET) {
633 size_t i;
635 con->cond_cache[dc->context_ndx].patterncount = 0;
636 con->cond_cache[dc->context_ndx].comp_value = NULL;
637 con->cond_cache[dc->context_ndx].result = COND_RESULT_UNSET;
639 for (i = 0; i < dc->children.used; ++i) {
640 data_config *dc_child = dc->children.data[i];
641 if (NULL == dc_child->prev) {
642 /* only call for first node in if-else chain */
643 config_cond_clear_node(srv, con, dc_child);
646 if (NULL != dc->next) config_cond_clear_node(srv, con, dc->next);
651 * reset the config-cache for a named item
653 * if the item is COND_LAST_ELEMENT we reset all items
655 void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
656 size_t i;
658 for (i = 0; i < srv->config_context->used; i++) {
659 data_config *dc = (data_config *)srv->config_context->data[i];
661 if (item == dc->comp) {
662 /* clear local_result */
663 con->cond_cache[i].local_result = COND_RESULT_UNSET;
664 /* clear result in subtree (including the node itself) */
665 config_cond_clear_node(srv, con, dc);
671 * reset the config cache to its initial state at connection start
673 void config_cond_cache_reset(server *srv, connection *con) {
674 size_t i;
676 /* resetting all entries; no need to follow children as in config_cond_cache_reset_item */
677 for (i = 0; i < srv->config_context->used; i++) {
678 con->cond_cache[i].result = COND_RESULT_UNSET;
679 con->cond_cache[i].local_result = COND_RESULT_UNSET;
680 con->cond_cache[i].patterncount = 0;
681 con->cond_cache[i].comp_value = NULL;
684 for (i = 0; i < COMP_LAST_ELEMENT; i++) {
685 con->conditional_is_valid[i] = 0;
689 int config_check_cond(server *srv, connection *con, data_config *dc) {
690 if (con->conf.log_condition_handling) {
691 log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
693 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
696 int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
698 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
699 if (n >= cache->patterncount) {
700 return 0;
703 n <<= 1; /* n *= 2 */
704 buffer_append_string_len(buf,
705 cache->comp_value->ptr + cache->matches[n],
706 cache->matches[n + 1] - cache->matches[n]);
707 return 1;