1 /* This program is free software; you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation; version 2 of the License. For a copy,
4  * see http://www.gnu.org/licenses/gpl-2.0.html.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  */
11 
12 #include "config.h"
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdbool.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <time.h>
21 #include <poll.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <errno.h>
25 #include <pthread.h>
26 #include <syslog.h>
27 #include <grp.h>
28 #ifdef HAVE_NETINET_IN_H
29 #include <netinet/in.h>
30 #endif
31 #ifdef HAVE_NETINET_TCP_H
32 #include <netinet/tcp.h>
33 #endif
34 #include <sys/socket.h>
35 #include <sys/resource.h>
36 #include "global.h"
37 #include "alternative.h"
38 #include "mimetype.h"
39 #include "serverconfig.h"
40 #include "cgi.h"
41 #include "session.h"
42 #include "workers.h"
43 #include "send.h"
44 #include "client.h"
45 #include "log.h"
46 #include "global.h"
47 #include "httpauth.h"
48 #include "tomahawk.h"
49 #include "tls.h"
50 #include "cache.h"
51 #include "xslt.h"
52 #include "monitor.h"
53 #include "memdbg.h"
54 #include "challenge.h"
55 
56 #define rs_NONE                  0
57 #define rs_QUIT_SERVER           1
58 #define rs_UNBAN_CLIENTS         2
59 #define rs_UNLOCK_LOGFILES       3
60 #define rs_CLEAR_CACHE           4
61 
62 #define MAX_TOMAHAWK_CONNECTIONS 3
63 
64 typedef struct {
65 	char *config_dir;
66 	bool daemon;
67 	bool config_check;
68 } t_settings;
69 
70 static volatile int received_signal = rs_NONE;
71 static bool must_quit = false;
72 #ifdef ENABLE_LOADCHECK
73 static double current_server_load = 0;
74 #endif
75 
76 char *fb_symlink     = "symlink not allowed";
77 char *version_string = "Hiawatha v"VERSION;
78 char *enabled_modules = ""
79 #ifdef ENABLE_CACHE
80 	", Cache"
81 #endif
82 #ifdef ENABLE_DEBUG
83 	", debug"
84 #endif
85 #ifdef ENABLE_HTTP2
86 	", HTTP/2"
87 #endif
88 #ifdef ENABLE_MONITOR
89 	", Monitor"
90 #endif
91 #ifdef ENABLE_RPROXY
92 	", ReverseProxy"
93 #endif
94 #ifdef ENABLE_TLS
95 	", TLS v"MBEDTLS_VERSION_STRING
96 #endif
97 #ifdef ENABLE_TOMAHAWK
98 	", Tomahawk"
99 #endif
100 #ifdef ENABLE_TOOLKIT
101 	", UrlToolkit"
102 #endif
103 #ifdef ENABLE_XSLT
104 	", XSLT"
105 #endif
106 ;
107 
108 /* Create all logfiles with the right ownership and accessrights
109  */
create_logfile(char * logfile,mode_t mode,uid_t uid,gid_t gid)110 void create_logfile(char *logfile, mode_t mode, uid_t uid, gid_t gid) {
111 	if (logfile != NULL) {
112 		if (create_file(logfile, mode, uid, gid) != 0) {
113 			fprintf(stderr, "Error creating logfile %s or changing its protection or ownership.\n", logfile);
114 		}
115 	}
116 }
117 
create_logfiles(t_config * config)118 void create_logfiles(t_config *config) {
119 	t_host *host;
120 
121 	create_logfile(config->system_logfile, LOG_PERM, config->server_uid, config->server_gid);
122 	create_logfile(config->garbage_logfile, LOG_PERM, config->server_uid, config->server_gid);
123 	create_logfile(config->exploit_logfile, LOG_PERM, config->server_uid, config->server_gid);
124 #ifdef ENABLE_DEBUG
125 	create_logfile(TLS_ERROR_LOGFILE, LOG_PERM, config->server_uid, config->server_gid);
126 #endif
127 
128 	host = config->first_host;
129 	while (host != NULL) {
130 		if (host->access_fileptr != NULL) {
131 			fflush(host->access_fileptr);
132 		}
133 
134 		create_logfile(host->access_logfile, LOG_PERM, config->server_uid, config->server_gid);
135 		create_logfile(host->error_logfile, LOG_PERM, config->server_uid, config->server_gid);
136 		host = host->next;
137 	}
138 }
139 
140 /* Task-runner starts periodic tasks
141  */
task_runner(t_config * config)142 void task_runner(t_config *config) {
143 	t_ip_addr ip_addr;
144 	int delay = 0;
145 	time_t now;
146 #ifdef ENABLE_LOADCHECK
147 #ifdef HAVE_GETLOADAVG
148 	double loadavg[1];
149 #else
150 	FILE *load_fp = NULL;
151 	char load_str[50], *c;
152 #endif
153 #ifdef ENABLE_MONITOR
154 	int  load_monitor_timer = 0;
155 #endif
156 #endif
157 
158 	do {
159 		sleep(1);
160 
161 		if (delay >= TASK_RUNNER_INTERVAL) {
162 			now = time(NULL);
163 
164 #ifdef ENABLE_MEMDBG
165 			/* Print memory usage
166 			 */
167 		    memdbg_print_log(true);
168 #endif
169 
170 #ifdef ENABLE_THREAD_POOL
171 			/* Manage thread pool
172 			 */
173 			manage_thread_pool(config->thread_pool_size, config->thread_kill_rate);
174 #endif
175 
176 			/* Client checks
177 			 */
178 			check_ban_list(config, now);
179 			check_remove_deadlines(config, now);
180 			remove_wrong_password_list(config);
181 
182 			/* FastCGI check
183 			 */
184 			manage_load_balancer(config, now);
185 
186 			/* Close idle logfile handles
187 			 */
188 			close_logfiles(config->first_host, now);
189 
190 #ifdef ENABLE_CACHE
191 			/* Cache check
192 			 */
193 			manage_cache(now);
194 #endif
195 
196 #ifdef ENABLE_MONITOR
197 			/* Monitor stats
198 			 */
199 			if (config->monitor_enabled) {
200 				monitor_stats_to_buffer(config, now);
201 			}
202 #endif
203 
204 			/* Rotate access logfiles
205 			 */
206 			if (config->rotate_access_logs) {
207 				rotate_access_logfiles(config, now);
208 			}
209 
210 			delay = 0;
211 		} else {
212 			delay++;
213 		}
214 
215 #ifdef ENABLE_TOMAHAWK
216 		/* Tomahawk check
217 		 */
218 		check_admin_list();
219 #endif
220 
221 #ifdef ENABLE_LOADCHECK
222 		if (config->max_server_load > 0) {
223 #ifdef HAVE_GETLOADAVG
224 			if (getloadavg(loadavg, 1) >= 1) {
225 				current_server_load = loadavg[0];
226 #ifdef ENABLE_MONITOR
227 				if (config->monitor_enabled) {
228 					if ((current_server_load > config->max_server_load) && (load_monitor_timer == 0)) {
229 						monitor_event("High server load (%0.2f)", current_server_load);
230 						load_monitor_timer = 60;
231 					}
232 				}
233 #endif
234 			} else {
235 				current_server_load = 0;
236 			}
237 #else
238 			if ((load_fp = fopen("/proc/loadavg", "r")) != NULL) {
239 				if (fgets(load_str, 49, load_fp) != NULL) {
240 					load_str[49] = '\0';
241 					if ((c = strchr(load_str, ' ')) != NULL) {
242 						*c = '\0';
243 						current_server_load = atof(load_str);
244 #ifdef ENABLE_MONITOR
245 						if (config->monitor_enabled) {
246 							if ((current_server_load > config->max_server_load) && (load_monitor_timer == 0)) {
247 								monitor_event("High server load (%0.2f)", current_server_load);
248 								load_monitor_timer = 60;
249 							}
250 						}
251 #endif
252 					} else {
253 						current_server_load = 0;
254 					}
255 				} else {
256 					current_server_load = 0;
257 				}
258 
259 				fclose(load_fp);
260 			} else {
261 				current_server_load = 0;
262 			}
263 #endif
264 
265 #ifdef ENABLE_MONITOR
266 			if (load_monitor_timer > 0) {
267 				load_monitor_timer--;
268 			}
269 #endif
270 		}
271 #endif
272 
273 		switch (received_signal) {
274 			case rs_NONE:
275 				break;
276 			case rs_QUIT_SERVER:
277 				must_quit = true;
278 				break;
279 			case rs_UNBAN_CLIENTS:
280 				default_ipv4(&ip_addr);
281 				unban_ip(&ip_addr);
282 				default_ipv6(&ip_addr);
283 				unban_ip(&ip_addr);
284 				received_signal = rs_NONE;
285 				break;
286 			case rs_UNLOCK_LOGFILES:
287 				close_logfiles(config->first_host, 0);
288 				received_signal = rs_NONE;
289 				break;
290 #ifdef ENABLE_CACHE
291 			case rs_CLEAR_CACHE:
292 				clear_cache();
293 				received_signal = rs_NONE;
294 				break;
295 #endif
296 		}
297 	} while (must_quit == false);
298 
299 	pthread_exit(NULL);
300 }
301 
302 /* Signal handlers
303  */
SEGV_handler()304 void SEGV_handler() {
305 	syslog(LOG_DAEMON | LOG_ALERT, "segmentation fault!");
306 #ifdef ENABLE_MONITOR
307 	monitor_event("Server crash!");
308 	shutdown_monitor_module();
309 #endif
310 	exit(EXIT_FAILURE);
311 }
312 
TERM_handler()313 void TERM_handler() {
314 	received_signal = rs_QUIT_SERVER;
315 }
316 
HUP_handler()317 void HUP_handler() {
318 	received_signal = rs_UNLOCK_LOGFILES;
319 }
320 
USR1_handler()321 void USR1_handler() {
322 	received_signal = rs_UNBAN_CLIENTS;
323 }
324 
325 #ifdef ENABLE_CACHE
USR2_handler()326 void USR2_handler() {
327 	received_signal = rs_CLEAR_CACHE;
328 }
329 #endif
330 
331 /* Create a socketlist.
332  */
bind_sockets(t_binding * binding)333 int bind_sockets(t_binding *binding) {
334 	char ip_address[MAX_IP_STR_LEN], separator;
335 	struct sockaddr_in  saddr4;
336 	struct sockaddr_in6 saddr6;
337 	int domain, optval, result;
338 
339 	while (binding != NULL) {
340 		domain = (binding->interface.family == AF_INET ? PF_INET : PF_INET6);
341 		if ((binding->socket = socket(domain, SOCK_STREAM, 0)) == -1) {
342 			perror("socket()");
343 			return -1;
344 		}
345 
346 		optval = 1;
347 		if (setsockopt(binding->socket, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) == -1) {
348 			perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
349 		}
350 
351 		optval = 1;
352 		if (setsockopt(binding->socket, IPPROTO_TCP, TCP_NODELAY, (void*)&optval, sizeof(int)) == -1) {
353 			perror("setsockopt(IPPROTO_TCP, TCP_NODELAY)");
354 		}
355 
356 		if (binding->interface.family == AF_INET) {
357 			/* IPv4
358 			 */
359 			memset(&saddr4, 0, sizeof(struct sockaddr_in));
360 			saddr4.sin_family = AF_INET;
361 			memcpy(&(saddr4.sin_addr.s_addr), &(binding->interface.value), IPv4_LEN);
362 			saddr4.sin_port = htons(binding->port);
363 
364 			result = bind(binding->socket, (struct sockaddr*)&saddr4, sizeof(struct sockaddr_in));
365 
366 			separator = ':';
367 		} else if (binding->interface.family == AF_INET6) {
368 			/* IPv6
369 			 */
370 			optval = 1;
371 			if (setsockopt(binding->socket, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(int)) < 0) {
372 				perror("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY)");
373 			}
374 
375 			memset(&saddr6, 0, sizeof(struct sockaddr_in6));
376 			saddr6.sin6_family = AF_INET6;
377 			memcpy(&(saddr6.sin6_addr.s6_addr), &(binding->interface.value), IPv6_LEN);
378 			saddr6.sin6_port = htons(binding->port);
379 
380 			result = bind(binding->socket, (struct sockaddr*)&saddr6, sizeof(struct sockaddr_in6));
381 
382 			separator = '.';
383 		} else {
384 			fprintf(stderr, "Unknown protocol (family %d).\n", binding->interface.family);
385 			return -1;
386 		}
387 
388 		if (result == -1) {
389 			/* Handle error
390 		 	 */
391 			if (inet_ntop(binding->interface.family, &(binding->interface.value), ip_address, MAX_IP_STR_LEN) == NULL) {
392 				strcpy(ip_address, "?.?.?.?");
393 			}
394 			fprintf(stderr, "Error binding %s%c%d\n", ip_address, separator, binding->port);
395 			return -1;
396 		}
397 
398 		binding = binding->next;
399 	}
400 
401 	return 0;
402 }
403 
404 /* Accept or deny an incoming connection.
405  */
accept_connection(t_binding * binding,t_config * config)406 int accept_connection(t_binding *binding, t_config *config) {
407 	socklen_t           size;
408 	bool                kick_client;
409 	t_session           *session;
410 	struct sockaddr_in  caddr4;
411 	struct sockaddr_in6 caddr6;
412 	int                 optval, connections_per_ip, total_connections;
413 	struct timeval      timer;
414 #ifdef ENABLE_DEBUG
415 	static int          thread_id = 1;
416 #endif
417 
418 	if ((session = (t_session*)malloc(sizeof(t_session))) == NULL) {
419 		return -1;
420 	}
421 #ifdef ENABLE_DEBUG
422 	session->thread_id = thread_id++;
423 	session->current_task = "new";
424 #endif
425 	session->config = config;
426 	session->binding = binding;
427 	init_session(session);
428 
429 	if (binding->interface.family == AF_INET) {
430 		/* IPv4
431 		 */
432 		size = sizeof(struct sockaddr_in);
433 		memset((void*)&caddr4, 0, (size_t)size);
434 		if ((session->client_socket = accept(binding->socket, (struct sockaddr*)&caddr4, &size)) == -1) {
435 			free(session);
436 			log_system(config, "Error accepting incoming IPv4 connection: %s", strerror(errno));
437 			if (errno == EINTR) {
438 				return 0;
439 			}
440 			return -1;
441 		}
442 
443 		session->ip_address.family = AF_INET;
444 		session->ip_address.size   = IPv4_LEN;
445 		memcpy(&(session->ip_address.value), (char*)&caddr4.sin_addr.s_addr, session->ip_address.size);
446 	} else if (binding->interface.family == AF_INET6) {
447 		/* IPv6
448 		 */
449 		size = sizeof(struct sockaddr_in6);
450 		memset((void*)&caddr6, 0, (size_t)size);
451 		if ((session->client_socket = accept(binding->socket, (struct sockaddr*)&caddr6, &size)) == -1) {
452 			free(session);
453 			log_system(config, "Error accepting incoming IPv6 connection: %s", strerror(errno));
454 			if (errno == EINTR) {
455 				return 0;
456 			}
457 			return -1;
458 		}
459 
460 		session->ip_address.family = AF_INET6;
461 		session->ip_address.size   = IPv6_LEN;
462 		memcpy(&(session->ip_address.value), (char*)&caddr6.sin6_addr.s6_addr, session->ip_address.size);
463 	} else {
464 		log_system_session(session, "Incoming connection via unknown protocol");
465 		free(session);
466 		return -1;
467 	}
468 
469 	session->request_limit = (ip_allowed(&(session->ip_address), session->config->request_limit_mask) != deny);
470 
471 #ifdef ENABLE_LOADCHECK
472 	if ((session->config->max_server_load > 0) && session->request_limit) {
473 		if (current_server_load > session->config->max_server_load) {
474 			close(session->client_socket);
475 			free(session);
476 			log_system(config, "Connection dropped due to high server load.");
477 			return -1;
478 		}
479 	}
480 #endif
481 
482 	if (in_iplist(config->hide_proxy, &(session->ip_address))) {
483 		session->via_trusted_proxy = true;
484 	}
485 
486 	if (session->request_limit == false) {
487 		connections_per_ip = config->total_connections;
488 	} else {
489 		connections_per_ip = config->connections_per_ip;
490 	}
491 
492 	kick_client = true;
493 
494 	if ((total_connections = connection_allowed(&(session->ip_address), session->via_trusted_proxy, connections_per_ip, config->total_connections)) >= 0) {
495 		if (total_connections < (config->total_connections >> 2)) {
496 			optval = 1;
497 			if (setsockopt(session->client_socket, IPPROTO_TCP, TCP_NODELAY, (void*)&optval, sizeof(int)) == -1) {
498 				close(session->client_socket);
499 				free(session);
500 				log_system(config, "error setsockopt(TCP_NODELAY)");
501 				return -1;
502 			}
503 		}
504 
505 		if (config->socket_send_timeout > 0) {
506 			timer.tv_sec  = config->socket_send_timeout;
507 			timer.tv_usec = 0;
508 			if (setsockopt(session->client_socket, SOL_SOCKET, SO_SNDTIMEO, &timer, sizeof(struct timeval)) == -1) {
509 				close(session->client_socket);
510 				free(session);
511 				log_system(config, "error setsockopt(SO_SNDTIMEO)");
512 				return -1;
513 			}
514 		}
515 
516 		/* Start worker
517 		 */
518 		if (start_worker(session) == 0) {
519 			kick_client = false;
520 		}
521 	} else {
522 		handle_connection_not_allowed(session, total_connections);
523 	}
524 
525 	if (kick_client) {
526 		close(session->client_socket);
527 		free(session);
528 	}
529 
530 	return 0;
531 }
532 
533 /* Change UID and GID
534  */
change_uid_gid(t_config * config)535 int change_uid_gid(t_config *config) {
536 	if (setgroups(config->groups.number, config->groups.array) == -1) {
537 		return -1;
538 	}
539 
540 	if (setgid(config->server_gid) == -1) {
541 		return -1;
542 	}
543 
544 	if (setuid(config->server_uid) == -1) {
545 		return -1;
546 	}
547 
548 	return 0;
549 }
550 
551 /* Run the Hiawatha webserver.
552  */
run_webserver(t_settings * settings)553 int run_webserver(t_settings *settings) {
554 	int                number_of_bindings = 0;
555 	pthread_attr_t     task_runner_attr;
556 	pthread_t          task_runner_thread;
557 	struct pollfd      *poll_data, *current_poll;
558 #ifdef ENABLE_TOMAHAWK
559 	int                number_of_admins;
560 	struct sockaddr_in caddr;
561 	socklen_t          size;
562 	int                admin_socket;
563 	FILE               *admin_fp;
564 #endif
565 	pid_t              pid;
566 	t_binding          *binding;
567 	t_config           *config;
568 	mode_t             access_rights;
569 #ifndef CYGWIN
570 	struct rlimit      resource_limit;
571 #endif
572 #ifdef ENABLE_TLS
573 	t_host             *host;
574 	t_tls_setup        tls_setup;
575 #endif
576 #ifdef HAVE_ACCF
577 	struct accept_filter_arg afa;
578 #endif
579 
580 	/* Read configuration
581 	 */
582 	if (init_config_module(settings->config_dir) == -1) {
583 		perror("init_config_module()");
584 		return -1;
585 	} else if ((config = default_config()) == NULL) {
586 		perror("default_config()");
587 		return -1;
588 	} else if (chdir(settings->config_dir) == -1) {
589 		perror(settings->config_dir);
590 		return -1;
591 	} else if (settings->config_check) {
592 		printf("Using %s\n", settings->config_dir);
593 	}
594 
595 	if (read_main_configfile("hiawatha.conf", config, settings->config_check) == -1) {
596 		return -1;
597 	} else if (check_configuration(config) == -1) {
598 		return -1;
599 	}
600 
601 	if (read_mimetypes(config->mimetype_config, &(config->mimetype), settings->config_check) == -1) {
602 		fprintf(stderr, "Error while reading mimetype configuration.\n");
603 		return -1;
604 	}
605 
606 	if (settings->config_check) {
607 		printf("Configuration OK.\n");
608 		return 0;
609 	}
610 
611 	/* Bind Serverports
612 	 */
613 	if (bind_sockets(config->binding) == -1) {
614 		return -1;
615 	}
616 
617 #ifdef ENABLE_TLS
618 	if (init_tls_module(config->ca_certificates) == -1) {
619 		return -1;
620 	}
621 
622 	tls_setup.min_tls_version = config->min_tls_version;
623 	tls_setup.dh_size         = config->dh_size;
624 #endif
625 
626 	/* Load private keys and certificate for bindings
627 	 */
628 	binding = config->binding;
629 	while (binding != NULL) {
630 #ifdef ENABLE_TLS
631 		if (binding->use_tls) {
632 			if (tls_load_key_cert(binding->key_cert_file, &(binding->private_key), &(binding->certificate)) != 0) {
633 				return -1;
634 			}
635 
636 			if (binding->ca_cert_file != NULL) {
637 				if (tls_load_ca_cert(binding->ca_cert_file, &(binding->ca_certificate)) != 0) {
638 					return -1;
639 				}
640 				if (binding->ca_crl_file != NULL) {
641 					if (tls_load_ca_crl(binding->ca_crl_file, &(binding->ca_crl)) != 0) {
642 						return -1;
643 					}
644 				}
645 			}
646 
647 			tls_setup.private_key    = binding->private_key;
648 			tls_setup.certificate    = binding->certificate;
649 			tls_setup.ca_certificate = binding->ca_certificate;
650 			tls_setup.ca_crl         = binding->ca_crl;
651 
652 			if (tls_set_config(&(binding->tls_config), &tls_setup) != 0) {
653 				return -1;
654 			}
655 
656 #ifdef ENABLE_HTTP2
657 			if (binding->use_tls && binding->accept_http2) {
658 				tls_accept_http2(binding->tls_config);
659 			}
660 #endif
661 		}
662 #endif
663 
664 		number_of_bindings++;
665 		binding = binding->next;
666 	}
667 
668 #ifdef ENABLE_TOMAHAWK
669 	binding = config->tomahawk_port;
670 	while (binding != NULL) {
671 		number_of_bindings++;
672 		binding = binding->next;
673 	}
674 #endif
675 
676 #ifdef ENABLE_TLS
677 	host = config->first_host;
678 	while (host != NULL) {
679 		/* Load private key and certificates for virtual hosts
680 		 */
681 		if (host->key_cert_file != NULL) {
682 			if (tls_load_key_cert(host->key_cert_file, &(host->private_key), &(host->certificate)) != 0) {
683 				return -1;
684 			}
685 		}
686 
687 		if (host->ca_cert_file != NULL) {
688 			if (tls_load_ca_cert(host->ca_cert_file, &(host->ca_certificate)) != 0) {
689 				return -1;
690 			}
691 			if (host->ca_crl_file != NULL) {
692 				if (tls_load_ca_crl(host->ca_crl_file, &(host->ca_crl)) != 0) {
693 					return -1;
694 				}
695 			}
696 		}
697 
698 		if (host->hpkp_data != NULL) {
699 			if (create_hpkp_header(host->hpkp_data) == -1) {
700 				fprintf(stderr, "Error generating HPKP header for %s.\n", host->hostname.item[0]);
701 				return -1;
702 			}
703 			host->hpkp_data->next = NULL;
704 		}
705 
706 		/* Initialize Server Name Indication
707 		 */
708 		if ((host->private_key != NULL) && (host->certificate != NULL)) {
709 			tls_setup.private_key    = host->private_key;
710 			tls_setup.certificate    = host->certificate;
711 			tls_setup.ca_certificate = host->ca_certificate;
712 			tls_setup.ca_crl         = host->ca_crl;
713 
714 			if (tls_register_sni(&(host->hostname), &tls_setup) == -1) {
715 				return -1;
716 			}
717 		}
718 
719 		host = host->next;
720 	}
721 #endif
722 
723 #ifdef ENABLE_TOMAHAWK
724 	/* Bind Tomahawk
725 	 */
726 	if (bind_sockets(config->tomahawk_port) == -1) {
727 		return -1;
728 	}
729 #endif
730 
731 	/* Misc settings
732 	 */
733 	tzset();
734 	clearenv();
735 	umask(0117);
736 
737 	/* Become a daemon
738 	 */
739 	if (settings->daemon) {
740 		switch (pid = fork()) {
741 			case -1:
742 				perror("fork()");
743 				return -1;
744 			case 0:
745 				if (setsid() == -1) {
746 					perror("setsid()");
747 					return -1;
748 				}
749 				break;
750 			default:
751 				log_pid(config, pid, config->server_uid);
752 				return 0;
753 		}
754 	} else {
755 		log_pid(config, getpid(), config->server_uid);
756 	}
757 
758 	/* Create work directory
759 	 */
760 	if (create_directory(config->work_directory, S_IRWXU, config->server_uid, config->server_gid) == -1) {
761 		fprintf(stderr, "Error creating work directory '%s'\n", config->work_directory);
762 		return -1;
763 	}
764 
765 	/* Create gzipped work directory
766 	 */
767 	if (create_directory(config->gzipped_directory, S_IRWXU, config->server_uid, config->server_gid) == -1) {
768 		fprintf(stderr, "Error creating gzip work directory '%s'\n", config->gzipped_directory);
769 		return -1;
770 	}
771 
772 	wipe_directory(config->gzipped_directory, ".gz");
773 
774 	/* Create the upload directory for PUT requests
775 	 */
776 	if ((getuid() == 0) || (geteuid() == 0)) {
777 		access_rights = S_ISVTX | S_IRWXU | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH;
778 	} else {
779 		access_rights = S_ISVTX | S_IWUSR | S_IXUSR | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH;
780 	}
781 
782 	if (create_directory(config->upload_directory, access_rights, 0, 0) != 0) {
783 		fprintf(stderr, "Error creating upload directory '%s'\n", config->upload_directory);
784 		return -1;
785 	}
786 
787 #ifdef ENABLE_MONITOR
788 	/* Create monitor cache directory
789 	 */
790 	if (config->monitor_enabled) {
791 		if (create_directory(config->monitor_directory, S_IRWXU, config->server_uid, config->server_gid) != 0) {
792 			fprintf(stderr, "Error creating monitor cache directory %s or changing its protection or ownership.\n", config->monitor_directory);
793 			return -1;
794 		}
795 	}
796 #endif
797 
798 	/* Initialize random generator
799 	 */
800 	srand((unsigned)time(NULL));
801 
802 	/* Create logfiles
803 	 */
804 	create_logfiles(config);
805 
806 #ifndef CYGWIN
807 	/* Set resource limits
808 	 */
809 	if (config->set_rlimits) {
810 		resource_limit.rlim_max = resource_limit.rlim_cur = config->total_connections + 3;
811 		if (setrlimit(RLIMIT_NPROC, &resource_limit) != 0) {
812 			fprintf(stderr, "Error setting RLIMIT_NPROC.\n");
813 		}
814 
815 		/* system: system.log, exploit.log, garbage.log, debug.log, all bindings, tomahawk connections
816 		 * per child: socket, access.log, error.log, 3 CGI pipes
817 		 */
818 		resource_limit.rlim_max = resource_limit.rlim_cur = 4 + number_of_bindings + MAX_TOMAHAWK_CONNECTIONS +
819 															6 * config->total_connections;
820 		if (setrlimit(RLIMIT_NOFILE, &resource_limit) != 0) {
821 			fprintf(stderr, "Error setting RLIMIT_NOFILE.\n");
822 		}
823 	}
824 
825 	/* Change user and group id
826 	 */
827 	if ((getuid() == 0) || (geteuid() == 0)) {
828 		if (change_uid_gid(config) == -1) {
829 			fprintf(stderr, "\nError while changing uid/gid!\n");
830 			return -1;
831 		}
832 	}
833 #endif
834 
835 	/* Set signal handlers
836 	 */
837 	if (settings->daemon == false) {
838 		printf("Press Ctrl-C to shutdown the Hiawatha webserver.\n");
839 		signal(SIGINT, TERM_handler);
840 	} else {
841 		signal(SIGINT, SIG_IGN);
842 	}
843 	if (config->wait_for_cgi == false) {
844 		signal(SIGCHLD, SIG_IGN);
845 	}
846 	signal(SIGPIPE, SIG_IGN);
847 	signal(SIGTSTP, SIG_IGN);
848 	signal(SIGABRT, SIG_IGN);
849 	signal(SIGQUIT, SIG_IGN);
850 	signal(SIGSEGV, SEGV_handler);
851 	signal(SIGTERM, TERM_handler);
852 	signal(SIGHUP,  HUP_handler);
853 	signal(SIGUSR1, USR1_handler);
854 #ifdef ENABLE_CACHE
855 	signal(SIGUSR2, USR2_handler);
856 #endif
857 
858 	/* Start listening for incoming connections
859 	 */
860 	binding = config->binding;
861 	while (binding != NULL) {
862 		if (listen(binding->socket, config->listen_backlog) == -1) {
863 			perror("listen(http(s))");
864 			return -1;
865 		}
866 		binding = binding->next;
867 	}
868 #ifdef ENABLE_TOMAHAWK
869 	binding = config->tomahawk_port;
870 	while (binding != NULL) {
871 		if (listen(binding->socket, 1) == -1) {
872 			perror("listen(tomahawk)");
873 			return -1;
874 		}
875 		binding = binding->next;
876 	}
877 #endif
878 
879 #ifdef ENABLE_THREAD_POOL
880 	if (init_workers_module(config->thread_pool_size) == -1) {
881 		fprintf(stderr, "Error initializing workers module.\n");
882 		return -1;
883 	}
884 #endif
885 	if (init_httpauth_module() == -1) {
886 		fprintf(stderr, "Error initializing HTTP authentication module.\n");
887 		return -1;
888 	}
889 	init_send_module();
890 	if (init_log_module(config) == -1) {
891 		fprintf(stderr, "Error initializing log module.\n");
892 		return -1;
893 	}
894 	if (init_client_module() == -1) {
895 		fprintf(stderr, "Error initializing client module.\n");
896 		return -1;
897 	}
898 	if (init_load_balancer(config->fcgi_server) == -1) {
899 		fprintf(stderr, "Error initializing FastCGI load balancer.\n");
900 		return -1;
901 	}
902 #ifdef ENABLE_CACHE
903 	if (init_cache_module() == -1) {
904 		fprintf(stderr, "Error initializing cache module.\n");
905 		return -1;
906 	}
907 #endif
908 #ifdef ENABLE_TOMAHAWK
909 	if (init_tomahawk_module() == -1) {
910 		fprintf(stderr, "Error initializing Tomahawk module.\n");
911 		return -1;
912 	}
913 #endif
914 #ifdef ENABLE_XSLT
915 	init_xslt_module();
916 #endif
917 #ifdef ENABLE_RPROXY
918 	if (init_rproxy_module() == -1) {
919 		fprintf(stderr, "Error initializing reverse proxy module.\n");
920 		return -1;
921 	}
922 #endif
923 	if (init_sqli_detection() == -1) {
924 		fprintf(stderr, "Error initializing SQL injection detection.\n");
925 		return -1;
926 	}
927 #ifdef ENABLE_MONITOR
928 	if (config->monitor_enabled) {
929 		if (init_monitor_module(config) == -1) {
930 			fprintf(stderr, "Error initializing Monitor module.\n");
931 			return -1;
932 		}
933 		monitor_event("Server start");
934 		monitor_version(version_string, enabled_modules);
935 	}
936 #endif
937 #ifdef ENABLE_MEMDBG
938 	init_memdbg();
939 #endif
940 	if (init_challenge_module(config->challenge_secret) == -1) {
941 		fprintf(stderr, "Error initializing ChallengeClient module.\n");
942 		return -1;
943 	}
944 
945 #ifdef HAVE_ACCF
946 	binding = config->binding;
947 	while (binding != NULL) {
948 		if (binding->enable_accf
949 #ifdef ENABLE_TLS
950 			&& (binding->use_tls == false)
951 #endif
952 		) {
953 			bzero(&afa, sizeof(afa));
954 			strcpy(afa.af_name, "httpready");
955 			if (setsockopt(binding->socket, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) == -1) {
956 				fprintf(stderr, "Error while enabling HTTP accept filter. Kernel module 'accf_http' loaded?");
957 				return -1;
958 			}
959 		}
960 		binding = binding->next;
961 	}
962 #endif
963 
964 	/* Redirecting I/O to /dev/null
965 	 */
966 	if (settings->daemon) {
967 		if (close(STDIN_FILENO) == -1) {
968 			fprintf(stderr, "Warning: error closing STDIN\n");
969 		} else if (open("/dev/null", O_RDONLY) == -1) {
970 			fprintf(stderr, "Warning: error redirecting stdin\n");
971 		}
972 		if (close(STDOUT_FILENO) == -1) {
973 			fprintf(stderr, "Warning: error closing STDOUT\n");
974 		} else if (open("/dev/null", O_WRONLY) == -1) {
975 			fprintf(stderr, "Warning: error redirecting stdout\n");
976 		}
977 		if (close(STDERR_FILENO) == -1) {
978 			fprintf(stderr, "Warning: error closing STDERR\n");
979 		} else if (open("/dev/null", O_WRONLY) == -1) {
980 			log_system(config, "Warning: error redirecting stderr\n");
981 		}
982 	}
983 
984 	log_system(config, "Hiawatha v"VERSION" started.");
985 
986 	/* Start task_runner
987 	 */
988 	if (pthread_attr_init(&task_runner_attr) != 0) {
989 		log_system(config, "Task-runner pthread init error.");
990 		return -1;
991 	} else if (pthread_attr_setdetachstate(&task_runner_attr, PTHREAD_CREATE_DETACHED) != 0) {
992 		log_system(config, "Task-runner pthread set detach state error.");
993 		return -1;
994 	} else if (pthread_attr_setstacksize(&task_runner_attr, PTHREAD_STACK_SIZE) != 0) {
995 		log_system(config, "Task-runner pthread set stack size error.");
996 		return -1;
997 	} else if (pthread_create(&task_runner_thread, &task_runner_attr, (void*)task_runner, (void*)config) != 0) {
998 		log_system(config, "Task-runner pthread create error.");
999 		return -1;
1000 	}
1001 	pthread_attr_destroy(&task_runner_attr);
1002 
1003 #ifdef ENABLE_MEMDBG
1004 	/* Clear memory debugger log
1005 	 */
1006 	memdbg_clear_log();
1007 #endif
1008 
1009 	/* Setup poll data
1010 	 */
1011 	if ((poll_data = (struct pollfd*)malloc((number_of_bindings + MAX_TOMAHAWK_CONNECTIONS) * sizeof(struct pollfd))) == NULL) {
1012 		return -1;
1013 	}
1014 
1015 	current_poll = poll_data;
1016 
1017 	binding = config->binding;
1018 	while (binding != NULL) {
1019 		current_poll->fd = binding->socket;
1020 		current_poll->events = POLL_EVENT_BITS;
1021 		binding->poll_data = current_poll;
1022 
1023 		current_poll++;
1024 		binding = binding->next;
1025 	}
1026 
1027 #ifdef ENABLE_TOMAHAWK
1028 	binding = config->tomahawk_port;
1029 	while (binding != NULL) {
1030 		current_poll->fd = binding->socket;
1031 		current_poll->events = POLL_EVENT_BITS;
1032 		binding->poll_data = current_poll;
1033 
1034 		current_poll++;
1035 		binding = binding->next;
1036 	}
1037 #endif
1038 
1039 	/* Main loop
1040 	 */
1041 	do {
1042 #ifdef ENABLE_TOMAHAWK
1043 		current_poll = poll_data + number_of_bindings;
1044 		number_of_admins = prepare_admins_for_poll(current_poll);
1045 
1046 		switch (poll(poll_data, number_of_bindings + number_of_admins, 1000)) {
1047 #else
1048 		switch (poll(poll_data, number_of_bindings, 1000)) {
1049 #endif
1050 			case -1:
1051 				if (errno != EINTR) {
1052 					log_system(config, "Fatal error selecting connection.");
1053 					usleep(1000);
1054 				}
1055 				break;
1056 			case 0:
1057 				break;
1058 			default:
1059 #ifdef ENABLE_TOMAHAWK
1060 				/* Connected admins */
1061 				handle_admins(config);
1062 #endif
1063 
1064 				/* HTTP(S) ports */
1065 				binding = config->binding;
1066 				while (binding != NULL) {
1067 					if (binding->poll_data->revents != 0) {
1068 						if (accept_connection(binding, config) != 0) {
1069 							usleep(1000);
1070 							break;
1071 
1072 						}
1073 					}
1074 					binding = binding->next;
1075 				}
1076 
1077 #ifdef ENABLE_TOMAHAWK
1078 				/* Tomahawk ports */
1079 				binding = config->tomahawk_port;
1080 				while (binding != NULL) {
1081 					if (binding->poll_data->revents != 0) {
1082 						size = sizeof(struct sockaddr_in);
1083 						memset((void*)&caddr, 0, (size_t)size);
1084 						if ((admin_socket = accept(binding->socket, (struct sockaddr*)&caddr, &size)) == -1) {
1085 							if (errno != EINTR) {
1086 								log_system(config, "Fatal error accepting Tomahawk connection.");
1087 								usleep(1000);
1088 								break;
1089 							}
1090 						} else if (number_of_admins >= MAX_TOMAHAWK_CONNECTIONS) {
1091 							if ((admin_fp = fdopen(admin_socket, "r+")) != NULL) {
1092 								fprintf(admin_fp, "Maximum number of admin connections reached.\n\n");
1093 								fclose(admin_fp);
1094 							} else {
1095 								close(admin_socket);
1096 							}
1097 						} else if (add_admin(admin_socket) == -1) {
1098 							close(admin_socket);
1099 						}
1100 					}
1101 					binding = binding->next;
1102 				}
1103 #endif
1104 		}
1105 	} while (must_quit == false);
1106 
1107 	signal(SIGTERM, SIG_DFL);
1108 
1109 	close_bindings(config->binding);
1110 
1111 	disconnect_clients(config);
1112 #ifdef ENABLE_TOMAHAWK
1113 	disconnect_admins();
1114 #endif
1115 
1116 #ifdef ENABLE_TOMAHAWK
1117 	binding = config->tomahawk_port;
1118 	while (binding != NULL) {
1119 		close(binding->socket);
1120 		binding = binding->next;
1121 	}
1122 #endif
1123 
1124 #ifdef ENABLE_MONITOR
1125 	if (config->monitor_enabled) {
1126 		monitor_event("Server stop");
1127 		shutdown_monitor_module();
1128 	}
1129 #endif
1130 
1131 	log_system(config, "Hiawatha v"VERSION" stopped.");
1132 	close_logfiles(config->first_host, 0);
1133 
1134 	free(poll_data);
1135 
1136 	return 0;
1137 }
1138 
1139 void show_help(char *hiawatha) {
1140 	printf("Usage: %s [options]\n", hiawatha);
1141 	printf("Options: -c <path>: path to where the configrationfiles are located.\n");
1142 	printf("         -d: don't fork to the background.\n");
1143 	printf("         -h: show this information and exit.\n");
1144 	printf("         -k: check configuration and exit.\n");
1145 	printf("         -m: show enabled modules and exit.\n");
1146 	printf("         -v: show version and copyright and exit.\n");
1147 }
1148 
1149 /* Main and stuff...
1150  */
1151 int main(int argc, char *argv[]) {
1152 	int i = 0;
1153 	t_settings settings;
1154 
1155 	/* Default settings
1156 	 */
1157 	settings.config_dir   = CONFIG_DIR;
1158 	settings.daemon       = true;
1159 	settings.config_check = false;
1160 
1161 	/* Read command line parameters
1162 	 */
1163 	while (++i < argc) {
1164 		if (strcmp(argv[i], "-c") == 0) {
1165 			if (++i < argc) {
1166 				settings.config_dir = argv[i];
1167 			} else {
1168 				fprintf(stderr, "Specify a directory.\n");
1169 				return EXIT_FAILURE;
1170 			}
1171 		} else if (strcmp(argv[i], "-d") == 0) {
1172 			settings.daemon = false;
1173 		} else if (strcmp(argv[i], "-h") == 0) {
1174 			show_help(argv[0]);
1175 			return EXIT_SUCCESS;
1176 		} else if (strcmp(argv[i], "-k") == 0) {
1177 			settings.config_check = true;
1178 		} else if (strcmp(argv[i], "-m") == 0) {
1179 			if (strlen(enabled_modules) == 0) {
1180 				enabled_modules = "none";
1181 			} else {
1182 				enabled_modules += 2;
1183 			}
1184 			printf("Enabled modules: %s\n", enabled_modules);
1185 			return EXIT_SUCCESS;
1186 		} else if (strcmp(argv[i], "-v") == 0) {
1187 			printf("%s, copyright (c) by Hugo Leisink <hugo@leisink.net>\n", version_string);
1188 			return EXIT_SUCCESS;
1189 		} else {
1190 			fprintf(stderr, "Unknown option. Use '-h' for help.\n");
1191 			return EXIT_FAILURE;
1192 		}
1193 	}
1194 
1195 	/* Run Hiawatha
1196 	 */
1197 	if (run_webserver(&settings) == -1) {
1198 		return EXIT_FAILURE;
1199 	}
1200 
1201 	return EXIT_SUCCESS;
1202 }
1203