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 <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <time.h>
17 #include <string.h>
18 #include <sys/socket.h>
19 #ifdef HAVE_NETINET_IN_H
20 #include <netinet/in.h>
21 #endif
22 #ifdef HAVE_ARPA_INET_H
23 #include <arpa/inet.h>
24 #endif
25 #include <pthread.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include "tls.h"
29 #include "libfs.h"
30 #include "libstr.h"
31 #include "liblist.h"
32 #include "http.h"
33 #include "log.h"
34 #include "send.h"
35 #include "serverconfig.h"
36 #include "tomahawk.h"
37 #include "memdbg.h"
38 
39 #define MAX_TO_BUFFER     1000
40 #define NONCE_DIGITS        10
41 #define TIMESTR_SIZE        64
42 #define FCGI_CHUNK_SIZE    (64 * KILOBYTE - 8)
43 #define STREAM_BUFFER_SIZE  32 * KILOBYTE
44 
45 char *hs_http10  = "HTTP/1.0 ";                  /*  9 */
46 char *hs_http11  = "HTTP/1.1 ";                  /*  9 */
47 char *hs_server  = "Server: ";                   /*  8 */
48 char *hs_conn    = "Connection: ";               /* 12 */
49 char *hs_concl   = "close\r\n";                  /*  7 */
50 char *hs_conka   = "keep-alive\r\n";             /* 12 */
51 char *hs_conup   = "upgrade\r\n";                /*  9 */
52 char *hs_contyp  = "Content-Type: ";             /* 14 */
53 char *hs_conlen  = "Content-Length: ";           /* 16 */
54 char *hs_lctn    = "Location: ";                 /* 10 */
55 char *hs_caco    = "Cache-Control: ";            /* 15 */
56 char *hs_public  = "public\r\n";                 /*  8 */
57 char *hs_private = "private\r\n";                /*  9 */
58 char *hs_expires = "Expires: ";                  /*  9 */
59 char *hs_http    = "http://";                    /*  7 */
60 char *hs_https   = "https://";                   /*  8 */
61 char *hs_hsts    = "Strict-Transport-Security: max-age="; /* 35 */
62 char *hs_range   = "Accept-Ranges: bytes\r\n";   /* 22 */
63 char *hs_gzip    = "Content-Encoding: gzip\r\n"; /* 24 */
64 char *hs_chunked = "Transfer-Encoding: chunked\r\n";  /* 28 */
65 char *hs_eol     = "\r\n";                       /*  2 */
66 char *hs_forwarded       = "Forwarded:";         /* 10 */
67 char *hs_x_forwarded_for = "X-Forwarded-For:";   /* 16 */
68 
69 char *unknown_http_code = "Unknown Error";
70 
71 static char *ec_doctype = "<!DOCTYPE html>\n";
72 static char *ec_head    = "<html>\n<head>\n<title>";
73 static char *ec_body1   = "</title>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<style type=\"text/css\">\n"
74                           "body { background-color:#d0d0d0; font-family:sans-serif; padding:0 30px }\n"
75                           "div { background-color:#f8f8f8; letter-spacing:4px; max-width:400px; margin:100px auto 0 auto; padding:50px; "
76                                 "border-radius:10px; border:1px solid #808080; box-shadow:8px 15px 20px #404040 }\n"
77                           "h1 { margin:0; font-size:22px; font-weight:normal }\n"
78                           "p { margin:10px 0 0 0; padding-top:2px; font-size:14px; color:#606060; border-top:1px solid #a0a0ff; "
79                               "text-align:right; font-weight:bold }\n"
80                           "@media (max-width:767px) { h1 { font-size:90%; letter-spacing:2px } p { font-size:70% } }\n"
81                           "</style>\n</head>\n<body>\n<div>\n<h1>";
82 static char *ec_body2   = "</h1>\n<p>";
83 static char *ec_tail    = "</p>\n</div>\n</body>\n</html>";
84 static int ec_doctype_len, ec_head_len, ec_body1_len, ec_body2_len, ec_tail_len;
85 
init_send_module(void)86 void init_send_module(void) {
87 	ec_doctype_len = strlen(ec_doctype);
88 	ec_head_len    = strlen(ec_head);
89 	ec_body1_len   = strlen(ec_body1);
90 	ec_body2_len   = strlen(ec_body2);
91 	ec_tail_len    = strlen(ec_tail);
92 }
93 
94 /* Send a char buffer to the client. Traffic throttling is handled here.
95  */
send_to_client(t_session * session,const char * buffer,int size)96 static int send_to_client(t_session *session, const char *buffer, int size) {
97 	int bytes_sent = 0, total_sent = 0, can_send, rest;
98 	time_t new_time;
99 
100 	/* Send buffer to browser.
101 	 */
102 	if (session->socket_open == false) {
103 		return -1;
104 	} else if ((buffer == NULL) || (size <= 0)) {
105 		return 0;
106 	}
107 
108 	if (session->directory != NULL) {
109 		if (session->directory->session_speed > 0) {
110 			session->throttle = session->directory->session_speed;
111 		}
112 	}
113 
114 	do {
115 		rest = size - total_sent;
116 		if (session->throttle > 0) {
117 			do {
118 				new_time = time(NULL);
119 				if (session->throttle_timer < new_time) {
120 					session->bytecounter = 0;
121 					session->throttle_timer = new_time;
122 				}
123 				can_send = session->throttle - session->bytecounter;
124 				if (can_send <= 0) {
125 					usleep(10000);
126 				}
127 			} while (can_send <= 0);
128 			if (can_send > rest) {
129 				can_send = rest;
130 			}
131 		} else {
132 			can_send = rest;
133 		}
134 
135 #ifdef ENABLE_TLS
136 		if (session->binding->use_tls) {
137 			if ((bytes_sent = tls_send(&(session->tls_context), (char*)(buffer + total_sent), can_send)) <= 0) {
138 				bytes_sent = -1;
139 			}
140 		} else
141 #endif
142 			if ((bytes_sent = send(session->client_socket, (char*)(buffer + total_sent), can_send, 0)) <= 0) {
143 				bytes_sent = -1;
144 			}
145 
146 		/* Handle read result
147 		 */
148 		if (bytes_sent == -1) {
149 			if (errno != EINTR) {
150 				if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
151 					if (session->config->log_timeouts) {
152 						log_error_session(session, "send timeout");
153 					}
154 				} else if ((errno != EPIPE) && (errno != ECONNRESET)) {
155 					log_error_session(session, "error while sending response");
156 				}
157 				close_socket(session);
158 				session->keep_alive = false;
159 				session->error_cause = ec_SOCKET_WRITE_ERROR;
160 				return -1;
161 			}
162 		} else {
163 			total_sent += bytes_sent;
164 			session->bytecounter += bytes_sent;
165 		}
166 	} while (total_sent < size);
167 #ifdef ENABLE_TOMAHAWK
168 	increment_transfer(TRANSFER_SEND, total_sent);
169 #endif
170 
171 	return 0;
172 }
173 
174 /* This function has been added to improve speed by buffering small amounts of data to be sent.
175  */
send_buffer(t_session * session,const char * buffer,int size)176 int send_buffer(t_session *session, const char *buffer, int size) {
177 	if (size > MAX_TO_BUFFER) {
178 		if (session->output_size > 0) {
179 			if (send_to_client(session, session->output_buffer, session->output_size) == -1) {
180 				return -1;
181 			}
182 			session->output_size = 0;
183 		}
184 		if (send_to_client(session, buffer, size) == -1) {
185 			return -1;
186 		}
187 	} else if (buffer == NULL) {
188 		if (session->output_size > 0) {
189 			if (send_to_client(session, session->output_buffer, session->output_size) == -1) {
190 				return -1;
191 			}
192 			session->output_size = 0;
193 		}
194 	} else {
195 		if ((session->output_size + size > OUTPUT_BUFFER_SIZE) && (session->output_size > 0)) {
196 			if (send_to_client(session, session->output_buffer, session->output_size) == -1) {
197 				return -1;
198 			}
199 			session->output_size = 0;
200 		}
201 
202 		memcpy(session->output_buffer + session->output_size, buffer, size);
203 		session->output_size += size;
204 	}
205 
206 	session->bytes_sent += size;
207 
208 	return 0;
209 }
210 
211 /* Send a HTTP header to the client. Header is not closed by this function.
212  */
send_header(t_session * session)213 int send_header(t_session *session) {
214 #ifdef ENABLE_TLS
215 	char random_header[MAX_RANDOM_HEADER_LENGTH + 13];
216 	char *rand_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789PR";
217 	unsigned long length, i;
218 	int random;
219 #endif
220 	char ecode[5], timestr[TIMESTR_SIZE];
221 	const char *emesg;
222 	time_t t;
223 	struct tm s;
224 	t_keyvalue *header;
225 
226 	/* Send HTTP header.
227 	 */
228 	ecode[4] = '\0';
229 	snprintf(ecode, 4, "%d", session->return_code);
230 	if ((emesg = http_error(session->return_code)) == NULL) {
231 		emesg = unknown_http_code;
232 	}
233 
234 	session->data_sent = true;
235 
236 	/* HTTP version
237 	 */
238 	if (session->http_version != NULL) {
239 		if (*(session->http_version + 7) == '0') {
240 			if (send_buffer(session, hs_http10, 9) == -1) {
241 				return -1;
242 			}
243 		} else {
244 			if (send_buffer(session, hs_http11, 9) == -1) {
245 				return -1;
246 			}
247 		}
248 	} else {
249 		if (send_buffer(session, hs_http11, 9) == -1) {
250 			return -1;
251 		}
252 	}
253 
254 	/* HTTP code
255 	 */
256 	if (send_buffer(session, ecode, 3) == -1) {
257 		return -1;
258 	} else if (send_buffer(session, " ", 1) == -1) {
259 		return -1;
260 	} else if (send_buffer(session, emesg, strlen(emesg)) == -1) {
261 		return -1;
262 	} else if (send_buffer(session, hs_eol, 2) == -1) {
263 		return -1;
264 	}
265 
266 	/* Date
267 	 */
268 	if (session->send_date) {
269 		if (time(&t) == -1) {
270 			return -1;
271 		} else if (gmtime_r(&t, &s) == NULL) {
272 			return -1;
273 		} else if (strftime(timestr, TIMESTR_SIZE, "%a, %d %b %Y %X GMT\r\n", &s) == 0) {
274 			return -1;
275 		} else if (send_buffer(session, "Date: ", 6) == -1) {
276 			return -1;
277 		} else if (send_buffer(session, timestr, strlen(timestr)) == -1) {
278 			return -1;
279 		}
280 	}
281 
282 	/* Server
283 	 */
284 	if (session->config->server_string != NULL) {
285 		if (send_buffer(session, hs_server, 8) == -1) {
286 			return -1;
287 		} else if (send_buffer(session, session->config->server_string, strlen(session->config->server_string)) == -1) {
288 			return -1;
289 		} else if (send_buffer(session, hs_eol, 2) == -1) {
290 			return -1;
291 		}
292 	}
293 
294 	/* Range
295 	 */
296 	if ((session->cgi_type == no_cgi) && (session->uri_is_dir == false)) {
297 		if (send_buffer(session, hs_range, 22) == -1) {
298 			return -1;
299 		}
300 	}
301 
302 	/* Connection
303 	 */
304 	if (send_buffer(session, hs_conn, 12) == -1) {
305 		return -1;
306 	} else if (session->keep_alive) {
307 		if (send_buffer(session, hs_conka, 12) == -1) {
308 			return -1;
309 		}
310 	} else if (send_buffer(session, hs_concl, 7) == -1) {
311 		return -1;
312 	}
313 
314 	/* Content-Encoding
315 	 */
316 	if (session->encode_gzip) {
317 		if (send_buffer(session, hs_gzip, 24) == -1) {
318 			return -1;
319 		}
320 	}
321 
322 	/* Content-Type
323 	 */
324 	if (session->mimetype != NULL) {
325 		if (send_buffer(session, hs_contyp, 14) == -1) {
326 			return -1;
327 		} else if (send_buffer(session, session->mimetype, strlen(session->mimetype)) == -1) {
328 			return -1;
329 		} else if (send_buffer(session, "\r\n", 2) == -1) {
330 			return -1;
331 		}
332 	}
333 
334 	/* Expires
335 	 */
336 	if (session->send_expires && (session->expires > -1) && (session->return_code == 200)) {
337 		if (time(&t) == -1) {
338 			return -1;
339 		}
340 		t += (time_t)session->expires;
341 
342 		if (gmtime_r(&t, &s) == NULL) {
343 			return -1;
344 		} else if (send_buffer(session, hs_caco, 15) == -1) {
345 			return -1;
346 		}
347 
348 		if (session->caco_private) {
349 			if (send_buffer(session, hs_private, 9) == -1) {
350 				return -1;
351 			}
352 		} else {
353 			if (send_buffer(session, hs_public, 8) == -1) {
354 				return -1;
355 			}
356 		}
357 
358 		if (send_buffer(session, hs_expires, 9) == -1) {
359 			return -1;
360 		} else if (strftime(timestr, TIMESTR_SIZE, "%a, %d %b %Y %X GMT\r\n", &s) == 0) {
361 			return -1;
362 		} else if (send_buffer(session, timestr, strlen(timestr)) == -1) {
363 			return -1;
364 		}
365 	}
366 
367 	/* Custom headers
368 	 */
369 	header = session->host->custom_headers_client;
370 	while (header != NULL) {
371 		if (send_buffer(session, header->key, strlen(header->key)) == -1) {
372 			return -1;
373 		} else if (send_buffer(session, ": ", 2) == -1) {
374 			return -1;
375 		} else if (send_buffer(session, header->value, strlen(header->value)) == -1) {
376 			return -1;
377 		} else if (send_buffer(session, "\r\n", 2) == -1) {
378 			return -1;
379 		}
380 
381 		header = header->next;
382 	}
383 
384 #ifdef ENABLE_TLS
385 	/* Random header
386 	 */
387 	if ((session->host->random_header_length > -1) && session->binding->use_tls) {
388 		sprintf(random_header, "X-Random: ");
389 		length = (session->host->random_header_length * ((unsigned int)rand() & MAX_RANDOM_HEADER_LENGTH_MASK)) / MAX_RANDOM_HEADER_LENGTH_MASK;
390 		if (length == 0) {
391 			length = 1;
392 		}
393 		sprintf(random_header + 10 + length, "\r\n");
394 
395 		random = rand() & 63;
396 		for (i = 0; i < length; i++) {
397 			random_header[10 + i] = rand_set[random];
398 		}
399 
400 		if (send_buffer(session, random_header, 12 + length) == -1) {
401 			return -1;
402 		}
403 	}
404 
405 	/* HTTP Strict Transport Security
406 	 */
407 	if ((session->host->hsts_time != NULL) && session->binding->use_tls) {
408 		if (send_buffer(session, hs_hsts, 35) == -1) {
409 			return -1;
410 		}
411 		if (send_buffer(session, session->host->hsts_time, strlen(session->host->hsts_time)) == -1) {
412 			return -1;
413 		}
414 		if (send_buffer(session, "\r\n", 2) == -1) {
415 			return -1;
416 		}
417 	}
418 
419 	/* HTTP Public Key Pinning
420 	 */
421 	if (session->binding->use_tls && (session->host->hpkp_data != NULL)) {
422 		if (session->host->hpkp_data->http_header != NULL) {
423 			send_buffer(session, session->host->hpkp_data->http_header, session->host->hpkp_data->header_size);
424 		}
425 	}
426 #endif
427 
428 	return 0;
429 }
430 
431 /* Send a datachunk to the client without buffering
432  */
send_chunk_to_client(t_session * session,const char * chunk,int size)433 static int send_chunk_to_client(t_session *session, const char *chunk, int size) {
434 	char hex[10];
435 
436 	if (session->keep_alive) {
437 		hex[9] = '\0';
438 		if (snprintf(hex, 9, "%x\r\n", size) < 0) {
439 			return -1;
440 		} else if (send_to_client(session, hex, strlen(hex)) == -1) {
441 			return -1;
442 		}
443 	}
444 
445 	if (send_to_client(session, chunk, size) == -1) {
446 		return -1;
447 	}
448 
449 	if (session->keep_alive) {
450 		if (send_to_client(session, "\r\n", 2) == -1) {
451 			return -1;
452 		}
453 	}
454 
455 	return 0;
456 }
457 
send_chunk(t_session * session,const char * chunk,int size)458 int send_chunk(t_session *session, const char *chunk, int size) {
459 	if (size > MAX_TO_BUFFER) {
460 		if (session->output_size > 0) {
461 			if (send_chunk_to_client(session, session->output_buffer, session->output_size) == -1) {
462 				return -1;
463 			}
464 			session->output_size = 0;
465 		}
466 		if (send_chunk_to_client(session, chunk, size) == -1) {
467 			return -1;
468 		}
469 	} else if (chunk == NULL) {
470 		if (session->output_size > 0) {
471 			if (send_chunk_to_client(session, session->output_buffer, session->output_size) == -1) {
472 				return -1;
473 			}
474 			session->output_size = 0;
475 		}
476 
477 		if (size == 0) {
478 			if (send_to_client(session, "0\r\n\r\n", 5) == -1) {
479 				return -1;
480 			}
481 		}
482 	} else {
483 		if ((session->output_size + size > OUTPUT_BUFFER_SIZE) && (session->output_size > 0)) {
484 			if (send_chunk_to_client(session, session->output_buffer, session->output_size) == -1) {
485 				return -1;
486 			}
487 			session->output_size = 0;
488 		}
489 
490 		memcpy(session->output_buffer + session->output_size, chunk, size);
491 		session->output_size += size;
492 	}
493 
494 	session->bytes_sent += size;
495 
496 	return 0;
497 }
498 
499 /* Send header of HTTP error message.
500  */
send_http_code_header(t_session * session)501 int send_http_code_header(t_session *session) {
502 	if (session->return_code == -1) {
503 		session->return_code = 500;
504 	}
505 
506 	session->encode_gzip = false;
507 	session->mimetype = NULL;
508 	if (send_header(session) == -1) {
509 		return -1;
510 	}
511 
512 	switch (session->return_code) {
513 		case 301:
514 		case 302:
515 		case 303:
516 		case 304:
517 		case 305:
518 		case 306:
519 		case 307:
520 		case 308:
521 			if (send_buffer(session, hs_lctn, 10) == -1) {
522 				return -1;
523 			}
524 
525 			if (session->cause_of_30x == enforce_first_hostname) {
526 #ifdef ENABLE_TLS
527 				if (session->binding->use_tls || session->host->require_tls) {
528 					if (send_buffer(session, hs_https, 8) == -1) {
529 						return -1;
530 					}
531 				} else
532 #endif
533 				if (send_buffer(session, hs_http, 7) == -1) {
534 					return -1;
535 				}
536 
537 				if (send_buffer(session, *(session->host->hostname.item), strlen(*(session->host->hostname.item))) == -1) {
538 					return -1;
539 				}
540 			}
541 
542 			if (session->cause_of_30x == location) {
543 				if (session->location != NULL) {
544 					if (send_buffer(session, session->location, strlen(session->location)) == -1) {
545 						return -1;
546 					}
547 				}
548 				if (send_buffer(session, "\r\n", 2) == -1) {
549 					return -1;
550 				}
551 				break;
552 			}
553 
554 #ifdef ENABLE_TLS
555 			if (session->cause_of_30x == require_tls) {
556 				if (send_buffer(session, hs_https, 8) == -1) {
557 					return -1;
558 				}
559 
560 				if (session->hostname != NULL) {
561 					if (send_buffer(session, session->hostname, strlen(session->hostname)) == -1) {
562 						return -1;
563 					}
564 				} else if (send_buffer(session, *(session->host->hostname.item), strlen(*(session->host->hostname.item))) == -1) {
565 					return -1;
566 				}
567 			}
568 #endif
569 
570 			if (send_buffer(session, session->uri, session->uri_len) == -1) {
571 				return -1;
572 			}
573 
574 			if (session->cause_of_30x == missing_slash) {
575 				if (send_buffer(session, "/", 1) == -1) {
576 					return -1;
577 				}
578 			}
579 			if (session->vars != NULL) {
580 				if (send_buffer(session, "?", 1) == -1) {
581 					return -1;
582 				} else if (send_buffer(session, session->vars, strlen(session->vars)) == -1) {
583 					return -1;
584 				}
585 			}
586 			if (send_buffer(session, "\r\n", 2) == -1) {
587 				return -1;
588 			}
589 			break;
590 		case 401:
591 			if (session->host->auth_method == basic) {
592 				if (send_basic_auth(session) == -1) {
593 					return -1;
594 				}
595 			} else {
596 				if (send_digest_auth(session) == -1) {
597 					return -1;
598 				}
599 			}
600 			break;
601 	}
602 
603 	return 0;
604 }
605 
606 /* Send body of HTTP error message
607  */
send_http_code_body(t_session * session)608 int send_http_code_body(t_session *session) {
609 	char ecode[5], len[10];
610 	const char *emesg;
611 	size_t ecode_len, emesg_len;
612 
613 	ecode[4] = '\0';
614 	snprintf(ecode, 4, "%d", session->return_code);
615 	ecode_len = strlen(ecode);
616 
617 	if ((emesg = http_error(session->return_code)) == NULL) {
618 		emesg = unknown_http_code;
619 	}
620 	emesg_len = strlen(emesg);
621 	len[9] = '\0';
622 	snprintf(len, 9, "%d", (int)((2 * emesg_len) + (2 * ecode_len) + 3 + ec_doctype_len + ec_head_len + ec_body1_len + ec_body2_len + ec_tail_len));
623 
624 	if (send_buffer(session, hs_conlen, 16) == -1) {
625 		return -1;
626 	} else if (send_buffer(session, len, strlen(len)) == -1) {
627 		return -1;
628 	} else if (send_buffer(session, "\r\n", 2) == -1) {
629 		return -1;
630 	} else if (send_buffer(session, hs_contyp, 14) == -1) {
631 		return -1;
632 	} else if (send_buffer(session, "text/html\r\n\r\n", 13) == -1) {
633 		return -1;
634 	}
635 	session->header_sent = true;
636 
637 	if (session->request_method == HEAD) {
638 		return 0;
639 	}
640 
641 	if (send_buffer(session, ec_doctype, ec_doctype_len) == -1) {
642 		return -1;
643 	} else if (send_buffer(session, ec_head, ec_head_len) == -1) {
644 		return -1;
645 	} else if (send_buffer(session, ecode, ecode_len) == -1) {
646 		return -1;
647 	} else if (send_buffer(session, " - ", 3) == -1) {
648 		return -1;
649 	} else if (send_buffer(session, emesg, emesg_len) == -1) {
650 		return -1;
651 	} else if (send_buffer(session,	ec_body1, ec_body1_len) == -1) {
652 		return -1;
653 	} else if (send_buffer(session, emesg, emesg_len) == -1) {
654 		return -1;
655 	} else if (send_buffer(session,	ec_body2, ec_body2_len) == -1) {
656 		return -1;
657 	} else if (send_buffer(session, ecode, ecode_len) == -1) {
658 		return -1;
659 	} else if (send_buffer(session, ec_tail, ec_tail_len) == -1) {
660 		return -1;
661 	}
662 
663 	return 0;
664 }
665 
fcgi_set_padding(t_fcgi_buffer * fcgi_buffer)666 static void fcgi_set_padding(t_fcgi_buffer *fcgi_buffer) {
667 	unsigned char padding;
668 
669 	if ((padding = fcgi_buffer->data[5] & 7) > 0) {
670 		padding = 8 - padding;
671 		memset(fcgi_buffer->data + fcgi_buffer->size, 0, (size_t)padding);
672 		fcgi_buffer->size += (long)padding;
673 	}
674 	fcgi_buffer->data[6] = padding;
675 }
676 
send_fcgi_buffer(t_fcgi_buffer * fcgi_buffer,const char * buffer,long size)677 int send_fcgi_buffer(t_fcgi_buffer *fcgi_buffer, const char *buffer, long size) {
678 	long written;
679 
680 	if (size > FCGI_BUFFER_SIZE) {
681 		if (fcgi_buffer->size > 0) {
682 			fcgi_set_padding(fcgi_buffer);
683 			if (write_buffer(fcgi_buffer->sock, (char*)fcgi_buffer->data, fcgi_buffer->size) == -1) {
684 				return -1;
685 			}
686 
687 			fcgi_buffer->size = 0;
688 		}
689 
690 		memcpy(fcgi_buffer->data, "\x01\x00\x00\x01" "\xff\xff\x00\x00", 8);
691 		fcgi_buffer->data[1] = fcgi_buffer->type;
692 		fcgi_buffer->data[4] = (FCGI_CHUNK_SIZE >> 8) & 255;
693 		fcgi_buffer->data[5] = FCGI_CHUNK_SIZE & 255;
694 
695 		written = 0;
696 		do {
697 			if (write_buffer(fcgi_buffer->sock, (char*)fcgi_buffer->data, 8) == -1) {
698 				return -1;
699 			} else if (write_buffer(fcgi_buffer->sock, buffer + written, FCGI_CHUNK_SIZE) == -1) {
700 				return -1;
701 			}
702 			written += FCGI_CHUNK_SIZE;
703 		} while (size - written > FCGI_BUFFER_SIZE);
704 
705 		if (send_fcgi_buffer(fcgi_buffer, buffer + written, size - written) == -1) {
706 			return -1;
707 		}
708 	} else if (buffer == NULL) {
709 		if (fcgi_buffer->size > 0) {
710 			fcgi_set_padding(fcgi_buffer);
711 			if (write_buffer(fcgi_buffer->sock, (char*)fcgi_buffer->data, fcgi_buffer->size) == -1) {
712 				return -1;
713 			}
714 		}
715 
716 		memcpy(fcgi_buffer->data, "\x01\x00\x00\x01" "\x00\x00\x00\x00", 8);
717 		fcgi_buffer->data[1] = fcgi_buffer->type;
718 		if (write_buffer(fcgi_buffer->sock, (char*)fcgi_buffer->data, 8) == -1) {
719 			return -1;
720 		}
721 
722 		fcgi_buffer->size = 0;
723 	} else {
724 		if ((fcgi_buffer->size + size > FCGI_BUFFER_SIZE) && (fcgi_buffer->size > 0)) {
725 			fcgi_set_padding(fcgi_buffer);
726 			if (write_buffer(fcgi_buffer->sock, (char*)fcgi_buffer->data, fcgi_buffer->size) == -1) {
727 				return -1;
728 			}
729 			fcgi_buffer->size = 0;
730 		}
731 
732 		if (fcgi_buffer->size == 0) {
733 			memcpy(fcgi_buffer->data, "\x01\x00\x00\x01" "\x00\x00\x00\x00", 8);
734 			fcgi_buffer->data[1] = fcgi_buffer->type;
735 			fcgi_buffer->size = 8;
736 		}
737 
738 		memcpy(fcgi_buffer->data + fcgi_buffer->size, buffer, size);
739 		fcgi_buffer->size += size;
740 		fcgi_buffer->data[4] = ((fcgi_buffer->size - 8) >> 8) & 255;
741 		fcgi_buffer->data[5] = (fcgi_buffer->size - 8) & 255;
742 	}
743 
744 	return 0;
745 }
746 
747 /* Send a Basic Authentication message to the client.
748  */
send_basic_auth(t_session * session)749 int send_basic_auth(t_session *session) {
750 	if (send_buffer(session, "WWW-Authenticate: Basic", 23) == -1) {
751 		return -1;
752 	} else if (session->host->login_message != NULL) {
753 		if (send_buffer(session, " realm=\"", 8) == -1) {
754 			return -1;
755 		} else if (send_buffer(session, session->host->login_message, strlen(session->host->login_message)) == -1) {
756 			return -1;
757 		} else if (send_buffer(session, "\"", 1) == -1) {
758 			return -1;
759 		}
760 	}
761 
762 	return send_buffer(session, "\r\n", 2);
763 }
764 
765 /* Send a Digest Authentication message to the client.
766  */
send_digest_auth(t_session * session)767 int send_digest_auth(t_session *session) {
768 	char nonce[2 * NONCE_DIGITS + 1];
769 	int i;
770 
771 	for (i = 0; i < NONCE_DIGITS; i++) {
772 		snprintf(nonce + (2 * i), 3, "%02hhX", (char)random());
773 	}
774 
775 	if (send_buffer(session, "WWW-Authenticate: Digest", 24) == -1) {
776 		return -1;
777 	} else if (session->host->login_message != NULL) {
778 		if (send_buffer(session, " realm=\"", 8) == -1) {
779 			return -1;
780 		} else if (send_buffer(session, session->host->login_message, strlen(session->host->login_message)) == -1) {
781 			return -1;
782 		} else if (send_buffer(session, "\"", 1) == -1) {
783 			return -1;
784 		}
785 	}
786 
787 	if (send_buffer(session, ", nonce=\"", 9) == -1) {
788 		return -1;
789 	} else if (send_buffer(session, nonce, 2 * NONCE_DIGITS) == -1) {
790 		return -1;
791 	}
792 
793 	return send_buffer(session, "\", algorithm=MD5\r\n", 18);
794 }
795 
796 /* Link two streams
797  */
link_streams(t_stream * stream1,t_stream * stream2,int poll_timeout)798 int link_streams(t_stream *stream1, t_stream *stream2, int poll_timeout) {
799 	struct pollfd poll_data[2];
800 	int result, poll_result, bytes_read;
801 	bool keep_reading;
802 	char buffer[STREAM_BUFFER_SIZE];
803 
804 	poll_data[0].fd = stream1->socket;
805 	poll_data[0].events = POLL_EVENT_BITS;
806 	poll_data[1].fd = stream2->socket;
807 	poll_data[1].events = POLL_EVENT_BITS;
808 
809 	result = 0;
810 	keep_reading = true;
811 	poll_timeout *= 1000;
812 
813 	/* Forward data
814 	 */
815 	do {
816 #ifdef ENABLE_TLS
817 		poll_result = stream1->use_tls ? tls_pending(stream1->tls_context) : 0;
818 		if (poll_result == 0) {
819 			poll_result = stream2->use_tls ? tls_pending(stream2->tls_context) : 0;
820 		}
821 
822 		if (poll_result == 0)
823 #endif
824 			poll_result = poll(poll_data, 2, poll_timeout);
825 
826 		switch (poll_result) {
827 			case -1:
828 				result = -1;
829 				keep_reading = false;
830 				break;
831 			case 0:
832 				result = 504;
833 				keep_reading = false;
834 				break;
835 			default:
836 				/* Data from stream1 to stream2
837 				 */
838 				if (poll_data[0].revents != 0) {
839 #ifdef ENABLE_TLS
840 					if (stream1->use_tls) {
841 						if ((bytes_read = tls_receive(stream1->tls_context, buffer, STREAM_BUFFER_SIZE)) == -1) {
842 							keep_reading = false;
843 							result = -1;
844 							break;
845 						}
846 					} else
847 #endif
848 						if ((bytes_read = read(stream1->socket, buffer, STREAM_BUFFER_SIZE)) == -1) {
849 							keep_reading = false;
850 							result = -1;
851 							break;
852 						}
853 
854 					if (bytes_read == 0) {
855 						keep_reading = false;
856 						break;
857 					}
858 
859 #ifdef ENABLE_TLS
860 					if (stream2->use_tls) {
861 						if (tls_send_buffer(stream2->tls_context, buffer, bytes_read) == -1) {
862 							keep_reading = false;
863 							result = -1;
864 							break;
865 						}
866 					} else
867 #endif
868 						if (write_buffer(stream2->socket, buffer, bytes_read) == -1) {
869 							keep_reading = false;
870 							result = -1;
871 							break;
872 						}
873 				}
874 
875 				/* Data from stream2 to stream1
876 				 */
877 				if (poll_data[1].revents != 0) {
878 #ifdef ENABLE_TLS
879 					if (stream2->use_tls) {
880 						if ((bytes_read = tls_receive(stream2->tls_context, buffer, STREAM_BUFFER_SIZE)) == -1) {
881 							keep_reading = false;
882 							result = -1;
883 							break;
884 						}
885 					} else
886 #endif
887 						if ((bytes_read = read(stream2->socket, buffer, STREAM_BUFFER_SIZE)) == -1) {
888 							keep_reading = false;
889 							result = -1;
890 							break;
891 						}
892 
893 					if (bytes_read == 0) {
894 						keep_reading = false;
895 						break;
896 					}
897 
898 #ifdef ENABLE_TLS
899 					if (stream1->use_tls) {
900 						if (tls_send_buffer(stream1->tls_context, buffer, bytes_read) == -1) {
901 							keep_reading = false;
902 							result = -1;
903 							break;
904 						}
905 					} else
906 #endif
907 						if (write_buffer(stream1->socket, buffer, bytes_read) == -1) {
908 							keep_reading = false;
909 							result = -1;
910 							break;
911 						}
912 				}
913 		}
914 	} while (keep_reading);
915 
916 	return result;
917 }
918