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