Annotation of embedaddon/php/sapi/cgi/fastcgi.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 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 321634 2012-01-01 13:15:04Z felipe $ */
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:
30: #ifdef _WIN32
31:
32: #include <windows.h>
33:
34: typedef unsigned int in_addr_t;
35:
36: struct sockaddr_un {
37: short sun_family;
38: char sun_path[MAXPATHLEN];
39: };
40:
41: static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
42: static int is_impersonate = 0;
43:
44: #define FCGI_LOCK(fd) \
45: if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
46: DWORD ret; \
47: while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
48: if (in_shutdown) return -1; \
49: } \
50: if (ret == WAIT_FAILED) { \
51: fprintf(stderr, "WaitForSingleObject() failed\n"); \
52: return -1; \
53: } \
54: }
55:
56: #define FCGI_UNLOCK(fd) \
57: if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
58: ReleaseMutex(fcgi_accept_mutex); \
59: }
60:
61: #else
62:
63: # include <sys/types.h>
64: # include <sys/stat.h>
65: # include <unistd.h>
66: # include <fcntl.h>
67: # include <sys/socket.h>
68: # include <sys/un.h>
69: # include <netinet/in.h>
70: # include <arpa/inet.h>
71: # include <netdb.h>
72: # include <signal.h>
73:
74: # define closesocket(s) close(s)
75:
76: # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
77: # include <sys/poll.h>
78: # endif
79: # if defined(HAVE_SYS_SELECT_H)
80: # include <sys/select.h>
81: # endif
82:
83: #ifndef INADDR_NONE
84: #define INADDR_NONE ((unsigned long) -1)
85: #endif
86:
87: # ifndef HAVE_SOCKLEN_T
88: typedef unsigned int socklen_t;
89: # endif
90:
91: # ifdef USE_LOCKING
92: # define FCGI_LOCK(fd) \
93: do { \
94: struct flock lock; \
95: lock.l_type = F_WRLCK; \
96: lock.l_start = 0; \
97: lock.l_whence = SEEK_SET; \
98: lock.l_len = 0; \
99: if (fcntl(fd, F_SETLKW, &lock) != -1) { \
100: break; \
101: } else if (errno != EINTR || in_shutdown) { \
102: return -1; \
103: } \
104: } while (1)
105:
106: # define FCGI_UNLOCK(fd) \
107: do { \
108: int orig_errno = errno; \
109: while (1) { \
110: struct flock lock; \
111: lock.l_type = F_UNLCK; \
112: lock.l_start = 0; \
113: lock.l_whence = SEEK_SET; \
114: lock.l_len = 0; \
115: if (fcntl(fd, F_SETLK, &lock) != -1) { \
116: break; \
117: } else if (errno != EINTR) { \
118: return -1; \
119: } \
120: } \
121: errno = orig_errno; \
122: } while (0)
123: # else
124: # define FCGI_LOCK(fd)
125: # define FCGI_UNLOCK(fd)
126: # endif
127:
128: #endif
129:
130: typedef union _sa_t {
131: struct sockaddr sa;
132: struct sockaddr_un sa_unix;
133: struct sockaddr_in sa_inet;
134: } sa_t;
135:
136: static HashTable fcgi_mgmt_vars;
137:
138: static int is_initialized = 0;
139: static int is_fastcgi = 0;
140: static int in_shutdown = 0;
141: static in_addr_t *allowed_clients = NULL;
142:
143: #ifdef _WIN32
144:
145: static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
146: {
147: HANDLE shutdown_event = (HANDLE) arg;
148: WaitForSingleObject(shutdown_event, INFINITE);
149: in_shutdown = 1;
150: return 0;
151: }
152:
153: #else
154:
155: static void fcgi_signal_handler(int signo)
156: {
157: if (signo == SIGUSR1 || signo == SIGTERM) {
158: in_shutdown = 1;
159: }
160: }
161:
162: static void fcgi_setup_signals(void)
163: {
164: struct sigaction new_sa, old_sa;
165:
166: sigemptyset(&new_sa.sa_mask);
167: new_sa.sa_flags = 0;
168: new_sa.sa_handler = fcgi_signal_handler;
169: sigaction(SIGUSR1, &new_sa, NULL);
170: sigaction(SIGTERM, &new_sa, NULL);
171: sigaction(SIGPIPE, NULL, &old_sa);
172: if (old_sa.sa_handler == SIG_DFL) {
173: sigaction(SIGPIPE, &new_sa, NULL);
174: }
175: }
176: #endif
177:
178: int fcgi_in_shutdown(void)
179: {
180: return in_shutdown;
181: }
182:
183: int fcgi_init(void)
184: {
185: if (!is_initialized) {
186: #ifndef _WIN32
187: sa_t sa;
188: socklen_t len = sizeof(sa);
189: #endif
190: zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
191: fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1);
192:
193: is_initialized = 1;
194: #ifdef _WIN32
195: # if 0
196: /* TODO: Support for TCP sockets */
197: WSADATA wsaData;
198:
199: if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
200: fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError());
201: return 0;
202: }
203: # endif
204: if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
205: (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) &&
206: (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) {
207: char *str;
208: DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
209: HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
210:
211: SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
212:
213: str = getenv("_FCGI_SHUTDOWN_EVENT_");
214: if (str != NULL) {
215: HANDLE shutdown_event = (HANDLE) atoi(str);
216: if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
217: shutdown_event, 0, NULL)) {
218: return -1;
219: }
220: }
221: str = getenv("_FCGI_MUTEX_");
222: if (str != NULL) {
223: fcgi_accept_mutex = (HANDLE) atoi(str);
224: }
225: return is_fastcgi = 1;
226: } else {
227: return is_fastcgi = 0;
228: }
229: #else
230: errno = 0;
231: if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
232: fcgi_setup_signals();
233: return is_fastcgi = 1;
234: } else {
235: return is_fastcgi = 0;
236: }
237: #endif
238: }
239: return is_fastcgi;
240: }
241:
242:
243: int fcgi_is_fastcgi(void)
244: {
245: if (!is_initialized) {
246: return fcgi_init();
247: } else {
248: return is_fastcgi;
249: }
250: }
251:
252: void fcgi_shutdown(void)
253: {
254: if (is_initialized) {
255: zend_hash_destroy(&fcgi_mgmt_vars);
256: }
257: is_fastcgi = 0;
258: if (allowed_clients) {
259: free(allowed_clients);
260: }
261: }
262:
263: #ifdef _WIN32
264: /* Do some black magic with the NT security API.
265: * We prepare a DACL (Discretionary Access Control List) so that
266: * we, the creator, are allowed all access, while "Everyone Else"
267: * is only allowed to read and write to the pipe.
268: * This avoids security issues on shared hosts where a luser messes
269: * with the lower-level pipe settings and screws up the FastCGI service.
270: */
271: static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd, LPSECURITY_ATTRIBUTES sa)
272: {
273: DWORD req_acl_size;
274: char everyone_buf[32], owner_buf[32];
275: PSID sid_everyone, sid_owner;
276: SID_IDENTIFIER_AUTHORITY
277: siaWorld = SECURITY_WORLD_SID_AUTHORITY,
278: siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
279: PACL acl;
280:
281: sid_everyone = (PSID)&everyone_buf;
282: sid_owner = (PSID)&owner_buf;
283:
284: req_acl_size = sizeof(ACL) +
285: (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetSidLengthRequired(1)));
286:
287: acl = malloc(req_acl_size);
288:
289: if (acl == NULL) {
290: return NULL;
291: }
292:
293: if (!InitializeSid(sid_everyone, &siaWorld, 1)) {
294: goto out_fail;
295: }
296: *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID;
297:
298: if (!InitializeSid(sid_owner, &siaCreator, 1)) {
299: goto out_fail;
300: }
301: *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID;
302:
303: if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) {
304: goto out_fail;
305: }
306:
307: if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE, sid_everyone)) {
308: goto out_fail;
309: }
310:
311: if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) {
312: goto out_fail;
313: }
314:
315: if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
316: goto out_fail;
317: }
318:
319: if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) {
320: goto out_fail;
321: }
322:
323: sa->lpSecurityDescriptor = sd;
324:
325: return acl;
326:
327: out_fail:
328: free(acl);
329: return NULL;
330: }
331: #endif
332:
333: static int is_port_number(const char *bindpath)
334: {
335: while (*bindpath) {
336: if (*bindpath < '0' || *bindpath > '9') {
337: return 0;
338: }
339: bindpath++;
340: }
341: return 1;
342: }
343:
344: int fcgi_listen(const char *path, int backlog)
345: {
346: char *s;
347: int tcp = 0;
348: char host[MAXPATHLEN];
349: short port = 0;
350: int listen_socket;
351: sa_t sa;
352: socklen_t sock_len;
353: #ifdef SO_REUSEADDR
354: # ifdef _WIN32
355: BOOL reuse = 1;
356: # else
357: int reuse = 1;
358: # endif
359: #endif
360:
361: if ((s = strchr(path, ':'))) {
362: port = atoi(s+1);
363: if (port != 0 && (s-path) < MAXPATHLEN) {
364: strncpy(host, path, s-path);
365: host[s-path] = '\0';
366: tcp = 1;
367: }
368: } else if (is_port_number(path)) {
369: port = atoi(path);
370: if (port != 0) {
371: host[0] = '\0';
372: tcp = 1;
373: }
374: }
375:
376: /* Prepare socket address */
377: if (tcp) {
378: memset(&sa.sa_inet, 0, sizeof(sa.sa_inet));
379: sa.sa_inet.sin_family = AF_INET;
380: sa.sa_inet.sin_port = htons(port);
381: sock_len = sizeof(sa.sa_inet);
382:
383: if (!*host || !strncmp(host, "*", sizeof("*")-1)) {
384: sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY);
385: } else {
386: sa.sa_inet.sin_addr.s_addr = inet_addr(host);
387: if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) {
388: struct hostent *hep;
389:
390: hep = gethostbyname(host);
391: if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
392: fprintf(stderr, "Cannot resolve host name '%s'!\n", host);
393: return -1;
394: } else if (hep->h_addr_list[1]) {
395: fprintf(stderr, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
396: return -1;
397: }
398: sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
399: }
400: }
401: } else {
402: #ifdef _WIN32
403: SECURITY_DESCRIPTOR sd;
404: SECURITY_ATTRIBUTES saw;
405: PACL acl;
406: HANDLE namedPipe;
407:
408: memset(&sa, 0, sizeof(saw));
409: saw.nLength = sizeof(saw);
410: saw.bInheritHandle = FALSE;
411: acl = prepare_named_pipe_acl(&sd, &saw);
412:
413: namedPipe = CreateNamedPipe(path,
414: PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
415: PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
416: PIPE_UNLIMITED_INSTANCES,
417: 8192, 8192, 0, &saw);
418: if (namedPipe == INVALID_HANDLE_VALUE) {
419: return -1;
420: }
421: listen_socket = _open_osfhandle((long)namedPipe, 0);
422: if (!is_initialized) {
423: fcgi_init();
424: }
425: is_fastcgi = 1;
426: return listen_socket;
427:
428: #else
429: int path_len = strlen(path);
430:
431: if (path_len >= sizeof(sa.sa_unix.sun_path)) {
432: fprintf(stderr, "Listening socket's path name is too long.\n");
433: return -1;
434: }
435:
436: memset(&sa.sa_unix, 0, sizeof(sa.sa_unix));
437: sa.sa_unix.sun_family = AF_UNIX;
438: memcpy(sa.sa_unix.sun_path, path, path_len + 1);
439: sock_len = (size_t)(((struct sockaddr_un *)0)->sun_path) + path_len;
440: #ifdef HAVE_SOCKADDR_UN_SUN_LEN
441: sa.sa_unix.sun_len = sock_len;
442: #endif
443: unlink(path);
444: #endif
445: }
446:
447: /* Create, bind socket and start listen on it */
448: if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 ||
449: #ifdef SO_REUSEADDR
450: setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0 ||
451: #endif
452: bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
453: listen(listen_socket, backlog) < 0) {
454:
455: fprintf(stderr, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
456: return -1;
457: }
458:
459: if (!tcp) {
460: chmod(path, 0777);
461: } else {
462: char *ip = getenv("FCGI_WEB_SERVER_ADDRS");
463: char *cur, *end;
464: int n;
465:
466: if (ip) {
467: ip = strdup(ip);
468: cur = ip;
469: n = 0;
470: while (*cur) {
471: if (*cur == ',') n++;
472: cur++;
473: }
474: allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
475: n = 0;
476: cur = ip;
477: while (cur) {
478: end = strchr(cur, ',');
479: if (end) {
480: *end = 0;
481: end++;
482: }
483: allowed_clients[n] = inet_addr(cur);
484: if (allowed_clients[n] == INADDR_NONE) {
485: fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur);
486: }
487: n++;
488: cur = end;
489: }
490: allowed_clients[n] = INADDR_NONE;
491: free(ip);
492: }
493: }
494:
495: if (!is_initialized) {
496: fcgi_init();
497: }
498: is_fastcgi = 1;
499:
500: #ifdef _WIN32
501: if (tcp) {
502: listen_socket = _open_osfhandle((long)listen_socket, 0);
503: }
504: #else
505: fcgi_setup_signals();
506: #endif
507: return listen_socket;
508: }
509:
510: void fcgi_init_request(fcgi_request *req, int listen_socket)
511: {
512: memset(req, 0, sizeof(fcgi_request));
513: req->listen_socket = listen_socket;
514: req->fd = -1;
515: req->id = -1;
516:
517: req->in_len = 0;
518: req->in_pad = 0;
519:
520: req->out_hdr = NULL;
521: req->out_pos = req->out_buf;
522:
523: #ifdef _WIN32
524: req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
525: #endif
526: }
527:
528: static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
529: {
530: int ret;
531: size_t n = 0;
532:
533: do {
534: errno = 0;
535: #ifdef _WIN32
536: if (!req->tcp) {
537: ret = write(req->fd, ((char*)buf)+n, count-n);
538: } else {
539: ret = send(req->fd, ((char*)buf)+n, count-n, 0);
540: if (ret <= 0) {
541: errno = WSAGetLastError();
542: }
543: }
544: #else
545: ret = write(req->fd, ((char*)buf)+n, count-n);
546: #endif
547: if (ret > 0) {
548: n += ret;
549: } else if (ret <= 0 && errno != 0 && errno != EINTR) {
550: return ret;
551: }
552: } while (n != count);
553: return n;
554: }
555:
556: static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
557: {
558: int ret;
559: size_t n = 0;
560:
561: do {
562: errno = 0;
563: #ifdef _WIN32
564: if (!req->tcp) {
565: ret = read(req->fd, ((char*)buf)+n, count-n);
566: } else {
567: ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
568: if (ret <= 0) {
569: errno = WSAGetLastError();
570: }
571: }
572: #else
573: ret = read(req->fd, ((char*)buf)+n, count-n);
574: #endif
575: if (ret > 0) {
576: n += ret;
577: } else if (ret == 0 && errno == 0) {
578: return n;
579: } else if (ret <= 0 && errno != 0 && errno != EINTR) {
580: return ret;
581: }
582: } while (n != count);
583: return n;
584: }
585:
586: static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
587: {
588: int pad = ((len + 7) & ~7) - len;
589:
590: hdr->contentLengthB0 = (unsigned char)(len & 0xff);
591: hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
592: hdr->paddingLength = (unsigned char)pad;
593: hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
594: hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
595: hdr->reserved = 0;
596: hdr->type = type;
597: hdr->version = FCGI_VERSION_1;
598: if (pad) {
599: memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
600: }
601: return pad;
602: }
603:
604: static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
605: {
606: char buf[128];
607: char *tmp = buf;
608: size_t buf_size = sizeof(buf);
609: unsigned int name_len, val_len;
610: char *s;
611: int ret = 1;
612:
613: while (p < end) {
614: name_len = *p++;
615: if (name_len >= 128) {
616: if (p + 3 >= end) {
617: ret = 0;
618: break;
619: }
620: name_len = ((name_len & 0x7f) << 24);
621: name_len |= (*p++ << 16);
622: name_len |= (*p++ << 8);
623: name_len |= *p++;
624: }
625: if (p >= end) {
626: ret = 0;
627: break;
628: }
629: val_len = *p++;
630: if (val_len >= 128) {
631: if (p + 3 >= end) {
632: ret = 0;
633: break;
634: }
635: val_len = ((val_len & 0x7f) << 24);
636: val_len |= (*p++ << 16);
637: val_len |= (*p++ << 8);
638: val_len |= *p++;
639: }
640: if (name_len + val_len > end - p) {
641: /* Malformated request */
642: ret = 0;
643: break;
644: }
645: if (name_len+1 >= buf_size) {
646: buf_size = name_len + 64;
647: tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
648: }
649: memcpy(tmp, p, name_len);
650: tmp[name_len] = 0;
651: s = estrndup((char*)p + name_len, val_len);
652: zend_hash_update(req->env, tmp, name_len+1, &s, sizeof(char*), NULL);
653: p += name_len + val_len;
654: }
655: if (tmp != buf && tmp != NULL) {
656: efree(tmp);
657: }
658: return ret;
659: }
660:
661: static void fcgi_free_var(char **s)
662: {
663: efree(*s);
664: }
665:
666: static int fcgi_read_request(fcgi_request *req)
667: {
668: fcgi_header hdr;
669: int len, padding;
670: unsigned char buf[FCGI_MAX_LENGTH+8];
671:
672: req->keep = 0;
673: req->closed = 0;
674: req->in_len = 0;
675: req->out_hdr = NULL;
676: req->out_pos = req->out_buf;
677: ALLOC_HASHTABLE(req->env);
678: zend_hash_init(req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 0);
679:
680: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
681: hdr.version < FCGI_VERSION_1) {
682: return 0;
683: }
684:
685: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
686: padding = hdr.paddingLength;
687:
688: while (hdr.type == FCGI_STDIN && len == 0) {
689: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
690: hdr.version < FCGI_VERSION_1) {
691: return 0;
692: }
693:
694: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
695: padding = hdr.paddingLength;
696: }
697:
698: if (len + padding > FCGI_MAX_LENGTH) {
699: return 0;
700: }
701:
702: req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
703:
704: if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
705: char *val;
706:
707: if (safe_read(req, buf, len+padding) != len+padding) {
708: return 0;
709: }
710:
711: req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
712: switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
713: case FCGI_RESPONDER:
714: val = estrdup("RESPONDER");
715: zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
716: break;
717: case FCGI_AUTHORIZER:
718: val = estrdup("AUTHORIZER");
719: zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
720: break;
721: case FCGI_FILTER:
722: val = estrdup("FILTER");
723: zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
724: break;
725: default:
726: return 0;
727: }
728:
729: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
730: hdr.version < FCGI_VERSION_1) {
731: return 0;
732: }
733:
734: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
735: padding = hdr.paddingLength;
736:
737: while (hdr.type == FCGI_PARAMS && len > 0) {
738: if (len + padding > FCGI_MAX_LENGTH) {
739: return 0;
740: }
741:
742: if (safe_read(req, buf, len+padding) != len+padding) {
743: req->keep = 0;
744: return 0;
745: }
746:
747: if (!fcgi_get_params(req, buf, buf+len)) {
748: req->keep = 0;
749: return 0;
750: }
751:
752: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
753: hdr.version < FCGI_VERSION_1) {
754: req->keep = 0;
755: return 0;
756: }
757: len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
758: padding = hdr.paddingLength;
759: }
760: } else if (hdr.type == FCGI_GET_VALUES) {
761: unsigned char *p = buf + sizeof(fcgi_header);
762: HashPosition pos;
763: char * str_index;
764: uint str_length;
765: ulong num_index;
766: int key_type;
767: zval ** value;
768:
769: if (safe_read(req, buf, len+padding) != len+padding) {
770: req->keep = 0;
771: return 0;
772: }
773:
774: if (!fcgi_get_params(req, buf, buf+len)) {
775: req->keep = 0;
776: return 0;
777: }
778:
779: zend_hash_internal_pointer_reset_ex(req->env, &pos);
780: while ((key_type = zend_hash_get_current_key_ex(req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
781: int zlen;
782: zend_hash_move_forward_ex(req->env, &pos);
783: if (key_type != HASH_KEY_IS_STRING) {
784: continue;
785: }
786: if (zend_hash_find(&fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
787: continue;
788: }
789: --str_length;
790: zlen = Z_STRLEN_PP(value);
791: if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
792: break;
793: }
794: if (str_length < 0x80) {
795: *p++ = str_length;
796: } else {
797: *p++ = ((str_length >> 24) & 0xff) | 0x80;
798: *p++ = (str_length >> 16) & 0xff;
799: *p++ = (str_length >> 8) & 0xff;
800: *p++ = str_length & 0xff;
801: }
802: if (zlen < 0x80) {
803: *p++ = zlen;
804: } else {
805: *p++ = ((zlen >> 24) & 0xff) | 0x80;
806: *p++ = (zlen >> 16) & 0xff;
807: *p++ = (zlen >> 8) & 0xff;
808: *p++ = zlen & 0xff;
809: }
810: memcpy(p, str_index, str_length);
811: p += str_length;
812: memcpy(p, Z_STRVAL_PP(value), zlen);
813: p += zlen;
814: }
815: len = p - buf - sizeof(fcgi_header);
816: len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
817: if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
818: req->keep = 0;
819: return 0;
820: }
821: return 0;
822: } else {
823: return 0;
824: }
825:
826: return 1;
827: }
828:
829: int fcgi_read(fcgi_request *req, char *str, int len)
830: {
831: int ret, n, rest;
832: fcgi_header hdr;
833: unsigned char buf[255];
834:
835: n = 0;
836: rest = len;
837: while (rest > 0) {
838: if (req->in_len == 0) {
839: if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
840: hdr.version < FCGI_VERSION_1 ||
841: hdr.type != FCGI_STDIN) {
842: req->keep = 0;
843: return 0;
844: }
845: req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
846: req->in_pad = hdr.paddingLength;
847: if (req->in_len == 0) {
848: return n;
849: }
850: }
851:
852: if (req->in_len >= rest) {
853: ret = safe_read(req, str, rest);
854: } else {
855: ret = safe_read(req, str, req->in_len);
856: }
857: if (ret < 0) {
858: req->keep = 0;
859: return ret;
860: } else if (ret > 0) {
861: req->in_len -= ret;
862: rest -= ret;
863: n += ret;
864: str += ret;
865: if (req->in_len == 0) {
866: if (req->in_pad) {
867: if (safe_read(req, buf, req->in_pad) != req->in_pad) {
868: req->keep = 0;
869: return ret;
870: }
871: }
872: } else {
873: return n;
874: }
875: } else {
876: return n;
877: }
878: }
879: return n;
880: }
881:
882: static inline void fcgi_close(fcgi_request *req, int force, int destroy)
883: {
884: if (destroy && req->env) {
885: zend_hash_destroy(req->env);
886: FREE_HASHTABLE(req->env);
887: req->env = NULL;
888: }
889:
890: #ifdef _WIN32
891: if (is_impersonate && !req->tcp) {
892: RevertToSelf();
893: }
894: #endif
895:
896: if ((force || !req->keep) && req->fd >= 0) {
897: #ifdef _WIN32
898: if (!req->tcp) {
899: HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
900:
901: if (!force) {
902: FlushFileBuffers(pipe);
903: }
904: DisconnectNamedPipe(pipe);
905: } else {
906: if (!force) {
907: char buf[8];
908:
909: shutdown(req->fd, 1);
910: while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
911: }
912: closesocket(req->fd);
913: }
914: #else
915: if (!force) {
916: char buf[8];
917:
918: shutdown(req->fd, 1);
919: while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
920: }
921: close(req->fd);
922: #endif
923: req->fd = -1;
924: }
925: }
926:
927: int fcgi_accept_request(fcgi_request *req)
928: {
929: #ifdef _WIN32
930: HANDLE pipe;
931: OVERLAPPED ov;
932: #endif
933:
934: while (1) {
935: if (req->fd < 0) {
936: while (1) {
937: if (in_shutdown) {
938: return -1;
939: }
940: #ifdef _WIN32
941: if (!req->tcp) {
942: pipe = (HANDLE)_get_osfhandle(req->listen_socket);
943: FCGI_LOCK(req->listen_socket);
944: ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
945: if (!ConnectNamedPipe(pipe, &ov)) {
946: errno = GetLastError();
947: if (errno == ERROR_IO_PENDING) {
948: while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
949: if (in_shutdown) {
950: CloseHandle(ov.hEvent);
951: FCGI_UNLOCK(req->listen_socket);
952: return -1;
953: }
954: }
955: } else if (errno != ERROR_PIPE_CONNECTED) {
956: }
957: }
958: CloseHandle(ov.hEvent);
959: req->fd = req->listen_socket;
960: FCGI_UNLOCK(req->listen_socket);
961: } else {
962: SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
963: #else
964: {
965: int listen_socket = req->listen_socket;
966: #endif
967: sa_t sa;
968: socklen_t len = sizeof(sa);
969:
970: FCGI_LOCK(req->listen_socket);
971: req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
972: FCGI_UNLOCK(req->listen_socket);
973: if (req->fd >= 0 && allowed_clients) {
974: int n = 0;
975: int allowed = 0;
976:
977: while (allowed_clients[n] != INADDR_NONE) {
978: if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
979: allowed = 1;
980: break;
981: }
982: n++;
983: }
984: if (!allowed) {
985: fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr));
986: closesocket(req->fd);
987: req->fd = -1;
988: continue;
989: }
990: }
991: }
992:
993: #ifdef _WIN32
994: if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
995: #else
996: if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
997: #endif
998: return -1;
999: }
1000:
1001: #ifdef _WIN32
1002: break;
1003: #else
1004: if (req->fd >= 0) {
1005: #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
1006: struct pollfd fds;
1007: int ret;
1008:
1009: fds.fd = req->fd;
1010: fds.events = POLLIN;
1011: fds.revents = 0;
1012: do {
1013: errno = 0;
1014: ret = poll(&fds, 1, 5000);
1015: } while (ret < 0 && errno == EINTR);
1016: if (ret > 0 && (fds.revents & POLLIN)) {
1017: break;
1018: }
1019: fcgi_close(req, 1, 0);
1020: #else
1021: if (req->fd < FD_SETSIZE) {
1022: struct timeval tv = {5,0};
1023: fd_set set;
1024: int ret;
1025:
1026: FD_ZERO(&set);
1027: FD_SET(req->fd, &set);
1028: do {
1029: errno = 0;
1030: ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
1031: } while (ret < 0 && errno == EINTR);
1032: if (ret > 0 && FD_ISSET(req->fd, &set)) {
1033: break;
1034: }
1035: fcgi_close(req, 1, 0);
1036: } else {
1037: fprintf(stderr, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
1038: fcgi_close(req, 1, 0);
1039: }
1040: #endif
1041: }
1042: #endif
1043: }
1044: } else if (in_shutdown) {
1045: return -1;
1046: }
1047: if (fcgi_read_request(req)) {
1048: #ifdef _WIN32
1049: if (is_impersonate && !req->tcp) {
1050: pipe = (HANDLE)_get_osfhandle(req->fd);
1051: if (!ImpersonateNamedPipeClient(pipe)) {
1052: fcgi_close(req, 1, 1);
1053: continue;
1054: }
1055: }
1056: #endif
1057: return req->fd;
1058: } else {
1059: fcgi_close(req, 1, 1);
1060: }
1061: }
1062: }
1063:
1064: static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
1065: {
1066: req->out_hdr = (fcgi_header*) req->out_pos;
1067: req->out_hdr->type = type;
1068: req->out_pos += sizeof(fcgi_header);
1069: return req->out_hdr;
1070: }
1071:
1072: static inline void close_packet(fcgi_request *req)
1073: {
1074: if (req->out_hdr) {
1075: int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
1076:
1077: req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
1078: req->out_hdr = NULL;
1079: }
1080: }
1081:
1082: int fcgi_flush(fcgi_request *req, int close)
1083: {
1084: int len;
1085:
1086: close_packet(req);
1087:
1088: len = req->out_pos - req->out_buf;
1089:
1090: if (close) {
1091: fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
1092:
1093: fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
1094: rec->body.appStatusB3 = 0;
1095: rec->body.appStatusB2 = 0;
1096: rec->body.appStatusB1 = 0;
1097: rec->body.appStatusB0 = 0;
1098: rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
1099: len += sizeof(fcgi_end_request_rec);
1100: }
1101:
1102: if (safe_write(req, req->out_buf, len) != len) {
1103: req->keep = 0;
1104: return 0;
1105: }
1106:
1107: req->out_pos = req->out_buf;
1108: return 1;
1109: }
1110:
1111: int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
1112: {
1113: int limit, rest;
1114:
1115: if (len <= 0) {
1116: return 0;
1117: }
1118:
1119: if (req->out_hdr && req->out_hdr->type != type) {
1120: close_packet(req);
1121: }
1122: #if 0
1123: /* Unoptimized, but clear version */
1124: rest = len;
1125: while (rest > 0) {
1126: limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1127:
1128: if (!req->out_hdr) {
1129: if (limit < sizeof(fcgi_header)) {
1130: if (!fcgi_flush(req, 0)) {
1131: return -1;
1132: }
1133: }
1134: open_packet(req, type);
1135: }
1136: limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1137: if (rest < limit) {
1138: memcpy(req->out_pos, str, rest);
1139: req->out_pos += rest;
1140: return len;
1141: } else {
1142: memcpy(req->out_pos, str, limit);
1143: req->out_pos += limit;
1144: rest -= limit;
1145: str += limit;
1146: if (!fcgi_flush(req, 0)) {
1147: return -1;
1148: }
1149: }
1150: }
1151: #else
1152: /* Optimized version */
1153: limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1154: if (!req->out_hdr) {
1155: limit -= sizeof(fcgi_header);
1156: if (limit < 0) limit = 0;
1157: }
1158:
1159: if (len < limit) {
1160: if (!req->out_hdr) {
1161: open_packet(req, type);
1162: }
1163: memcpy(req->out_pos, str, len);
1164: req->out_pos += len;
1165: } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
1166: if (!req->out_hdr) {
1167: open_packet(req, type);
1168: }
1169: if (limit > 0) {
1170: memcpy(req->out_pos, str, limit);
1171: req->out_pos += limit;
1172: }
1173: if (!fcgi_flush(req, 0)) {
1174: return -1;
1175: }
1176: if (len > limit) {
1177: open_packet(req, type);
1178: memcpy(req->out_pos, str + limit, len - limit);
1179: req->out_pos += len - limit;
1180: }
1181: } else {
1182: int pos = 0;
1183: int pad;
1184:
1185: close_packet(req);
1186: while ((len - pos) > 0xffff) {
1187: open_packet(req, type);
1188: fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1189: req->out_hdr = NULL;
1190: if (!fcgi_flush(req, 0)) {
1191: return -1;
1192: }
1193: if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1194: req->keep = 0;
1195: return -1;
1196: }
1197: pos += 0xfff8;
1198: }
1199:
1200: pad = (((len - pos) + 7) & ~7) - (len - pos);
1201: rest = pad ? 8 - pad : 0;
1202:
1203: open_packet(req, type);
1204: fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1205: req->out_hdr = NULL;
1206: if (!fcgi_flush(req, 0)) {
1207: return -1;
1208: }
1209: if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1210: req->keep = 0;
1211: return -1;
1212: }
1213: if (pad) {
1214: open_packet(req, type);
1215: memcpy(req->out_pos, str + len - rest, rest);
1216: req->out_pos += rest;
1217: }
1218: }
1219: #endif
1220: return len;
1221: }
1222:
1223: int fcgi_finish_request(fcgi_request *req, int force_close)
1224: {
1225: int ret = 1;
1226:
1227: if (req->fd >= 0) {
1228: if (!req->closed) {
1229: ret = fcgi_flush(req, 1);
1230: req->closed = 1;
1231: }
1232: fcgi_close(req, force_close, 1);
1233: }
1234: return ret;
1235: }
1236:
1237: char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1238: {
1239: char **val;
1240:
1241: if (!req) return NULL;
1242:
1243: if (zend_hash_find(req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
1244: return *val;
1245: }
1246: return NULL;
1247: }
1248:
1249: char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1250: {
1251: if (var && req) {
1252: if (val == NULL) {
1253: zend_hash_del(req->env, var, var_len+1);
1254: } else {
1255: char **ret;
1256:
1257: val = estrdup(val);
1258: if (zend_hash_update(req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
1259: return *ret;
1260: }
1261: }
1262: }
1263: return NULL;
1264: }
1265:
1266: #ifdef _WIN32
1267: void fcgi_impersonate(void)
1268: {
1269: char *os_name;
1270:
1271: os_name = getenv("OS");
1272: if (os_name && stricmp(os_name, "Windows_NT") == 0) {
1273: is_impersonate = 1;
1274: }
1275: }
1276: #endif
1277:
1278: void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1279: {
1280: zval * zvalue;
1281: zvalue = pemalloc(sizeof(*zvalue), 1);
1282: Z_TYPE_P(zvalue) = IS_STRING;
1283: Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
1284: Z_STRLEN_P(zvalue) = value_len;
1285: zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
1286: }
1287:
1288: void fcgi_free_mgmt_var_cb(void * ptr)
1289: {
1290: zval ** var = (zval **)ptr;
1291: pefree(Z_STRVAL_PP(var), 1);
1292: pefree(*var, 1);
1293: }
1294:
1295: /*
1296: * Local variables:
1297: * tab-width: 4
1298: * c-basic-offset: 4
1299: * End:
1300: * vim600: sw=4 ts=4 fdm=marker
1301: * vim<600: sw=4 ts=4
1302: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>