dmitry Wed Mar 28 15:39:35 2007 UTC Modified files: /php-src/sapi/cgi cgi_main.c fastcgi.c fastcgi.h Log: Improved FastCGI SAPI to support external pipe and socket servers on win32
http://cvs.php.net/viewvc.cgi/php-src/sapi/cgi/cgi_main.c?r1=1.316&r2=1.317&diff_format=u Index: php-src/sapi/cgi/cgi_main.c diff -u php-src/sapi/cgi/cgi_main.c:1.316 php-src/sapi/cgi/cgi_main.c:1.317 --- php-src/sapi/cgi/cgi_main.c:1.316 Fri Mar 9 16:50:17 2007 +++ php-src/sapi/cgi/cgi_main.c Wed Mar 28 15:39:35 2007 @@ -21,7 +21,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: cgi_main.c,v 1.316 2007/03/09 16:50:17 dmitry Exp $ */ +/* $Id: cgi_main.c,v 1.317 2007/03/28 15:39:35 dmitry Exp $ */ #include "php.h" #include "php_globals.h" @@ -120,9 +120,7 @@ static const opt_struct OPTIONS[] = { {'a', 0, "interactive"}, -#ifndef PHP_WIN32 {'b', 1, "bindpath"}, -#endif {'C', 0, "no-chdir"}, {'c', 1, "php-ini"}, {'d', 1, "define"}, @@ -611,9 +609,7 @@ php_printf("Usage: %s [-q] [-h] [-s] [-v] [-i] [-f <file>]\n" " %s <file> [args...]\n" " -a Run interactively\n" -#if !defined(PHP_WIN32) " -b <address:port>|<port> Bind Path for external FASTCGI Server mode\n" -#endif " -C Do not chdir to the script's directory\n" " -c <path>|<file> Look for php.ini file in this directory\n" " -n No php.ini file will be used\n" @@ -970,19 +966,6 @@ exit(0); } -#ifndef PHP_WIN32 -static int is_port_number(const char *bindpath) -{ - while (*bindpath) { - if (*bindpath < '0' || *bindpath > '9') { - return 0; - } - bindpath++; - } - return 1; -} -#endif - PHP_INI_BEGIN() STD_PHP_INI_ENTRY("cgi.rfc2616_headers", "0", PHP_INI_ALL, OnUpdateBool, rfc2616_headers, php_cgi_globals_struct, php_cgi_globals) STD_PHP_INI_ENTRY("cgi.nph", "0", PHP_INI_ALL, OnUpdateBool, nph, php_cgi_globals_struct, php_cgi_globals) @@ -1089,9 +1072,7 @@ int max_requests = 500; int requests = 0; int fastcgi = fcgi_is_fastcgi(); -#ifndef PHP_WIN32 char *bindpath = NULL; -#endif int fcgi_fd = 0; fcgi_request request; #ifndef PHP_WIN32 @@ -1152,7 +1133,6 @@ case 'n': cgi_sapi_module.php_ini_ignore = 1; break; -#ifndef PHP_WIN32 /* if we're started on command line, check to see if we are being started as an 'external' fastcgi server by accepting a bindpath parameter. */ @@ -1192,7 +1172,6 @@ bindpath = strdup(php_optarg); } break; -#endif } } @@ -1259,26 +1238,10 @@ } } -#ifndef PHP_WIN32 /* for windows, socket listening is broken in the fastcgi library itself so dissabling this feature on windows till time is available to fix it */ if (bindpath) { - /* Pass on the arg to the FastCGI library, with one exception. - * If just a port is specified, then we prepend a ':' onto the - * path (it's what the fastcgi library expects) - */ - if (strchr(bindpath, ':') == NULL && is_port_number(bindpath)) { - char *tmp; - - tmp = malloc(strlen(bindpath) + 2); - tmp[0] = ':'; - memcpy(tmp + 1, bindpath, strlen(bindpath) + 1); - - fcgi_fd = fcgi_listen(tmp, 128); - free(tmp); - } else { - fcgi_fd = fcgi_listen(bindpath, 128); - } + fcgi_fd = fcgi_listen(bindpath, 128); if (fcgi_fd < 0) { fprintf(stderr, "Couldn't create FastCGI listen socket on port %s\n", bindpath); #ifdef ZTS @@ -1288,7 +1251,6 @@ } fastcgi = fcgi_is_fastcgi(); } -#endif if (fastcgi) { /* How many times to run PHP scripts before dying */ if (getenv("PHP_FCGI_MAX_REQUESTS")) { @@ -1749,11 +1711,9 @@ requests++; if (max_requests && (requests == max_requests)) { fcgi_finish_request(&request); -#ifndef PHP_WIN32 if (bindpath) { free(bindpath); } -#endif break; } /* end of fastcgi loop */ http://cvs.php.net/viewvc.cgi/php-src/sapi/cgi/fastcgi.c?r1=1.35&r2=1.36&diff_format=u Index: php-src/sapi/cgi/fastcgi.c diff -u php-src/sapi/cgi/fastcgi.c:1.35 php-src/sapi/cgi/fastcgi.c:1.36 --- php-src/sapi/cgi/fastcgi.c:1.35 Mon Mar 12 07:39:24 2007 +++ php-src/sapi/cgi/fastcgi.c Wed Mar 28 15:39:35 2007 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: fastcgi.c,v 1.35 2007/03/12 07:39:24 dmitry Exp $ */ +/* $Id: fastcgi.c,v 1.36 2007/03/28 15:39:35 dmitry Exp $ */ #include "php.h" #include "fastcgi.h" @@ -32,6 +32,7 @@ #include <windows.h> typedef unsigned int size_t; + typedef unsigned int in_addr_t; struct sockaddr_un { short sun_family; @@ -71,6 +72,8 @@ # include <netdb.h> # include <signal.h> +# define closesocket(s) close(s) + # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL) # include <sys/poll.h> # endif @@ -147,6 +150,7 @@ static int is_initialized = 0; static int is_fastcgi = 0; static int in_shutdown = 0; +static in_addr_t *allowed_clients = NULL; #ifdef _WIN32 @@ -160,8 +164,6 @@ #else -static in_addr_t *allowed_clients = NULL; - static void fcgi_signal_handler(int signo) { if (signo == SIGUSR1 || signo == SIGTERM) { @@ -254,12 +256,89 @@ } } +#ifdef _WIN32 +/* Do some black magic with the NT security API. + * We prepare a DACL (Discretionary Access Control List) so that + * we, the creator, are allowed all access, while "Everyone Else" + * is only allowed to read and write to the pipe. + * This avoids security issues on shared hosts where a luser messes + * with the lower-level pipe settings and screws up the FastCGI service. + */ +static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd, LPSECURITY_ATTRIBUTES sa) +{ + DWORD req_acl_size; + char everyone_buf[32], owner_buf[32]; + PSID sid_everyone, sid_owner; + SID_IDENTIFIER_AUTHORITY + siaWorld = SECURITY_WORLD_SID_AUTHORITY, + siaCreator = SECURITY_CREATOR_SID_AUTHORITY; + PACL acl; + + sid_everyone = (PSID)&everyone_buf; + sid_owner = (PSID)&owner_buf; + + req_acl_size = sizeof(ACL) + + (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetSidLengthRequired(1))); + + acl = malloc(req_acl_size); + + if (acl == NULL) { + return NULL; + } + + if (!InitializeSid(sid_everyone, &siaWorld, 1)) { + goto out_fail; + } + *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID; + + if (!InitializeSid(sid_owner, &siaCreator, 1)) { + goto out_fail; + } + *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID; + + if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) { + goto out_fail; + } + + if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE, sid_everyone)) { + goto out_fail; + } + + if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) { + goto out_fail; + } + + if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) { + goto out_fail; + } + + if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) { + goto out_fail; + } + + sa->lpSecurityDescriptor = sd; + + return acl; + +out_fail: + free(acl); + return NULL; +} +#endif + +static int is_port_number(const char *bindpath) +{ + while (*bindpath) { + if (*bindpath < '0' || *bindpath > '9') { + return 0; + } + bindpath++; + } + return 1; +} + int fcgi_listen(const char *path, int backlog) { -#ifdef _WIN32 - /* TODO: Support for manual binding on TCP sockets (php -b <port>) */ - return -1; -#else char *s; int tcp = 0; char host[MAXPATHLEN]; @@ -275,6 +354,12 @@ host[s-path] = '\0'; tcp = 1; } + } else if (is_port_number(path)) { + port = atoi(path); + if (port != 0) { + host[0] = '\0'; + tcp = 1; + } } /* Prepare socket address */ @@ -303,6 +388,33 @@ } } } else { +#ifdef _WIN32 + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + PACL acl; + HANDLE namedPipe; + + memset(&sa, 0, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = FALSE; + acl = prepare_named_pipe_acl(&sd, &sa); + + namedPipe = CreateNamedPipe(path, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE, + PIPE_UNLIMITED_INSTANCES, + 8192, 8192, 0, &sa); + if (namedPipe == INVALID_HANDLE_VALUE) { + return -1; + } + listen_socket = _open_osfhandle((long)namedPipe, 0); + if (!is_initialized) { + fcgi_init(); + } + is_fastcgi = 1; + return listen_socket; + +#else int path_len = strlen(path); if (path_len >= sizeof(sa.sa_unix.sun_path)) { @@ -318,6 +430,7 @@ sa.sa_unix.sun_len = sock_len; #endif unlink(path); +#endif } /* Create, bind socket and start listen on it */ @@ -369,8 +482,13 @@ fcgi_init(); } is_fastcgi = 1; - return listen_socket; + +#ifdef _WIN32 + if (tcp) { + listen_socket = _open_osfhandle((long)listen_socket, 0); + } #endif + return listen_socket; } void fcgi_init_request(fcgi_request *req, int listen_socket) @@ -385,6 +503,10 @@ req->out_hdr = NULL; req->out_pos = req->out_buf; + +#ifdef _WIN32 + req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL); +#endif } static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count) @@ -394,7 +516,18 @@ do { errno = 0; +#ifdef _WIN32 + if (!req->tcp) { + ret = write(req->fd, ((char*)buf)+n, count-n); + } else { + ret = send(req->fd, ((char*)buf)+n, count-n, 0); + if (ret <= 0) { + errno = WSAGetLastError(); + } + } +#else ret = write(req->fd, ((char*)buf)+n, count-n); +#endif if (ret > 0) { n += ret; } else if (ret <= 0 && errno != 0 && errno != EINTR) { @@ -411,7 +544,18 @@ do { errno = 0; +#ifdef _WIN32 + if (!req->tcp) { + ret = read(req->fd, ((char*)buf)+n, count-n); + } else { + ret = recv(req->fd, ((char*)buf)+n, count-n, 0); + if (ret <= 0) { + errno = WSAGetLastError(); + } + } +#else ret = read(req->fd, ((char*)buf)+n, count-n); +#endif if (ret > 0) { n += ret; } else if (ret == 0 && errno == 0) { @@ -666,19 +810,29 @@ } #ifdef _WIN32 - if (is_impersonate) { + if (is_impersonate && !req->tcp) { RevertToSelf(); } #endif if ((force || !req->keep) && req->fd >= 0) { #ifdef _WIN32 - HANDLE pipe = (HANDLE)_get_osfhandle(req->fd); + if (!req->tcp) { + HANDLE pipe = (HANDLE)_get_osfhandle(req->fd); - if (!force) { - FlushFileBuffers(pipe); + if (!force) { + FlushFileBuffers(pipe); + } + DisconnectNamedPipe(pipe); + } else { + if (!force) { + char buf[8]; + + shutdown(req->fd, 1); + while (recv(req->fd, buf, sizeof(buf), 0) > 0) {} + } + closesocket(req->fd); } - DisconnectNamedPipe(pipe); #else if (!force) { char buf[8]; @@ -707,33 +861,37 @@ return -1; } #ifdef _WIN32 - pipe = (HANDLE)_get_osfhandle(req->listen_socket); - - FCGI_LOCK(req->listen_socket); - ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!ConnectNamedPipe(pipe, &ov)) { - errno = GetLastError(); - if (errno == ERROR_IO_PENDING) { - while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) { - if (in_shutdown) { - CloseHandle(ov.hEvent); - FCGI_UNLOCK(req->listen_socket); - return -1; + if (!req->tcp) { + pipe = (HANDLE)_get_osfhandle(req->listen_socket); + FCGI_LOCK(req->listen_socket); + ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!ConnectNamedPipe(pipe, &ov)) { + errno = GetLastError(); + if (errno == ERROR_IO_PENDING) { + while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) { + if (in_shutdown) { + CloseHandle(ov.hEvent); + FCGI_UNLOCK(req->listen_socket); + return -1; + } } + } else if (errno != ERROR_PIPE_CONNECTED) { } - } else if (errno != ERROR_PIPE_CONNECTED) { } - } - CloseHandle(ov.hEvent); - req->fd = req->listen_socket; - FCGI_UNLOCK(req->listen_socket); + CloseHandle(ov.hEvent); + req->fd = req->listen_socket; + FCGI_UNLOCK(req->listen_socket); + } else { + SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket); #else { + int listen_socket = req->listen_socket; +#endif sa_t sa; socklen_t len = sizeof(sa); FCGI_LOCK(req->listen_socket); - req->fd = accept(req->listen_socket, (struct sockaddr *)&sa, &len); + req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len); FCGI_UNLOCK(req->listen_socket); if (req->fd >= 0 && allowed_clients) { int n = 0; @@ -748,13 +906,12 @@ } if (!allowed) { fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr)); - close(req->fd); + closesocket(req->fd); req->fd = -1; continue; } } } -#endif if (req->fd < 0 && (in_shutdown || errno != EINTR)) { return -1; @@ -808,7 +965,7 @@ } if (fcgi_read_request(req)) { #ifdef _WIN32 - if (is_impersonate) { + if (is_impersonate && !req->tcp) { pipe = (HANDLE)_get_osfhandle(req->fd); if (!ImpersonateNamedPipeClient(pipe)) { fcgi_close(req, 1, 1); http://cvs.php.net/viewvc.cgi/php-src/sapi/cgi/fastcgi.h?r1=1.7&r2=1.8&diff_format=u Index: php-src/sapi/cgi/fastcgi.h diff -u php-src/sapi/cgi/fastcgi.h:1.7 php-src/sapi/cgi/fastcgi.h:1.8 --- php-src/sapi/cgi/fastcgi.h:1.7 Thu Feb 15 12:33:54 2007 +++ php-src/sapi/cgi/fastcgi.h Wed Mar 28 15:39:35 2007 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: fastcgi.h,v 1.7 2007/02/15 12:33:54 dmitry Exp $ */ +/* $Id: fastcgi.h,v 1.8 2007/03/28 15:39:35 dmitry Exp $ */ /* FastCGI protocol */ @@ -93,6 +93,9 @@ typedef struct _fcgi_request { int listen_socket; +#ifdef _WIN32 + int tcp; +#endif int fd; int id; int keep;
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php