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