xref: /PHP-5.4/sapi/fpm/fpm/fastcgi.c (revision c0d060f5)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2014 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
16    +----------------------------------------------------------------------+
17 */
18 
19 /* $Id: fastcgi.c 287777 2009-08-26 19:17:32Z pajoye $ */
20 
21 #include "php.h"
22 #include "fastcgi.h"
23 
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <errno.h>
29 #include <limits.h>
30 
31 #include <php_config.h>
32 #include "fpm.h"
33 #include "fpm_request.h"
34 #include "zlog.h"
35 
36 #ifdef _WIN32
37 
38 #include <windows.h>
39 
40 	typedef unsigned int in_addr_t;
41 
42 	struct sockaddr_un {
43 		short   sun_family;
44 		char    sun_path[MAXPATHLEN];
45 	};
46 
47 	static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
48 	static int is_impersonate = 0;
49 
50 #define FCGI_LOCK(fd) \
51 	if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
52 		DWORD ret; \
53 		while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
54 			if (in_shutdown) return -1; \
55 		} \
56 		if (ret == WAIT_FAILED) { \
57 			fprintf(stderr, "WaitForSingleObject() failed\n"); \
58 			return -1; \
59 		} \
60 	}
61 
62 #define FCGI_UNLOCK(fd) \
63 	if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
64 		ReleaseMutex(fcgi_accept_mutex); \
65 	}
66 
67 #else
68 
69 # include <sys/types.h>
70 # include <sys/stat.h>
71 # include <unistd.h>
72 # include <fcntl.h>
73 # include <sys/socket.h>
74 # include <sys/un.h>
75 # include <netinet/in.h>
76 # include <arpa/inet.h>
77 # include <netdb.h>
78 # include <signal.h>
79 
80 # define closesocket(s) close(s)
81 
82 # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
83 #  include <sys/poll.h>
84 # endif
85 # if defined(HAVE_SYS_SELECT_H)
86 #  include <sys/select.h>
87 # endif
88 
89 #ifndef INADDR_NONE
90 #define INADDR_NONE ((unsigned long) -1)
91 #endif
92 
93 # ifndef HAVE_SOCKLEN_T
94 	typedef unsigned int socklen_t;
95 # endif
96 
97 # ifdef USE_LOCKING
98 #  define FCGI_LOCK(fd)								\
99 	do {											\
100 		struct flock lock;							\
101 		lock.l_type = F_WRLCK;						\
102 		lock.l_start = 0;							\
103 		lock.l_whence = SEEK_SET;					\
104 		lock.l_len = 0;								\
105 		if (fcntl(fd, F_SETLKW, &lock) != -1) {		\
106 			break;									\
107 		} else if (errno != EINTR || in_shutdown) {	\
108 			return -1;								\
109 		}											\
110 	} while (1)
111 
112 #  define FCGI_UNLOCK(fd)							\
113 	do {											\
114 		int orig_errno = errno;						\
115 		while (1) {									\
116 			struct flock lock;						\
117 			lock.l_type = F_UNLCK;					\
118 			lock.l_start = 0;						\
119 			lock.l_whence = SEEK_SET;				\
120 			lock.l_len = 0;							\
121 			if (fcntl(fd, F_SETLK, &lock) != -1) {	\
122 				break;								\
123 			} else if (errno != EINTR) {			\
124 				return -1;							\
125 			}										\
126 		}											\
127 		errno = orig_errno;							\
128 	} while (0)
129 # else
130 #  define FCGI_LOCK(fd)
131 #  define FCGI_UNLOCK(fd)
132 # endif
133 
134 #endif
135 
136 typedef union _sa_t {
137 	struct sockaddr     sa;
138 	struct sockaddr_un  sa_unix;
139 	struct sockaddr_in  sa_inet;
140 } sa_t;
141 
142 static HashTable fcgi_mgmt_vars;
143 
144 static int is_initialized = 0;
145 static int in_shutdown = 0;
146 static in_addr_t *allowed_clients = NULL;
147 
148 static sa_t client_sa;
149 
150 #ifdef _WIN32
151 
fcgi_shutdown_thread(LPVOID arg)152 static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
153 {
154 	HANDLE shutdown_event = (HANDLE) arg;
155 	WaitForSingleObject(shutdown_event, INFINITE);
156 	in_shutdown = 1;
157 	return 0;
158 }
159 
160 #else
161 
fcgi_signal_handler(int signo)162 static void fcgi_signal_handler(int signo)
163 {
164 	if (signo == SIGUSR1 || signo == SIGTERM) {
165 		in_shutdown = 1;
166 	}
167 }
168 
fcgi_setup_signals(void)169 static void fcgi_setup_signals(void)
170 {
171 	struct sigaction new_sa, old_sa;
172 
173 	sigemptyset(&new_sa.sa_mask);
174 	new_sa.sa_flags = 0;
175 	new_sa.sa_handler = fcgi_signal_handler;
176 	sigaction(SIGUSR1, &new_sa, NULL);
177 	sigaction(SIGTERM, &new_sa, NULL);
178 	sigaction(SIGPIPE, NULL, &old_sa);
179 	if (old_sa.sa_handler == SIG_DFL) {
180 		sigaction(SIGPIPE, &new_sa, NULL);
181 	}
182 }
183 #endif
184 
fcgi_init(void)185 int fcgi_init(void)
186 {
187 	if (!is_initialized) {
188 		zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
189 		fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS") - 1, "0", sizeof("0")-1);
190 
191 		is_initialized = 1;
192 #ifdef _WIN32
193 # if 0
194 		/* TODO: Support for TCP sockets */
195 		WSADATA wsaData;
196 
197 		if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
198 			fprintf(stderr, "Error starting Windows Sockets.  Error: %d", WSAGetLastError());
199 			return 0;
200 		}
201 # endif
202 		{
203 			char *str;
204 			DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
205 			HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
206 
207 			SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
208 
209 			str = getenv("_FCGI_SHUTDOWN_EVENT_");
210 			if (str != NULL) {
211 				HANDLE shutdown_event = (HANDLE) atoi(str);
212 				if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
213 				                  shutdown_event, 0, NULL)) {
214 					return -1;
215 				}
216 			}
217 			str = getenv("_FCGI_MUTEX_");
218 			if (str != NULL) {
219 				fcgi_accept_mutex = (HANDLE) atoi(str);
220 			}
221 			return 1;
222 		}
223 #else
224 		fcgi_setup_signals();
225 		return 1;
226 #endif
227 	}
228 	return 1;
229 }
230 
fcgi_set_in_shutdown(int new_value)231 void fcgi_set_in_shutdown(int new_value)
232 {
233 	in_shutdown = new_value;
234 }
235 
fcgi_shutdown(void)236 void fcgi_shutdown(void)
237 {
238 	if (is_initialized) {
239 		zend_hash_destroy(&fcgi_mgmt_vars);
240 	}
241 	if (allowed_clients) {
242 		free(allowed_clients);
243 	}
244 }
245 
fcgi_set_allowed_clients(char * ip)246 void fcgi_set_allowed_clients(char *ip)
247 {
248 	char *cur, *end;
249 	int n;
250 
251 	if (ip) {
252 		ip = strdup(ip);
253 		cur = ip;
254 		n = 0;
255 		while (*cur) {
256 			if (*cur == ',') n++;
257 			cur++;
258 		}
259 		if (allowed_clients) free(allowed_clients);
260 		allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
261 		n = 0;
262 		cur = ip;
263 		while (cur) {
264 			end = strchr(cur, ',');
265 			if (end) {
266 				*end = 0;
267 				end++;
268 			}
269 			allowed_clients[n] = inet_addr(cur);
270 			if (allowed_clients[n] == INADDR_NONE) {
271 				zlog(ZLOG_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
272 			}
273 			n++;
274 			cur = end;
275 		}
276 		allowed_clients[n] = INADDR_NONE;
277 		free(ip);
278 	}
279 }
280 
fcgi_init_request(fcgi_request * req,int listen_socket)281 void fcgi_init_request(fcgi_request *req, int listen_socket)
282 {
283 	memset(req, 0, sizeof(fcgi_request));
284 	req->listen_socket = listen_socket;
285 	req->fd = -1;
286 	req->id = -1;
287 
288 	req->in_len = 0;
289 	req->in_pad = 0;
290 
291 	req->out_hdr = NULL;
292 	req->out_pos = req->out_buf;
293 
294 #ifdef _WIN32
295 	req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
296 #endif
297 }
298 
safe_write(fcgi_request * req,const void * buf,size_t count)299 static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
300 {
301 	int    ret;
302 	size_t n = 0;
303 
304 	do {
305 		errno = 0;
306 #ifdef _WIN32
307 		if (!req->tcp) {
308 			ret = write(req->fd, ((char*)buf)+n, count-n);
309 		} else {
310 			ret = send(req->fd, ((char*)buf)+n, count-n, 0);
311 			if (ret <= 0) {
312 				errno = WSAGetLastError();
313 			}
314 		}
315 #else
316 		ret = write(req->fd, ((char*)buf)+n, count-n);
317 #endif
318 		if (ret > 0) {
319 			n += ret;
320 		} else if (ret <= 0 && errno != 0 && errno != EINTR) {
321 			return ret;
322 		}
323 	} while (n != count);
324 	return n;
325 }
326 
safe_read(fcgi_request * req,const void * buf,size_t count)327 static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
328 {
329 	int    ret;
330 	size_t n = 0;
331 
332 	do {
333 		errno = 0;
334 #ifdef _WIN32
335 		if (!req->tcp) {
336 			ret = read(req->fd, ((char*)buf)+n, count-n);
337 		} else {
338 			ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
339 			if (ret <= 0) {
340 				errno = WSAGetLastError();
341 			}
342 		}
343 #else
344 		ret = read(req->fd, ((char*)buf)+n, count-n);
345 #endif
346 		if (ret > 0) {
347 			n += ret;
348 		} else if (ret == 0 && errno == 0) {
349 			return n;
350 		} else if (ret <= 0 && errno != 0 && errno != EINTR) {
351 			return ret;
352 		}
353 	} while (n != count);
354 	return n;
355 }
356 
fcgi_make_header(fcgi_header * hdr,fcgi_request_type type,int req_id,int len)357 static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
358 {
359 	int pad = ((len + 7) & ~7) - len;
360 
361 	hdr->contentLengthB0 = (unsigned char)(len & 0xff);
362 	hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
363 	hdr->paddingLength = (unsigned char)pad;
364 	hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
365 	hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
366 	hdr->reserved = 0;
367 	hdr->type = type;
368 	hdr->version = FCGI_VERSION_1;
369 	if (pad) {
370 		memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
371 	}
372 	return pad;
373 }
374 
fcgi_get_params_len(int * result,unsigned char * p,unsigned char * end)375 static inline size_t fcgi_get_params_len( int *result, unsigned char *p, unsigned char *end)
376 {
377 	size_t ret = 0;
378 
379 	if (p < end) {
380 		*result = p[0];
381 		if (*result < 128) {
382 			ret = 1;
383 		}
384 		else if (p + 3 < end) {
385 			*result = ((*result & 0x7f) << 24);
386 			*result |= (p[1] << 16);
387 			*result |= (p[2] << 8);
388 			*result |= p[3];
389 			ret = 4;
390 		}
391 	}
392 	if (*result < 0) {
393 		ret = 0;
394 	}
395 	return ret;
396 }
397 
fcgi_param_get_eff_len(unsigned char * p,unsigned char * end,uint * eff_len)398 static inline int fcgi_param_get_eff_len( unsigned char *p, unsigned char *end, uint *eff_len)
399 {
400 	int ret = 1;
401 	int zero_found = 0;
402 	*eff_len = 0;
403 	for (; p != end; ++p) {
404 		if (*p == '\0') {
405 			zero_found = 1;
406 		}
407 		else {
408 			if (zero_found) {
409 				ret = 0;
410 				break;
411 			}
412 			if (*eff_len < ((uint)-1)) {
413 				++*eff_len;
414 			}
415 			else {
416 				ret = 0;
417 				break;
418 			}
419 		}
420 	}
421 	return ret;
422 }
423 
fcgi_get_params(fcgi_request * req,unsigned char * p,unsigned char * end)424 static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
425 {
426 	char buf[128];
427 	char *tmp = buf;
428 	size_t buf_size = sizeof(buf);
429 	int name_len = 0;
430 	int val_len = 0;
431 	uint eff_name_len = 0;
432 	char *s;
433 	int ret = 1;
434 	size_t bytes_consumed;
435 
436 	while (p < end) {
437 		bytes_consumed = fcgi_get_params_len(&name_len, p, end);
438 		if (!bytes_consumed) {
439 			/* Malformated request */
440 			ret = 0;
441 			break;
442 		}
443 		p += bytes_consumed;
444 		bytes_consumed = fcgi_get_params_len(&val_len, p, end);
445 		if (!bytes_consumed) {
446 			/* Malformated request */
447 			ret = 0;
448 			break;
449 		}
450 		p += bytes_consumed;
451 		if (name_len > (INT_MAX - val_len) || /* would the addition overflow? */
452 		    name_len + val_len > end - p) {   /* would we exceed the buffer? */
453 			/* Malformated request */
454 			ret = 0;
455 			break;
456 		}
457 
458 		/*
459 		 * get the effective length of the name in case it's not a valid string
460 		 * don't do this on the value because it can be binary data
461 		 */
462 		if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len)){
463 			/* Malicious request */
464 			ret = 0;
465 			break;
466 		}
467 		if (eff_name_len >= buf_size-1) {
468 			if (eff_name_len > ((uint)-1)-64) {
469 				ret = 0;
470 				break;
471 			}
472 			buf_size = eff_name_len + 64;
473 			tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
474 			if (tmp == NULL) {
475 				ret = 0;
476 				break;
477 			}
478 		}
479 		memcpy(tmp, p, eff_name_len);
480 		tmp[eff_name_len] = 0;
481 		s = estrndup((char*)p + name_len, val_len);
482 		if (s == NULL) {
483 			ret = 0;
484 			break;
485 		}
486 		zend_hash_update(req->env, tmp, eff_name_len+1, &s, sizeof(char*), NULL);
487 		p += name_len + val_len;
488 	}
489 	if (tmp != buf && tmp != NULL) {
490 		efree(tmp);
491 	}
492 	return ret;
493 }
494 
fcgi_free_var(char ** s)495 static void fcgi_free_var(char **s)
496 {
497 	efree(*s);
498 }
499 
fcgi_read_request(fcgi_request * req)500 static int fcgi_read_request(fcgi_request *req)
501 {
502 	fcgi_header hdr;
503 	int len, padding;
504 	unsigned char buf[FCGI_MAX_LENGTH+8];
505 
506 	req->keep = 0;
507 	req->closed = 0;
508 	req->in_len = 0;
509 	req->out_hdr = NULL;
510 	req->out_pos = req->out_buf;
511 	ALLOC_HASHTABLE(req->env);
512 	zend_hash_init(req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 0);
513 
514 	if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
515 	    hdr.version < FCGI_VERSION_1) {
516 		return 0;
517 	}
518 
519 	len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
520 	padding = hdr.paddingLength;
521 
522 	while (hdr.type == FCGI_STDIN && len == 0) {
523 		if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
524 		    hdr.version < FCGI_VERSION_1) {
525 			return 0;
526 		}
527 
528 		len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
529 		padding = hdr.paddingLength;
530 	}
531 
532 	if (len + padding > FCGI_MAX_LENGTH) {
533 		return 0;
534 	}
535 
536 	req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
537 
538 	if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
539 		char *val;
540 
541 		if (safe_read(req, buf, len+padding) != len+padding) {
542 			return 0;
543 		}
544 
545 		req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
546 		switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
547 			case FCGI_RESPONDER:
548 				val = estrdup("RESPONDER");
549 				zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
550 				break;
551 			case FCGI_AUTHORIZER:
552 				val = estrdup("AUTHORIZER");
553 				zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
554 				break;
555 			case FCGI_FILTER:
556 				val = estrdup("FILTER");
557 				zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
558 				break;
559 			default:
560 				return 0;
561 		}
562 
563 		if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
564 		    hdr.version < FCGI_VERSION_1) {
565 			return 0;
566 		}
567 
568 		len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
569 		padding = hdr.paddingLength;
570 
571 		while (hdr.type == FCGI_PARAMS && len > 0) {
572 			if (len + padding > FCGI_MAX_LENGTH) {
573 				return 0;
574 			}
575 
576 			if (safe_read(req, buf, len+padding) != len+padding) {
577 				req->keep = 0;
578 				return 0;
579 			}
580 
581 			if (!fcgi_get_params(req, buf, buf+len)) {
582 				req->keep = 0;
583 				return 0;
584 			}
585 
586 			if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
587 			    hdr.version < FCGI_VERSION_1) {
588 				req->keep = 0;
589 				return 0;
590 			}
591 			len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
592 			padding = hdr.paddingLength;
593 		}
594 	} else if (hdr.type == FCGI_GET_VALUES) {
595 		unsigned char *p = buf + sizeof(fcgi_header);
596 		HashPosition pos;
597 		char * str_index;
598 		uint str_length;
599 		ulong num_index;
600 		int key_type;
601 		zval ** value;
602 
603 		if (safe_read(req, buf, len+padding) != len+padding) {
604 			req->keep = 0;
605 			return 0;
606 		}
607 
608 		if (!fcgi_get_params(req, buf, buf+len)) {
609 			req->keep = 0;
610 			return 0;
611 		}
612 
613 		zend_hash_internal_pointer_reset_ex(req->env, &pos);
614 		while ((key_type = zend_hash_get_current_key_ex(req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
615 			int zlen;
616 			zend_hash_move_forward_ex(req->env, &pos);
617 			if (key_type != HASH_KEY_IS_STRING) {
618 				continue;
619 			}
620 			if (zend_hash_find(&fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
621 				continue;
622 			}
623 			--str_length;
624 			zlen = Z_STRLEN_PP(value);
625 			if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
626 				break;
627 			}
628 			if (str_length < 0x80) {
629 				*p++ = str_length;
630 			} else {
631 				*p++ = ((str_length >> 24) & 0xff) | 0x80;
632 				*p++ = (str_length >> 16) & 0xff;
633 				*p++ = (str_length >> 8) & 0xff;
634 				*p++ = str_length & 0xff;
635 			}
636 			if (zlen < 0x80) {
637 				*p++ = zlen;
638 			} else {
639 				*p++ = ((zlen >> 24) & 0xff) | 0x80;
640 				*p++ = (zlen >> 16) & 0xff;
641 				*p++ = (zlen >> 8) & 0xff;
642 				*p++ = zlen & 0xff;
643 			}
644 			memcpy(p, str_index, str_length);
645 			p += str_length;
646 			memcpy(p, Z_STRVAL_PP(value), zlen);
647 			p += zlen;
648 		}
649 		len = p - buf - sizeof(fcgi_header);
650 		len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
651 		if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
652 			req->keep = 0;
653 			return 0;
654 		}
655 		return 0;
656 	} else {
657 		return 0;
658 	}
659 
660 	return 1;
661 }
662 
fcgi_read(fcgi_request * req,char * str,int len)663 int fcgi_read(fcgi_request *req, char *str, int len)
664 {
665 	int ret, n, rest;
666 	fcgi_header hdr;
667 	unsigned char buf[255];
668 
669 	n = 0;
670 	rest = len;
671 	while (rest > 0) {
672 		if (req->in_len == 0) {
673 			if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
674 			    hdr.version < FCGI_VERSION_1 ||
675 			    hdr.type != FCGI_STDIN) {
676 				req->keep = 0;
677 				return 0;
678 			}
679 			req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
680 			req->in_pad = hdr.paddingLength;
681 			if (req->in_len == 0) {
682 				return n;
683 			}
684 		}
685 
686 		if (req->in_len >= rest) {
687 			ret = safe_read(req, str, rest);
688 		} else {
689 			ret = safe_read(req, str, req->in_len);
690 		}
691 		if (ret < 0) {
692 			req->keep = 0;
693 			return ret;
694 		} else if (ret > 0) {
695 			req->in_len -= ret;
696 			rest -= ret;
697 			n += ret;
698 			str += ret;
699 			if (req->in_len == 0) {
700 				if (req->in_pad) {
701 					if (safe_read(req, buf, req->in_pad) != req->in_pad) {
702 						req->keep = 0;
703 						return ret;
704 					}
705 				}
706 			} else {
707 				return n;
708 			}
709 		} else {
710 			return n;
711 		}
712 	}
713 	return n;
714 }
715 
fcgi_close(fcgi_request * req,int force,int destroy)716 void fcgi_close(fcgi_request *req, int force, int destroy)
717 {
718 	if (destroy && req->env) {
719 		zend_hash_destroy(req->env);
720 		FREE_HASHTABLE(req->env);
721 		req->env = NULL;
722 	}
723 
724 #ifdef _WIN32
725 	if (is_impersonate && !req->tcp) {
726 		RevertToSelf();
727 	}
728 #endif
729 
730 	if ((force || !req->keep) && req->fd >= 0) {
731 #ifdef _WIN32
732 		if (!req->tcp) {
733 			HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
734 
735 			if (!force) {
736 				FlushFileBuffers(pipe);
737 			}
738 			DisconnectNamedPipe(pipe);
739 		} else {
740 			if (!force) {
741 				char buf[8];
742 
743 				shutdown(req->fd, 1);
744 				while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
745 			}
746 			closesocket(req->fd);
747 		}
748 #else
749 		if (!force) {
750 			char buf[8];
751 
752 			shutdown(req->fd, 1);
753 			while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
754 		}
755 		close(req->fd);
756 #endif
757 		req->fd = -1;
758 		fpm_request_finished();
759 	}
760 }
761 
fcgi_accept_request(fcgi_request * req)762 int fcgi_accept_request(fcgi_request *req)
763 {
764 #ifdef _WIN32
765 	HANDLE pipe;
766 	OVERLAPPED ov;
767 #endif
768 
769 	while (1) {
770 		if (req->fd < 0) {
771 			while (1) {
772 				if (in_shutdown) {
773 					return -1;
774 				}
775 #ifdef _WIN32
776 				if (!req->tcp) {
777 					pipe = (HANDLE)_get_osfhandle(req->listen_socket);
778 					FCGI_LOCK(req->listen_socket);
779 					ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
780 					if (!ConnectNamedPipe(pipe, &ov)) {
781 						errno = GetLastError();
782 						if (errno == ERROR_IO_PENDING) {
783 							while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
784 								if (in_shutdown) {
785 									CloseHandle(ov.hEvent);
786 									FCGI_UNLOCK(req->listen_socket);
787 									return -1;
788 								}
789 							}
790 						} else if (errno != ERROR_PIPE_CONNECTED) {
791 						}
792 					}
793 					CloseHandle(ov.hEvent);
794 					req->fd = req->listen_socket;
795 					FCGI_UNLOCK(req->listen_socket);
796 				} else {
797 					SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
798 #else
799 				{
800 					int listen_socket = req->listen_socket;
801 #endif
802 					sa_t sa;
803 					socklen_t len = sizeof(sa);
804 
805 					fpm_request_accepting();
806 
807 					FCGI_LOCK(req->listen_socket);
808 					req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
809 					FCGI_UNLOCK(req->listen_socket);
810 
811 					client_sa = sa;
812 					if (sa.sa.sa_family == AF_INET && req->fd >= 0 && allowed_clients) {
813 						int n = 0;
814 						int allowed = 0;
815 
816 						while (allowed_clients[n] != INADDR_NONE) {
817 							if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
818 								allowed = 1;
819 								break;
820 							}
821 							n++;
822 						}
823 						if (!allowed) {
824 							zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", inet_ntoa(sa.sa_inet.sin_addr));
825 							closesocket(req->fd);
826 							req->fd = -1;
827 							continue;
828 						}
829 					}
830 				}
831 
832 #ifdef _WIN32
833 				if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
834 #else
835 				if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
836 #endif
837 					return -1;
838 				}
839 
840 #ifdef _WIN32
841 				break;
842 #else
843 				if (req->fd >= 0) {
844 #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
845 					struct pollfd fds;
846 					int ret;
847 
848 					fpm_request_reading_headers();
849 
850 					fds.fd = req->fd;
851 					fds.events = POLLIN;
852 					fds.revents = 0;
853 					do {
854 						errno = 0;
855 						ret = poll(&fds, 1, 5000);
856 					} while (ret < 0 && errno == EINTR);
857 					if (ret > 0 && (fds.revents & POLLIN)) {
858 						break;
859 					}
860 					fcgi_close(req, 1, 0);
861 #else
862 					fpm_request_reading_headers();
863 
864 					if (req->fd < FD_SETSIZE) {
865 						struct timeval tv = {5,0};
866 						fd_set set;
867 						int ret;
868 
869 						FD_ZERO(&set);
870 						FD_SET(req->fd, &set);
871 						do {
872 							errno = 0;
873 							ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
874 						} while (ret < 0 && errno == EINTR);
875 						if (ret > 0 && FD_ISSET(req->fd, &set)) {
876 							break;
877 						}
878 						fcgi_close(req, 1, 0);
879 					} else {
880 						zlog(ZLOG_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
881 						fcgi_close(req, 1, 0);
882 					}
883 #endif
884 				}
885 #endif
886 			}
887 		} else if (in_shutdown) {
888 			return -1;
889 		}
890 		if (fcgi_read_request(req)) {
891 #ifdef _WIN32
892 			if (is_impersonate && !req->tcp) {
893 				pipe = (HANDLE)_get_osfhandle(req->fd);
894 				if (!ImpersonateNamedPipeClient(pipe)) {
895 					fcgi_close(req, 1, 1);
896 					continue;
897 				}
898 			}
899 #endif
900 			return req->fd;
901 		} else {
902 			fcgi_close(req, 1, 1);
903 		}
904 	}
905 }
906 
907 static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
908 {
909 	req->out_hdr = (fcgi_header*) req->out_pos;
910 	req->out_hdr->type = type;
911 	req->out_pos += sizeof(fcgi_header);
912 	return req->out_hdr;
913 }
914 
915 static inline void close_packet(fcgi_request *req)
916 {
917 	if (req->out_hdr) {
918 		int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
919 
920 		req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
921 		req->out_hdr = NULL;
922 	}
923 }
924 
925 int fcgi_flush(fcgi_request *req, int close)
926 {
927 	int len;
928 
929 	close_packet(req);
930 
931 	len = req->out_pos - req->out_buf;
932 
933 	if (close) {
934 		fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
935 
936 		fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
937 		rec->body.appStatusB3 = 0;
938 		rec->body.appStatusB2 = 0;
939 		rec->body.appStatusB1 = 0;
940 		rec->body.appStatusB0 = 0;
941 		rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
942 		len += sizeof(fcgi_end_request_rec);
943 	}
944 
945 	if (safe_write(req, req->out_buf, len) != len) {
946 		req->keep = 0;
947 		return 0;
948 	}
949 
950 	req->out_pos = req->out_buf;
951 	return 1;
952 }
953 
954 ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
955 {
956 	int limit, rest;
957 
958 	if (len <= 0) {
959 		return 0;
960 	}
961 
962 	if (req->out_hdr && req->out_hdr->type != type) {
963 		close_packet(req);
964 	}
965 
966 	/* Optimized version */
967 	limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
968 	if (!req->out_hdr) {
969 		limit -= sizeof(fcgi_header);
970 		if (limit < 0) limit = 0;
971 	}
972 
973 	if (len < limit) {
974 		if (!req->out_hdr) {
975 			open_packet(req, type);
976 		}
977 		memcpy(req->out_pos, str, len);
978 		req->out_pos += len;
979 	} else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
980 		if (!req->out_hdr) {
981 			open_packet(req, type);
982 		}
983 		if (limit > 0) {
984 			memcpy(req->out_pos, str, limit);
985 			req->out_pos += limit;
986 		}
987 		if (!fcgi_flush(req, 0)) {
988 			return -1;
989 		}
990 		if (len > limit) {
991 			open_packet(req, type);
992 			memcpy(req->out_pos, str + limit, len - limit);
993 			req->out_pos += len - limit;
994 		}
995 	} else {
996 		int pos = 0;
997 		int pad;
998 
999 		close_packet(req);
1000 		while ((len - pos) > 0xffff) {
1001 			open_packet(req, type);
1002 			fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1003 			req->out_hdr = NULL;
1004 			if (!fcgi_flush(req, 0)) {
1005 				return -1;
1006 			}
1007 			if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1008 				req->keep = 0;
1009 				return -1;
1010 			}
1011 			pos += 0xfff8;
1012 		}
1013 
1014 		pad = (((len - pos) + 7) & ~7) - (len - pos);
1015 		rest = pad ? 8 - pad : 0;
1016 
1017 		open_packet(req, type);
1018 		fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1019 		req->out_hdr = NULL;
1020 		if (!fcgi_flush(req, 0)) {
1021 			return -1;
1022 		}
1023 		if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1024 			req->keep = 0;
1025 			return -1;
1026 		}
1027 		if (pad) {
1028 			open_packet(req, type);
1029 			memcpy(req->out_pos, str + len - rest,  rest);
1030 			req->out_pos += rest;
1031 		}
1032 	}
1033 
1034 	return len;
1035 }
1036 
1037 int fcgi_finish_request(fcgi_request *req, int force_close)
1038 {
1039 	int ret = 1;
1040 
1041 	if (req->fd >= 0) {
1042 		if (!req->closed) {
1043 			ret = fcgi_flush(req, 1);
1044 			req->closed = 1;
1045 		}
1046 		fcgi_close(req, force_close, 1);
1047 	}
1048 	return ret;
1049 }
1050 
1051 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1052 {
1053 	char **val;
1054 
1055 	if (!req) return NULL;
1056 
1057 	if (zend_hash_find(req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
1058 		return *val;
1059 	}
1060 	return NULL;
1061 }
1062 
1063 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1064 {
1065 	if (var && req) {
1066 		if (val == NULL) {
1067 			zend_hash_del(req->env, var, var_len+1);
1068 		} else {
1069 			char **ret;
1070 
1071 			val = estrdup(val);
1072 			if (zend_hash_update(req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
1073 				return *ret;
1074 			}
1075 		}
1076 	}
1077 	return NULL;
1078 }
1079 
1080 void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1081 {
1082 	zval * zvalue;
1083 	zvalue = pemalloc(sizeof(*zvalue), 1);
1084 	Z_TYPE_P(zvalue) = IS_STRING;
1085 	Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
1086 	Z_STRLEN_P(zvalue) = value_len;
1087 	zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
1088 }
1089 
1090 void fcgi_free_mgmt_var_cb(void * ptr)
1091 {
1092 	zval ** var = (zval **)ptr;
1093 	pefree(Z_STRVAL_PP(var), 1);
1094 	pefree(*var, 1);
1095 }
1096 
1097 char *fcgi_get_last_client_ip() /* {{{ */
1098 {
1099 	if (client_sa.sa.sa_family == AF_UNIX) {
1100 		return NULL;
1101 	}
1102 	return inet_ntoa(client_sa.sa_inet.sin_addr);
1103 }
1104 /* }}} */
1105 /*
1106  * Local variables:
1107  * tab-width: 4
1108  * c-basic-offset: 4
1109  * End:
1110  * vim600: sw=4 ts=4 fdm=marker
1111  * vim<600: sw=4 ts=4
1112  */
1113