root/main/fastcgi.c

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

DEFINITIONS

This source file includes following definitions.
  1. fcgi_hash_init
  2. fcgi_hash_destroy
  3. fcgi_hash_clean
  4. fcgi_hash_strndup
  5. fcgi_hash_set
  6. fcgi_hash_del
  7. fcgi_hash_get
  8. fcgi_hash_apply
  9. fcgi_shutdown_thread
  10. fcgi_signal_handler
  11. fcgi_setup_signals
  12. fcgi_set_in_shutdown
  13. fcgi_in_shutdown
  14. fcgi_terminate
  15. fcgi_set_logger
  16. fcgi_log
  17. fcgi_init
  18. fcgi_is_fastcgi
  19. fcgi_shutdown
  20. prepare_named_pipe_acl
  21. is_port_number
  22. fcgi_listen
  23. fcgi_set_allowed_clients
  24. fcgi_hook_dummy
  25. fcgi_init_request
  26. fcgi_destroy_request
  27. safe_write
  28. safe_read
  29. fcgi_make_header
  30. fcgi_get_params
  31. fcgi_read_request
  32. fcgi_read
  33. fcgi_close
  34. fcgi_is_closed
  35. fcgi_is_allowed
  36. fcgi_accept_request
  37. open_packet
  38. close_packet
  39. fcgi_flush
  40. fcgi_write
  41. fcgi_finish_request
  42. fcgi_has_env
  43. fcgi_getenv
  44. fcgi_quick_getenv
  45. fcgi_putenv
  46. fcgi_quick_putenv
  47. fcgi_loadenv
  48. fcgi_impersonate
  49. fcgi_set_mgmt_var
  50. fcgi_free_mgmt_var_cb
  51. fcgi_get_last_client_ip

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   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$ */
  20 
  21 #include "php.h"
  22 #include "php_network.h"
  23 
  24 #include <string.h>
  25 #include <stdlib.h>
  26 #include <stdio.h>
  27 #include <stdarg.h>
  28 #include <errno.h>
  29 
  30 #ifndef MAXFQDNLEN
  31 #define MAXFQDNLEN 255
  32 #endif
  33 
  34 #ifdef _WIN32
  35 
  36 #include <windows.h>
  37 
  38 typedef unsigned int in_addr_t;
  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 <netinet/tcp.h>
  75 # include <arpa/inet.h>
  76 # include <netdb.h>
  77 # include <signal.h>
  78 
  79 # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
  80 #  include <sys/poll.h>
  81 # endif
  82 # if defined(HAVE_SYS_SELECT_H)
  83 #  include <sys/select.h>
  84 # endif
  85 
  86 #ifndef INADDR_NONE
  87 #define INADDR_NONE ((unsigned long) -1)
  88 #endif
  89 
  90 # ifndef HAVE_SOCKLEN_T
  91         typedef unsigned int socklen_t;
  92 # endif
  93 
  94 # ifdef USE_LOCKING
  95 #  define FCGI_LOCK(fd)                                                         \
  96         do {                                                                                    \
  97                 struct flock lock;                                                      \
  98                 lock.l_type = F_WRLCK;                                          \
  99                 lock.l_start = 0;                                                       \
 100                 lock.l_whence = SEEK_SET;                                       \
 101                 lock.l_len = 0;                                                         \
 102                 if (fcntl(fd, F_SETLKW, &lock) != -1) {         \
 103                         break;                                                                  \
 104                 } else if (errno != EINTR || in_shutdown) {     \
 105                         return -1;                                                              \
 106                 }                                                                                       \
 107         } while (1)
 108 
 109 #  define FCGI_UNLOCK(fd)                                                       \
 110         do {                                                                                    \
 111                 int orig_errno = errno;                                         \
 112                 while (1) {                                                                     \
 113                         struct flock lock;                                              \
 114                         lock.l_type = F_UNLCK;                                  \
 115                         lock.l_start = 0;                                               \
 116                         lock.l_whence = SEEK_SET;                               \
 117                         lock.l_len = 0;                                                 \
 118                         if (fcntl(fd, F_SETLK, &lock) != -1) {  \
 119                                 break;                                                          \
 120                         } else if (errno != EINTR) {                    \
 121                                 return -1;                                                      \
 122                         }                                                                               \
 123                 }                                                                                       \
 124                 errno = orig_errno;                                                     \
 125         } while (0)
 126 # else
 127 #  define FCGI_LOCK(fd)
 128 #  define FCGI_UNLOCK(fd)
 129 # endif
 130 
 131 #endif
 132 
 133 #include "fastcgi.h"
 134 
 135 typedef struct _fcgi_header {
 136         unsigned char version;
 137         unsigned char type;
 138         unsigned char requestIdB1;
 139         unsigned char requestIdB0;
 140         unsigned char contentLengthB1;
 141         unsigned char contentLengthB0;
 142         unsigned char paddingLength;
 143         unsigned char reserved;
 144 } fcgi_header;
 145 
 146 typedef struct _fcgi_begin_request {
 147         unsigned char roleB1;
 148         unsigned char roleB0;
 149         unsigned char flags;
 150         unsigned char reserved[5];
 151 } fcgi_begin_request;
 152 
 153 typedef struct _fcgi_begin_request_rec {
 154         fcgi_header hdr;
 155         fcgi_begin_request body;
 156 } fcgi_begin_request_rec;
 157 
 158 typedef struct _fcgi_end_request {
 159     unsigned char appStatusB3;
 160     unsigned char appStatusB2;
 161     unsigned char appStatusB1;
 162     unsigned char appStatusB0;
 163     unsigned char protocolStatus;
 164     unsigned char reserved[3];
 165 } fcgi_end_request;
 166 
 167 typedef struct _fcgi_end_request_rec {
 168         fcgi_header hdr;
 169         fcgi_end_request body;
 170 } fcgi_end_request_rec;
 171 
 172 typedef struct _fcgi_hash_bucket {
 173         unsigned int              hash_value;
 174         unsigned int              var_len;
 175         char                     *var;
 176         unsigned int              val_len;
 177         char                     *val;
 178         struct _fcgi_hash_bucket *next;
 179         struct _fcgi_hash_bucket *list_next;
 180 } fcgi_hash_bucket;
 181 
 182 typedef struct _fcgi_hash_buckets {
 183         unsigned int               idx;
 184         struct _fcgi_hash_buckets *next;
 185         struct _fcgi_hash_bucket   data[FCGI_HASH_TABLE_SIZE];
 186 } fcgi_hash_buckets;
 187 
 188 typedef struct _fcgi_data_seg {
 189         char                  *pos;
 190         char                  *end;
 191         struct _fcgi_data_seg *next;
 192         char                   data[1];
 193 } fcgi_data_seg;
 194 
 195 typedef struct _fcgi_hash {
 196         fcgi_hash_bucket  *hash_table[FCGI_HASH_TABLE_SIZE];
 197         fcgi_hash_bucket  *list;
 198         fcgi_hash_buckets *buckets;
 199         fcgi_data_seg     *data;
 200 } fcgi_hash;
 201 
 202 typedef struct _fcgi_req_hook   fcgi_req_hook;
 203 
 204 struct _fcgi_req_hook {
 205         void(*on_accept)();
 206         void(*on_read)();
 207         void(*on_close)();
 208 };
 209 
 210 struct _fcgi_request {
 211         int            listen_socket;
 212         int            tcp;
 213         int            fd;
 214         int            id;
 215         int            keep;
 216 #ifdef TCP_NODELAY
 217         int            nodelay;
 218 #endif
 219         int            closed;
 220         int            in_len;
 221         int            in_pad;
 222 
 223         fcgi_header   *out_hdr;
 224 
 225         unsigned char *out_pos;
 226         unsigned char  out_buf[1024*8];
 227         unsigned char  reserved[sizeof(fcgi_end_request_rec)];
 228 
 229         fcgi_req_hook  hook;
 230 
 231         int            has_env;
 232         fcgi_hash      env;
 233 };
 234 
 235 /* maybe it's better to use weak name instead */
 236 #ifndef HAVE_ATTRIBUTE_WEAK
 237 static fcgi_logger fcgi_log;
 238 #endif
 239 
 240 typedef union _sa_t {
 241         struct sockaddr     sa;
 242         struct sockaddr_un  sa_unix;
 243         struct sockaddr_in  sa_inet;
 244         struct sockaddr_in6 sa_inet6;
 245 } sa_t;
 246 
 247 static HashTable fcgi_mgmt_vars;
 248 
 249 static int is_initialized = 0;
 250 static int is_fastcgi = 0;
 251 static int in_shutdown = 0;
 252 static sa_t *allowed_clients = NULL;
 253 static sa_t client_sa;
 254 
 255 /* hash table */
 256 static void fcgi_hash_init(fcgi_hash *h)
 257 {
 258         memset(h->hash_table, 0, sizeof(h->hash_table));
 259         h->list = NULL;
 260         h->buckets = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
 261         h->buckets->idx = 0;
 262         h->buckets->next = NULL;
 263         h->data = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + FCGI_HASH_SEG_SIZE);
 264         h->data->pos = h->data->data;
 265         h->data->end = h->data->pos + FCGI_HASH_SEG_SIZE;
 266         h->data->next = NULL;
 267 }
 268 
 269 static void fcgi_hash_destroy(fcgi_hash *h)
 270 {
 271         fcgi_hash_buckets *b;
 272         fcgi_data_seg *p;
 273 
 274         b = h->buckets;
 275         while (b) {
 276                 fcgi_hash_buckets *q = b;
 277                 b = b->next;
 278                 free(q);
 279         }
 280         p = h->data;
 281         while (p) {
 282                 fcgi_data_seg *q = p;
 283                 p = p->next;
 284                 free(q);
 285         }
 286 }
 287 
 288 static void fcgi_hash_clean(fcgi_hash *h)
 289 {
 290         memset(h->hash_table, 0, sizeof(h->hash_table));
 291         h->list = NULL;
 292         /* delete all bucket blocks except the first one */
 293         while (h->buckets->next) {
 294                 fcgi_hash_buckets *q = h->buckets;
 295 
 296                 h->buckets = h->buckets->next;
 297                 free(q);
 298         }
 299         h->buckets->idx = 0;
 300         /* delete all data segments except the first one */
 301         while (h->data->next) {
 302                 fcgi_data_seg *q = h->data;
 303 
 304                 h->data = h->data->next;
 305                 free(q);
 306         }
 307         h->data->pos = h->data->data;
 308 }
 309 
 310 static inline char* fcgi_hash_strndup(fcgi_hash *h, char *str, unsigned int str_len)
 311 {
 312         char *ret;
 313 
 314         if (UNEXPECTED(h->data->pos + str_len + 1 >= h->data->end)) {
 315                 unsigned int seg_size = (str_len + 1 > FCGI_HASH_SEG_SIZE) ? str_len + 1 : FCGI_HASH_SEG_SIZE;
 316                 fcgi_data_seg *p = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + seg_size);
 317 
 318                 p->pos = p->data;
 319                 p->end = p->pos + seg_size;
 320                 p->next = h->data;
 321                 h->data = p;
 322         }
 323         ret = h->data->pos;
 324         memcpy(ret, str, str_len);
 325         ret[str_len] = 0;
 326         h->data->pos += str_len + 1;
 327         return ret;
 328 }
 329 
 330 static char* fcgi_hash_set(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, char *val, unsigned int val_len)
 331 {
 332         unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 333         fcgi_hash_bucket *p = h->hash_table[idx];
 334 
 335         while (UNEXPECTED(p != NULL)) {
 336                 if (UNEXPECTED(p->hash_value == hash_value) &&
 337                     p->var_len == var_len &&
 338                     memcmp(p->var, var, var_len) == 0) {
 339 
 340                         p->val_len = val_len;
 341                         p->val = fcgi_hash_strndup(h, val, val_len);
 342                         return p->val;
 343                 }
 344                 p = p->next;
 345         }
 346 
 347         if (UNEXPECTED(h->buckets->idx >= FCGI_HASH_TABLE_SIZE)) {
 348                 fcgi_hash_buckets *b = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
 349                 b->idx = 0;
 350                 b->next = h->buckets;
 351                 h->buckets = b;
 352         }
 353         p = h->buckets->data + h->buckets->idx;
 354         h->buckets->idx++;
 355         p->next = h->hash_table[idx];
 356         h->hash_table[idx] = p;
 357         p->list_next = h->list;
 358         h->list = p;
 359         p->hash_value = hash_value;
 360         p->var_len = var_len;
 361         p->var = fcgi_hash_strndup(h, var, var_len);
 362         p->val_len = val_len;
 363         p->val = fcgi_hash_strndup(h, val, val_len);
 364         return p->val;
 365 }
 366 
 367 static void fcgi_hash_del(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len)
 368 {
 369         unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 370         fcgi_hash_bucket **p = &h->hash_table[idx];
 371 
 372         while (*p != NULL) {
 373                 if ((*p)->hash_value == hash_value &&
 374                     (*p)->var_len == var_len &&
 375                     memcmp((*p)->var, var, var_len) == 0) {
 376 
 377                     (*p)->val = NULL; /* NULL value means deleted */
 378                     (*p)->val_len = 0;
 379                         *p = (*p)->next;
 380                     return;
 381                 }
 382                 p = &(*p)->next;
 383         }
 384 }
 385 
 386 static char *fcgi_hash_get(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, unsigned int *val_len)
 387 {
 388         unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 389         fcgi_hash_bucket *p = h->hash_table[idx];
 390 
 391         while (p != NULL) {
 392                 if (p->hash_value == hash_value &&
 393                     p->var_len == var_len &&
 394                     memcmp(p->var, var, var_len) == 0) {
 395                     *val_len = p->val_len;
 396                     return p->val;
 397                 }
 398                 p = p->next;
 399         }
 400         return NULL;
 401 }
 402 
 403 static void fcgi_hash_apply(fcgi_hash *h, fcgi_apply_func func, void *arg)
 404 {
 405         fcgi_hash_bucket *p     = h->list;
 406 
 407         while (p) {
 408                 if (EXPECTED(p->val != NULL)) {
 409                         func(p->var, p->var_len, p->val, p->val_len, arg);
 410                 }
 411                 p = p->list_next;
 412         }
 413 }
 414 
 415 #ifdef _WIN32
 416 
 417 static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
 418 {
 419         HANDLE shutdown_event = (HANDLE) arg;
 420         WaitForSingleObject(shutdown_event, INFINITE);
 421         in_shutdown = 1;
 422         return 0;
 423 }
 424 
 425 #else
 426 
 427 static void fcgi_signal_handler(int signo)
 428 {
 429         if (signo == SIGUSR1 || signo == SIGTERM) {
 430                 in_shutdown = 1;
 431         }
 432 }
 433 
 434 static void fcgi_setup_signals(void)
 435 {
 436         struct sigaction new_sa, old_sa;
 437 
 438         sigemptyset(&new_sa.sa_mask);
 439         new_sa.sa_flags = 0;
 440         new_sa.sa_handler = fcgi_signal_handler;
 441         sigaction(SIGUSR1, &new_sa, NULL);
 442         sigaction(SIGTERM, &new_sa, NULL);
 443         sigaction(SIGPIPE, NULL, &old_sa);
 444         if (old_sa.sa_handler == SIG_DFL) {
 445                 sigaction(SIGPIPE, &new_sa, NULL);
 446         }
 447 }
 448 #endif
 449 
 450 void fcgi_set_in_shutdown(int new_value)
 451 {
 452         in_shutdown = new_value;
 453 }
 454 
 455 int fcgi_in_shutdown(void)
 456 {
 457         return in_shutdown;
 458 }
 459 
 460 void fcgi_terminate(void)
 461 {
 462         in_shutdown = 1;
 463 }
 464 
 465 #ifndef HAVE_ATTRIBUTE_WEAK
 466 void fcgi_set_logger(fcgi_logger lg) {
 467         fcgi_log = lg;
 468 }
 469 #else
 470 void __attribute__((weak)) fcgi_log(int type, const char *format, ...) {
 471         va_list ap;
 472 
 473         va_start(ap, format);
 474         vfprintf(stderr, format, ap);
 475         va_end(ap);
 476 }
 477 #endif
 478 
 479 int fcgi_init(void)
 480 {
 481         if (!is_initialized) {
 482 #ifndef _WIN32
 483                 sa_t sa;
 484                 socklen_t len = sizeof(sa);
 485 #endif
 486                 zend_hash_init(&fcgi_mgmt_vars, 8, NULL, fcgi_free_mgmt_var_cb, 1);
 487                 fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1);
 488 
 489                 is_initialized = 1;
 490 #ifdef _WIN32
 491 # if 0
 492                 /* TODO: Support for TCP sockets */
 493                 WSADATA wsaData;
 494 
 495                 if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
 496                         fprintf(stderr, "Error starting Windows Sockets.  Error: %d", WSAGetLastError());
 497                         return 0;
 498                 }
 499 # endif
 500                 if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
 501                     (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
 502                     (GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE)) {
 503                         char *str;
 504                         DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
 505                         HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
 506 
 507                         SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
 508 
 509                         str = getenv("_FCGI_SHUTDOWN_EVENT_");
 510                         if (str != NULL) {
 511                                 zend_long ev;
 512                                 HANDLE shutdown_event;
 513 
 514                                 ZEND_ATOL(ev, str);
 515                                 shutdown_event = (HANDLE) ev;
 516                                 if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
 517                                                   shutdown_event, 0, NULL)) {
 518                                         return -1;
 519                                 }
 520                         }
 521                         str = getenv("_FCGI_MUTEX_");
 522                         if (str != NULL) {
 523                                 zend_long mt;
 524                                 ZEND_ATOL(mt, str);
 525                                 fcgi_accept_mutex = (HANDLE) mt;
 526                         }
 527                         return is_fastcgi = 1;
 528                 } else {
 529                         return is_fastcgi = 0;
 530                 }
 531 #else
 532                 errno = 0;
 533                 if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
 534                         fcgi_setup_signals();
 535                         return is_fastcgi = 1;
 536                 } else {
 537                         return is_fastcgi = 0;
 538                 }
 539 #endif
 540         }
 541         return is_fastcgi;
 542 }
 543 
 544 
 545 int fcgi_is_fastcgi(void)
 546 {
 547         if (!is_initialized) {
 548                 return fcgi_init();
 549         } else {
 550                 return is_fastcgi;
 551         }
 552 }
 553 
 554 void fcgi_shutdown(void)
 555 {
 556         if (is_initialized) {
 557                 zend_hash_destroy(&fcgi_mgmt_vars);
 558         }
 559         is_fastcgi = 0;
 560         if (allowed_clients) {
 561                 free(allowed_clients);
 562         }
 563 }
 564 
 565 #ifdef _WIN32
 566 /* Do some black magic with the NT security API.
 567  * We prepare a DACL (Discretionary Access Control List) so that
 568  * we, the creator, are allowed all access, while "Everyone Else"
 569  * is only allowed to read and write to the pipe.
 570  * This avoids security issues on shared hosts where a luser messes
 571  * with the lower-level pipe settings and screws up the FastCGI service.
 572  */
 573 static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd, LPSECURITY_ATTRIBUTES sa)
 574 {
 575         DWORD req_acl_size;
 576         char everyone_buf[32], owner_buf[32];
 577         PSID sid_everyone, sid_owner;
 578         SID_IDENTIFIER_AUTHORITY
 579                 siaWorld = SECURITY_WORLD_SID_AUTHORITY,
 580                 siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
 581         PACL acl;
 582 
 583         sid_everyone = (PSID)&everyone_buf;
 584         sid_owner = (PSID)&owner_buf;
 585 
 586         req_acl_size = sizeof(ACL) +
 587                 (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetSidLengthRequired(1)));
 588 
 589         acl = malloc(req_acl_size);
 590 
 591         if (acl == NULL) {
 592                 return NULL;
 593         }
 594 
 595         if (!InitializeSid(sid_everyone, &siaWorld, 1)) {
 596                 goto out_fail;
 597         }
 598         *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID;
 599 
 600         if (!InitializeSid(sid_owner, &siaCreator, 1)) {
 601                 goto out_fail;
 602         }
 603         *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID;
 604 
 605         if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) {
 606                 goto out_fail;
 607         }
 608 
 609         if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE, sid_everyone)) {
 610                 goto out_fail;
 611         }
 612 
 613         if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) {
 614                 goto out_fail;
 615         }
 616 
 617         if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
 618                 goto out_fail;
 619         }
 620 
 621         if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) {
 622                 goto out_fail;
 623         }
 624 
 625         sa->lpSecurityDescriptor = sd;
 626 
 627         return acl;
 628 
 629 out_fail:
 630         free(acl);
 631         return NULL;
 632 }
 633 #endif
 634 
 635 static int is_port_number(const char *bindpath)
 636 {
 637         while (*bindpath) {
 638                 if (*bindpath < '0' || *bindpath > '9') {
 639                         return 0;
 640                 }
 641                 bindpath++;
 642         }
 643         return 1;
 644 }
 645 
 646 int fcgi_listen(const char *path, int backlog)
 647 {
 648         char     *s;
 649         int       tcp = 0;
 650         char      host[MAXPATHLEN];
 651         short     port = 0;
 652         int       listen_socket;
 653         sa_t      sa;
 654         socklen_t sock_len;
 655 #ifdef SO_REUSEADDR
 656 # ifdef _WIN32
 657         BOOL reuse = 1;
 658 # else
 659         int reuse = 1;
 660 # endif
 661 #endif
 662 
 663         if ((s = strchr(path, ':'))) {
 664                 port = atoi(s+1);
 665                 if (port != 0 && (s-path) < MAXPATHLEN) {
 666                         strncpy(host, path, s-path);
 667                         host[s-path] = '\0';
 668                         tcp = 1;
 669                 }
 670         } else if (is_port_number(path)) {
 671                 port = atoi(path);
 672                 if (port != 0) {
 673                         host[0] = '\0';
 674                         tcp = 1;
 675                 }
 676         }
 677 
 678         /* Prepare socket address */
 679         if (tcp) {
 680                 memset(&sa.sa_inet, 0, sizeof(sa.sa_inet));
 681                 sa.sa_inet.sin_family = AF_INET;
 682                 sa.sa_inet.sin_port = htons(port);
 683                 sock_len = sizeof(sa.sa_inet);
 684 
 685                 if (!*host || !strncmp(host, "*", sizeof("*")-1)) {
 686                         sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY);
 687                 } else {
 688                         sa.sa_inet.sin_addr.s_addr = inet_addr(host);
 689                         if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) {
 690                                 struct hostent *hep;
 691 
 692                                 if(strlen(host) > MAXFQDNLEN) {
 693                                         hep = NULL;
 694                                 } else {
 695                                         hep = gethostbyname(host);
 696                                 }
 697                                 if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
 698                                         fcgi_log(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host);
 699                                         return -1;
 700                                 } else if (hep->h_addr_list[1]) {
 701                                         fcgi_log(FCGI_ERROR, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
 702                                         return -1;
 703                                 }
 704                                 sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
 705                         }
 706                 }
 707         } else {
 708 #ifdef _WIN32
 709                 SECURITY_DESCRIPTOR  sd;
 710                 SECURITY_ATTRIBUTES  saw;
 711                 PACL                 acl;
 712                 HANDLE namedPipe;
 713 
 714                 memset(&sa, 0, sizeof(saw));
 715                 saw.nLength = sizeof(saw);
 716                 saw.bInheritHandle = FALSE;
 717                 acl = prepare_named_pipe_acl(&sd, &saw);
 718 
 719                 namedPipe = CreateNamedPipe(path,
 720                         PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
 721                         PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
 722                         PIPE_UNLIMITED_INSTANCES,
 723                         8192, 8192, 0, &saw);
 724                 if (namedPipe == INVALID_HANDLE_VALUE) {
 725                         return -1;
 726                 }
 727                 listen_socket = _open_osfhandle((intptr_t)namedPipe, 0);
 728                 if (!is_initialized) {
 729                         fcgi_init();
 730                 }
 731                 is_fastcgi = 1;
 732                 return listen_socket;
 733 
 734 #else
 735                 int path_len = strlen(path);
 736 
 737                 if (path_len >= sizeof(sa.sa_unix.sun_path)) {
 738                         fcgi_log(FCGI_ERROR, "Listening socket's path name is too long.\n");
 739                         return -1;
 740                 }
 741 
 742                 memset(&sa.sa_unix, 0, sizeof(sa.sa_unix));
 743                 sa.sa_unix.sun_family = AF_UNIX;
 744                 memcpy(sa.sa_unix.sun_path, path, path_len + 1);
 745                 sock_len = (size_t)(((struct sockaddr_un *)0)->sun_path)        + path_len;
 746 #ifdef HAVE_SOCKADDR_UN_SUN_LEN
 747                 sa.sa_unix.sun_len = sock_len;
 748 #endif
 749                 unlink(path);
 750 #endif
 751         }
 752 
 753         /* Create, bind socket and start listen on it */
 754         if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 ||
 755 #ifdef SO_REUSEADDR
 756             setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0 ||
 757 #endif
 758             bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
 759             listen(listen_socket, backlog) < 0) {
 760 
 761                 fcgi_log(FCGI_ERROR, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
 762                 return -1;
 763         }
 764 
 765         if (!tcp) {
 766                 chmod(path, 0777);
 767         } else {
 768                 char *ip = getenv("FCGI_WEB_SERVER_ADDRS");
 769                 char *cur, *end;
 770                 int n;
 771 
 772                 if (ip) {
 773                         ip = strdup(ip);
 774                         cur = ip;
 775                         n = 0;
 776                         while (*cur) {
 777                                 if (*cur == ',') n++;
 778                                 cur++;
 779                         }
 780                         allowed_clients = malloc(sizeof(sa_t) * (n+2));
 781                         n = 0;
 782                         cur = ip;
 783                         while (cur) {
 784                                 end = strchr(cur, ',');
 785                                 if (end) {
 786                                         *end = 0;
 787                                         end++;
 788                                 }
 789                                 if (inet_pton(AF_INET, cur, &allowed_clients[n].sa_inet.sin_addr)>0) {
 790                                         allowed_clients[n].sa.sa_family = AF_INET;
 791                                         n++;
 792 #ifdef HAVE_IPV6
 793                                 } else if (inet_pton(AF_INET6, cur, &allowed_clients[n].sa_inet6.sin6_addr)>0) {
 794                                         allowed_clients[n].sa.sa_family = AF_INET6;
 795                                         n++;
 796 #endif
 797                                 } else {
 798                                         fcgi_log(FCGI_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
 799                                 }
 800                                 cur = end;
 801                         }
 802                         allowed_clients[n].sa.sa_family = 0;
 803                         free(ip);
 804                         if (!n) {
 805                                 fcgi_log(FCGI_ERROR, "There are no allowed addresses");
 806                                 /* don't clear allowed_clients as it will create an "open for all" security issue */
 807                         }
 808                 }
 809         }
 810 
 811         if (!is_initialized) {
 812                 fcgi_init();
 813         }
 814         is_fastcgi = 1;
 815 
 816 #ifdef _WIN32
 817         if (tcp) {
 818                 listen_socket = _open_osfhandle((intptr_t)listen_socket, 0);
 819         }
 820 #else
 821         fcgi_setup_signals();
 822 #endif
 823         return listen_socket;
 824 }
 825 
 826 void fcgi_set_allowed_clients(char *ip)
 827 {
 828         char *cur, *end;
 829         int n;
 830 
 831         if (ip) {
 832                 ip = strdup(ip);
 833                 cur = ip;
 834                 n = 0;
 835                 while (*cur) {
 836                         if (*cur == ',') n++;
 837                         cur++;
 838                 }
 839                 if (allowed_clients) free(allowed_clients);
 840                 allowed_clients = malloc(sizeof(sa_t) * (n+2));
 841                 n = 0;
 842                 cur = ip;
 843                 while (cur) {
 844                         end = strchr(cur, ',');
 845                         if (end) {
 846                                 *end = 0;
 847                                 end++;
 848                         }
 849                         if (inet_pton(AF_INET, cur, &allowed_clients[n].sa_inet.sin_addr)>0) {
 850                                 allowed_clients[n].sa.sa_family = AF_INET;
 851                                 n++;
 852 #ifdef HAVE_IPV6
 853                         } else if (inet_pton(AF_INET6, cur, &allowed_clients[n].sa_inet6.sin6_addr)>0) {
 854                                 allowed_clients[n].sa.sa_family = AF_INET6;
 855                                 n++;
 856 #endif
 857                         } else {
 858                                 fcgi_log(FCGI_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
 859                         }
 860                         cur = end;
 861                 }
 862                 allowed_clients[n].sa.sa_family = 0;
 863                 free(ip);
 864                 if (!n) {
 865                         fcgi_log(FCGI_ERROR, "There are no allowed addresses");
 866                         /* don't clear allowed_clients as it will create an "open for all" security issue */
 867                 }
 868         }
 869 }
 870 
 871 static void fcgi_hook_dummy() {
 872         return;
 873 }
 874 
 875 fcgi_request *fcgi_init_request(int listen_socket, void(*on_accept)(), void(*on_read)(), void(*on_close)())
 876 {
 877         fcgi_request *req = calloc(1, sizeof(fcgi_request));
 878         req->listen_socket = listen_socket;
 879         req->fd = -1;
 880         req->id = -1;
 881 
 882         /*
 883         req->in_len = 0;
 884         req->in_pad = 0;
 885 
 886         req->out_hdr = NULL;
 887 
 888 #ifdef TCP_NODELAY
 889         req->nodelay = 0;
 890 #endif
 891 
 892         req->env = NULL;
 893         req->has_env = 0;
 894 
 895         */
 896         req->out_pos = req->out_buf;
 897         req->hook.on_accept = on_accept ? on_accept : fcgi_hook_dummy;
 898         req->hook.on_read = on_read ? on_read : fcgi_hook_dummy;
 899         req->hook.on_close = on_close ? on_close : fcgi_hook_dummy;
 900 
 901 #ifdef _WIN32
 902         req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
 903 #endif
 904 
 905         fcgi_hash_init(&req->env);
 906 
 907         return req;
 908 }
 909 
 910 void fcgi_destroy_request(fcgi_request *req) {
 911         fcgi_hash_destroy(&req->env);
 912         free(req);
 913 }
 914 
 915 static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
 916 {
 917         int    ret;
 918         size_t n = 0;
 919 
 920         do {
 921 #ifdef _WIN32
 922                 size_t tmp;
 923 #endif
 924                 errno = 0;
 925 #ifdef _WIN32
 926                 tmp = count - n;
 927 
 928                 if (!req->tcp) {
 929                         unsigned int out_len = tmp > UINT_MAX ? UINT_MAX : (unsigned int)tmp;
 930 
 931                         ret = write(req->fd, ((char*)buf)+n, out_len);
 932                 } else {
 933                         int out_len = tmp > INT_MAX ? INT_MAX : (int)tmp;
 934 
 935                         ret = send(req->fd, ((char*)buf)+n, out_len, 0);
 936                         if (ret <= 0) {
 937                                 errno = WSAGetLastError();
 938                         }
 939                 }
 940 #else
 941                 ret = write(req->fd, ((char*)buf)+n, count-n);
 942 #endif
 943                 if (ret > 0) {
 944                         n += ret;
 945                 } else if (ret <= 0 && errno != 0 && errno != EINTR) {
 946                         return ret;
 947                 }
 948         } while (n != count);
 949         return n;
 950 }
 951 
 952 static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
 953 {
 954         int    ret;
 955         size_t n = 0;
 956 
 957         do {
 958 #ifdef _WIN32
 959                 size_t tmp;
 960 #endif
 961                 errno = 0;
 962 #ifdef _WIN32
 963                 tmp = count - n;
 964 
 965                 if (!req->tcp) {
 966                         unsigned int in_len = tmp > UINT_MAX ? UINT_MAX : (unsigned int)tmp;
 967 
 968                         ret = read(req->fd, ((char*)buf)+n, in_len);
 969                 } else {
 970                         int in_len = tmp > INT_MAX ? INT_MAX : (int)tmp;
 971 
 972                         ret = recv(req->fd, ((char*)buf)+n, in_len, 0);
 973                         if (ret <= 0) {
 974                                 errno = WSAGetLastError();
 975                         }
 976                 }
 977 #else
 978                 ret = read(req->fd, ((char*)buf)+n, count-n);
 979 #endif
 980                 if (ret > 0) {
 981                         n += ret;
 982                 } else if (ret == 0 && errno == 0) {
 983                         return n;
 984                 } else if (ret <= 0 && errno != 0 && errno != EINTR) {
 985                         return ret;
 986                 }
 987         } while (n != count);
 988         return n;
 989 }
 990 
 991 static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
 992 {
 993         int pad = ((len + 7) & ~7) - len;
 994 
 995         hdr->contentLengthB0 = (unsigned char)(len & 0xff);
 996         hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
 997         hdr->paddingLength = (unsigned char)pad;
 998         hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
 999         hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
1000         hdr->reserved = 0;
1001         hdr->type = type;
1002         hdr->version = FCGI_VERSION_1;
1003         if (pad) {
1004                 memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
1005         }
1006         return pad;
1007 }
1008 
1009 static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
1010 {
1011         unsigned int name_len, val_len;
1012 
1013         while (p < end) {
1014                 name_len = *p++;
1015                 if (UNEXPECTED(name_len >= 128)) {
1016                         if (UNEXPECTED(p + 3 >= end)) return 0;
1017                         name_len = ((name_len & 0x7f) << 24);
1018                         name_len |= (*p++ << 16);
1019                         name_len |= (*p++ << 8);
1020                         name_len |= *p++;
1021                 }
1022                 if (UNEXPECTED(p >= end)) return 0;
1023                 val_len = *p++;
1024                 if (UNEXPECTED(val_len >= 128)) {
1025                         if (UNEXPECTED(p + 3 >= end)) return 0;
1026                         val_len = ((val_len & 0x7f) << 24);
1027                         val_len |= (*p++ << 16);
1028                         val_len |= (*p++ << 8);
1029                         val_len |= *p++;
1030                 }
1031                 if (UNEXPECTED(name_len + val_len > (unsigned int) (end - p))) {
1032                         /* Malformated request */
1033                         return 0;
1034                 }
1035                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC(p, name_len), (char*)p, name_len, (char*)p + name_len, val_len);
1036                 p += name_len + val_len;
1037         }
1038         return 1;
1039 }
1040 
1041 static int fcgi_read_request(fcgi_request *req)
1042 {
1043         fcgi_header hdr;
1044         int len, padding;
1045         unsigned char buf[FCGI_MAX_LENGTH+8];
1046 
1047         req->keep = 0;
1048         req->closed = 0;
1049         req->in_len = 0;
1050         req->out_hdr = NULL;
1051         req->out_pos = req->out_buf;
1052         req->has_env = 1;
1053 
1054         if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
1055             hdr.version < FCGI_VERSION_1) {
1056                 return 0;
1057         }
1058 
1059         len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
1060         padding = hdr.paddingLength;
1061 
1062         while (hdr.type == FCGI_STDIN && len == 0) {
1063                 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
1064                     hdr.version < FCGI_VERSION_1) {
1065                         return 0;
1066                 }
1067 
1068                 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
1069                 padding = hdr.paddingLength;
1070         }
1071 
1072         if (len + padding > FCGI_MAX_LENGTH) {
1073                 return 0;
1074         }
1075 
1076         req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
1077 
1078         if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
1079                 if (safe_read(req, buf, len+padding) != len+padding) {
1080                         return 0;
1081                 }
1082 
1083                 req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
1084 #ifdef TCP_NODELAY
1085                 if (req->keep && req->tcp && !req->nodelay) {
1086 # ifdef _WIN32
1087                         BOOL on = 1;
1088 # else
1089                         int on = 1;
1090 # endif
1091 
1092                         setsockopt(req->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on));
1093                         req->nodelay = 1;
1094                 }
1095 #endif
1096                 switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
1097                         case FCGI_RESPONDER:
1098                                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
1099                                 break;
1100                         case FCGI_AUTHORIZER:
1101                                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
1102                                 break;
1103                         case FCGI_FILTER:
1104                                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
1105                                 break;
1106                         default:
1107                                 return 0;
1108                 }
1109 
1110                 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
1111                     hdr.version < FCGI_VERSION_1) {
1112                         return 0;
1113                 }
1114 
1115                 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
1116                 padding = hdr.paddingLength;
1117 
1118                 while (hdr.type == FCGI_PARAMS && len > 0) {
1119                         if (len + padding > FCGI_MAX_LENGTH) {
1120                                 return 0;
1121                         }
1122 
1123                         if (safe_read(req, buf, len+padding) != len+padding) {
1124                                 req->keep = 0;
1125                                 return 0;
1126                         }
1127 
1128                         if (!fcgi_get_params(req, buf, buf+len)) {
1129                                 req->keep = 0;
1130                                 return 0;
1131                         }
1132 
1133                         if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
1134                             hdr.version < FCGI_VERSION_1) {
1135                                 req->keep = 0;
1136                                 return 0;
1137                         }
1138                         len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
1139                         padding = hdr.paddingLength;
1140                 }
1141         } else if (hdr.type == FCGI_GET_VALUES) {
1142                 unsigned char *p = buf + sizeof(fcgi_header);
1143                 zval *value;
1144                 unsigned int zlen;
1145                 fcgi_hash_bucket *q;
1146 
1147                 if (safe_read(req, buf, len+padding) != len+padding) {
1148                         req->keep = 0;
1149                         return 0;
1150                 }
1151 
1152                 if (!fcgi_get_params(req, buf, buf+len)) {
1153                         req->keep = 0;
1154                         return 0;
1155                 }
1156 
1157                 q = req->env.list;
1158                 while (q != NULL) {
1159                         if ((value = zend_hash_str_find(&fcgi_mgmt_vars, q->var, q->var_len)) == NULL) {
1160                                 q = q->list_next;
1161                                 continue;
1162                         }
1163                         zlen = (unsigned int)Z_STRLEN_P(value);
1164                         if ((p + 4 + 4 + q->var_len + zlen) >= (buf + sizeof(buf))) {
1165                                 break;
1166                         }
1167                         if (q->var_len < 0x80) {
1168                                 *p++ = q->var_len;
1169                         } else {
1170                                 *p++ = ((q->var_len >> 24) & 0xff) | 0x80;
1171                                 *p++ = (q->var_len >> 16) & 0xff;
1172                                 *p++ = (q->var_len >> 8) & 0xff;
1173                                 *p++ = q->var_len & 0xff;
1174                         }
1175                         if (zlen < 0x80) {
1176                                 *p++ = zlen;
1177                         } else {
1178                                 *p++ = ((zlen >> 24) & 0xff) | 0x80;
1179                                 *p++ = (zlen >> 16) & 0xff;
1180                                 *p++ = (zlen >> 8) & 0xff;
1181                                 *p++ = zlen & 0xff;
1182                         }
1183                         memcpy(p, q->var, q->var_len);
1184                         p += q->var_len;
1185                         memcpy(p, Z_STRVAL_P(value), zlen);
1186                         p += zlen;
1187                         q = q->list_next;
1188                 }
1189                 len = (int)(p - buf - sizeof(fcgi_header));
1190                 len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
1191                 if (safe_write(req, buf, sizeof(fcgi_header) + len) != (ssize_t)sizeof(fcgi_header)+len) {
1192                         req->keep = 0;
1193                         return 0;
1194                 }
1195                 return 0;
1196         } else {
1197                 return 0;
1198         }
1199 
1200         return 1;
1201 }
1202 
1203 int fcgi_read(fcgi_request *req, char *str, int len)
1204 {
1205         int ret, n, rest;
1206         fcgi_header hdr;
1207         unsigned char buf[255];
1208 
1209         n = 0;
1210         rest = len;
1211         while (rest > 0) {
1212                 if (req->in_len == 0) {
1213                         if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
1214                             hdr.version < FCGI_VERSION_1 ||
1215                             hdr.type != FCGI_STDIN) {
1216                                 req->keep = 0;
1217                                 return 0;
1218                         }
1219                         req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
1220                         req->in_pad = hdr.paddingLength;
1221                         if (req->in_len == 0) {
1222                                 return n;
1223                         }
1224                 }
1225 
1226                 if (req->in_len >= rest) {
1227                         ret = (int)safe_read(req, str, rest);
1228                 } else {
1229                         ret = (int)safe_read(req, str, req->in_len);
1230                 }
1231                 if (ret < 0) {
1232                         req->keep = 0;
1233                         return ret;
1234                 } else if (ret > 0) {
1235                         req->in_len -= ret;
1236                         rest -= ret;
1237                         n += ret;
1238                         str += ret;
1239                         if (req->in_len == 0) {
1240                                 if (req->in_pad) {
1241                                         if (safe_read(req, buf, req->in_pad) != req->in_pad) {
1242                                                 req->keep = 0;
1243                                                 return ret;
1244                                         }
1245                                 }
1246                         } else {
1247                                 return n;
1248                         }
1249                 } else {
1250                         return n;
1251                 }
1252         }
1253         return n;
1254 }
1255 
1256 void fcgi_close(fcgi_request *req, int force, int destroy)
1257 {
1258         if (destroy && req->has_env) {
1259                 fcgi_hash_clean(&req->env);
1260                 req->has_env = 0;
1261         }
1262 
1263 #ifdef _WIN32
1264         if (is_impersonate && !req->tcp) {
1265                 RevertToSelf();
1266         }
1267 #endif
1268 
1269         if ((force || !req->keep) && req->fd >= 0) {
1270 #ifdef _WIN32
1271                 if (!req->tcp) {
1272                         HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
1273 
1274                         if (!force) {
1275                                 FlushFileBuffers(pipe);
1276                         }
1277                         DisconnectNamedPipe(pipe);
1278                 } else {
1279                         if (!force) {
1280                                 char buf[8];
1281 
1282                                 shutdown(req->fd, 1);
1283                                 /* read any remaining data, it may be omitted */
1284                                 while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
1285                         }
1286                         closesocket(req->fd);
1287                 }
1288 #else
1289                 if (!force) {
1290                         char buf[8];
1291 
1292                         shutdown(req->fd, 1);
1293                         /* read any remaining data, it may be omitted */
1294                         while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
1295                 }
1296                 close(req->fd);
1297 #endif
1298 #ifdef TCP_NODELAY
1299                 req->nodelay = 0;
1300 #endif
1301                 req->fd = -1;
1302 
1303                 req->hook.on_close();
1304         }
1305 }
1306 
1307 int fcgi_is_closed(fcgi_request *req)
1308 {
1309         return (req->fd < 0);
1310 }
1311 
1312 static int fcgi_is_allowed() {
1313         int i;
1314 
1315         if (client_sa.sa.sa_family == AF_UNIX) {
1316                 return 1;
1317         }
1318         if (!allowed_clients) {
1319                 return 1;
1320         }
1321         if (client_sa.sa.sa_family == AF_INET) {
1322                 for (i = 0; allowed_clients[i].sa.sa_family ; i++) {
1323                         if (allowed_clients[i].sa.sa_family == AF_INET
1324                                 && !memcmp(&client_sa.sa_inet.sin_addr, &allowed_clients[i].sa_inet.sin_addr, 4)) {
1325                                 return 1;
1326                         }
1327                 }
1328         }
1329 #ifdef HAVE_IPV6
1330         if (client_sa.sa.sa_family == AF_INET6) {
1331                 for (i = 0; allowed_clients[i].sa.sa_family ; i++) {
1332                         if (allowed_clients[i].sa.sa_family == AF_INET6
1333                                 && !memcmp(&client_sa.sa_inet6.sin6_addr, &allowed_clients[i].sa_inet6.sin6_addr, 12)) {
1334                                 return 1;
1335                         }
1336 #ifdef IN6_IS_ADDR_V4MAPPED
1337                         if (allowed_clients[i].sa.sa_family == AF_INET
1338                             && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)
1339                                 && !memcmp(((char *)&client_sa.sa_inet6.sin6_addr)+12, &allowed_clients[i].sa_inet.sin_addr, 4)) {
1340                                 return 1;
1341                         }
1342 #endif
1343                 }
1344         }
1345 #endif
1346 
1347         return 0;
1348 }
1349 
1350 int fcgi_accept_request(fcgi_request *req)
1351 {
1352 #ifdef _WIN32
1353         HANDLE pipe;
1354         OVERLAPPED ov;
1355 #endif
1356 
1357         while (1) {
1358                 if (req->fd < 0) {
1359                         while (1) {
1360                                 if (in_shutdown) {
1361                                         return -1;
1362                                 }
1363 #ifdef _WIN32
1364                                 if (!req->tcp) {
1365                                         pipe = (HANDLE)_get_osfhandle(req->listen_socket);
1366                                         FCGI_LOCK(req->listen_socket);
1367                                         ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1368                                         if (!ConnectNamedPipe(pipe, &ov)) {
1369                                                 errno = GetLastError();
1370                                                 if (errno == ERROR_IO_PENDING) {
1371                                                         while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
1372                                                                 if (in_shutdown) {
1373                                                                         CloseHandle(ov.hEvent);
1374                                                                         FCGI_UNLOCK(req->listen_socket);
1375                                                                         return -1;
1376                                                                 }
1377                                                         }
1378                                                 } else if (errno != ERROR_PIPE_CONNECTED) {
1379                                                 }
1380                                         }
1381                                         CloseHandle(ov.hEvent);
1382                                         req->fd = req->listen_socket;
1383                                         FCGI_UNLOCK(req->listen_socket);
1384                                 } else {
1385                                         SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
1386 #else
1387                                 {
1388                                         int listen_socket = req->listen_socket;
1389 #endif
1390                                         sa_t sa;
1391                                         socklen_t len = sizeof(sa);
1392 
1393                                         req->hook.on_accept();
1394 
1395                                         FCGI_LOCK(req->listen_socket);
1396                                         req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
1397                                         FCGI_UNLOCK(req->listen_socket);
1398 
1399                                         client_sa = sa;
1400                                         if (req->fd >= 0 && !fcgi_is_allowed()) {
1401                                                 fcgi_log(FCGI_ERROR, "Connection disallowed: IP address '%s' has been dropped.", fcgi_get_last_client_ip());
1402                                                 closesocket(req->fd);
1403                                                 req->fd = -1;
1404                                                 continue;
1405                                         }
1406                                 }
1407 
1408 #ifdef _WIN32
1409                                 if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
1410 #else
1411                                 if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
1412 #endif
1413                                         return -1;
1414                                 }
1415 
1416 #ifdef _WIN32
1417                                 break;
1418 #else
1419                                 if (req->fd >= 0) {
1420 #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
1421                                         struct pollfd fds;
1422                                         int ret;
1423 
1424                                         req->hook.on_read();
1425 
1426                                         fds.fd = req->fd;
1427                                         fds.events = POLLIN;
1428                                         fds.revents = 0;
1429                                         do {
1430                                                 errno = 0;
1431                                                 ret = poll(&fds, 1, 5000);
1432                                         } while (ret < 0 && errno == EINTR);
1433                                         if (ret > 0 && (fds.revents & POLLIN)) {
1434                                                 break;
1435                                         }
1436                                         fcgi_close(req, 1, 0);
1437 #else
1438                                         req->hook.on_read();
1439 
1440                                         if (req->fd < FD_SETSIZE) {
1441                                                 struct timeval tv = {5,0};
1442                                                 fd_set set;
1443                                                 int ret;
1444 
1445                                                 FD_ZERO(&set);
1446                                                 FD_SET(req->fd, &set);
1447                                                 do {
1448                                                         errno = 0;
1449                                                         ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
1450                                                 } while (ret < 0 && errno == EINTR);
1451                                                 if (ret > 0 && FD_ISSET(req->fd, &set)) {
1452                                                         break;
1453                                                 }
1454                                                 fcgi_close(req, 1, 0);
1455                                         } else {
1456                                                 fcgi_log(FCGI_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
1457                                                 fcgi_close(req, 1, 0);
1458                                         }
1459 #endif
1460                                 }
1461 #endif
1462                         }
1463                 } else if (in_shutdown) {
1464                         return -1;
1465                 }
1466                 if (fcgi_read_request(req)) {
1467 #ifdef _WIN32
1468                         if (is_impersonate && !req->tcp) {
1469                                 pipe = (HANDLE)_get_osfhandle(req->fd);
1470                                 if (!ImpersonateNamedPipeClient(pipe)) {
1471                                         fcgi_close(req, 1, 1);
1472                                         continue;
1473                                 }
1474                         }
1475 #endif
1476                         return req->fd;
1477                 } else {
1478                         fcgi_close(req, 1, 1);
1479                 }
1480         }
1481 }
1482 
1483 static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
1484 {
1485         req->out_hdr = (fcgi_header*) req->out_pos;
1486         req->out_hdr->type = type;
1487         req->out_pos += sizeof(fcgi_header);
1488         return req->out_hdr;
1489 }
1490 
1491 static inline void close_packet(fcgi_request *req)
1492 {
1493         if (req->out_hdr) {
1494                 int len = (int)(req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header)));
1495 
1496                 req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
1497                 req->out_hdr = NULL;
1498         }
1499 }
1500 
1501 int fcgi_flush(fcgi_request *req, int close)
1502 {
1503         int len;
1504 
1505         close_packet(req);
1506 
1507         len = (int)(req->out_pos - req->out_buf);
1508 
1509         if (close) {
1510                 fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
1511 
1512                 fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
1513                 rec->body.appStatusB3 = 0;
1514                 rec->body.appStatusB2 = 0;
1515                 rec->body.appStatusB1 = 0;
1516                 rec->body.appStatusB0 = 0;
1517                 rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
1518                 len += sizeof(fcgi_end_request_rec);
1519         }
1520 
1521         if (safe_write(req, req->out_buf, len) != len) {
1522                 req->keep = 0;
1523                 req->out_pos = req->out_buf;
1524                 return 0;
1525         }
1526 
1527         req->out_pos = req->out_buf;
1528         return 1;
1529 }
1530 
1531 int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
1532 {
1533         int limit, rest;
1534 
1535         if (len <= 0) {
1536                 return 0;
1537         }
1538 
1539         if (req->out_hdr && req->out_hdr->type != type) {
1540                 close_packet(req);
1541         }
1542 #if 0
1543         /* Unoptimized, but clear version */
1544         rest = len;
1545         while (rest > 0) {
1546                 limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1547 
1548                 if (!req->out_hdr) {
1549                         if (limit < sizeof(fcgi_header)) {
1550                                 if (!fcgi_flush(req, 0)) {
1551                                         return -1;
1552                                 }
1553                         }
1554                         open_packet(req, type);
1555                 }
1556                 limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1557                 if (rest < limit) {
1558                         memcpy(req->out_pos, str, rest);
1559                         req->out_pos += rest;
1560                         return len;
1561                 } else {
1562                         memcpy(req->out_pos, str, limit);
1563                         req->out_pos += limit;
1564                         rest -= limit;
1565                         str += limit;
1566                         if (!fcgi_flush(req, 0)) {
1567                                 return -1;
1568                         }
1569                 }
1570         }
1571 #else
1572         /* Optimized version */
1573         limit = (int)(sizeof(req->out_buf) - (req->out_pos - req->out_buf));
1574         if (!req->out_hdr) {
1575                 limit -= sizeof(fcgi_header);
1576                 if (limit < 0) limit = 0;
1577         }
1578 
1579         if (len < limit) {
1580                 if (!req->out_hdr) {
1581                         open_packet(req, type);
1582                 }
1583                 memcpy(req->out_pos, str, len);
1584                 req->out_pos += len;
1585         } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
1586                 if (!req->out_hdr) {
1587                         open_packet(req, type);
1588                 }
1589                 if (limit > 0) {
1590                         memcpy(req->out_pos, str, limit);
1591                         req->out_pos += limit;
1592                 }
1593                 if (!fcgi_flush(req, 0)) {
1594                         return -1;
1595                 }
1596                 if (len > limit) {
1597                         open_packet(req, type);
1598                         memcpy(req->out_pos, str + limit, len - limit);
1599                         req->out_pos += len - limit;
1600                 }
1601         } else {
1602                 int pos = 0;
1603                 int pad;
1604 
1605                 close_packet(req);
1606                 while ((len - pos) > 0xffff) {
1607                         open_packet(req, type);
1608                         fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1609                         req->out_hdr = NULL;
1610                         if (!fcgi_flush(req, 0)) {
1611                                 return -1;
1612                         }
1613                         if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1614                                 req->keep = 0;
1615                                 return -1;
1616                         }
1617                         pos += 0xfff8;
1618                 }
1619 
1620                 pad = (((len - pos) + 7) & ~7) - (len - pos);
1621                 rest = pad ? 8 - pad : 0;
1622 
1623                 open_packet(req, type);
1624                 fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1625                 req->out_hdr = NULL;
1626                 if (!fcgi_flush(req, 0)) {
1627                         return -1;
1628                 }
1629                 if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1630                         req->keep = 0;
1631                         return -1;
1632                 }
1633                 if (pad) {
1634                         open_packet(req, type);
1635                         memcpy(req->out_pos, str + len - rest,  rest);
1636                         req->out_pos += rest;
1637                 }
1638         }
1639 #endif
1640         return len;
1641 }
1642 
1643 int fcgi_finish_request(fcgi_request *req, int force_close)
1644 {
1645         int ret = 1;
1646 
1647         if (req->fd >= 0) {
1648                 if (!req->closed) {
1649                         ret = fcgi_flush(req, 1);
1650                         req->closed = 1;
1651                 }
1652                 fcgi_close(req, force_close, 1);
1653         }
1654         return ret;
1655 }
1656 
1657 int fcgi_has_env(fcgi_request *req)
1658 {
1659         return req && req->has_env;
1660 }
1661 
1662 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1663 {
1664         unsigned int val_len;
1665 
1666         if (!req) return NULL;
1667 
1668         return fcgi_hash_get(&req->env, FCGI_HASH_FUNC(var, var_len), (char*)var, var_len, &val_len);
1669 }
1670 
1671 char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value)
1672 {
1673         unsigned int val_len;
1674 
1675         return fcgi_hash_get(&req->env, hash_value, (char*)var, var_len, &val_len);
1676 }
1677 
1678 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1679 {
1680         if (!req) return NULL;
1681         if (val == NULL) {
1682                 fcgi_hash_del(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len);
1683                 return NULL;
1684         } else {
1685                 return fcgi_hash_set(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len, val, (unsigned int)strlen(val));
1686         }
1687 }
1688 
1689 char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val)
1690 {
1691         if (val == NULL) {
1692                 fcgi_hash_del(&req->env, hash_value, var, var_len);
1693                 return NULL;
1694         } else {
1695                 return fcgi_hash_set(&req->env, hash_value, var, var_len, val, (unsigned int)strlen(val));
1696         }
1697 }
1698 
1699 void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array)
1700 {
1701         fcgi_hash_apply(&req->env, func, array);
1702 }
1703 
1704 #ifdef _WIN32
1705 void fcgi_impersonate(void)
1706 {
1707         char *os_name;
1708 
1709         os_name = getenv("OS");
1710         if (os_name && stricmp(os_name, "Windows_NT") == 0) {
1711                 is_impersonate = 1;
1712         }
1713 }
1714 #endif
1715 
1716 void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1717 {
1718         zval zvalue;
1719         ZVAL_NEW_STR(&zvalue, zend_string_init(value, value_len, 1));
1720         zend_hash_str_add(&fcgi_mgmt_vars, name, name_len, &zvalue);
1721 }
1722 
1723 void fcgi_free_mgmt_var_cb(zval *zv)
1724 {
1725         pefree(Z_STR_P(zv), 1);
1726 }
1727 
1728 const char *fcgi_get_last_client_ip()
1729 {
1730         static char str[INET6_ADDRSTRLEN];
1731 
1732         /* Ipv4 */
1733         if (client_sa.sa.sa_family == AF_INET) {
1734                 return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet.sin_addr, str, INET6_ADDRSTRLEN);
1735         }
1736 #ifdef HAVE_IPV6
1737 #ifdef IN6_IS_ADDR_V4MAPPED
1738         /* Ipv4-Mapped-Ipv6 */
1739         if (client_sa.sa.sa_family == AF_INET6
1740                 && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)) {
1741                 return inet_ntop(AF_INET, ((char *)&client_sa.sa_inet6.sin6_addr)+12, str, INET6_ADDRSTRLEN);
1742         }
1743 #endif
1744         /* Ipv6 */
1745         if (client_sa.sa.sa_family == AF_INET6) {
1746                 return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet6.sin6_addr, str, INET6_ADDRSTRLEN);
1747         }
1748 #endif
1749         /* Unix socket */
1750         return NULL;
1751 }
1752 
1753 /*
1754  * Local variables:
1755  * tab-width: 4
1756  * c-basic-offset: 4
1757  * End:
1758  * vim600: sw=4 ts=4 fdm=marker
1759  * vim<600: sw=4 ts=4
1760  */

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