xref: /PHP-5.3/sapi/fpm/fpm/fastcgi.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 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, val_len;
430 	uint eff_name_len;
431 	char *s;
432 	int ret = 1;
433 	size_t bytes_consumed;
434 
435 	while (p < end) {
436 		bytes_consumed = fcgi_get_params_len(&name_len, p, end);
437 		if (!bytes_consumed) {
438 			/* Malformated request */
439 			ret = 0;
440 			break;
441 		}
442 		p += bytes_consumed;
443 		bytes_consumed = fcgi_get_params_len(&val_len, p, end);
444 		if (!bytes_consumed) {
445 			/* Malformated request */
446 			ret = 0;
447 			break;
448 		}
449 		p += bytes_consumed;
450 		if (name_len > (INT_MAX - val_len) || /* would the addition overflow? */
451 		    name_len + val_len > end - p) {   /* would we exceed the buffer? */
452 			/* Malformated request */
453 			ret = 0;
454 			break;
455 		}
456 
457 		/*
458 		 * get the effective length of the name in case it's not a valid string
459 		 * don't do this on the value because it can be binary data
460 		 */
461 		if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len)){
462 			/* Malicious request */
463 			ret = 0;
464 			break;
465 		}
466 		if (eff_name_len >= buf_size-1) {
467 			if (eff_name_len > ((uint)-1)-64) {
468 				ret = 0;
469 				break;
470 			}
471 			buf_size = eff_name_len + 64;
472 			tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
473 			if (tmp == NULL) {
474 				ret = 0;
475 				break;
476 			}
477 		}
478 		memcpy(tmp, p, eff_name_len);
479 		tmp[eff_name_len] = 0;
480 		s = estrndup((char*)p + name_len, val_len);
481 		if (s == NULL) {
482 			ret = 0;
483 			break;
484 		}
485 		zend_hash_update(req->env, tmp, eff_name_len+1, &s, sizeof(char*), NULL);
486 		p += name_len + val_len;
487 	}
488 	if (tmp != buf && tmp != NULL) {
489 		efree(tmp);
490 	}
491 	return ret;
492 }
493 
fcgi_free_var(char ** s)494 static void fcgi_free_var(char **s)
495 {
496 	efree(*s);
497 }
498 
fcgi_read_request(fcgi_request * req)499 static int fcgi_read_request(fcgi_request *req)
500 {
501 	fcgi_header hdr;
502 	int len, padding;
503 	unsigned char buf[FCGI_MAX_LENGTH+8];
504 
505 	req->keep = 0;
506 	req->closed = 0;
507 	req->in_len = 0;
508 	req->out_hdr = NULL;
509 	req->out_pos = req->out_buf;
510 	ALLOC_HASHTABLE(req->env);
511 	zend_hash_init(req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 0);
512 
513 	if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
514 	    hdr.version < FCGI_VERSION_1) {
515 		return 0;
516 	}
517 
518 	len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
519 	padding = hdr.paddingLength;
520 
521 	while (hdr.type == FCGI_STDIN && len == 0) {
522 		if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
523 		    hdr.version < FCGI_VERSION_1) {
524 			return 0;
525 		}
526 
527 		len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
528 		padding = hdr.paddingLength;
529 	}
530 
531 	if (len + padding > FCGI_MAX_LENGTH) {
532 		return 0;
533 	}
534 
535 	req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
536 
537 	if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
538 		char *val;
539 
540 		if (safe_read(req, buf, len+padding) != len+padding) {
541 			return 0;
542 		}
543 
544 		req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
545 		switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
546 			case FCGI_RESPONDER:
547 				val = estrdup("RESPONDER");
548 				zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
549 				break;
550 			case FCGI_AUTHORIZER:
551 				val = estrdup("AUTHORIZER");
552 				zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
553 				break;
554 			case FCGI_FILTER:
555 				val = estrdup("FILTER");
556 				zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
557 				break;
558 			default:
559 				return 0;
560 		}
561 
562 		if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
563 		    hdr.version < FCGI_VERSION_1) {
564 			return 0;
565 		}
566 
567 		len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
568 		padding = hdr.paddingLength;
569 
570 		while (hdr.type == FCGI_PARAMS && len > 0) {
571 			if (len + padding > FCGI_MAX_LENGTH) {
572 				return 0;
573 			}
574 
575 			if (safe_read(req, buf, len+padding) != len+padding) {
576 				req->keep = 0;
577 				return 0;
578 			}
579 
580 			if (!fcgi_get_params(req, buf, buf+len)) {
581 				req->keep = 0;
582 				return 0;
583 			}
584 
585 			if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
586 			    hdr.version < FCGI_VERSION_1) {
587 				req->keep = 0;
588 				return 0;
589 			}
590 			len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
591 			padding = hdr.paddingLength;
592 		}
593 	} else if (hdr.type == FCGI_GET_VALUES) {
594 		unsigned char *p = buf + sizeof(fcgi_header);
595 		HashPosition pos;
596 		char * str_index;
597 		uint str_length;
598 		ulong num_index;
599 		int key_type;
600 		zval ** value;
601 
602 		if (safe_read(req, buf, len+padding) != len+padding) {
603 			req->keep = 0;
604 			return 0;
605 		}
606 
607 		if (!fcgi_get_params(req, buf, buf+len)) {
608 			req->keep = 0;
609 			return 0;
610 		}
611 
612 		zend_hash_internal_pointer_reset_ex(req->env, &pos);
613 		while ((key_type = zend_hash_get_current_key_ex(req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
614 			int zlen;
615 			zend_hash_move_forward_ex(req->env, &pos);
616 			if (key_type != HASH_KEY_IS_STRING) {
617 				continue;
618 			}
619 			if (zend_hash_find(&fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
620 				continue;
621 			}
622 			--str_length;
623 			zlen = Z_STRLEN_PP(value);
624 			if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
625 				break;
626 			}
627 			if (str_length < 0x80) {
628 				*p++ = str_length;
629 			} else {
630 				*p++ = ((str_length >> 24) & 0xff) | 0x80;
631 				*p++ = (str_length >> 16) & 0xff;
632 				*p++ = (str_length >> 8) & 0xff;
633 				*p++ = str_length & 0xff;
634 			}
635 			if (zlen < 0x80) {
636 				*p++ = zlen;
637 			} else {
638 				*p++ = ((zlen >> 24) & 0xff) | 0x80;
639 				*p++ = (zlen >> 16) & 0xff;
640 				*p++ = (zlen >> 8) & 0xff;
641 				*p++ = zlen & 0xff;
642 			}
643 			memcpy(p, str_index, str_length);
644 			p += str_length;
645 			memcpy(p, Z_STRVAL_PP(value), zlen);
646 			p += zlen;
647 		}
648 		len = p - buf - sizeof(fcgi_header);
649 		len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
650 		if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
651 			req->keep = 0;
652 			return 0;
653 		}
654 		return 0;
655 	} else {
656 		return 0;
657 	}
658 
659 	return 1;
660 }
661 
fcgi_read(fcgi_request * req,char * str,int len)662 int fcgi_read(fcgi_request *req, char *str, int len)
663 {
664 	int ret, n, rest;
665 	fcgi_header hdr;
666 	unsigned char buf[255];
667 
668 	n = 0;
669 	rest = len;
670 	while (rest > 0) {
671 		if (req->in_len == 0) {
672 			if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
673 			    hdr.version < FCGI_VERSION_1 ||
674 			    hdr.type != FCGI_STDIN) {
675 				req->keep = 0;
676 				return 0;
677 			}
678 			req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
679 			req->in_pad = hdr.paddingLength;
680 			if (req->in_len == 0) {
681 				return n;
682 			}
683 		}
684 
685 		if (req->in_len >= rest) {
686 			ret = safe_read(req, str, rest);
687 		} else {
688 			ret = safe_read(req, str, req->in_len);
689 		}
690 		if (ret < 0) {
691 			req->keep = 0;
692 			return ret;
693 		} else if (ret > 0) {
694 			req->in_len -= ret;
695 			rest -= ret;
696 			n += ret;
697 			str += ret;
698 			if (req->in_len == 0) {
699 				if (req->in_pad) {
700 					if (safe_read(req, buf, req->in_pad) != req->in_pad) {
701 						req->keep = 0;
702 						return ret;
703 					}
704 				}
705 			} else {
706 				return n;
707 			}
708 		} else {
709 			return n;
710 		}
711 	}
712 	return n;
713 }
714 
fcgi_close(fcgi_request * req,int force,int destroy)715 void fcgi_close(fcgi_request *req, int force, int destroy)
716 {
717 	if (destroy && req->env) {
718 		zend_hash_destroy(req->env);
719 		FREE_HASHTABLE(req->env);
720 		req->env = NULL;
721 	}
722 
723 #ifdef _WIN32
724 	if (is_impersonate && !req->tcp) {
725 		RevertToSelf();
726 	}
727 #endif
728 
729 	if ((force || !req->keep) && req->fd >= 0) {
730 #ifdef _WIN32
731 		if (!req->tcp) {
732 			HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
733 
734 			if (!force) {
735 				FlushFileBuffers(pipe);
736 			}
737 			DisconnectNamedPipe(pipe);
738 		} else {
739 			if (!force) {
740 				char buf[8];
741 
742 				shutdown(req->fd, 1);
743 				while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
744 			}
745 			closesocket(req->fd);
746 		}
747 #else
748 		if (!force) {
749 			char buf[8];
750 
751 			shutdown(req->fd, 1);
752 			while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
753 		}
754 		close(req->fd);
755 #endif
756 		req->fd = -1;
757 		fpm_request_finished();
758 	}
759 }
760 
fcgi_accept_request(fcgi_request * req)761 int fcgi_accept_request(fcgi_request *req)
762 {
763 #ifdef _WIN32
764 	HANDLE pipe;
765 	OVERLAPPED ov;
766 #endif
767 
768 	while (1) {
769 		if (req->fd < 0) {
770 			while (1) {
771 				if (in_shutdown) {
772 					return -1;
773 				}
774 #ifdef _WIN32
775 				if (!req->tcp) {
776 					pipe = (HANDLE)_get_osfhandle(req->listen_socket);
777 					FCGI_LOCK(req->listen_socket);
778 					ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
779 					if (!ConnectNamedPipe(pipe, &ov)) {
780 						errno = GetLastError();
781 						if (errno == ERROR_IO_PENDING) {
782 							while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
783 								if (in_shutdown) {
784 									CloseHandle(ov.hEvent);
785 									FCGI_UNLOCK(req->listen_socket);
786 									return -1;
787 								}
788 							}
789 						} else if (errno != ERROR_PIPE_CONNECTED) {
790 						}
791 					}
792 					CloseHandle(ov.hEvent);
793 					req->fd = req->listen_socket;
794 					FCGI_UNLOCK(req->listen_socket);
795 				} else {
796 					SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
797 #else
798 				{
799 					int listen_socket = req->listen_socket;
800 #endif
801 					sa_t sa;
802 					socklen_t len = sizeof(sa);
803 
804 					fpm_request_accepting();
805 
806 					FCGI_LOCK(req->listen_socket);
807 					req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
808 					FCGI_UNLOCK(req->listen_socket);
809 
810 					client_sa = sa;
811 					if (sa.sa.sa_family == AF_INET && req->fd >= 0 && allowed_clients) {
812 						int n = 0;
813 						int allowed = 0;
814 
815 						while (allowed_clients[n] != INADDR_NONE) {
816 							if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
817 								allowed = 1;
818 								break;
819 							}
820 							n++;
821 						}
822 						if (!allowed) {
823 							zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", inet_ntoa(sa.sa_inet.sin_addr));
824 							closesocket(req->fd);
825 							req->fd = -1;
826 							continue;
827 						}
828 					}
829 				}
830 
831 #ifdef _WIN32
832 				if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
833 #else
834 				if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
835 #endif
836 					return -1;
837 				}
838 
839 #ifdef _WIN32
840 				break;
841 #else
842 				if (req->fd >= 0) {
843 #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
844 					struct pollfd fds;
845 					int ret;
846 
847 					fpm_request_reading_headers();
848 
849 					fds.fd = req->fd;
850 					fds.events = POLLIN;
851 					fds.revents = 0;
852 					do {
853 						errno = 0;
854 						ret = poll(&fds, 1, 5000);
855 					} while (ret < 0 && errno == EINTR);
856 					if (ret > 0 && (fds.revents & POLLIN)) {
857 						break;
858 					}
859 					fcgi_close(req, 1, 0);
860 #else
861 					fpm_request_reading_headers();
862 
863 					if (req->fd < FD_SETSIZE) {
864 						struct timeval tv = {5,0};
865 						fd_set set;
866 						int ret;
867 
868 						FD_ZERO(&set);
869 						FD_SET(req->fd, &set);
870 						do {
871 							errno = 0;
872 							ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
873 						} while (ret < 0 && errno == EINTR);
874 						if (ret > 0 && FD_ISSET(req->fd, &set)) {
875 							break;
876 						}
877 						fcgi_close(req, 1, 0);
878 					} else {
879 						zlog(ZLOG_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
880 						fcgi_close(req, 1, 0);
881 					}
882 #endif
883 				}
884 #endif
885 			}
886 		} else if (in_shutdown) {
887 			return -1;
888 		}
889 		if (fcgi_read_request(req)) {
890 #ifdef _WIN32
891 			if (is_impersonate && !req->tcp) {
892 				pipe = (HANDLE)_get_osfhandle(req->fd);
893 				if (!ImpersonateNamedPipeClient(pipe)) {
894 					fcgi_close(req, 1, 1);
895 					continue;
896 				}
897 			}
898 #endif
899 			return req->fd;
900 		} else {
901 			fcgi_close(req, 1, 1);
902 		}
903 	}
904 }
905 
906 static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
907 {
908 	req->out_hdr = (fcgi_header*) req->out_pos;
909 	req->out_hdr->type = type;
910 	req->out_pos += sizeof(fcgi_header);
911 	return req->out_hdr;
912 }
913 
914 static inline void close_packet(fcgi_request *req)
915 {
916 	if (req->out_hdr) {
917 		int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
918 
919 		req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
920 		req->out_hdr = NULL;
921 	}
922 }
923 
924 int fcgi_flush(fcgi_request *req, int close)
925 {
926 	int len;
927 
928 	close_packet(req);
929 
930 	len = req->out_pos - req->out_buf;
931 
932 	if (close) {
933 		fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
934 
935 		fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
936 		rec->body.appStatusB3 = 0;
937 		rec->body.appStatusB2 = 0;
938 		rec->body.appStatusB1 = 0;
939 		rec->body.appStatusB0 = 0;
940 		rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
941 		len += sizeof(fcgi_end_request_rec);
942 	}
943 
944 	if (safe_write(req, req->out_buf, len) != len) {
945 		req->keep = 0;
946 		return 0;
947 	}
948 
949 	req->out_pos = req->out_buf;
950 	return 1;
951 }
952 
953 ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
954 {
955 	int limit, rest;
956 
957 	if (len <= 0) {
958 		return 0;
959 	}
960 
961 	if (req->out_hdr && req->out_hdr->type != type) {
962 		close_packet(req);
963 	}
964 
965 	/* Optimized version */
966 	limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
967 	if (!req->out_hdr) {
968 		limit -= sizeof(fcgi_header);
969 		if (limit < 0) limit = 0;
970 	}
971 
972 	if (len < limit) {
973 		if (!req->out_hdr) {
974 			open_packet(req, type);
975 		}
976 		memcpy(req->out_pos, str, len);
977 		req->out_pos += len;
978 	} else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
979 		if (!req->out_hdr) {
980 			open_packet(req, type);
981 		}
982 		if (limit > 0) {
983 			memcpy(req->out_pos, str, limit);
984 			req->out_pos += limit;
985 		}
986 		if (!fcgi_flush(req, 0)) {
987 			return -1;
988 		}
989 		if (len > limit) {
990 			open_packet(req, type);
991 			memcpy(req->out_pos, str + limit, len - limit);
992 			req->out_pos += len - limit;
993 		}
994 	} else {
995 		int pos = 0;
996 		int pad;
997 
998 		close_packet(req);
999 		while ((len - pos) > 0xffff) {
1000 			open_packet(req, type);
1001 			fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1002 			req->out_hdr = NULL;
1003 			if (!fcgi_flush(req, 0)) {
1004 				return -1;
1005 			}
1006 			if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1007 				req->keep = 0;
1008 				return -1;
1009 			}
1010 			pos += 0xfff8;
1011 		}
1012 
1013 		pad = (((len - pos) + 7) & ~7) - (len - pos);
1014 		rest = pad ? 8 - pad : 0;
1015 
1016 		open_packet(req, type);
1017 		fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1018 		req->out_hdr = NULL;
1019 		if (!fcgi_flush(req, 0)) {
1020 			return -1;
1021 		}
1022 		if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1023 			req->keep = 0;
1024 			return -1;
1025 		}
1026 		if (pad) {
1027 			open_packet(req, type);
1028 			memcpy(req->out_pos, str + len - rest,  rest);
1029 			req->out_pos += rest;
1030 		}
1031 	}
1032 
1033 	return len;
1034 }
1035 
1036 int fcgi_finish_request(fcgi_request *req, int force_close)
1037 {
1038 	int ret = 1;
1039 
1040 	if (req->fd >= 0) {
1041 		if (!req->closed) {
1042 			ret = fcgi_flush(req, 1);
1043 			req->closed = 1;
1044 		}
1045 		fcgi_close(req, force_close, 1);
1046 	}
1047 	return ret;
1048 }
1049 
1050 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1051 {
1052 	char **val;
1053 
1054 	if (!req) return NULL;
1055 
1056 	if (zend_hash_find(req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
1057 		return *val;
1058 	}
1059 	return NULL;
1060 }
1061 
1062 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1063 {
1064 	if (var && req) {
1065 		if (val == NULL) {
1066 			zend_hash_del(req->env, var, var_len+1);
1067 		} else {
1068 			char **ret;
1069 
1070 			val = estrdup(val);
1071 			if (zend_hash_update(req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
1072 				return *ret;
1073 			}
1074 		}
1075 	}
1076 	return NULL;
1077 }
1078 
1079 void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1080 {
1081 	zval * zvalue;
1082 	zvalue = pemalloc(sizeof(*zvalue), 1);
1083 	Z_TYPE_P(zvalue) = IS_STRING;
1084 	Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
1085 	Z_STRLEN_P(zvalue) = value_len;
1086 	zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
1087 }
1088 
1089 void fcgi_free_mgmt_var_cb(void * ptr)
1090 {
1091 	zval ** var = (zval **)ptr;
1092 	pefree(Z_STRVAL_PP(var), 1);
1093 	pefree(*var, 1);
1094 }
1095 
1096 char *fcgi_get_last_client_ip() /* {{{ */
1097 {
1098 	if (client_sa.sa.sa_family == AF_UNIX) {
1099 		return NULL;
1100 	}
1101 	return inet_ntoa(client_sa.sa_inet.sin_addr);
1102 }
1103 /* }}} */
1104 /*
1105  * Local variables:
1106  * tab-width: 4
1107  * c-basic-offset: 4
1108  * End:
1109  * vim600: sw=4 ts=4 fdm=marker
1110  * vim<600: sw=4 ts=4
1111  */
1112