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