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 <stdio.h>
15 #include <stdlib.h>
16 #include <stdbool.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <time.h>
22 #include <signal.h>
23 #include <pthread.h>
24 #include <poll.h>
25 #include <sys/file.h>
26 #include <sys/time.h>
27 #include <sys/stat.h>
28 #include <sys/wait.h>
29 #include <sys/socket.h>
30 #include "global.h"
31 #include "alternative.h"
32 #include "client.h"
33 #include "libstr.h"
34 #include "libfs.h"
35 #include "target.h"
36 #include "http.h"
37 #include "httpauth.h"
38 #include "log.h"
39 #include "cgi.h"
40 #include "send.h"
41 #include "cache.h"
42 #include "monitor.h"
43 #include "tomahawk.h"
44 #include "xslt.h"
45 #include "memdbg.h"
46 #include "mbedtls/sha256.h"
47 
48 #define FILE_BUFFER_SIZE      32 * KILOBYTE
49 #define MAX_OUTPUT_HEADER     16 * KILOBYTE
50 #define CGI_BUFFER_SIZE       32 * KILOBYTE
51 #define RPROXY_BUFFER_SIZE    32 * KILOBYTE
52 #define MAX_TRACE_HEADER       2 * KILOBYTE
53 #define WS_BUFFER_SIZE        32 * KILOBYTE
54 #define VALUE_SIZE            64
55 #define WAIT_FOR_LOCK          3
56 
57 #define rs_QUIT       -1
58 #define rs_DISCONNECT -2
59 #define rs_FORCE_QUIT -3
60 
61 #define NEW_FILE -1
62 
63 char *fb_alterlist = "access denied via alterlist";
64 
65 extern char *fb_filesystem;
66 extern char *fb_symlink;
67 extern char *hs_eol;
68 extern char *hs_conn;
69 extern char *hs_concl;
70 extern char *hs_conlen;
71 extern char *hs_contyp;
72 extern char *hs_chunked;
73 
74 extern char *upgrade_websocket;
75 
76 /* Read a file from disk and send it to the client.
77  */
send_file(t_session * session)78 int send_file(t_session *session) {
79 	char *buffer = NULL, value[VALUE_SIZE + 1], *pos, *date;
80 	char *range = NULL, *range_begin, *range_end, gz_file[1024], gz_hex[65];
81 	bool use_gz_file = false;
82 	unsigned char gz_hash[32];
83 	long bytes_read, speed;
84 	off_t file_size, send_begin, send_end, send_size;
85 	int  retval, handle = -1;
86 	struct stat status, gz_status;
87 	struct tm fdate;
88 #ifdef ENABLE_CACHE
89 	char *file_for_cache = NULL;
90 	t_cached_object *cached_object;
91 	int result;
92 #endif
93 
94 #ifdef ENABLE_DEBUG
95 	session->current_task = "send file";
96 #endif
97 #ifdef ENABLE_TOMAHAWK
98 	increment_counter(COUNTER_FILE);
99 #endif
100 
101 	session->mimetype = get_mimetype(session->extension, session->config->mimetype);
102 	session->send_expires = true;
103 
104 	if (session->handling_error == false) {
105 		if ((range = get_http_header("Range:", session->http_headers)) != NULL) {
106 			goto no_gzip;
107 		}
108 	}
109 
110 	/* GZip content encoding
111 	 */
112 	if (file_can_be_compressed(session) == false) {
113 		goto no_gzip;
114 	} else if ((pos = get_http_header("Accept-Encoding:", session->http_headers)) == NULL) {
115 		goto no_gzip;
116 	} else if (strstr(pos, "gzip") == NULL) {
117 		goto no_gzip;
118 	}
119 
120 	mbedtls_sha256((unsigned char*)session->file_on_disk, strlen(session->file_on_disk), gz_hash, 0);
121 	sha256_bin2hex(gz_hash, gz_hex);
122 
123 	if (snprintf(gz_file, 1023, "%s/%s.gz", session->config->gzipped_directory, gz_hex) > 1020) {
124 		goto no_gzip;
125 	}
126 
127 	if (stat(session->file_on_disk, &status) == -1) {
128 		goto no_gzip;
129 	} else if (stat(gz_file, &gz_status) == -1) {
130 		/* GZipped file does not exist
131 		 */
132 		if (gzip_file(session->file_on_disk, gz_file) == -1) {
133 			goto no_gzip;
134 		}
135 		if ((handle = open(gz_file, O_RDONLY)) != -1) {
136 			session->encode_gzip = true;
137 			use_gz_file = true;
138 		}
139 	} else {
140 		/* GZipped file exists
141 		 */
142 		if ((status.st_mtime > gz_status.st_mtime) || (status.st_ctime > gz_status.st_ctime)) {
143 			unlink(gz_file);
144 			if (gzip_file(session->file_on_disk, gz_file) == -1) {
145 				goto no_gzip;
146 			}
147 		}
148 		if ((handle = open(gz_file, O_RDONLY)) != -1) {
149 			session->encode_gzip = true;
150 			use_gz_file = true;
151 		}
152 	}
153 no_gzip:
154 
155 	/* Open the file for reading
156 	 */
157 	if (handle == -1) {
158 		if ((handle = open(session->file_on_disk, O_RDONLY)) == -1) {
159 			if (errno == EACCES) {
160 				log_error_session(session, fb_filesystem);
161 				return 403;
162 			}
163 			return 404;
164 		}
165 	}
166 
167 	if (in_charlist(session->extension, &(session->config->block_extensions))) {
168 		session->encode_gzip = false;
169 		close(handle);
170 		return 403;
171 	}
172 
173 	/* File hashes
174 	 */
175 	if ((session->host->file_hashes != NULL) && (session->letsencrypt_auth_request == false)) {
176 		if (file_hash_match(session->file_on_disk, session->host->file_hashes) == false) {
177 			log_error_file(session, session->file_on_disk, "invalid file hash");
178 #ifdef ENABLE_MONITOR
179 			if (session->config->monitor_enabled) {
180 				monitor_count_exploit_attempt(session);
181 				monitor_event("Invalid file hash for %s", session->file_on_disk);
182 			}
183 #endif
184 			close(handle);
185 			return 403;
186 		}
187 	}
188 
189 	/* Symlink check
190 	 */
191 	if (session->host->follow_symlinks == false) {
192 		switch (contains_not_allowed_symlink(session->file_on_disk, session->host->website_root)) {
193 			case fb_error:
194 				close(handle);
195 				log_error_session(session, "error while scanning file for symlinks");
196 				return 500;
197 			case fb_not_found:
198 				close(handle);
199 				return 404;
200 			case fb_no_access:
201 			case fb_yes:
202 				close(handle);
203 				log_error_session(session, fb_symlink);
204 				return 403;
205 			case fb_no:
206 				break;
207 		}
208 	}
209 
210 	/* Modified-Since
211 	 */
212 	if (session->handling_error == false) {
213 		if ((date = get_http_header("If-Modified-Since:", session->http_headers)) != NULL) {
214 			if (if_modified_since(session->file_on_disk, date) == 0) {
215 				close(handle);
216 				return 304;
217 			}
218 		} else if ((date = get_http_header("If-Unmodified-Since:", session->http_headers)) != NULL) {
219 			if (if_modified_since(session->file_on_disk, date) == 1) {
220 				close(handle);
221 				return 412;
222 			}
223 		}
224 	}
225 
226 	/* Set throttlespeed
227 	 */
228 	pos = session->uri + session->uri_len;
229 	while ((*pos != '.') && (pos != session->uri)) {
230 		pos--;
231 	}
232 	if (*pos == '.') {
233 		if ((speed = get_throttlespeed(pos, session->config->throttle)) != 0) {
234 			if ((session->throttle == 0) || (speed < session->throttle)) {
235 				session->throttle = speed;
236 			}
237 		}
238 		if ((speed = get_throttlespeed(session->mimetype, session->config->throttle)) != 0) {
239 			if ((session->throttle == 0) || (speed < session->throttle)) {
240 				session->throttle = speed;
241 			}
242 		}
243 	}
244 
245 	if (use_gz_file) {
246 		file_size = filesize(gz_file);
247 	}  else {
248 		file_size = filesize(session->file_on_disk);
249 	}
250 	if (file_size == -1) {
251 		close(handle);
252 		log_error_session(session, "error while determining filesize");
253 		return 500;
254 	}
255 
256 	send_begin = 0;
257 	send_end = file_size - 1;
258 	send_size = file_size;
259 
260 	/* Range
261 	 */
262 	if (range != NULL) {
263 		/* Check for multi-range
264 		 */
265 		if (strchr(range, ',') != NULL) {
266 			close(handle);
267 			return 416;
268 		}
269 
270 		if (strncmp(range, "bytes=", 6) == 0) {
271 			if ((range = strdup(range + 6)) == NULL) {
272 				close(handle);
273 				log_error_session(session, "strdup() error");
274 				return 500;
275 			}
276 
277 			if (split_string(range, &range_begin, &range_end, '-') == 0) {
278 				if (*range_begin != '\0') {
279 					if ((send_begin = str_to_off(range_begin)) >= 0) {
280 						if (*range_end != '\0') {
281 							if ((send_end = str_to_off(range_end)) >= 0) {
282 								/* bytes=XX-XX */
283 								session->return_code = 206;
284 							}
285 						} else {
286 							/* bytes=XX- */
287 							session->return_code = 206;
288 						}
289 					}
290 				} else {
291 					if ((send_begin = str_to_off(range_end)) >= 0) {
292 						/* bytes=-XX */
293 						send_begin = file_size - send_begin - 1;
294 						session->return_code = 206;
295 					}
296 				}
297 
298 				if (session->return_code == 206) {
299 					if (send_begin >= file_size) {
300 						close(handle);
301 						free(range);
302 						return 416;
303 					}
304 					if (send_begin < 0) {
305 						send_begin = 0;
306 					}
307 					if (send_end >= file_size) {
308 						send_end = file_size - 1;
309 					}
310 					if (send_begin <= send_end) {
311 						send_size = send_end - send_begin + 1;
312 					} else {
313 						close(handle);
314 						free(range);
315 						return 416;
316 					}
317 				}
318 
319 				/* Change filepointer offset
320 				 */
321 				if (send_begin > 0) {
322 					if (lseek(handle, send_begin, SEEK_SET) == -1) {
323 						session->return_code = 200;
324 					}
325 				}
326 
327 				if (session->return_code == 200) {
328 					send_begin = 0;
329 					send_end = file_size - 1;
330 					send_size = file_size;
331 				}
332 			}
333 			free(range);
334 		}
335 	}
336 
337 	if (session->extension != NULL) {
338 		if (strcmp(session->extension, "svgz") == 0) {
339 			session->encode_gzip = true;
340 		}
341 	}
342 
343 	retval = -1;
344 	if (send_header(session) == -1) {
345 		goto fail;
346 	}
347 	if (session->return_code == 401) {
348 		if (session->host->auth_method == basic) {
349 			if (send_basic_auth(session) == -1) {
350 				goto fail;
351 			}
352 		} else {
353 			if (send_digest_auth(session) == -1) {
354 				goto fail;
355 			}
356 		}
357 	}
358 
359 	value[VALUE_SIZE] = '\0';
360 
361 	/* Last-Modified
362 	 */
363 	if (stat(session->file_on_disk, &status) == -1) {
364 		goto fail;
365 	} else if (gmtime_r(&(status.st_mtime), &fdate) == NULL) {
366 		goto fail;
367 	} else if (send_buffer(session, "Last-Modified: ", 15) == -1) {
368 		goto fail;
369 	} else if (strftime(value, VALUE_SIZE, "%a, %d %b %Y %X GMT\r\n", &fdate) == 0) {
370 		goto fail;
371 	} else if (send_buffer(session, value, strlen(value)) == -1) {
372 		goto fail;
373 	}
374 
375 	/* Content-Range
376 	 */
377 	if (session->return_code == 206) {
378 		if (send_buffer(session, "Content-Range: bytes ", 21) == -1) {
379 			goto fail;
380 		} else if (snprintf(value, VALUE_SIZE, "%lld-%lld/%lld\r\n", (long long)send_begin, (long long)send_end, (long long)file_size) == -1) {
381 			goto fail;
382 		} else if (send_buffer(session, value, strlen(value)) == -1) {
383 			goto fail;
384 		}
385 	}
386 
387 	if (send_buffer(session, hs_conlen, 16) == -1) {
388 		goto fail;
389 	} else if (snprintf(value, VALUE_SIZE, "%lld\r\n\r\n", (long long)send_size) == -1) {
390 		goto fail;
391 	} else if (send_buffer(session, value, strlen(value)) == -1) {
392 		goto fail;
393 	}
394 	session->header_sent = true;
395 
396 	if ((session->request_method != HEAD) && (send_size > 0)) {
397 #ifdef ENABLE_CACHE
398 #ifdef ENABLE_MONITOR
399 		if (session->host->monitor_host) {
400 			cached_object = NULL;
401 		} else
402 #endif
403 		{
404 			file_for_cache = use_gz_file ? gz_file : session->file_on_disk;
405 			if ((cached_object = search_cache_for_file(session, file_for_cache)) == NULL) {
406 				cached_object = add_file_to_cache(session, file_for_cache);
407 			}
408 		}
409 
410 		if (cached_object != NULL) {
411 			if (send_begin + send_size > cached_object->content_length) {
412 				done_with_cached_object(cached_object, true);
413 				cached_object = NULL;
414 			}
415 		}
416 
417 		if (cached_object != NULL) {
418 			result = send_buffer(session, cached_object->content + send_begin, send_size);
419 			done_with_cached_object(cached_object, false);
420 			cached_object = NULL;
421 
422 			if (result == -1) {
423 				goto fail;
424 			}
425 		} else
426 #endif
427 		if ((buffer = (char*)malloc(FILE_BUFFER_SIZE)) == NULL) {
428 			goto fail;
429 		} else {
430 			do {
431 				switch ((bytes_read = read(handle, buffer, FILE_BUFFER_SIZE))) {
432 					case -1:
433 						if (errno != EINTR) {
434 							goto fail;
435 						}
436 						break;
437 					case 0:
438 						send_size = 0;
439 						break;
440 					default:
441 						if (bytes_read > send_size) {
442 							bytes_read = send_size;
443 						}
444 						if (send_buffer(session, buffer, bytes_read) == -1) {
445 							goto fail;
446 						}
447 						send_size -= bytes_read;
448 				}
449 			} while (send_size > 0);
450 
451 			memset(buffer, 0, FILE_BUFFER_SIZE);
452 		}
453 	}
454 
455 	retval = 200;
456 
457 fail:
458 	if (buffer != NULL) {
459 		free(buffer);
460 	}
461 
462 	close(handle);
463 
464 	return retval;
465 }
466 
extract_http_code(char * data)467 static int extract_http_code(char *data) {
468 	int result = -1;
469 	char *code, c;
470 
471 	while (*data == ' ') {
472 		data++;
473 	}
474 	code = data;
475 
476 	while (*data != '\0') {
477 		if ((*data == '\r') || (*data == ' ')) {
478 			c = *data;
479 			*data = '\0';
480 			result = str_to_int(code);
481 			*data = c;
482 			break;
483 		}
484 		data++;
485 	}
486 
487 	return result;
488 }
489 
remove_header(char * buffer,char * header,int * header_length,unsigned long * size)490 static int remove_header(char *buffer, char *header, int *header_length, unsigned long *size) {
491 	char *pos;
492 	size_t len;
493 
494 	if ((pos = find_cgi_header(buffer, *header_length, header)) == NULL) {
495 		return 0;
496 	}
497 
498 	len = strlen(header);
499 	while (*(pos + len) != '\n') {
500 		if (*(pos + len) == '\0') {
501 			return 0;
502 		}
503 		len++;
504 	}
505 	len++;
506 
507 	memmove(pos, pos + len, *size - len - (pos - buffer));
508 
509 	*header_length -= len;
510 	*size -= len;
511 
512 	return len;
513 }
514 
515 /* Run a CGI program and send output to the client.
516  */
execute_cgi(t_session * session)517 int execute_cgi(t_session *session) {
518 	int retval = 200, result, handle, len, header_length, value, flush_after_send = false, delta, return_code;
519 	char *end_of_header, *str_begin, *str_end, *code, c, *str, *sendfile = NULL;
520 	bool in_body = false, send_in_chunks = true, wrap_cgi, check_file_exists;
521 	t_cgi_result cgi_result;
522 	t_connect_to *connect_to;
523 	t_cgi_info cgi_info;
524 	pid_t cgi_pid = -1;
525 #ifdef CYGWIN
526 	char *old_path, *win32_path;
527 #endif
528 #ifdef ENABLE_CACHE
529 	bool skip_cache;
530 	t_cached_object *cached_object;
531 	char *cache_buffer = NULL, *cookie;
532 	int  cache_size = 0, cache_time = 0, i;
533 #endif
534 #ifdef ENABLE_MONITOR
535 	bool timed_out = false, measure_runtime = false;
536 	bool error_printed = false;
537 	struct timeval tv_begin, tv_end;
538 	struct timezone tz_begin, tz_end;
539 	int runtime, diff;
540 	char *event_key, *event_value, *event_end;
541 #endif
542 
543 #ifdef ENABLE_DEBUG
544 	session->current_task = "execute CGI";
545 #endif
546 #ifdef ENABLE_TOMAHAWK
547 	increment_counter(COUNTER_CGI);
548 #endif
549 
550 	if (session->cgi_type != fastcgi) {
551 		wrap_cgi = (session->host->wrap_cgi != NULL) ||
552 			((session->local_user != NULL) && session->config->wrap_user_cgi);
553 	} else {
554 		wrap_cgi = false;
555 	}
556 
557 	/* HTTP/1.0 does not support chunked Transfer-Encoding.
558 	 */
559 	if (*(session->http_version + 7) == '0') {
560 		session->keep_alive = false;
561 	}
562 
563 	if ((wrap_cgi == false) && (session->cgi_type != fastcgi)) {
564 		check_file_exists = true;
565 	} else if ((session->cgi_type == fastcgi) && session->fcgi_server->localhost
566 #if defined(ENABLE_XSLT) || defined(ENABLE_MONITOR)
567 		&& session->host->show_index
568 #endif
569 		) {
570 		check_file_exists = true;
571 	} else {
572 		check_file_exists = false;
573 	}
574 
575 	if (check_file_exists) {
576 		if ((handle = open(session->file_on_disk, O_RDONLY)) == -1) {
577 			if (errno == EACCES) {
578 				log_error_session(session, fb_filesystem);
579 				return 403;
580 			}
581 			return 404;
582 		} else {
583 			close(handle);
584 		}
585 
586 		/* File hashes
587 		 */
588 		if (session->host->file_hashes != NULL) {
589 			if (file_hash_match(session->file_on_disk, session->host->file_hashes) == false) {
590 				log_error_file(session, session->file_on_disk, "invalid file hash");
591 #ifdef ENABLE_MONITOR
592 				if (session->config->monitor_enabled) {
593 					monitor_count_exploit_attempt(session);
594 					monitor_event("Invalid file hash for %s", session->file_on_disk);
595 				}
596 #endif
597 				return 403;
598 			}
599 		}
600 	}
601 
602 	if (session->host->execute_cgi == false) {
603 		log_error_session(session, "CGI execution not allowed");
604 		return 403;
605 	}
606 
607 #ifdef CYGWIN
608 	if ((session->config->platform == windows) && (session->cgi_type == binary)) {
609 		chmod(session->file_on_disk, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
610 	}
611 #endif
612 
613 	if ((wrap_cgi == false) && (session->cgi_type != fastcgi)) {
614 		if (session->cgi_type == binary) {
615 			switch (can_execute(session->file_on_disk, session->config->server_uid, session->config->server_gid, &(session->config->groups))) {
616 				case fb_error:
617 					log_error_session(session, "error during CGI preprocess");
618 					return 500;
619 				case fb_not_found:
620 					return 404;
621 				case fb_no_access:
622 				case fb_no:
623 					log_error_session(session, fb_filesystem);
624 					return 403;
625 				case fb_yes:
626 					break;
627 			}
628 		}
629 
630 		if (session->host->follow_symlinks == false) {
631 			switch (contains_not_allowed_symlink(session->file_on_disk, session->host->website_root)) {
632 				case fb_error:
633 					log_error_session(session, "error while searching for symlinks in CGI path");
634 					return 500;
635 				case fb_not_found:
636 					return 404;
637 				case fb_no_access:
638 				case fb_yes:
639 					log_error_session(session, fb_symlink);
640 					return 403;
641 				case fb_no:
642 					break;
643 			}
644 		}
645 	}
646 
647 	/* Prevent SQL injection
648 	 */
649 	if (session->host->prevent_sqli != p_no) {
650 		result = prevent_sqli(session);
651 		if ((result > 0) && (session->host->prevent_sqli >= p_prevent)) {
652 			session->error_cause = ec_SQL_INJECTION;
653 			return -1;
654 		} else if (result == -1) {
655 			return -1;
656 		}
657 	}
658 
659 	/* Prevent Cross-site Scripting
660 	 */
661 	if (session->host->prevent_xss != p_no) {
662 		if ((prevent_xss(session) > 0) && (session->host->prevent_xss == p_block)) {
663 			session->error_cause = ec_XSS;
664 			return -1;
665 		}
666 	}
667 
668 	/* Prevent Cross-site Request Forgery
669 	 */
670 	if (session->host->prevent_csrf != p_no) {
671 		if ((prevent_csrf(session) > 0) && (session->host->prevent_csrf == p_block)) {
672 			session->error_cause = ec_CSRF;
673 			return -1;
674 		}
675 	}
676 
677 #ifdef ENABLE_CACHE
678 	/* Search for CGI output in cache
679 	 */
680 	skip_cache = false;
681 	if (session->cookies != NULL) {
682 		for (i = 0; i < session->host->skip_cache_cookies.size; i++) {
683 			cookie = session->host->skip_cache_cookies.item[i];
684 			if ((str = strstr(session->cookies, cookie)) != NULL) {
685 				if (*(str + strlen(cookie)) != '=') {
686 					continue;
687 				}
688 				if (str > session->cookies) {
689 					if (*(str - 1) != ' ') {
690 						continue;
691 					}
692 				}
693 				skip_cache = true;
694 				break;
695 			}
696 		}
697 	}
698 
699 	if ((session->request_method == GET) && (skip_cache == false)) {
700 		if ((cached_object = search_cache_for_cgi_output(session)) != NULL) {
701 			if (send_header(session) == -1) {
702 				retval = rs_DISCONNECT;
703 			} else if (send_buffer(session, cached_object->header, cached_object->header_length) == -1) {
704 				retval = rs_DISCONNECT;
705 			} else if (send_buffer(session, cached_object->content, cached_object->content_length) == -1) {
706 				retval = rs_DISCONNECT;
707 			}
708 
709 			done_with_cached_object(cached_object, false);
710 
711 			return retval;
712 		}
713 	}
714 #endif
715 
716 	cgi_info.type = session->cgi_type;
717 	cgi_info.input_buffer_size = cgi_info.error_buffer_size = CGI_BUFFER_SIZE;
718 	cgi_info.input_len = cgi_info.error_len = 0;
719 
720 #ifdef CYGWIN
721 	if ((session->config->platform == windows) && ((session->cgi_type == fastcgi) || (session->cgi_type == script))) {
722 		if ((old_path = strdup(session->file_on_disk)) == NULL) {
723 			return -1;
724 		}
725 		if ((win32_path = strdup(cygwin_to_windows(old_path))) == NULL) {
726 			free(old_path);
727 			return -1;
728 		}
729 		free(session->file_on_disk);
730 		session->file_on_disk = win32_path;
731 		free(old_path);
732 	}
733 #endif
734 
735 #ifdef ENABLE_MONITOR
736 	if (session->config->monitor_enabled) {
737 		measure_runtime = gettimeofday(&tv_begin, &tz_begin) == 0;
738 	}
739 #endif
740 
741 	if (session->cgi_type == fastcgi) {
742 		cgi_info.read_header = true;
743 		if ((connect_to = select_connect_to(session->fcgi_server, &(session->ip_address))) == NULL) {
744 			return 503;
745 		} else if ((cgi_info.from_cgi = connect_to_fcgi_server(connect_to)) == -1) {
746 			connect_to->available = false;
747 			log_system(session->config, "can't connect to FastCGI server %s", session->fcgi_server->fcgi_id);
748 			return 503;
749 		} else {
750 			connect_to->available = true;
751 			if (send_fcgi_request(session, cgi_info.from_cgi) == -1) {
752 				log_error_session(session, "error while sending data to FastCGI server");
753 				return 500;
754 			}
755 		}
756 	} else {
757 		cgi_info.wrap_cgi = wrap_cgi;
758 		if ((cgi_pid = fork_cgi_process(session, &cgi_info)) == -1) {
759 			log_error_session(session, "error while forking CGI process");
760 			return 500;
761 		}
762 	}
763 
764 	if ((cgi_info.input_buffer = (char*)malloc(cgi_info.input_buffer_size + 1)) == NULL) {
765 		retval = -1;
766 	} else if ((cgi_info.error_buffer = (char*)malloc(cgi_info.error_buffer_size + 1)) == NULL) {
767 		free(cgi_info.input_buffer);
768 		retval = -1;
769 	}
770 
771 	if (retval != 200) {
772 		if (session->cgi_type == fastcgi) {
773 			close(cgi_info.from_cgi);
774 		} else {
775 			close(cgi_info.to_cgi);
776 			close(cgi_info.from_cgi);
777 			close(cgi_info.cgi_error);
778 		}
779 		return retval;
780 	}
781 
782 	cgi_info.deadline = session->time + session->host->time_for_cgi;
783 
784 	do {
785 		if (time(NULL) > cgi_info.deadline) {
786 			cgi_result = cgi_TIMEOUT;
787 		} else if (session->cgi_type == fastcgi) {
788 			cgi_result = read_from_fcgi_server(session, &cgi_info);
789 		} else {
790 			cgi_result = read_from_cgi_process(session, &cgi_info);
791 		}
792 
793 		switch (cgi_result) {
794 			case cgi_ERROR:
795 				log_error_session(session, "error while executing CGI");
796 				retval = 500;
797 				break;
798 			case cgi_TIMEOUT:
799 				log_error_session(session, "CGI application timeout");
800 				if (in_body) {
801 					retval = rs_DISCONNECT;
802 				} else {
803 					retval = 500;
804 				}
805 				if (session->config->kill_timedout_cgi && (session->cgi_type != fastcgi)) {
806 					if (kill(cgi_pid, SIGTERM) != -1) {
807 						sleep(1);
808 						kill(cgi_pid, SIGKILL);
809 					}
810 				}
811 #ifdef ENABLE_MONITOR
812 				if (session->config->monitor_enabled) {
813 					timed_out = true;
814 				}
815 #endif
816 				break;
817 			case cgi_FORCE_QUIT:
818 				retval = rs_FORCE_QUIT;
819 				break;
820 			case cgi_OKE:
821 				if (cgi_info.error_len > 0) {
822 					/* Error received from CGI
823 					 */
824 					*(cgi_info.error_buffer + cgi_info.error_len) = '\0';
825 					log_error_cgi(session, cgi_info.error_buffer);
826 					cgi_info.error_len = 0;
827 #ifdef ENABLE_MONITOR
828 					error_printed = true;
829 #endif
830 				}
831 
832 				if (cgi_info.input_len > 0) {
833 					/* Data received from CGI
834 					 */
835 					if (in_body) {
836 						/* Read content
837 						 */
838 						if (session->request_method != HEAD) {
839 							if (send_in_chunks) {
840 								result = send_chunk(session, cgi_info.input_buffer, cgi_info.input_len);
841 							} else {
842 								result = send_buffer(session, cgi_info.input_buffer, cgi_info.input_len);
843 							}
844 
845 							if (result == -1) {
846 								retval = rs_DISCONNECT;
847 							} else if (flush_after_send) {
848 								if (send_in_chunks) {
849 									result = send_chunk(session, NULL, -1);
850 								} else {
851 									result = send_buffer(session, NULL, 0);
852 								}
853 							}
854 						}
855 
856 #ifdef ENABLE_CACHE
857 						/* Add body content to cache buffer
858 						 */
859 						if ((cache_buffer != NULL) && (retval == 200)) {
860 							if ((off_t)(cache_size + cgi_info.input_len) > session->config->cache_max_filesize) {
861 								free(cache_buffer);
862 								cache_buffer = NULL;
863 							} else {
864 								memcpy(cache_buffer + cache_size, cgi_info.input_buffer, cgi_info.input_len);
865 								cache_size += cgi_info.input_len;
866 								*(cache_buffer + cache_size) = '\0';
867 							}
868 						}
869 #endif
870 						cgi_info.input_len = 0;
871 					} else {
872 						/* Read CGI header
873 						 */
874 						*(cgi_info.input_buffer + cgi_info.input_len) = '\0';
875 
876 						if ((end_of_header = strstr(cgi_info.input_buffer, "\r\n\r\n")) == NULL) {
877 							/* Fix crappy CGI headers
878 							 */
879 							if ((result = fix_crappy_cgi_headers(&cgi_info)) == -1) {
880 								log_error_session(session, "error fixing crappy CGI headers");
881 								retval = 500;
882 								break;
883 							} else if (result == 0) {
884 								end_of_header = strstr(cgi_info.input_buffer, "\r\n\r\n");
885 							}
886 						}
887 
888 						if (end_of_header != NULL) {
889 							return_code = 200;
890 
891 							if ((strncmp(cgi_info.input_buffer, "HTTP/1.0 ", 9) == 0) || (strncmp(cgi_info.input_buffer, "HTTP/1.1 ", 9) == 0)) {
892 								if ((str_end = strstr(cgi_info.input_buffer, "\r\n")) != NULL) {
893 									return_code = extract_http_code(cgi_info.input_buffer + 9);
894 
895 									delta = str_end - cgi_info.input_buffer + 2;
896 									memmove(cgi_info.input_buffer, cgi_info.input_buffer + delta, cgi_info.input_len - delta);
897 									cgi_info.input_len -= delta;
898 									end_of_header -= delta;
899 								}
900 							}
901 
902 							header_length = end_of_header + 4 - cgi_info.input_buffer;
903 
904 							if (return_code == 200) {
905 								if ((code = find_cgi_header(cgi_info.input_buffer, header_length, "Status:")) != NULL) {
906 									return_code = extract_http_code(code + 7);
907 								}
908 							}
909 
910 							if ((return_code <= 0) || (return_code > 999)) {
911 								log_error_session(session, "invalid status code received from CGI");
912 							} else if (return_code != 200) {
913 								session->return_code = return_code;
914 
915 								if (return_code == 500) {
916 									log_error_session(session, "CGI returned 500 Internal Error");
917 								}
918 								if (session->host->trigger_on_cgi_status) {
919 									retval = return_code;
920 									break;
921 								}
922 							}
923 
924 							if (session->throttle == 0) {
925 								if ((str_begin = find_cgi_header(cgi_info.input_buffer, header_length, hs_contyp)) != NULL) {
926 									if ((str_end = strchr(str_begin, '\r')) != NULL) {
927 										str_begin += 14;
928 										c = *str_end;
929 										*str_end = '\0';
930 										session->throttle = get_throttlespeed(str_begin, session->config->throttle);
931 										*str_end = c;
932 									}
933 								}
934 							}
935 
936 							if ((str = find_cgi_header(cgi_info.input_buffer, header_length, hs_conn)) != NULL) {
937 								if (strncmp(str + 12, hs_concl, 7) == 0) {
938 									session->keep_alive = false;
939 								}
940 
941 							}
942 
943 							/* Search for X-Hiawatha-Ban
944 							 */
945 							if (session->host->ban_by_cgi) {
946 								if (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny) {
947 									if ((str_begin = find_cgi_header(cgi_info.input_buffer, header_length, "X-Hiawatha-Ban:")) != NULL) {
948 										str_begin += 15;
949 										while (*str_begin == ' ') {
950 											str_begin++;
951 										}
952 
953 										str_end = str_begin;
954 										while ((*str_end != '\r') && (*str_end != '\0')) {
955 											str_end++;
956 										}
957 
958 										if (*str_end == '\r') {
959 											*str_end = '\0';
960 											value = str_to_int(str_begin);
961 											*str_end = '\r';
962 
963 											if (value > 0) {
964 												if ((session->host->ban_by_cgi_max > -1) && (value > session->host->ban_by_cgi_max)) {
965 													value = session->host->ban_by_cgi_max;
966 												}
967 
968 												ban_ip(&(session->ip_address), value, session->config->kick_on_ban);
969 												log_system_session(session, "Client banned for %d seconds by CGI %s", value, session->file_on_disk);
970 #ifdef ENABLE_MONITOR
971 												if (session->config->monitor_enabled) {
972 													monitor_count_ban(session);
973 												}
974 #endif
975 											}
976 										}
977 									}
978 								}
979 							}
980 
981 #ifdef ENABLE_MONITOR
982 							/* Log X-Hiawatha-Monitor header
983 							 */
984 							str = cgi_info.input_buffer;
985 							len = header_length;
986 							while ((event_key = find_cgi_header(str, len, "X-Hiawatha-Monitor:")) != NULL) {
987 								event_value = event_key + 19;
988 								while (*event_value == ' ') {
989 									event_value++;
990 								}
991 
992 								if ((event_end = strstr(event_value, "\r\n")) == NULL) {
993 									break;
994 								}
995 
996 								if (session->config->monitor_enabled) {
997 									*event_end = '\0';
998 									if (strcmp(event_value, "exploit_attempt") == 0) {
999 										monitor_count_exploit_attempt(session);
1000 										log_exploit_attempt(session, "reported by CGI", NULL);
1001 									} else if (strcmp(event_value, "failed_login") == 0) {
1002 										monitor_count_failed_login(session);
1003 										log_error_file(session, session->request_uri, "failed login");
1004 									} else {
1005 										monitor_event("%s", event_value);
1006 									}
1007 									*event_end = '\r';
1008 								}
1009 
1010 								event_end += 2;
1011 								memmove(event_key, event_end, cgi_info.input_len - (event_end - cgi_info.input_buffer));
1012 
1013 								diff = event_end - event_key;
1014 								header_length -= diff;
1015 								end_of_header -= diff;
1016 								cgi_info.input_len -= diff;
1017 
1018 								len = header_length - (str - cgi_info.input_buffer);
1019 							}
1020 #endif
1021 
1022 							/* Look for X-Sendfile header
1023 							 */
1024 							if ((sendfile = find_cgi_header(cgi_info.input_buffer, header_length, "X-Sendfile:")) != NULL) {
1025 								sendfile = sendfile + 11;
1026 								while (*sendfile == ' ') {
1027 									sendfile++;
1028 								}
1029 
1030 								if ((str = strstr(sendfile, "\r\n")) != NULL) {
1031 									*str = '\0';
1032 									sendfile = strdup(sendfile);
1033 									*str = '\r';
1034 								}
1035 
1036 								retval = rs_QUIT;
1037 								break;
1038 							}
1039 
1040 #ifdef ENABLE_CACHE
1041 							/* Look for store-in-cache CGI header
1042 							 */
1043 							if ((session->request_method == GET) && (skip_cache == false)) {
1044 								if ((cache_time = cgi_cache_time(cgi_info.input_buffer, header_length)) > 0) {
1045 									if ((cache_buffer = (char*)malloc(session->config->cache_max_filesize + 1)) != NULL) {
1046 										*(cache_buffer + session->config->cache_max_filesize) = '\0';
1047 									}
1048 								}
1049 							}
1050 
1051 							/* Look for remove-from-cache CGI header
1052 							 */
1053 							handle_remove_header_for_cgi_cache(session, cgi_info.input_buffer, header_length);
1054 #endif
1055 
1056 							/* Look for X-Accel-Buffering header
1057 							 */
1058 							if ((str = find_cgi_header(cgi_info.input_buffer, header_length, "X-Accel-Buffering:")) != NULL) {
1059 								str += 18;
1060 								while (*str == ' ') {
1061 									str++;
1062 								}
1063 
1064 								if (strncasecmp(str, "no\r\n", 4) == 0) {
1065 									flush_after_send = true;
1066 								}
1067 							}
1068 
1069 							if (find_cgi_header(cgi_info.input_buffer, header_length, "Date:") != NULL) {
1070 								session->send_date = false;
1071 							}
1072 
1073 							if (find_cgi_header(cgi_info.input_buffer, header_length, "Location:") != NULL) {
1074 								if (session->return_code == 200) {
1075 									session->return_code = 302;
1076 								}
1077 							}
1078 
1079 							/* Remove headers from CGI output
1080 							 */
1081 							while ((delta = remove_header(cgi_info.input_buffer, "X-Hiawatha-", &header_length, &(cgi_info.input_len))) > 0) {
1082 								end_of_header -= delta;
1083 							}
1084 							if ((delta = remove_header(cgi_info.input_buffer, "X-Sendfile:", &header_length, &(cgi_info.input_len))) > 0) {
1085 								end_of_header -= delta;
1086 							}
1087 							if ((delta = remove_header(cgi_info.input_buffer, "Status:", &header_length, &(cgi_info.input_len))) > 0) {
1088 								end_of_header -= delta;
1089 							}
1090 
1091 							if (send_header(session) == -1) {
1092 								retval = rs_DISCONNECT;
1093 								break;
1094 							}
1095 
1096 							if ((find_cgi_header(cgi_info.input_buffer, header_length, hs_conlen) != NULL) || (session->keep_alive == false)) {
1097 								send_in_chunks = false;
1098 							} else if (send_buffer(session, hs_chunked, 28) == -1) {
1099 								retval = rs_DISCONNECT;
1100 								break;
1101 							}
1102 
1103 							/* Send the header.
1104 							 */
1105 							end_of_header += 4;
1106 							len = end_of_header - cgi_info.input_buffer;
1107 							if (send_buffer(session, cgi_info.input_buffer, len) == -1) {
1108 								retval = rs_DISCONNECT;
1109 								break;
1110 							}
1111 							if (send_buffer(session, NULL, 0) == -1) {
1112 								retval = rs_DISCONNECT;
1113 								break;
1114 							}
1115 							session->header_sent = true;
1116 
1117 							/* Send first part of the body
1118 							 */
1119 							if (session->request_method != HEAD) {
1120 								if ((len = cgi_info.input_len - len) > 0) {
1121 									if (send_in_chunks) {
1122 										result = send_chunk(session, end_of_header, len);
1123 									} else {
1124 										result = send_buffer(session, end_of_header, len);
1125 									}
1126 									if (result == -1) {
1127 										retval = rs_DISCONNECT;
1128 										break;
1129 									}
1130 								}
1131 							}
1132 
1133 #ifdef ENABLE_CACHE
1134 							/* Add header to cache buffer
1135 							 */
1136 							if (cache_buffer != NULL) {
1137 								if ((off_t)(cache_size + cgi_info.input_len) > session->config->cache_max_filesize) {
1138 									clear_free(cache_buffer, cache_size);
1139 									cache_buffer = NULL;
1140 								} else {
1141 									memcpy(cache_buffer + cache_size, cgi_info.input_buffer, cgi_info.input_len);
1142 									cache_size += cgi_info.input_len;
1143 									*(cache_buffer + cache_size) = '\0';
1144 								}
1145 							}
1146 #endif
1147 
1148 							in_body = true;
1149 							cgi_info.input_len = 0;
1150 						} else if (cgi_info.input_len > MAX_OUTPUT_HEADER) {
1151 							log_error_session(session, "CGI header too large");
1152 							retval = 500;
1153 							break;
1154 						}
1155 					}
1156 				}
1157 				break;
1158 			case cgi_END_OF_DATA:
1159 				if (in_body) {
1160 					retval = rs_QUIT;
1161 					if (send_in_chunks && (session->request_method != HEAD)) {
1162 						if (send_chunk(session, NULL, 0) == -1) {
1163 							retval = rs_DISCONNECT;
1164 						}
1165 					}
1166 				} else {
1167 					retval = 500;
1168 					if (cgi_info.input_len == 0) {
1169 						log_error_session(session, "no output");
1170 					} else {
1171 						log_error_session(session, "CGI only printed a header, no content");
1172 					}
1173 				}
1174 		} /* switch */
1175 	} while (retval == 200);
1176 
1177 #ifdef ENABLE_MONITOR
1178 	if (session->config->monitor_enabled && measure_runtime) {
1179 		if (gettimeofday(&tv_end, &tz_end) == 0) {
1180 			runtime = tv_end.tv_sec - tv_begin.tv_sec;
1181 			if (tv_end.tv_usec < tv_begin.tv_usec) {
1182 				runtime--;
1183 			}
1184 			monitor_count_cgi(session, runtime, timed_out, error_printed);
1185 		}
1186 	}
1187 #endif
1188 
1189 	session->time = time(NULL);
1190 
1191 #ifdef ENABLE_CACHE
1192 	/* Add cache buffer to cache
1193 	 */
1194 	if (cache_buffer != NULL) {
1195 		if (retval == rs_QUIT) {
1196 			add_cgi_output_to_cache(session, cache_buffer, cache_size, cache_time);
1197 		}
1198 		clear_free(cache_buffer, cache_size);
1199 	}
1200 #endif
1201 
1202 	if (session->cgi_type == fastcgi) {
1203 		close(cgi_info.from_cgi);
1204 	} else {
1205 		close(cgi_info.to_cgi);
1206 		if (cgi_info.from_cgi != -1) {
1207 			close(cgi_info.from_cgi);
1208 		}
1209 		if (cgi_info.cgi_error != -1) {
1210 			close(cgi_info.cgi_error);
1211 		}
1212 	}
1213 
1214 	if (session->config->wait_for_cgi && (cgi_pid != -1)) {
1215 		waitpid(cgi_pid, NULL, 0);
1216 	}
1217 
1218 	switch (retval) {
1219 		case rs_DISCONNECT:
1220 		case rs_FORCE_QUIT:
1221 			session->keep_alive = false;
1222 		case rs_QUIT:
1223 			retval = 200;
1224 	}
1225 
1226 	clear_free(cgi_info.input_buffer, cgi_info.input_len);
1227 	clear_free(cgi_info.error_buffer, cgi_info.error_len);
1228 
1229 	if (sendfile != NULL) {
1230 		str = session->file_on_disk;
1231 		session->file_on_disk = sendfile;
1232 
1233 		if (get_target_extension(session) != -1) {
1234 			retval = send_file(session);
1235 		}
1236 
1237 		session->file_on_disk = str;
1238 
1239 		free(sendfile);
1240 	}
1241 
1242 	return retval;
1243 }
1244 
1245 /* Handle TRACE requests
1246  */
handle_trace_request(t_session * session)1247 int handle_trace_request(t_session *session) {
1248 	int code, body_size;
1249 	size_t len;
1250 	char buffer[MAX_TRACE_HEADER + 1];
1251 	t_http_header *header;
1252 
1253 #ifdef ENABLE_DEBUG
1254 	session->current_task = "handle TRACE";
1255 #endif
1256 
1257 	body_size = 3;
1258 	body_size += strlen(session->method) + session->uri_len;
1259 	if (session->vars != NULL) {
1260 		body_size += 1 + strlen(session->vars);
1261 	}
1262 	body_size += strlen(session->http_version);
1263 
1264 	header = session->http_headers;
1265 	while (header != NULL) {
1266 		body_size += header->length + 1;
1267 		header = header->next;
1268 	}
1269 
1270 	buffer[MAX_TRACE_HEADER] = '\0';
1271 
1272 	/* Header
1273 	 */
1274 	if (snprintf(buffer, MAX_TRACE_HEADER, "%d\r\nContent-Type: message/http\r\n\r\n", body_size) < 0) {
1275 		log_error_session(session, "snprintf() error");
1276 		return 500;
1277 	} else if (send_header(session) == -1) {
1278 		return -1;
1279 	} else if (send_buffer(session, hs_conlen, 16) == -1) {
1280 		return -1;
1281 	} else if (send_buffer(session, buffer, strlen(buffer)) == -1) {
1282 		return -1;
1283 	}
1284 	session->header_sent = true;
1285 
1286 	/* Body
1287 	 */
1288 	if ((code = snprintf(buffer, MAX_TRACE_HEADER, "%s %s", session->method, session->uri)) < 0) {
1289 		return -1;
1290 	} else if (code >= MAX_TRACE_HEADER) {
1291 		return -1;
1292 	} else if (session->vars != NULL) {
1293 		len = strlen(buffer);
1294 		if ((code = snprintf(buffer + len, MAX_TRACE_HEADER - len, "?%s", session->vars)) < 0) {
1295 			return -1;
1296 		} else if (code >= MAX_TRACE_HEADER) {
1297 			return -1;
1298 		}
1299 	}
1300 	len = strlen(buffer);
1301 	if ((code = snprintf(buffer + len, MAX_TRACE_HEADER - len, " %s\r\n", session->http_version)) < 0) {
1302 		return -1;
1303 	} else if (send_buffer(session, buffer, strlen(buffer)) == -1) {
1304 		return -1;
1305 	}
1306 
1307 	header = session->http_headers;
1308 	while (header != NULL) {
1309 		if (send_buffer(session, header->data, header->length) == -1) {
1310 			return -1;
1311 		} else if (send_buffer(session, "\n", 1) == -1) {
1312 			return -1;
1313 		}
1314 		header = header->next;
1315 	}
1316 
1317 	return 200;
1318 }
1319 
1320 /* Determine allowance of alter requests
1321  */
allow_alter(t_session * session)1322 static t_access allow_alter(t_session *session) {
1323 	t_ip_addr forwarded_ip;
1324 	t_access access;
1325 
1326 	if ((access = ip_allowed(&(session->ip_address), session->host->alter_list)) != allow) {
1327 		return access;
1328 	} else if (last_forwarded_ip(session->http_headers, &forwarded_ip) == -1) {
1329 		return allow;
1330 	} else if (ip_allowed(&forwarded_ip, session->host->alter_list) == deny) {
1331 		return deny;
1332 	}
1333 
1334 	return unspecified;
1335 }
1336 
1337 /* Handle PUT requests
1338  */
handle_put_request(t_session * session)1339 int handle_put_request(t_session *session) {
1340 	int auth_result, handle_write, handle_read = -1, result = -1, total_written = 0, lock_timeout;
1341 	off_t write_begin, write_end, total_size, file_size;
1342 	ssize_t bytes_read;
1343 	char *range, *value, *rest, *buffer;
1344 	bool range_found;
1345 	struct flock file_lock;
1346 
1347 #ifdef ENABLE_DEBUG
1348 	session->current_task = "handle PUT";
1349 #endif
1350 
1351 	if (session->uploaded_file == NULL) {
1352 		log_error_session(session, "no uploaded file available for PUT request");
1353 		return 500;
1354 	}
1355 
1356 	/* Access check
1357 	 */
1358 	switch (allow_alter(session)) {
1359 		case deny:
1360 		case unspecified:
1361 			log_error_session(session, fb_alterlist);
1362 			return 403;
1363 		case allow:
1364 			break;
1365 		case pwd:
1366 			if ((auth_result = http_authentication_result(session, false)) != 200) {
1367 				return auth_result;
1368 			}
1369 			if (group_oke(session, session->remote_user, &(session->host->alter_group)) == false) {
1370 				return 403;
1371 			}
1372 			break;
1373 	}
1374 
1375 	if (session->uri_is_dir) {
1376 		return 405;
1377 	}
1378 
1379 	range = get_http_header("Content-Range:", session->http_headers);
1380 	range_found = (range != NULL);
1381 
1382 	/* Open file for writing
1383 	 */
1384 	if ((handle_write = open(session->file_on_disk, O_WRONLY)) == -1) {
1385 		/* New file */
1386 		if (range_found) {
1387 			return 416;
1388 		}
1389 		if ((handle_write = open(session->file_on_disk, O_CREAT|O_WRONLY, session->host->alter_fmode)) == -1) {
1390 			log_error_session(session, fb_filesystem);
1391 			return 403;
1392 		}
1393 		file_size = NEW_FILE;
1394 		result = 201;
1395 	} else {
1396 		/* Existing file */
1397 		if ((file_size = filesize(session->file_on_disk)) == -1) {
1398 			close(handle_write);
1399 			log_error_session(session, "filesize() error");
1400 			return 500;
1401 		}
1402 		result = 204;
1403 	}
1404 
1405 	/* Lock file for writing
1406 	 */
1407 	file_lock.l_type = F_WRLCK;
1408 	file_lock.l_whence = SEEK_SET;
1409 	file_lock.l_start = 0;
1410 	file_lock.l_len = 0;
1411 	file_lock.l_pid = 0;
1412 	lock_timeout = WAIT_FOR_LOCK;
1413 
1414 	while (fcntl(handle_write, F_SETLK, &file_lock) == -1) {
1415 		if (errno == EINTR) {
1416 			continue;
1417 		} else if ((lock_timeout > 0) && ((errno == EACCES) || (errno == EAGAIN))) {
1418 			lock_timeout--;
1419 			sleep(1);
1420 		} else {
1421 			log_error_session(session, "can't lock file for writing (PUT)");
1422 			close(handle_write);
1423 			if (file_size == NEW_FILE) {
1424 				unlink(session->file_on_disk);
1425 			}
1426 			return 500;
1427 		}
1428 	}
1429 
1430 	file_lock.l_type = F_UNLCK;
1431 
1432 	/* Handle upload range
1433 	 */
1434 	if (range_found) {
1435 		if (strncmp(range, "bytes ", 6) != 0) {
1436 			result = 416;
1437 		} else {
1438 			if ((range = strdup(range + 6)) == NULL) {
1439 				result = -1;
1440 			} else if (split_string(range, &value, &rest, '-') == -1) {
1441 				result = 416;
1442 			} else if (strlen(value) > 9) {
1443 				result = 416;
1444 			} else if ((write_begin = str_to_int(value)) == -1) {
1445 				result = 416;
1446 			} else if (split_string(rest, &value, &rest, '/') == -1) {
1447 				result = 416;
1448 			} else if ((write_end = str_to_int(value)) == -1) {
1449 				result = 416;
1450 			} else if ((total_size = str_to_int(rest)) == -1) {
1451 				result = 416;
1452 			} else if (total_size != file_size) {
1453 				result = 416;
1454 			} else if (write_begin > write_end) {
1455 				result = 416;
1456 			} else if (write_begin > file_size) {
1457 				result = 416;
1458 			} else if (session->content_length != (write_end - write_begin + 1)) {
1459 				result = 416;
1460 			} else if (write_begin > 0) {
1461 				if (lseek(handle_write, write_begin, SEEK_SET) == -1) {
1462 					log_error_session(session, "lseek() error");
1463 					result = 500;
1464 				}
1465 			}
1466 
1467 			free(range);
1468 		}
1469 	}
1470 
1471 	/* Open temporary file for reading
1472 	 */
1473 	if ((result == 201) || (result == 204)) {
1474 		if ((handle_read = open(session->uploaded_file, O_RDONLY)) == -1) {
1475 			fcntl(handle_write, F_SETLK, &file_lock);
1476 			close(handle_write);
1477 			if (file_size == NEW_FILE) {
1478 				unlink(session->file_on_disk);
1479 			}
1480 			log_error_session(session, "can't open uploaded file of PUT request");
1481 			return 500;
1482 		}
1483 
1484 		if ((file_size != NEW_FILE) && (range_found == false)) {
1485 			if (ftruncate(handle_write, session->content_length) == -1) {
1486 				log_error_session(session, "ftruncate() error");
1487 				result = 500;
1488 			}
1489 		}
1490 
1491 		/* Write content
1492 		 */
1493 		if (result != 500) {
1494 			if ((buffer = (char*)malloc(FILE_BUFFER_SIZE)) != NULL) {
1495 				while (total_written < session->content_length) {
1496 					if ((bytes_read = read(handle_read, buffer, FILE_BUFFER_SIZE)) != -1) {
1497 						if (bytes_read == 0) {
1498 							break;
1499 						} else if (write_buffer(handle_write, buffer, bytes_read) != -1) {
1500 							total_written += bytes_read;
1501 						} else {
1502 							log_error_session(session, "error writing file of PUT request");
1503 							result = 500;
1504 							break;
1505 						}
1506 					} else if (errno != EINTR) {
1507 						log_error_session(session, "error reading file of PUT request");
1508 						result = 500;
1509 						break;
1510 					}
1511 				}
1512 				free(buffer);
1513 			} else {
1514 				log_error_session(session, "malloc() error for PUT request");
1515 				result = 500;
1516 			}
1517 		}
1518 	}
1519 
1520 	/* Finish upload
1521 	 */
1522 	if (handle_read != -1) {
1523 		close(handle_read);
1524 	}
1525 	fcntl(handle_write, F_SETLK, &file_lock);
1526 	fsync(handle_write);
1527 	close(handle_write);
1528 	if ((result != 201) && (result != 204) && (file_size == NEW_FILE)) {
1529 		unlink(session->file_on_disk);
1530 	}
1531 
1532 	return result;
1533 }
1534 
1535 /* Handle DELETE requests
1536  */
handle_delete_request(t_session * session)1537 int handle_delete_request(t_session *session) {
1538 	int auth_result;
1539 
1540 #ifdef ENABLE_DEBUG
1541 	session->current_task = "handle DELETE";
1542 #endif
1543 
1544 	/* Access check
1545 	 */
1546 	switch (allow_alter(session)) {
1547 		case deny:
1548 		case unspecified:
1549 			log_error_session(session, fb_alterlist);
1550 			return 403;
1551 		case allow:
1552 			break;
1553 		case pwd:
1554 			if ((auth_result = http_authentication_result(session, false)) != 200) {
1555 				return auth_result;
1556 			}
1557 			if (group_oke(session, session->remote_user, &(session->host->alter_group)) == false) {
1558 				return 403;
1559 			}
1560 			break;
1561 	}
1562 
1563 	/* Don't delete directories
1564 	 */
1565 	if (session->uri_is_dir) {
1566 		return 405;
1567 	}
1568 
1569 	/* Delete file
1570 	 */
1571 	if (unlink(session->file_on_disk) == -1) {
1572 		switch (errno) {
1573 			case EACCES:
1574 				log_error_session(session, fb_filesystem);
1575 				return 403;
1576 			case ENOENT:
1577 				return 404;
1578 			case EISDIR:
1579 			case ENOTDIR:
1580 				return 405;
1581 			default:
1582 				log_error_session(session, "error deleting file for DELETE request");
1583 				return 500;
1584 		}
1585 	}
1586 
1587 	return 204;
1588 }
1589 
1590 #ifdef ENABLE_XSLT
handle_xml_file(t_session * session,char * xslt_file)1591 int handle_xml_file(t_session *session, char *xslt_file) {
1592 	int handle;
1593 
1594 #ifdef ENABLE_DEBUG
1595 	session->current_task = "handle XML";
1596 #endif
1597 
1598 	if ((handle = open(session->file_on_disk, O_RDONLY)) == -1) {
1599 		if (errno == EACCES) {
1600 			log_error_session(session, fb_filesystem);
1601 			return 403;
1602 		}
1603 		return 404;
1604 	} else {
1605 		close(handle);
1606 	}
1607 
1608 	/* Symlink check
1609 	 */
1610 	if (session->host->follow_symlinks == false) {
1611 		switch (contains_not_allowed_symlink(session->file_on_disk, session->host->website_root)) {
1612 			case fb_error:
1613 				log_error_session(session, "error while scanning file for symlinks");
1614 				return 500;
1615 			case fb_not_found:
1616 				return 404;
1617 			case fb_no_access:
1618 			case fb_yes:
1619 				log_error_session(session, fb_symlink);
1620 				return 403;
1621 			case fb_no:
1622 				break;
1623 		}
1624 	}
1625 
1626 	return transform_xml(session, xslt_file);
1627 }
1628 #endif
1629 
1630 #ifdef ENABLE_RPROXY
find_chunk_size(char * buffer,int size,int * chunk_size,int * chunk_left)1631 static int find_chunk_size(char *buffer, int size, int *chunk_size, int *chunk_left) {
1632 	int total;
1633 	char *c;
1634 
1635 	if (*chunk_left > 0) {
1636 		if (*chunk_left >= size) {
1637 			*chunk_left -= size;
1638 			return 0;
1639 		}
1640 		buffer += *chunk_left;
1641 		size -= *chunk_left;
1642 		*chunk_left = 0;
1643 	}
1644 
1645 	if ((c = strstr(buffer, "\r\n")) == NULL) {
1646 		return -1;
1647 	} else if (c - buffer > 10) {
1648 		return -1;
1649 	}
1650 
1651 	*c = '\0';
1652 	*chunk_size = hex_to_int(buffer);
1653 	*c = '\r';
1654 
1655 	if (*chunk_size == -1) {
1656 		return -1;
1657 	} else if (*chunk_size == 0) {
1658 		return 0;
1659 	}
1660 
1661 	total = *chunk_size + 4 + (c - buffer);
1662 
1663 	if (total < size) {
1664 		return find_chunk_size(buffer + total, size - total, chunk_size, chunk_left);
1665 	}
1666 
1667 	if (total > size) {
1668 		*chunk_left = total - size;
1669 	}
1670 
1671 	return 0;
1672 }
1673 
proxy_request(t_session * session,t_rproxy * rproxy)1674 int proxy_request(t_session *session, t_rproxy *rproxy) {
1675 	t_rproxy_options options;
1676 	t_rproxy_webserver webserver;
1677 	t_rproxy_result rproxy_result;
1678 	char buffer[RPROXY_BUFFER_SIZE + 1], *end_of_header, *str, *eol;
1679 	char *reverse_proxy, ip_address[MAX_IP_STR_LEN + 1];
1680 	unsigned long bytes_in_buffer = 0;
1681 	int bytes_read, result = 200, code, poll_result, send_result, delta;
1682 	int content_length = -1, content_read = 0, chunk_size = 0, chunk_left = 0, header_length;
1683 	bool header_read = false, keep_reading, keep_alive, upgraded_to_websocket = false;
1684 	bool chunked_transfer = false, send_in_chunks = false;
1685 	struct pollfd poll_data[2];
1686 	time_t deadline;
1687 	t_stream stream1, stream2;
1688 #ifdef ENABLE_TLS
1689 	char *hostname;
1690 #endif
1691 #ifdef ENABLE_CACHE
1692 	t_cached_object *cached_object;
1693 	char *cache_buffer = NULL;
1694 	int  cache_size = 0, cache_time = 0;
1695 #endif
1696 
1697 #ifdef ENABLE_DEBUG
1698 	session->current_task = "proxy request";
1699 #endif
1700 
1701 #ifdef ENABLE_CACHE
1702 	/* Search for CGI output in cache
1703 	 */
1704 	if (session->request_method == GET) {
1705 		if ((cached_object = search_cache_for_rproxy_output(session)) != NULL) {
1706 			if (session->keep_alive) {
1707 				if (send_buffer(session, cached_object->header, cached_object->header_length) == -1) {
1708 					result = rs_DISCONNECT;
1709 				}
1710 			} else {
1711 				if (send_buffer(session, cached_object->header, cached_object->header_length - 2) == -1) {
1712 					result = rs_DISCONNECT;
1713 				} else if (send_buffer(session, hs_conn, 12) == -1) {
1714 					result = rs_DISCONNECT;
1715 				} else if (send_buffer(session, hs_concl, 7) == -1) {
1716 					result = rs_DISCONNECT;
1717 				} else if (send_buffer(session, "\r\n", 2) == -1) {
1718 					result = rs_DISCONNECT;
1719 				}
1720 			}
1721 
1722 			if (send_buffer(session, cached_object->content, cached_object->content_length) == -1) {
1723 				result = rs_DISCONNECT;
1724 			}
1725 
1726 			done_with_cached_object(cached_object, false);
1727 
1728 			return result;
1729 		}
1730 	}
1731 #endif
1732 
1733 	keep_alive = session->keep_alive && rproxy->keep_alive;
1734 
1735 	/* Intialize data structure
1736 	 */
1737 	options.client_socket = session->client_socket;
1738 	options.client_ip = &(session->ip_address);
1739 	options.port = session->binding->port;
1740 	options.method = session->method;
1741 	options.uri = session->uri;
1742 	options.vars = session->vars;
1743 	options.hostname = session->hostname;
1744 	options.http_headers = session->http_headers;
1745 	options.body = session->body;
1746 	options.uploaded_file = session->uploaded_file;
1747 	options.content_length = session->content_length;
1748 	options.remote_user = session->remote_user;
1749 	options.custom_headers = session->host->custom_headers_rproxy;
1750 #ifdef ENABLE_TLS
1751 	options.use_tls = session->binding->use_tls;
1752 #endif
1753 #ifdef ENABLE_CACHE
1754 	options.cache_extensions = &(session->config->cache_rproxy_extensions);
1755 #endif
1756 
1757 	init_rproxy_result(&rproxy_result);
1758 
1759 	if (session->rproxy_kept_alive && ((same_ip(&(session->rproxy_addr), &(rproxy->ip_addr)) == false) || (session->rproxy_port != rproxy->port))) {
1760 #ifdef ENABLE_TLS
1761 		if (session->rproxy_use_tls) {
1762 			tls_close(&(session->rproxy_tls));
1763 		}
1764 #endif
1765 		close(session->rproxy_socket);
1766 		session->rproxy_kept_alive = false;
1767 	}
1768 
1769 	/* Test if kept-alive connection is still alive
1770 	 */
1771 	if (session->rproxy_kept_alive) {
1772 		if (recv(session->rproxy_socket, buffer, 1, MSG_DONTWAIT | MSG_PEEK) == -1) {
1773 			if (errno != EAGAIN) {
1774 #ifdef ENABLE_TLS
1775 				if (session->rproxy_use_tls) {
1776 					tls_close(&(session->rproxy_tls));
1777 				}
1778 #endif
1779 				close(session->rproxy_socket);
1780 
1781 				session->rproxy_kept_alive = false;
1782 			}
1783 		}
1784 	}
1785 
1786 	if (session->rproxy_kept_alive) {
1787 		/* Use kept alive connection
1788 		 */
1789 		webserver.socket = session->rproxy_socket;
1790 #ifdef ENABLE_TLS
1791 		webserver.use_tls = session->rproxy_use_tls;
1792 
1793 		if (webserver.use_tls) {
1794 			memcpy(&(webserver.tls_context), &(session->rproxy_tls), sizeof(mbedtls_ssl_context));
1795 		}
1796 #endif
1797 	} else {
1798 		/* Connect to webserver
1799 		 */
1800 		if (rproxy->unix_socket != NULL) {
1801 			webserver.socket = connect_to_unix_socket(rproxy->unix_socket);
1802 		} else {
1803 			webserver.socket = connect_to_server(&(rproxy->ip_addr), rproxy->port);
1804 		}
1805 		if (webserver.socket == -1) {
1806 			log_error_session(session, "error connecting to reverse proxy");
1807 			return 503;
1808 		}
1809 
1810 #ifdef ENABLE_TLS
1811 		webserver.use_tls = rproxy->use_tls;
1812 
1813 		if (webserver.use_tls) {
1814 			hostname = rproxy->hostname != NULL ? rproxy->hostname : session->hostname;
1815 			if (tls_connect(&(webserver.tls_context), &(webserver.socket), hostname) != TLS_HANDSHAKE_OKE) {
1816 				log_error_session(session, "TLS handshake error with reverse proxy");
1817 				close(webserver.socket);
1818 				return 503;
1819 			}
1820 		}
1821 #endif
1822 	}
1823 
1824 	/* Send request to webserver
1825 	 */
1826 	if (send_request_to_webserver(&webserver, &options, rproxy, &rproxy_result, session->keep_alive) == -1) {
1827 		result = -1;
1828 	}
1829 	session->bytes_sent += rproxy_result.bytes_sent;
1830 
1831 	/* Read result from webserver and send to client
1832 	 */
1833 	deadline = time(NULL) + rproxy->timeout;
1834 
1835 	poll_data[0].fd = webserver.socket;
1836 	poll_data[0].events = POLL_EVENT_BITS;
1837 
1838 	keep_reading = true;
1839 
1840 	do {
1841 #ifdef ENABLE_TLS
1842 		poll_result = session->binding->use_tls ? tls_pending(&(session->tls_context)) : 0;
1843 
1844 		if (poll_result == 0)
1845 #endif
1846 			poll_result = poll(poll_data, 1, 1000);
1847 
1848 		switch (poll_result) {
1849 			case -1:
1850 				if (errno != EINTR) {
1851 					result = -1;
1852 					keep_reading = false;
1853 					keep_alive = false;
1854 					if (rproxy->hostname == NULL) {
1855 						ip_to_str(&(rproxy->ip_addr), ip_address, MAX_IP_STR_LEN);
1856 						reverse_proxy = ip_address;
1857 					} else {
1858 						reverse_proxy = rproxy->hostname;
1859 					}
1860 					log_error_session(session, "Reverse proxy connection error for %s", reverse_proxy);
1861 				}
1862 				break;
1863 			case 0:
1864 				if (time(NULL) > deadline) {
1865 					result = 504;
1866 					keep_reading = false;
1867 					keep_alive = false;
1868 					if (rproxy->hostname == NULL) {
1869 						ip_to_str(&(rproxy->ip_addr), ip_address, MAX_IP_STR_LEN);
1870 						reverse_proxy = ip_address;
1871 					} else {
1872 						reverse_proxy = rproxy->hostname;
1873 					}
1874 					log_error_session(session, "Reverse proxy timeout for %s", reverse_proxy);
1875 				}
1876 				break;
1877 			default:
1878 				if (RPROXY_BUFFER_SIZE - bytes_in_buffer > 0) {
1879 #ifdef ENABLE_TLS
1880 					if (webserver.use_tls) {
1881 						bytes_read = tls_receive(&(webserver.tls_context), buffer + bytes_in_buffer, RPROXY_BUFFER_SIZE - bytes_in_buffer);
1882 					} else
1883 #endif
1884 						bytes_read = read(webserver.socket, buffer + bytes_in_buffer, RPROXY_BUFFER_SIZE - bytes_in_buffer);
1885 				} else {
1886 					bytes_read = -1;
1887 				}
1888 
1889 				switch (bytes_read) {
1890 					case -1:
1891 						if (errno != EINTR) {
1892 							result = -1;
1893 							keep_reading = false;
1894 							keep_alive = false;
1895 							if (rproxy->hostname == NULL) {
1896 								ip_to_str(&(rproxy->ip_addr), ip_address, MAX_IP_STR_LEN);
1897 								reverse_proxy = ip_address;
1898 							} else {
1899 								reverse_proxy = rproxy->hostname;
1900 							}
1901 							log_error_session(session, "Reverse proxy read error for %s", reverse_proxy);
1902 						}
1903 						break;
1904 					case 0:
1905 						keep_reading = false;
1906 						break;
1907 					default:
1908 						/* Read first line and extract return code
1909 						 */
1910 						bytes_in_buffer += bytes_read;
1911 						*(buffer + bytes_in_buffer) = '\0';
1912 
1913 						if (header_read == false) {
1914 							/* Look for header
1915 							 */
1916 							if ((end_of_header = strstr(buffer, "\r\n\r\n")) != NULL) {
1917 								header_length = end_of_header + 4 - buffer;
1918 
1919 								if (strncmp(buffer, "HTTP/1.1 ", 9) != 0) {
1920 									if (strncmp(buffer, "HTTP/1.0 ", 9) != 0) {
1921 										result = 502;
1922 										keep_reading = false;
1923 										keep_alive = false;
1924 										break;
1925 									} else {
1926 										buffer[7] = '1';
1927 									}
1928 								}
1929 
1930 								if ((code = extract_http_code(buffer + 9)) != -1) {
1931 									session->return_code = code;
1932 								}
1933 
1934 								if ((code >= 300) && session->host->trigger_on_cgi_status) {
1935 									result = code;
1936 									keep_reading = false;
1937 									keep_alive = false;
1938 									break;
1939 								}
1940 
1941 #ifdef ENABLE_CACHE
1942 								if ((code == 200) && (session->request_method == GET)) {
1943 									if ((cache_time = rproxy_cache_time(session, buffer, header_length)) > 0) {
1944 										if ((cache_buffer = (char*)malloc(session->config->cache_max_filesize + 1)) != NULL) {
1945 											*(cache_buffer + session->config->cache_max_filesize) = '\0';
1946 										}
1947 									}
1948 								}
1949 
1950 								handle_remove_header_for_rproxy_cache(session, buffer, header_length);
1951 #endif
1952 
1953 								/* Check for close-connection
1954 								 */
1955 								if (session->keep_alive) {
1956 									if ((str = find_cgi_header(buffer, header_length, hs_conn)) != NULL) {
1957 										str += 12;
1958 										if (strncmp(str, "close\r\n", 7) == 0) {
1959 											keep_alive = false;
1960 										}
1961 									}
1962 								}
1963 
1964 								/* Check for WebSocket upgrade
1965 								 */
1966 								if (find_cgi_header(buffer, header_length, "Connection: upgrade") != NULL) {
1967 									if (find_cgi_header(buffer, header_length, upgrade_websocket) != NULL) {
1968 										upgraded_to_websocket = true;
1969 										keep_reading = false;
1970 									}
1971 								}
1972 
1973 								if (upgraded_to_websocket == false) {
1974 									delta = remove_header(buffer, hs_conn, &header_length, &bytes_in_buffer);
1975 									end_of_header -= delta;
1976 									bytes_read -= delta;
1977 								}
1978 
1979 								if ((session->request_method == HEAD) || empty_body_because_of_http_status(code)) {
1980 									content_length = 0;
1981 								} else if (keep_alive) {
1982 									/* Parse content length
1983 									 */
1984 									if ((str = find_cgi_header(buffer, header_length, hs_conlen)) != NULL) {
1985 										str += 16;
1986 										if ((eol = strchr(str, '\r')) != NULL) {
1987 											*eol = '\0';
1988 											content_length = str_to_int(str);
1989 											*eol = '\r';
1990 										}
1991 									}
1992 
1993 									/* Determine if is chunked transfer encoding
1994 									 */
1995 									if (find_cgi_header(buffer, header_length, hs_chunked) != NULL) {
1996 										chunked_transfer = true;
1997 										content_length = -1;
1998 										chunk_size = header_length;
1999 										chunk_left = chunk_size;
2000 									}
2001 								} else if (session->keep_alive &&
2002 								          (find_cgi_header(buffer, header_length, hs_conlen) == NULL) &&
2003 									      (find_cgi_header(buffer, header_length, hs_chunked) == NULL)) {
2004 									/* We need to forward result in chunks
2005 									 */
2006 									if (send_buffer(session, buffer, header_length - 2) == -1) {
2007 										result = -1;
2008 										keep_reading = false;
2009 										keep_alive = false;
2010 										break;
2011 									} else if (send_buffer(session, hs_chunked, 28) == -1) {
2012 										result = -1;
2013 										keep_reading = false;
2014 										keep_alive = false;
2015 										break;
2016 									} else if (send_buffer(session, "\r\n", 2) == -1) {
2017 										result = -1;
2018 										keep_reading = false;
2019 										keep_alive = false;
2020 										break;
2021 									} else if (send_buffer(session, NULL, 0) == -1) {
2022 										result = -1;
2023 										keep_reading = false;
2024 										keep_alive = false;
2025 										break;
2026 									}
2027 
2028 #ifdef ENABLE_CACHE
2029 									/* Add output to cache buffer
2030 									 */
2031 									if (cache_buffer != NULL) {
2032 										if ((off_t)(cache_size + header_length) > session->config->cache_max_filesize) {
2033 											clear_free(cache_buffer, cache_size);
2034 											cache_buffer = NULL;
2035 										} else {
2036 											memcpy(cache_buffer + cache_size, buffer, header_length);
2037 											cache_size += header_length;
2038 											*(cache_buffer + cache_size) = '\0';
2039 										}
2040 									}
2041 #endif
2042 
2043 									if ((content_read = bytes_in_buffer - header_length) > 0) {
2044 										memmove(buffer, end_of_header + 4, content_read);
2045 									}
2046 									bytes_in_buffer = content_read;
2047 									send_in_chunks = true;
2048 								}
2049 
2050 								if (send_in_chunks == false) {
2051 									content_read = bytes_in_buffer - header_length;
2052 								}
2053 
2054 								header_read = true;
2055 
2056 								if (bytes_in_buffer == 0) {
2057 									continue;
2058 								}
2059 							} else if (bytes_in_buffer == RPROXY_BUFFER_SIZE) {
2060 								result = -1;
2061 								keep_reading = false;
2062 								keep_alive = false;
2063 								break;
2064 							} else {
2065 								continue;
2066 							}
2067 						} else {
2068 							/* Dealing with body
2069 							 */
2070 							content_read += bytes_read;
2071 						}
2072 
2073 						if (content_read == content_length) {
2074 							keep_reading = false;
2075 						}
2076 
2077 						/* Send buffer content
2078 						 */
2079 						if (send_in_chunks) {
2080 							send_result = send_chunk(session, buffer, bytes_in_buffer);
2081 						} else {
2082 							send_result = send_buffer(session, buffer, bytes_in_buffer);
2083 						}
2084 
2085 						if (send_result == -1) {
2086 							result = -1;
2087 							keep_reading = false;
2088 							keep_alive = false;
2089 							break;
2090 						}
2091 
2092 #ifdef ENABLE_CACHE
2093 						/* Add output to cache buffer
2094 						 */
2095 						if (cache_buffer != NULL) {
2096 							if ((off_t)(cache_size + bytes_in_buffer) > session->config->cache_max_filesize) {
2097 								clear_free(cache_buffer, cache_size);
2098 								cache_buffer = NULL;
2099 							} else {
2100 								memcpy(cache_buffer + cache_size, buffer, bytes_in_buffer);
2101 								cache_size += bytes_in_buffer;
2102 								*(cache_buffer + cache_size) = '\0';
2103 							}
2104 						}
2105 #endif
2106 
2107 						if (chunked_transfer) {
2108 							if (find_chunk_size(buffer, bytes_in_buffer, &chunk_size, &chunk_left) == -1) {
2109 								keep_reading = false;
2110 								keep_alive = false;
2111 							} else if (chunk_size == 0) {
2112 								keep_reading = false;
2113 							}
2114 						}
2115 
2116 						bytes_in_buffer = 0;
2117 						session->data_sent = true;
2118 				}
2119 		}
2120 	} while (keep_reading);
2121 
2122 	if (send_in_chunks && ((result < 300) || (session->host->trigger_on_cgi_status == false))) {
2123 		send_chunk(session, NULL, 0);
2124 	}
2125 
2126 	if (upgraded_to_websocket) {
2127 		/* Connection upgraded to Websocket
2128 		 */
2129 		if (send_in_chunks == false) {
2130 			send_buffer(session, NULL, 0);
2131 		}
2132 
2133 		stream1.socket = webserver.socket;
2134 #ifdef ENABLE_TLS
2135 		stream1.use_tls = webserver.use_tls;
2136 		stream1.tls_context = &(webserver.tls_context);
2137 #endif
2138 
2139 		stream2.socket = session->client_socket;
2140 #ifdef ENABLE_TLS
2141 		stream2.use_tls = session->binding->use_tls;
2142 		stream2.tls_context = &(session->tls_context);
2143 #endif
2144 
2145 		result = link_streams(&stream1, &stream2, rproxy->timeout);
2146 
2147 		keep_alive = false;
2148 		session->return_code = 101;
2149 #ifdef ENABLE_CACHE
2150 		cache_buffer = NULL;
2151 #endif
2152 	}
2153 
2154 	session->time = time(NULL);
2155 
2156 #ifdef ENABLE_CACHE
2157 	if (cache_buffer != NULL) {
2158 		add_rproxy_output_to_cache(session, cache_buffer, cache_size, cache_time);
2159 		clear_free(cache_buffer, cache_size);
2160 	}
2161 #endif
2162 
2163 	if (keep_alive == false) {
2164 		/* Close connection to webserver
2165 		 */
2166 #ifdef ENABLE_TLS
2167 		if (webserver.use_tls) {
2168 			tls_close(&(webserver.tls_context));
2169 		}
2170 #endif
2171 		close(webserver.socket);
2172 	} else if (session->rproxy_kept_alive == false) {
2173 		/* Keep connection alive
2174 		 */
2175 		memcpy(&(session->rproxy_addr), &(rproxy->ip_addr), sizeof(t_ip_addr));
2176 		session->rproxy_port = rproxy->port;
2177 		session->rproxy_socket = webserver.socket;
2178 #ifdef ENABLE_TLS
2179 		session->rproxy_use_tls = webserver.use_tls;
2180 		if (session->rproxy_use_tls) {
2181 			memcpy(&(session->rproxy_tls), &(webserver.tls_context), sizeof(mbedtls_ssl_context));
2182 		}
2183 #endif
2184 	}
2185 
2186 	session->rproxy_kept_alive = keep_alive;
2187 
2188 	return result;
2189 }
2190 #endif
2191 
add_to_buffer(char * str,char * buffer,size_t * size,size_t max_size)2192 static int add_to_buffer(char *str, char *buffer, size_t *size, size_t max_size) {
2193 	size_t str_len;
2194 
2195 	str_len = strlen(str);
2196 	if (*size + str_len >= max_size) {
2197 		return -1;
2198 	}
2199 
2200 	memcpy(buffer + *size, str, str_len);
2201 	*size += str_len;
2202 	*(buffer + *size) = '\0';
2203 
2204 	return 0;
2205 }
2206 
forward_to_websocket(t_session * session)2207 int forward_to_websocket(t_session *session) {
2208 	t_websocket *ws;
2209 	int result = -1, ws_socket;
2210 	size_t size;
2211 	t_http_header *http_header;
2212 	char buffer[WS_BUFFER_SIZE];
2213 	t_stream stream1, stream2;
2214 #ifdef ENABLE_TLS
2215 	mbedtls_ssl_context ws_tls_context;
2216 #endif
2217 
2218 	ws = session->host->websockets;
2219 	while (ws != NULL) {
2220 		if (matches_charlist(session->uri, &(ws->path))) {
2221 			break;
2222 		} else if (in_charlist("*", &(ws->path))) {
2223 			break;
2224 		}
2225 		ws = ws->next;
2226 	}
2227 
2228 	if (ws == NULL) {
2229 		return -1;
2230 	}
2231 
2232 	if (ws->unix_socket != NULL) {
2233 		ws_socket = connect_to_unix_socket(ws->unix_socket);
2234 	} else {
2235 		ws_socket = connect_to_server(&(ws->ip_address), ws->port);
2236 	}
2237 
2238 	if (ws_socket == -1) {
2239 		log_error_session(session, "error connecting to websocket");
2240 		return 503;
2241 	}
2242 
2243 #ifdef ENABLE_TLS
2244 	if (ws->use_tls) {
2245 		if (tls_connect(&ws_tls_context, &ws_socket, NULL) != TLS_HANDSHAKE_OKE) {
2246 			log_error_session(session, "TLS handshake error with websocket");
2247 			close(ws_socket);
2248 			return -1;
2249 		}
2250 	}
2251 #endif
2252 
2253 	size = 0;
2254 	add_to_buffer("GET ", buffer, &size, WS_BUFFER_SIZE);
2255 	if (add_to_buffer(session->uri, buffer, &size, WS_BUFFER_SIZE) == -1) {
2256 		goto ws_error;
2257 	}
2258 
2259 	if (add_to_buffer(" HTTP/1.1\r\n", buffer, &size, WS_BUFFER_SIZE) == -1) {
2260 		goto ws_error;
2261 	}
2262 
2263 	http_header = session->http_headers;
2264 	while (http_header != NULL) {
2265 		if (add_to_buffer(http_header->data, buffer, &size, WS_BUFFER_SIZE) == -1) {
2266 			goto ws_error;
2267 		}
2268 
2269 		if (add_to_buffer("\r\n", buffer, &size, WS_BUFFER_SIZE) == -1) {
2270 			goto ws_error;
2271 		}
2272 
2273 		http_header = http_header->next;
2274 	}
2275 
2276 	if (add_to_buffer("\r\n", buffer, &size, WS_BUFFER_SIZE) == -1) {
2277 		goto ws_error;
2278 	}
2279 
2280 #ifdef ENABLE_TLS
2281 	if (ws->use_tls) {
2282 		if (tls_send_buffer(&ws_tls_context, buffer, size) == -1) {
2283 			goto ws_error;
2284 		}
2285 	} else
2286 #endif
2287 		if (write_buffer(ws_socket, buffer, size) == -1) {
2288 			goto ws_error;
2289 		}
2290 
2291 	stream1.socket = ws_socket;
2292 #ifdef ENABLE_TLS
2293 	stream1.use_tls = ws->use_tls;
2294 	stream1.tls_context = &ws_tls_context;
2295 #endif
2296 
2297 	stream2.socket = session->client_socket;
2298 #ifdef ENABLE_TLS
2299 	stream2.use_tls = session->binding->use_tls;
2300 	stream2.tls_context = &(session->tls_context);
2301 #endif
2302 
2303 	result = link_streams(&stream1, &stream2, ws->timeout);
2304 
2305 ws_error:
2306 #ifdef ENABLE_TLS
2307 	if (ws->use_tls) {
2308 		tls_close(&ws_tls_context);
2309 	}
2310 #endif
2311 	close(ws_socket);
2312 
2313 	return result;
2314 }
2315