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

Reply via email to