1#include "base.h"
2#include "buffer.h"
3#include "array.h"
4#include "log.h"
5#include "plugin.h"
6
7#include "configfile.h"
8
9#include <string.h>
10#include <stdlib.h>
11
12/**
13 * like all glue code this file contains functions which
14 * are the external interface of lighttpd. The functions
15 * are used by the server itself and the plugins.
16 *
17 * The main-goal is to have a small library in the end
18 * which is linked against both and which will define
19 * the interface itself in the end.
20 *
21 */
22
23
24/* handle global options */
25
26/* parse config array */
27int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
28	size_t i;
29	data_unset *du;
30
31	for (i = 0; cv[i].key; i++) {
32
33		if (NULL == (du = array_get_element(ca, cv[i].key))) {
34			/* no found */
35
36			continue;
37		}
38
39		if ((T_CONFIG_SCOPE_SERVER == cv[i].scope)
40		    && (T_CONFIG_SCOPE_SERVER != scope)) {
41			/* server scope options should only be set in server scope, not in conditionals */
42			log_error_write(srv, __FILE__, __LINE__, "ss",
43				"DEPRECATED: don't set server options in conditionals, variable:",
44				cv[i].key);
45		}
46
47		switch (cv[i].type) {
48		case T_CONFIG_ARRAY:
49			if (du->type == TYPE_ARRAY) {
50				size_t j;
51				data_array *da = (data_array *)du;
52
53				for (j = 0; j < da->value->used; j++) {
54					if (da->value->data[j]->type == TYPE_STRING) {
55						data_string *ds = data_string_init();
56
57						buffer_copy_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
58						if (!da->is_index_key) {
59							/* the id's were generated automaticly, as we copy now we might have to renumber them
60							 * this is used to prepend server.modules by mod_indexfile as it has to be loaded
61							 * before mod_fastcgi and friends */
62							buffer_copy_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
63						}
64
65						array_insert_unique(cv[i].destination, (data_unset *)ds);
66					} else {
67						log_error_write(srv, __FILE__, __LINE__, "sssbsd",
68								"the value of an array can only be a string, variable:",
69								cv[i].key, "[", da->value->data[j]->key, "], type:", da->value->data[j]->type);
70
71						return -1;
72					}
73				}
74			} else {
75				log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
76
77				return -1;
78			}
79			break;
80		case T_CONFIG_STRING:
81			if (du->type == TYPE_STRING) {
82				data_string *ds = (data_string *)du;
83				buffer_copy_buffer(cv[i].destination, ds->value);
84			} else {
85				log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
86
87				return -1;
88			}
89			break;
90		case T_CONFIG_SHORT:
91			switch(du->type) {
92			case TYPE_INTEGER: {
93				data_integer *di = (data_integer *)du;
94
95				*((unsigned short *)(cv[i].destination)) = di->value;
96				break;
97			}
98			case TYPE_STRING: {
99				data_string *ds = (data_string *)du;
100
101				/* If the value came from an environment variable, then it is a
102				 * data_string, although it may contain a number in ASCII
103				 * decimal format.  We try to interpret the string as a decimal
104				 * short before giving up, in order to support setting numeric
105				 * values with environment variables (eg, port number).
106				 */
107				if (ds->value->ptr && *ds->value->ptr) {
108					char *e;
109					long l = strtol(ds->value->ptr, &e, 10);
110					if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
111						*((unsigned short *)(cv[i].destination)) = l;
112						break;
113					}
114				}
115
116				log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
117
118				return -1;
119			}
120			default:
121				log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
122				return -1;
123			}
124			break;
125		case T_CONFIG_INT:
126			switch(du->type) {
127			case TYPE_INTEGER: {
128				data_integer *di = (data_integer *)du;
129
130				*((unsigned int *)(cv[i].destination)) = di->value;
131				break;
132			}
133			case TYPE_STRING: {
134				data_string *ds = (data_string *)du;
135
136				if (ds->value->ptr && *ds->value->ptr) {
137					char *e;
138					long l = strtol(ds->value->ptr, &e, 10);
139					if (e != ds->value->ptr && !*e && l >= 0) {
140						*((unsigned int *)(cv[i].destination)) = l;
141						break;
142					}
143				}
144
145				log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);
146
147				return -1;
148			}
149			default:
150				log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
151				return -1;
152			}
153			break;
154		case T_CONFIG_BOOLEAN:
155			if (du->type == TYPE_STRING) {
156				data_string *ds = (data_string *)du;
157
158				if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
159					*((unsigned short *)(cv[i].destination)) = 1;
160				} else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
161					*((unsigned short *)(cv[i].destination)) = 0;
162				} else {
163					log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
164
165					return -1;
166				}
167			} else {
168				log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
169
170				return -1;
171			}
172			break;
173		case T_CONFIG_LOCAL:
174		case T_CONFIG_UNSET:
175			break;
176		case T_CONFIG_UNSUPPORTED:
177			log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
178
179			srv->config_unsupported = 1;
180
181			break;
182		case T_CONFIG_DEPRECATED:
183			log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
184
185			srv->config_deprecated = 1;
186
187			break;
188		}
189	}
190
191	return 0;
192}
193
194int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
195	size_t i;
196	data_unset *du;
197
198	for (i = 0; cv[i].key; i++) {
199		data_string *touched;
200
201		if (NULL == (du = array_get_element(ca, cv[i].key))) {
202			/* no found */
203
204			continue;
205		}
206
207		/* touched */
208		touched = data_string_init();
209
210		buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
211		buffer_copy_buffer(touched->key, du->key);
212
213		array_insert_unique(srv->config_touched, (data_unset *)touched);
214	}
215
216	return config_insert_values_internal(srv, ca, cv, scope);
217}
218
219static unsigned short sock_addr_get_port(sock_addr *addr) {
220#ifdef HAVE_IPV6
221	return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
222#else
223	return ntohs(addr->ipv4.sin_port);
224#endif
225}
226
227static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
228
229static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
230	buffer *l;
231	server_socket *srv_sock = con->srv_socket;
232
233	/* check parent first */
234	if (dc->parent && dc->parent->context_ndx) {
235		/**
236		 * a nested conditional
237		 *
238		 * if the parent is not decided yet or false, we can't be true either
239		 */
240		if (con->conf.log_condition_handling) {
241			log_error_write(srv, __FILE__, __LINE__,  "sb", "go parent", dc->parent->key);
242		}
243
244		switch (config_check_cond_cached(srv, con, dc->parent)) {
245		case COND_RESULT_FALSE:
246			return COND_RESULT_FALSE;
247		case COND_RESULT_UNSET:
248			return COND_RESULT_UNSET;
249		default:
250			break;
251		}
252	}
253
254	if (dc->prev) {
255		/**
256		 * a else branch
257		 *
258		 * we can only be executed, if all of our previous brothers
259		 * are false
260		 */
261		if (con->conf.log_condition_handling) {
262			log_error_write(srv, __FILE__, __LINE__,  "sb", "go prev", dc->prev->key);
263		}
264
265		/* make sure prev is checked first */
266		config_check_cond_cached(srv, con, dc->prev);
267
268		/* one of prev set me to FALSE */
269		switch (con->cond_cache[dc->context_ndx].result) {
270		case COND_RESULT_FALSE:
271			return con->cond_cache[dc->context_ndx].result;
272		default:
273			break;
274		}
275	}
276
277	if (!con->conditional_is_valid[dc->comp]) {
278		if (con->conf.log_condition_handling) {
279			log_error_write(srv, __FILE__, __LINE__,  "dss",
280				dc->comp,
281				dc->key->ptr,
282				con->conditional_is_valid[dc->comp] ? "yeah" : "nej");
283		}
284
285		return COND_RESULT_UNSET;
286	}
287
288	/* pass the rules */
289
290	switch (dc->comp) {
291	case COMP_HTTP_HOST: {
292		char *ck_colon = NULL, *val_colon = NULL;
293
294		if (!buffer_string_is_empty(con->uri.authority)) {
295
296			/*
297			 * append server-port to the HTTP_POST if necessary
298			 */
299
300			l = con->uri.authority;
301
302			switch(dc->cond) {
303			case CONFIG_COND_NE:
304			case CONFIG_COND_EQ:
305				ck_colon = strchr(dc->string->ptr, ':');
306				val_colon = strchr(l->ptr, ':');
307
308				if (NULL != ck_colon && NULL == val_colon) {
309					/* condition "host:port" but client send "host" */
310					buffer_copy_buffer(srv->cond_check_buf, l);
311					buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
312					buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
313					l = srv->cond_check_buf;
314				} else if (NULL != val_colon && NULL == ck_colon) {
315					/* condition "host" but client send "host:port" */
316					buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
317					l = srv->cond_check_buf;
318				}
319				break;
320			default:
321				break;
322			}
323#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
324		} else if (!buffer_string_is_empty(con->tlsext_server_name)) {
325			l = con->tlsext_server_name;
326#endif
327		} else {
328			l = srv->empty_string;
329		}
330		break;
331	}
332	case COMP_HTTP_REMOTE_IP: {
333		char *nm_slash;
334		/* handle remoteip limitations
335		 *
336		 * "10.0.0.1" is provided for all comparisions
337		 *
338		 * only for == and != we support
339		 *
340		 * "10.0.0.1/24"
341		 */
342
343		if ((dc->cond == CONFIG_COND_EQ ||
344		     dc->cond == CONFIG_COND_NE) &&
345		    (con->dst_addr.plain.sa_family == AF_INET) &&
346		    (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
347			int nm_bits;
348			long nm;
349			char *err;
350			struct in_addr val_inp;
351
352			if (*(nm_slash+1) == '\0') {
353				log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
354
355				return COND_RESULT_FALSE;
356			}
357
358			nm_bits = strtol(nm_slash + 1, &err, 10);
359
360			if (*err) {
361				log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err);
362
363				return COND_RESULT_FALSE;
364			}
365
366			if (nm_bits > 32 || nm_bits < 0) {
367				log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask:", dc->string, err);
368
369				return COND_RESULT_FALSE;
370			}
371
372			/* take IP convert to the native */
373			buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
374#ifdef __WIN32
375			if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
376				log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
377
378				return COND_RESULT_FALSE;
379			}
380
381#else
382			if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
383				log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
384
385				return COND_RESULT_FALSE;
386			}
387#endif
388
389			/* build netmask */
390			nm = nm_bits ? htonl(~((1 << (32 - nm_bits)) - 1)) : 0;
391
392			if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
393				return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
394			} else {
395				return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
396			}
397		} else {
398			l = con->dst_addr_buf;
399		}
400		break;
401	}
402	case COMP_HTTP_SCHEME:
403		l = con->uri.scheme;
404		break;
405
406	case COMP_HTTP_URL:
407		l = con->uri.path;
408		break;
409
410	case COMP_HTTP_QUERY_STRING:
411		l = con->uri.query;
412		break;
413
414	case COMP_SERVER_SOCKET:
415		l = srv_sock->srv_token;
416		break;
417
418	case COMP_HTTP_REFERER: {
419		data_string *ds;
420
421		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
422			l = ds->value;
423		} else {
424			l = srv->empty_string;
425		}
426		break;
427	}
428	case COMP_HTTP_COOKIE: {
429		data_string *ds;
430		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
431			l = ds->value;
432		} else {
433			l = srv->empty_string;
434		}
435		break;
436	}
437	case COMP_HTTP_USER_AGENT: {
438		data_string *ds;
439		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
440			l = ds->value;
441		} else {
442			l = srv->empty_string;
443		}
444		break;
445	}
446	case COMP_HTTP_REQUEST_METHOD: {
447		const char *method = get_http_method_name(con->request.http_method);
448
449		/* we only have the request method as const char but we need a buffer for comparing */
450
451		buffer_copy_string(srv->tmp_buf, method);
452
453		l = srv->tmp_buf;
454
455		break;
456	}
457	case COMP_HTTP_LANGUAGE: {
458		data_string *ds;
459		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) {
460			l = ds->value;
461		} else {
462			l = srv->empty_string;
463		}
464		break;
465	}
466	default:
467		return COND_RESULT_FALSE;
468	}
469
470	if (NULL == l) {
471		if (con->conf.log_condition_handling) {
472			log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
473					"(", l, ") compare to NULL");
474		}
475		return COND_RESULT_FALSE;
476	}
477
478	if (con->conf.log_condition_handling) {
479		log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
480				"(", l, ") compare to ", dc->string);
481	}
482	switch(dc->cond) {
483	case CONFIG_COND_NE:
484	case CONFIG_COND_EQ:
485		if (buffer_is_equal(l, dc->string)) {
486			return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
487		} else {
488			return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
489		}
490		break;
491#ifdef HAVE_PCRE_H
492	case CONFIG_COND_NOMATCH:
493	case CONFIG_COND_MATCH: {
494		cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
495		int n;
496
497#ifndef elementsof
498#define elementsof(x) (sizeof(x) / sizeof(x[0]))
499#endif
500		n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0,
501				cache->matches, elementsof(cache->matches));
502
503		cache->patterncount = n;
504		if (n > 0) {
505			cache->comp_value = l;
506			cache->comp_type  = dc->comp;
507			return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
508		} else {
509			/* cache is already cleared */
510			return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
511		}
512		break;
513	}
514#endif
515	default:
516		/* no way */
517		break;
518	}
519
520	return COND_RESULT_FALSE;
521}
522
523static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
524	cond_cache_t *caches = con->cond_cache;
525
526	if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
527		if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
528			if (dc->next) {
529				data_config *c;
530				if (con->conf.log_condition_handling) {
531					log_error_write(srv, __FILE__, __LINE__, "s",
532							"setting remains of chaining to false");
533				}
534				for (c = dc->next; c; c = c->next) {
535					caches[c->context_ndx].result = COND_RESULT_FALSE;
536				}
537			}
538		}
539		caches[dc->context_ndx].comp_type = dc->comp;
540
541		if (con->conf.log_condition_handling) {
542			log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
543					"(uncached) result:",
544					caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
545						(caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
546		}
547	} else {
548		if (con->conf.log_condition_handling) {
549			log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
550					"(cached) result:",
551					caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
552						(caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
553		}
554	}
555	return caches[dc->context_ndx].result;
556}
557
558/**
559 * reset the config-cache for a named item
560 *
561 * if the item is COND_LAST_ELEMENT we reset all items
562 */
563void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
564	size_t i;
565
566	for (i = 0; i < srv->config_context->used; i++) {
567		if (item == COMP_LAST_ELEMENT ||
568		    con->cond_cache[i].comp_type == item) {
569			con->cond_cache[i].result = COND_RESULT_UNSET;
570			con->cond_cache[i].patterncount = 0;
571			con->cond_cache[i].comp_value = NULL;
572		}
573	}
574}
575
576/**
577 * reset the config cache to its initial state at connection start
578 */
579void config_cond_cache_reset(server *srv, connection *con) {
580	size_t i;
581
582	config_cond_cache_reset_all_items(srv, con);
583
584	for (i = 0; i < COMP_LAST_ELEMENT; i++) {
585		con->conditional_is_valid[i] = 0;
586	}
587}
588
589int config_check_cond(server *srv, connection *con, data_config *dc) {
590	if (con->conf.log_condition_handling) {
591		log_error_write(srv, __FILE__, __LINE__,  "s",  "=== start of condition block ===");
592	}
593	return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
594}
595
596int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
597{
598	cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
599	if (n >= cache->patterncount) {
600		return 0;
601	}
602
603	n <<= 1; /* n *= 2 */
604	buffer_append_string_len(buf,
605			cache->comp_value->ptr + cache->matches[n],
606			cache->matches[n + 1] - cache->matches[n]);
607	return 1;
608}
609
610