root/sapi/fpm/fpm/fastcgi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fcgi_shutdown_thread
  2. fcgi_signal_handler
  3. fcgi_setup_signals
  4. fcgi_init
  5. fcgi_set_in_shutdown
  6. fcgi_shutdown
  7. fcgi_set_allowed_clients
  8. fcgi_init_request
  9. safe_write
  10. safe_read
  11. fcgi_make_header
  12. fcgi_get_params_len
  13. fcgi_param_get_eff_len
  14. fcgi_get_params
  15. fcgi_free_var
  16. fcgi_read_request
  17. fcgi_read
  18. fcgi_close
  19. fcgi_is_allowed
  20. fcgi_accept_request
  21. open_packet
  22. close_packet
  23. fcgi_flush
  24. fcgi_write
  25. fcgi_finish_request
  26. fcgi_getenv
  27. fcgi_putenv
  28. fcgi_set_mgmt_var
  29. fcgi_free_mgmt_var_cb
  30. fcgi_get_last_client_ip

   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 
 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 
 161 static void fcgi_signal_handler(int signo)
 162 {
 163         if (signo == SIGUSR1 || signo == SIGTERM) {
 164                 in_shutdown = 1;
 165         }
 166 }
 167 
 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 
 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 
 230 void fcgi_set_in_shutdown(int new_value)
 231 {
 232         in_shutdown = new_value;
 233 }
 234 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 502 static void fcgi_free_var(char **s)
 503 {
 504         efree(*s);
 505 }
 506 
 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 
 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 
 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 
 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 
 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  */

/* [<][>][^][v][top][bottom][index][help] */