1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2016 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