root/sapi/nsapi/nsapi.c

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

DEFINITIONS

This source file includes following definitions.
  1. nsapi_free
  2. php_nsapi_init_dynamic_symbols
  3. php_nsapi_init_globals
  4. PHP_MINIT_FUNCTION
  5. PHP_MSHUTDOWN_FUNCTION
  6. PHP_MINFO_FUNCTION
  7. PHP_FUNCTION
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. sapi_nsapi_ub_write
  11. sapi_nsapi_flush
  12. php_nsapi_remove_header
  13. sapi_nsapi_header_handler
  14. sapi_nsapi_send_headers
  15. sapi_nsapi_read_post
  16. sapi_nsapi_read_cookies
  17. sapi_nsapi_register_server_variables
  18. nsapi_log_message
  19. sapi_nsapi_get_request_time
  20. php_nsapi_startup
  21. sapi_nsapi_get_stat
  22. nsapi_php_ini_entries
  23. php5_close
  24. php5_init
  25. php5_execute
  26. php5_auth_trans

   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    | Author: Jayakumar Muthukumarasamy <jk@kasenna.com>                   |
  16    |         Uwe Schindler <uwe@thetaphi.de>                              |
  17    +----------------------------------------------------------------------+
  18 */
  19 
  20 /* $Id: 71d7860a23c8ac8b5120062a29fec6557de307a6 $ */
  21 
  22 /*
  23  * PHP includes
  24  */
  25 #define NSAPI 1
  26 
  27 #ifdef HAVE_CONFIG_H
  28 #include "config.h"
  29 #endif
  30 
  31 #include "php.h"
  32 #include "php_variables.h"
  33 #include "ext/standard/info.h"
  34 #include "php_ini.h"
  35 #include "php_globals.h"
  36 #include "SAPI.h"
  37 #include "php_main.h"
  38 #include "php_version.h"
  39 #include "TSRM.h"
  40 #include "ext/standard/php_standard.h"
  41 #include <sys/types.h>
  42 #include <sys/stat.h>
  43 
  44 #ifndef RTLD_DEFAULT
  45 #define RTLD_DEFAULT NULL
  46 #endif
  47 
  48 /*
  49  * If neither XP_UNIX not XP_WIN32 is defined use PHP_WIN32
  50  */
  51 #if !defined(XP_UNIX) && !defined(XP_WIN32)
  52 #ifdef PHP_WIN32
  53 #define XP_WIN32
  54 #else
  55 #define XP_UNIX
  56 #endif
  57 #endif
  58 
  59 /*
  60  * The manual define of HPUX is to fix bug #46020, nsapi.h needs this to detect HPUX
  61  */
  62 #ifdef __hpux
  63 #define HPUX
  64 #endif
  65  
  66 /*
  67  * NSAPI includes
  68  */
  69 #include "nsapi.h"
  70 
  71 /* fix for gcc4 visibility issue */
  72 #ifndef PHP_WIN32
  73 # undef NSAPI_PUBLIC
  74 # define NSAPI_PUBLIC PHPAPI
  75 #endif
  76 
  77 #define NSLS_D          struct nsapi_request_context *request_context
  78 #define NSLS_DC         , NSLS_D
  79 #define NSLS_C          request_context
  80 #define NSLS_CC         , NSLS_C
  81 #define NSG(v)          (request_context->v)
  82 
  83 /*
  84  * ZTS needs to be defined for NSAPI to work
  85  */
  86 #if !defined(ZTS)
  87 #error "NSAPI module needs ZTS to be defined"
  88 #endif
  89 
  90 /*
  91  * Structure to encapsulate the NSAPI request in SAPI
  92  */
  93 typedef struct nsapi_request_context {
  94         pblock  *pb;
  95         Session *sn;
  96         Request *rq;
  97         int     read_post_bytes;
  98         char *path_info;
  99         int fixed_script; /* 0 if script is from URI, 1 if script is from "script" parameter */
 100         short http_error; /* 0 in normal mode; for errors the HTTP error code */
 101 } nsapi_request_context;
 102 
 103 /*
 104  * Mappings between NSAPI names and environment variables. This
 105  * mapping was obtained from the sample programs at the iplanet
 106  * website.
 107  */
 108 typedef struct nsapi_equiv {
 109         const char *env_var;
 110         const char *nsapi_eq;
 111 } nsapi_equiv;
 112 
 113 static nsapi_equiv nsapi_reqpb[] = {
 114         { "QUERY_STRING",               "query" },
 115         { "REQUEST_LINE",               "clf-request" },
 116         { "REQUEST_METHOD",             "method" },
 117         { "PHP_SELF",                   "uri" },
 118         { "SERVER_PROTOCOL",    "protocol" }
 119 };
 120 static size_t nsapi_reqpb_size = sizeof(nsapi_reqpb)/sizeof(nsapi_reqpb[0]);
 121 
 122 static nsapi_equiv nsapi_vars[] = {
 123         { "AUTH_TYPE",                  "auth-type" },
 124         { "CLIENT_CERT",                "auth-cert" },
 125         { "REMOTE_USER",                "auth-user" }
 126 };
 127 static size_t nsapi_vars_size = sizeof(nsapi_vars)/sizeof(nsapi_vars[0]);
 128 
 129 static nsapi_equiv nsapi_client[] = {
 130         { "HTTPS_KEYSIZE",              "keysize" },
 131         { "HTTPS_SECRETSIZE",   "secret-keysize" },
 132         { "REMOTE_ADDR",                "ip" },
 133         { "REMOTE_HOST",                "ip" }
 134 };
 135 static size_t nsapi_client_size = sizeof(nsapi_client)/sizeof(nsapi_client[0]);
 136 
 137 /* this parameters to "Service"/"Error" are NSAPI ones which should not be php.ini keys and are excluded */
 138 static char *nsapi_exclude_from_ini_entries[] = { "fn", "type", "method", "directive", "code", "reason", "script", "bucket", NULL };
 139 
 140 static void nsapi_free(void *addr)
 141 {
 142         if (addr != NULL) {
 143                 FREE(addr);
 144         }
 145 }
 146 
 147 
 148 /*******************/
 149 /* PHP module part */
 150 /*******************/
 151 
 152 PHP_MINIT_FUNCTION(nsapi);
 153 PHP_MSHUTDOWN_FUNCTION(nsapi);
 154 PHP_RINIT_FUNCTION(nsapi);
 155 PHP_RSHUTDOWN_FUNCTION(nsapi);
 156 PHP_MINFO_FUNCTION(nsapi);
 157 
 158 PHP_FUNCTION(nsapi_virtual);
 159 PHP_FUNCTION(nsapi_request_headers);
 160 PHP_FUNCTION(nsapi_response_headers);
 161 
 162 ZEND_BEGIN_MODULE_GLOBALS(nsapi)
 163         long read_timeout;
 164 ZEND_END_MODULE_GLOBALS(nsapi)
 165 
 166 ZEND_DECLARE_MODULE_GLOBALS(nsapi)
 167 
 168 #define NSAPI_G(v) TSRMG(nsapi_globals_id, zend_nsapi_globals *, v)
 169 
 170 
 171 /* {{{ arginfo */
 172 ZEND_BEGIN_ARG_INFO_EX(arginfo_nsapi_virtual, 0, 0, 1)
 173         ZEND_ARG_INFO(0, uri)
 174 ZEND_END_ARG_INFO()
 175 
 176 ZEND_BEGIN_ARG_INFO(arginfo_nsapi_request_headers, 0)
 177 ZEND_END_ARG_INFO()
 178 
 179 ZEND_BEGIN_ARG_INFO(arginfo_nsapi_response_headers, 0)
 180 ZEND_END_ARG_INFO()
 181 /* }}} */
 182 
 183 /* {{{ nsapi_functions[]
 184  *
 185  * Every user visible function must have an entry in nsapi_functions[].
 186  */
 187 const zend_function_entry nsapi_functions[] = {
 188         PHP_FE(nsapi_virtual,   arginfo_nsapi_virtual)                                          /* Make subrequest */
 189         PHP_FALIAS(virtual, nsapi_virtual, arginfo_nsapi_virtual)                       /* compatibility */
 190         PHP_FE(nsapi_request_headers, arginfo_nsapi_request_headers)            /* get request headers */
 191         PHP_FALIAS(getallheaders, nsapi_request_headers, arginfo_nsapi_request_headers) /* compatibility */
 192         PHP_FALIAS(apache_request_headers, nsapi_request_headers, arginfo_nsapi_request_headers)        /* compatibility */
 193         PHP_FE(nsapi_response_headers, arginfo_nsapi_response_headers)          /* get response headers */
 194         PHP_FALIAS(apache_response_headers, nsapi_response_headers, arginfo_nsapi_response_headers)     /* compatibility */
 195         {NULL, NULL, NULL}
 196 };
 197 /* }}} */
 198 
 199 /* {{{ nsapi_module_entry
 200  */
 201 zend_module_entry nsapi_module_entry = {
 202         STANDARD_MODULE_HEADER,
 203         "nsapi",
 204         nsapi_functions,
 205         PHP_MINIT(nsapi),
 206         PHP_MSHUTDOWN(nsapi),
 207         NULL,
 208         NULL,
 209         PHP_MINFO(nsapi),
 210         NO_VERSION_YET,
 211         STANDARD_MODULE_PROPERTIES
 212 };
 213 /* }}} */
 214 
 215 /* {{{ PHP_INI
 216  */
 217 PHP_INI_BEGIN()
 218     STD_PHP_INI_ENTRY("nsapi.read_timeout", "60", PHP_INI_ALL, OnUpdateLong, read_timeout, zend_nsapi_globals, nsapi_globals)
 219 PHP_INI_END()
 220 /* }}} */
 221 
 222 /* newer servers hide this functions from the programmer so redefine the functions dynamically
 223    thanks to Chris Elving from Sun for the function declarations */
 224 typedef int (*nsapi_servact_prototype)(Session *sn, Request *rq);
 225 nsapi_servact_prototype nsapi_servact_uri2path = NULL;
 226 nsapi_servact_prototype nsapi_servact_pathchecks = NULL;
 227 nsapi_servact_prototype nsapi_servact_fileinfo = NULL;
 228 nsapi_servact_prototype nsapi_servact_service = NULL;
 229 
 230 #ifdef PHP_WIN32
 231 /* The following dll-names for nsapi are in use at this time. The undocumented
 232  * servact_* functions are always in the newest one, older ones are supported by
 233  * the server only by wrapping the function table nothing else. So choose
 234  * the newest one found in process space for dynamic linking */
 235 static char *nsapi_dlls[] = { "ns-httpd40.dll", "ns-httpd36.dll", "ns-httpd35.dll", "ns-httpd30.dll", NULL };
 236 /* if user specifies an other dll name by server_lib parameter 
 237  * it is placed in the following variable and only this DLL is
 238  * checked for the servact_* functions */
 239 char *nsapi_dll = NULL;
 240 #endif
 241 
 242 /* {{{ php_nsapi_init_dynamic_symbols
 243  */
 244 static void php_nsapi_init_dynamic_symbols(void)
 245 {
 246         /* find address of internal NSAPI functions */
 247 #ifdef PHP_WIN32
 248         register int i;
 249         DL_HANDLE module = NULL;
 250         if (nsapi_dll) {
 251                 /* try user specified server_lib */
 252                 module = GetModuleHandle(nsapi_dll);
 253                 if (!module) {
 254                         log_error(LOG_WARN, "php5_init", NULL, NULL, "Cannot find DLL specified by server_lib parameter: %s", nsapi_dll);
 255                 }
 256         } else {
 257                 /* find a LOADED dll module from nsapi_dlls */
 258                 for (i=0; nsapi_dlls[i]; i++) {
 259                         if (module = GetModuleHandle(nsapi_dlls[i])) {
 260                                 break;
 261                         }
 262                 }
 263         }
 264         if (!module) return;
 265 #else
 266         DL_HANDLE module = RTLD_DEFAULT;
 267 #endif
 268         nsapi_servact_uri2path = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_uri2path");
 269         nsapi_servact_pathchecks = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_pathchecks");
 270         nsapi_servact_fileinfo = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_fileinfo");
 271         nsapi_servact_service = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_service");
 272         if (!(nsapi_servact_uri2path && nsapi_servact_pathchecks && nsapi_servact_fileinfo && nsapi_servact_service)) {
 273                 /* not found - could be cause they are undocumented */
 274                 nsapi_servact_uri2path = NULL;
 275                 nsapi_servact_pathchecks = NULL;
 276                 nsapi_servact_fileinfo = NULL;
 277                 nsapi_servact_service = NULL;
 278         }
 279 }
 280 /* }}} */
 281 
 282 /* {{{ php_nsapi_init_globals
 283  */
 284 static void php_nsapi_init_globals(zend_nsapi_globals *nsapi_globals)
 285 {
 286         nsapi_globals->read_timeout = 60;
 287 }
 288 /* }}} */
 289 
 290 /* {{{ PHP_MINIT_FUNCTION
 291  */
 292 PHP_MINIT_FUNCTION(nsapi)
 293 {
 294         php_nsapi_init_dynamic_symbols();
 295         ZEND_INIT_MODULE_GLOBALS(nsapi, php_nsapi_init_globals, NULL);
 296         REGISTER_INI_ENTRIES();
 297         return SUCCESS;
 298 }
 299 /* }}} */
 300 
 301 /* {{{ PHP_MSHUTDOWN_FUNCTION
 302  */
 303 PHP_MSHUTDOWN_FUNCTION(nsapi)
 304 {
 305         UNREGISTER_INI_ENTRIES();
 306         return SUCCESS;
 307 }
 308 /* }}} */
 309 
 310 /* {{{ PHP_MINFO_FUNCTION
 311  */
 312 PHP_MINFO_FUNCTION(nsapi)
 313 {
 314         php_info_print_table_start();
 315         php_info_print_table_row(2, "NSAPI Module Revision", "$Id: 71d7860a23c8ac8b5120062a29fec6557de307a6 $");
 316         php_info_print_table_row(2, "Server Software", system_version());
 317         php_info_print_table_row(2, "Sub-requests with nsapi_virtual()",
 318          (nsapi_servact_service)?((zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0))?"not supported with zlib.output_compression":"enabled"):"not supported on this platform" );
 319         php_info_print_table_end();
 320 
 321         DISPLAY_INI_ENTRIES();
 322 }
 323 /* }}} */
 324 
 325 /* {{{ proto bool nsapi_virtual(string uri)
 326    Perform an NSAPI sub-request */
 327 /* This function is equivalent to <!--#include virtual...-->
 328  * in SSI. It does an NSAPI sub-request. It is useful
 329  * for including CGI scripts or .shtml files, or anything else
 330  * that you'd parse through webserver.
 331  */
 332 PHP_FUNCTION(nsapi_virtual)
 333 {
 334         int uri_len,rv;
 335         char *uri,*value;
 336         Request *rq;
 337         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 338 
 339         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &uri, &uri_len) == FAILURE) {
 340                 return;
 341         }
 342 
 343         if (!nsapi_servact_service) {
 344                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests not supported on this platform", uri);
 345                 RETURN_FALSE;
 346         } else if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
 347                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests do not work with zlib.output_compression", uri);
 348                 RETURN_FALSE;
 349         } else {
 350                 php_output_end_all(TSRMLS_C);
 351                 php_header(TSRMLS_C);
 352 
 353                 /* do the sub-request */
 354                 /* thanks to Chris Elving from Sun for this code sniplet */
 355                 if ((rq = request_restart_internal(uri, NULL)) == NULL) {
 356                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Internal request creation failed", uri);
 357                         RETURN_FALSE;
 358                 }
 359 
 360                 /* insert host of current request to get page from same vhost */
 361                 param_free(pblock_remove("host", rq->headers));
 362                 if (value = pblock_findval("host", rc->rq->headers)) {
 363                         pblock_nvinsert("host", value, rq->headers);
 364                 }
 365 
 366                 /* go through the normal request stages as given in obj.conf,
 367                    but leave out the logging/error section */
 368                 do {
 369                         rv = (*nsapi_servact_uri2path)(rc->sn, rq);
 370                         if (rv != REQ_PROCEED) {
 371                                 continue;
 372                         }
 373 
 374                         rv = (*nsapi_servact_pathchecks)(rc->sn, rq);
 375                         if (rv != REQ_PROCEED) {
 376                                 continue;
 377                         }
 378 
 379                         rv = (*nsapi_servact_fileinfo)(rc->sn, rq);
 380                         if (rv != REQ_PROCEED) {
 381                                 continue;
 382                         }
 383 
 384                         rv = (*nsapi_servact_service)(rc->sn, rq);
 385                 } while (rv == REQ_RESTART);
 386 
 387                 if (rq->status_num != 200) {
 388                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - HTTP status code %d during subrequest", uri, rq->status_num);
 389                         request_free(rq);
 390                         RETURN_FALSE;
 391                 }
 392 
 393                 request_free(rq);
 394 
 395                 RETURN_TRUE;
 396         }
 397 }
 398 /* }}} */
 399 
 400 /* {{{ proto array nsapi_request_headers(void)
 401    Get all headers from the request */
 402 PHP_FUNCTION(nsapi_request_headers)
 403 {
 404         register int i;
 405         struct pb_entry *entry;
 406         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 407 
 408         if (zend_parse_parameters_none() == FAILURE) {
 409                 return;
 410         }
 411         
 412         array_init(return_value);
 413 
 414         for (i=0; i < rc->rq->headers->hsize; i++) {
 415                 entry=rc->rq->headers->ht[i];
 416                 while (entry) {
 417                         add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
 418                         entry=entry->next;
 419                 }
 420         }
 421 }
 422 /* }}} */
 423 
 424 /* {{{ proto array nsapi_response_headers(void)
 425    Get all headers from the response */
 426 PHP_FUNCTION(nsapi_response_headers)
 427 {
 428         register int i;
 429         struct pb_entry *entry;
 430         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 431 
 432         if (zend_parse_parameters_none() == FAILURE) {
 433                 return;
 434         }
 435         
 436         array_init(return_value);
 437 
 438         for (i=0; i < rc->rq->srvhdrs->hsize; i++) {
 439                 entry=rc->rq->srvhdrs->ht[i];
 440                 while (entry) {
 441                         add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
 442                         entry=entry->next;
 443                 }
 444         }
 445 }
 446 /* }}} */
 447 
 448 
 449 /*************/
 450 /* SAPI part */
 451 /*************/
 452 
 453 static int sapi_nsapi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
 454 {
 455         int retval;
 456         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 457         
 458         if (!SG(headers_sent)) {
 459                 sapi_send_headers(TSRMLS_C);
 460         }
 461 
 462         retval = net_write(rc->sn->csd, (char *)str, str_length);
 463         if (retval == IO_ERROR /* -1 */ || retval == IO_EOF /* 0 */) {
 464                 php_handle_aborted_connection();
 465         }
 466         return retval;
 467 }
 468 
 469 /* modified version of apache2 */
 470 static void sapi_nsapi_flush(void *server_context)
 471 {
 472         nsapi_request_context *rc = (nsapi_request_context *)server_context;
 473         TSRMLS_FETCH();
 474         
 475         if (!rc) {
 476                 /* we have no context, so no flushing needed. This fixes a SIGSEGV on shutdown */
 477                 return;
 478         }
 479 
 480         if (!SG(headers_sent)) {
 481                 sapi_send_headers(TSRMLS_C);
 482         }
 483 
 484         /* flushing is only supported in iPlanet servers from version 6.1 on, make it conditional */
 485 #if NSAPI_VERSION >= 302
 486         if (net_flush(rc->sn->csd) < 0) {
 487                 php_handle_aborted_connection();
 488         }
 489 #endif
 490 }
 491 
 492 /* callback for zend_llist_apply on SAPI_HEADER_DELETE_ALL operation */
 493 static int php_nsapi_remove_header(sapi_header_struct *sapi_header TSRMLS_DC)
 494 {
 495         char *header_name, *p;
 496         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 497         
 498         /* copy the header, because NSAPI needs reformatting and we do not want to change the parameter */
 499         header_name = pool_strdup(rc->sn->pool, sapi_header->header);
 500 
 501         /* extract name, this works, if only the header without ':' is given, too */
 502         if (p = strchr(header_name, ':')) {
 503                 *p = 0;
 504         }
 505         
 506         /* header_name to lower case because NSAPI reformats the headers and wants lowercase */
 507         for (p=header_name; *p; p++) {
 508                 *p=tolower(*p);
 509         }
 510         
 511         /* remove the header */
 512         param_free(pblock_remove(header_name, rc->rq->srvhdrs));
 513         pool_free(rc->sn->pool, header_name);
 514         
 515         return ZEND_HASH_APPLY_KEEP;
 516 }
 517 
 518 static int sapi_nsapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
 519 {
 520         char *header_name, *header_content, *p;
 521         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 522 
 523         switch(op) {
 524                 case SAPI_HEADER_DELETE_ALL:
 525                         /* this only deletes headers set or overwritten by PHP, headers previously set by NSAPI are left intact */
 526                         zend_llist_apply(&sapi_headers->headers, (llist_apply_func_t) php_nsapi_remove_header TSRMLS_CC);
 527                         return 0;
 528 
 529                 case SAPI_HEADER_DELETE:
 530                         /* reuse the zend_llist_apply callback function for this, too */
 531                         php_nsapi_remove_header(sapi_header TSRMLS_CC);
 532                         return 0;
 533 
 534                 case SAPI_HEADER_ADD:
 535                 case SAPI_HEADER_REPLACE:
 536                         /* copy the header, because NSAPI needs reformatting and we do not want to change the parameter */
 537                         header_name = pool_strdup(rc->sn->pool, sapi_header->header);
 538 
 539                         /* split header and align pointer for content */
 540                         header_content = strchr(header_name, ':');
 541                         if (header_content) {
 542                                 *header_content = 0;
 543                                 do {
 544                                         header_content++;
 545                                 } while (*header_content==' ');
 546                                 
 547                                 /* header_name to lower case because NSAPI reformats the headers and wants lowercase */
 548                                 for (p=header_name; *p; p++) {
 549                                         *p=tolower(*p);
 550                                 }
 551 
 552                                 /* if REPLACE, remove first.  "Content-type" is always removed, as SAPI has a bug according to this */
 553                                 if (op==SAPI_HEADER_REPLACE || strcmp(header_name, "content-type")==0) {
 554                                         param_free(pblock_remove(header_name, rc->rq->srvhdrs));
 555                                 }
 556                                 /* ADD header to nsapi table */
 557                                 pblock_nvinsert(header_name, header_content, rc->rq->srvhdrs);
 558                         }
 559                         
 560                         pool_free(rc->sn->pool, header_name);
 561                         return SAPI_HEADER_ADD;
 562                         
 563                 default:
 564                         return 0;
 565         }
 566 }
 567 
 568 static int sapi_nsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
 569 {
 570         int retval;
 571         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 572 
 573         if (SG(sapi_headers).send_default_content_type) {
 574                 char *hd;
 575                 param_free(pblock_remove("content-type", rc->rq->srvhdrs));
 576                 hd = sapi_get_default_content_type(TSRMLS_C);
 577                 pblock_nvinsert("content-type", hd, rc->rq->srvhdrs);
 578                 efree(hd);
 579         }
 580 
 581         protocol_status(rc->sn, rc->rq, SG(sapi_headers).http_response_code, NULL);
 582         retval = protocol_start_response(rc->sn, rc->rq);
 583 
 584         if (retval == REQ_PROCEED || retval == REQ_NOACTION) {
 585                 return SAPI_HEADER_SENT_SUCCESSFULLY;
 586         } else {
 587                 return SAPI_HEADER_SEND_FAILED;
 588         }
 589 }
 590 
 591 static int sapi_nsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
 592 {
 593         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 594         char *read_ptr = buffer, *content_length_str = NULL;
 595         uint bytes_read = 0;
 596         int length, content_length = 0;
 597         netbuf *nbuf = rc->sn->inbuf;
 598 
 599         /*
 600          *      Yesss!
 601          */
 602         count_bytes = MIN(count_bytes, SG(request_info).content_length-rc->read_post_bytes);
 603         content_length = SG(request_info).content_length;
 604 
 605         if (content_length <= 0) {
 606                 return 0;
 607         }
 608 
 609         /*
 610          * Gobble any pending data in the netbuf.
 611          */
 612         length = nbuf->cursize - nbuf->pos;
 613         length = MIN(count_bytes, length);
 614         if (length > 0) {
 615                 memcpy(read_ptr, nbuf->inbuf + nbuf->pos, length);
 616                 bytes_read += length;
 617                 read_ptr += length;
 618                 content_length -= length;
 619                 nbuf->pos += length;
 620         }
 621 
 622         /*
 623          * Read the remaining from the socket.
 624          */
 625         while (content_length > 0 && bytes_read < count_bytes) {
 626                 int bytes_to_read = count_bytes - bytes_read;
 627 
 628                 if (content_length < bytes_to_read) {
 629                         bytes_to_read = content_length;
 630                 }
 631 
 632                 length = net_read(rc->sn->csd, read_ptr, bytes_to_read, NSAPI_G(read_timeout));
 633 
 634                 if (length == IO_ERROR || length == IO_EOF) {
 635                         break;
 636                 }
 637 
 638                 bytes_read += length;
 639                 read_ptr += length;
 640                 content_length -= length;
 641         }
 642 
 643         if ( bytes_read > 0 ) {
 644                 rc->read_post_bytes += bytes_read;
 645         }
 646         return bytes_read;
 647 }
 648 
 649 static char *sapi_nsapi_read_cookies(TSRMLS_D)
 650 {
 651         char *cookie_string;
 652         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 653 
 654         cookie_string = pblock_findval("cookie", rc->rq->headers);
 655         return cookie_string;
 656 }
 657 
 658 static void sapi_nsapi_register_server_variables(zval *track_vars_array TSRMLS_DC)
 659 {
 660         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 661         register size_t i;
 662         int pos;
 663         char *value,*p;
 664         char buf[32];
 665         struct pb_entry *entry;
 666 
 667         for (i = 0; i < nsapi_reqpb_size; i++) {
 668                 value = pblock_findval(nsapi_reqpb[i].nsapi_eq, rc->rq->reqpb);
 669                 if (value) {
 670                         php_register_variable((char *)nsapi_reqpb[i].env_var, value, track_vars_array TSRMLS_CC);
 671                 }
 672         }
 673 
 674         for (i=0; i < rc->rq->headers->hsize; i++) {
 675                 entry=rc->rq->headers->ht[i];
 676                 while (entry) {
 677                         if (strcasecmp(entry->param->name, "content-length")==0 || strcasecmp(entry->param->name, "content-type")==0) {
 678                                 value=estrdup(entry->param->name);
 679                                 pos = 0;
 680                         } else {
 681                                 spprintf(&value, 0, "HTTP_%s", entry->param->name);
 682                                 pos = 5;
 683                         }
 684                         if (value) {
 685                                 for(p = value + pos; *p; p++) {
 686                                         *p = toupper(*p);
 687                                         if (!isalnum(*p)) {
 688                                                 *p = '_';
 689                                         }
 690                                 }
 691                                 php_register_variable(value, entry->param->value, track_vars_array TSRMLS_CC);
 692                                 efree(value);
 693                         }
 694                         entry=entry->next;
 695                 }
 696         }
 697 
 698         for (i = 0; i < nsapi_vars_size; i++) {
 699                 value = pblock_findval(nsapi_vars[i].nsapi_eq, rc->rq->vars);
 700                 if (value) {
 701                         php_register_variable((char *)nsapi_vars[i].env_var, value, track_vars_array TSRMLS_CC);
 702                 }
 703         }
 704 
 705         for (i = 0; i < nsapi_client_size; i++) {
 706                 value = pblock_findval(nsapi_client[i].nsapi_eq, rc->sn->client);
 707                 if (value) {
 708                         php_register_variable((char *)nsapi_client[i].env_var, value, track_vars_array TSRMLS_CC);
 709                 }
 710         }
 711 
 712         if (value = session_dns(rc->sn)) {
 713                 php_register_variable("REMOTE_HOST", value, track_vars_array TSRMLS_CC);
 714                 nsapi_free(value);
 715         }
 716 
 717         slprintf(buf, sizeof(buf), "%d", conf_getglobals()->Vport);
 718         php_register_variable("SERVER_PORT", buf, track_vars_array TSRMLS_CC);
 719         php_register_variable("SERVER_NAME", conf_getglobals()->Vserver_hostname, track_vars_array TSRMLS_CC);
 720 
 721         value = http_uri2url_dynamic("", "", rc->sn, rc->rq);
 722         php_register_variable("SERVER_URL", value, track_vars_array TSRMLS_CC);
 723         nsapi_free(value);
 724 
 725         php_register_variable("SERVER_SOFTWARE", system_version(), track_vars_array TSRMLS_CC);
 726         if (security_active) {
 727                 php_register_variable("HTTPS", "ON", track_vars_array TSRMLS_CC);
 728         }
 729         php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
 730 
 731         /* DOCUMENT_ROOT */
 732         if (value = request_translate_uri("/", rc->sn)) {
 733                 pos = strlen(value);
 734                 php_register_variable_safe("DOCUMENT_ROOT", value, pos-1, track_vars_array TSRMLS_CC);
 735                 nsapi_free(value);
 736         }
 737 
 738         /* PATH_INFO / PATH_TRANSLATED */
 739         if (rc->path_info) {
 740                 if (value = request_translate_uri(rc->path_info, rc->sn)) {
 741                         php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
 742                         nsapi_free(value);
 743                 }
 744                 php_register_variable("PATH_INFO", rc->path_info, track_vars_array TSRMLS_CC);
 745         }
 746 
 747         /* Create full Request-URI & Script-Name */
 748         if (SG(request_info).request_uri) {
 749                 pos = strlen(SG(request_info).request_uri);
 750                 
 751                 if (SG(request_info).query_string) {
 752                         spprintf(&value, 0, "%s?%s", SG(request_info).request_uri, SG(request_info).query_string);
 753                         if (value) {
 754                                 php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC);
 755                                 efree(value);
 756                         }
 757                 } else {
 758                         php_register_variable_safe("REQUEST_URI", SG(request_info).request_uri, pos, track_vars_array TSRMLS_CC);
 759                 }
 760 
 761                 if (rc->path_info) {
 762                         pos -= strlen(rc->path_info);
 763                         if (pos<0) {
 764                                 pos = 0;
 765                         }
 766                 }
 767                 php_register_variable_safe("SCRIPT_NAME", SG(request_info).request_uri, pos, track_vars_array TSRMLS_CC);
 768         }
 769         php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
 770 
 771         /* special variables in error mode */
 772         if (rc->http_error) {
 773                 slprintf(buf, sizeof(buf), "%d", rc->http_error);
 774                 php_register_variable("ERROR_TYPE", buf, track_vars_array TSRMLS_CC);
 775         }
 776 }
 777 
 778 static void nsapi_log_message(char *message TSRMLS_DC)
 779 {
 780         nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
 781 
 782         if (rc) {
 783                 log_error(LOG_INFORM, pblock_findval("fn", rc->pb), rc->sn, rc->rq, "%s", message);
 784         } else {
 785                 log_error(LOG_INFORM, "php5", NULL, NULL, "%s", message);
 786         }
 787 }
 788 
 789 static double sapi_nsapi_get_request_time(TSRMLS_D)
 790 {
 791         return REQ_TIME( ((nsapi_request_context *)SG(server_context))->rq );
 792 }
 793 
 794 static int php_nsapi_startup(sapi_module_struct *sapi_module)
 795 {
 796         if (php_module_startup(sapi_module, &nsapi_module_entry, 1)==FAILURE) {
 797                 return FAILURE;
 798         }
 799         return SUCCESS;
 800 }
 801 
 802 static struct stat* sapi_nsapi_get_stat(TSRMLS_D)
 803 {
 804         return request_stat_path(
 805                 SG(request_info).path_translated,
 806                 ((nsapi_request_context *)SG(server_context))->rq
 807         );
 808 }
 809 
 810 static sapi_module_struct nsapi_sapi_module = {
 811         "nsapi",                                /* name */
 812         "NSAPI",                                /* pretty name */
 813 
 814         php_nsapi_startup,                      /* startup */
 815         php_module_shutdown_wrapper,            /* shutdown */
 816 
 817         NULL,                                   /* activate */
 818         NULL,                                   /* deactivate */
 819 
 820         sapi_nsapi_ub_write,                    /* unbuffered write */
 821         sapi_nsapi_flush,                       /* flush */
 822         sapi_nsapi_get_stat,                    /* get uid/stat */
 823         NULL,                                   /* getenv */
 824 
 825         php_error,                              /* error handler */
 826 
 827         sapi_nsapi_header_handler,              /* header handler */
 828         sapi_nsapi_send_headers,                /* send headers handler */
 829         NULL,                                   /* send header handler */
 830 
 831         sapi_nsapi_read_post,                   /* read POST data */
 832         sapi_nsapi_read_cookies,                /* read Cookies */
 833 
 834         sapi_nsapi_register_server_variables,   /* register server variables */
 835         nsapi_log_message,                      /* Log message */
 836         sapi_nsapi_get_request_time,                    /* Get request time */
 837         NULL,                                                                   /* Child terminate */
 838 
 839         NULL,                                   /* Block interruptions */
 840         NULL,                                   /* Unblock interruptions */
 841 
 842         STANDARD_SAPI_MODULE_PROPERTIES
 843 };
 844 
 845 static void nsapi_php_ini_entries(NSLS_D TSRMLS_DC)
 846 {
 847         struct pb_entry *entry;
 848         register int i,j,ok;
 849 
 850         for (i=0; i < NSG(pb)->hsize; i++) {
 851                 entry=NSG(pb)->ht[i];
 852                 while (entry) {
 853                         /* exclude standard entries given to "Service" which should not go into ini entries */
 854                         ok=1;
 855                         for (j=0; nsapi_exclude_from_ini_entries[j]; j++) {
 856                                 ok&=(strcasecmp(entry->param->name, nsapi_exclude_from_ini_entries[j])!=0);
 857                         }
 858 
 859                         if (ok) {
 860                                 /* change the ini entry */
 861                                 if (zend_alter_ini_entry(entry->param->name, strlen(entry->param->name)+1,
 862                                  entry->param->value, strlen(entry->param->value),
 863                                  PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE)==FAILURE) {
 864                                         log_error(LOG_WARN, pblock_findval("fn", NSG(pb)), NSG(sn), NSG(rq), "Cannot change php.ini key \"%s\" to \"%s\"", entry->param->name, entry->param->value);
 865                                 }
 866                         }
 867                         entry=entry->next;
 868                 }
 869         }
 870 }
 871 
 872 void NSAPI_PUBLIC php5_close(void *vparam)
 873 {
 874         if (nsapi_sapi_module.shutdown) {
 875                 nsapi_sapi_module.shutdown(&nsapi_sapi_module);
 876         }
 877 
 878         if (nsapi_sapi_module.php_ini_path_override) {
 879                 free(nsapi_sapi_module.php_ini_path_override);
 880         }
 881         
 882 #ifdef PHP_WIN32
 883         if (nsapi_dll) {
 884                 free(nsapi_dll);
 885                 nsapi_dll = NULL;
 886         }
 887 #endif  
 888 
 889         sapi_shutdown();
 890         tsrm_shutdown();
 891 
 892         log_error(LOG_INFORM, "php5_close", NULL, NULL, "Shutdown PHP Module");
 893 }
 894 
 895 /*********************************************************
 896 / init SAF
 897 /
 898 / Init fn="php5_init" [php_ini="/path/to/php.ini"] [server_lib="ns-httpdXX.dll"]
 899 /   Initialize the NSAPI module in magnus.conf
 900 /
 901 / php_ini: gives path to php.ini file
 902 / server_lib: (only Win32) gives name of DLL (without path) to look for
 903 /  servact_* functions
 904 /
 905 /*********************************************************/
 906 int NSAPI_PUBLIC php5_init(pblock *pb, Session *sn, Request *rq)
 907 {
 908         php_core_globals *core_globals;
 909         char *strval;
 910         int threads=128; /* default for server */
 911 
 912         /* fetch max threads from NSAPI and initialize TSRM with it */
 913         threads=conf_getglobals()->Vpool_maxthreads;
 914         if (threads<1) {
 915                 threads=128; /* default for server */
 916         }
 917         tsrm_startup(threads, 1, 0, NULL);
 918 
 919         core_globals = ts_resource(core_globals_id);
 920 
 921         /* look if php_ini parameter is given to php5_init */
 922         if (strval = pblock_findval("php_ini", pb)) {
 923                 nsapi_sapi_module.php_ini_path_override = strdup(strval);
 924         }
 925         
 926 #ifdef PHP_WIN32
 927         /* look if server_lib parameter is given to php5_init
 928          * (this disables the automatic search for the newest ns-httpdXX.dll) */
 929         if (strval = pblock_findval("server_lib", pb)) {
 930                 nsapi_dll = strdup(strval);
 931         }
 932 #endif  
 933 
 934         /* start SAPI */
 935         sapi_startup(&nsapi_sapi_module);
 936         nsapi_sapi_module.startup(&nsapi_sapi_module);
 937 
 938         daemon_atrestart(&php5_close, NULL);
 939 
 940         log_error(LOG_INFORM, pblock_findval("fn", pb), sn, rq, "Initialized PHP Module (%d threads expected)", threads);
 941         return REQ_PROCEED;
 942 }
 943 
 944 /*********************************************************
 945 / normal use in Service directive:
 946 /
 947 / Service fn="php5_execute" type=... method=... [inikey=inivalue inikey=inivalue...]
 948 /
 949 / use in Service for a directory to supply a php-made directory listing instead of server default:
 950 /
 951 / Service fn="php5_execute" type="magnus-internal/directory" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
 952 /
 953 / use in Error SAF to display php script as error page:
 954 /
 955 / Error fn="php5_execute" code=XXX script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
 956 / Error fn="php5_execute" reason="Reason" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
 957 /
 958 /*********************************************************/
 959 int NSAPI_PUBLIC php5_execute(pblock *pb, Session *sn, Request *rq)
 960 {
 961         int retval;
 962         nsapi_request_context *request_context;
 963         zend_file_handle file_handle = {0};
 964         struct stat *fst;
 965 
 966         char *path_info;
 967         char *query_string    = pblock_findval("query", rq->reqpb);
 968         char *uri             = pblock_findval("uri", rq->reqpb);
 969         char *request_method  = pblock_findval("method", rq->reqpb);
 970         char *content_type    = pblock_findval("content-type", rq->headers);
 971         char *content_length  = pblock_findval("content-length", rq->headers);
 972         char *directive       = pblock_findval("Directive", pb);
 973         int error_directive   = (directive && !strcasecmp(directive, "error"));
 974         int fixed_script      = 1;
 975 
 976         /* try to use script parameter -> Error or Service for directory listing */
 977         char *path_translated = pblock_findval("script", pb);
 978 
 979         TSRMLS_FETCH();
 980 
 981         /* if script parameter is missing: normal use as Service SAF  */
 982         if (!path_translated) {
 983                 path_translated = pblock_findval("path", rq->vars);
 984                 path_info       = pblock_findval("path-info", rq->vars);
 985                 fixed_script = 0;
 986                 if (error_directive) {
 987                         /* go to next error directive if script parameter is missing */
 988                         log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Missing 'script' parameter");
 989                         return REQ_NOACTION;
 990                 }
 991         } else {
 992                 /* in error the path_info is the uri to the requested page */
 993                 path_info = pblock_findval("uri", rq->reqpb);
 994         }
 995 
 996         /* check if this uri was included in an other PHP script with nsapi_virtual()
 997            by looking for a request context in the current thread */
 998         if (SG(server_context)) {
 999                 /* send 500 internal server error */
1000                 log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot make nesting PHP requests with nsapi_virtual()");
1001                 if (error_directive) {
1002                         return REQ_NOACTION;
1003                 } else {
1004                         protocol_status(sn, rq, 500, NULL);
1005                         return REQ_ABORTED;
1006                 }
1007         }
1008 
1009         request_context = (nsapi_request_context *)pool_malloc(sn->pool, sizeof(nsapi_request_context));
1010         if (!request_context) {
1011                 log_error(LOG_CATASTROPHE, pblock_findval("fn", pb), sn, rq, "Insufficient memory to process PHP request!");
1012                 return REQ_ABORTED;
1013         }
1014         request_context->pb = pb;
1015         request_context->sn = sn;
1016         request_context->rq = rq;
1017         request_context->read_post_bytes = 0;
1018         request_context->fixed_script = fixed_script;
1019         request_context->http_error = (error_directive) ? rq->status_num : 0;
1020         request_context->path_info = path_info;
1021 
1022         SG(server_context) = request_context;
1023         SG(request_info).query_string = query_string;
1024         SG(request_info).request_uri = uri;
1025         SG(request_info).request_method = request_method;
1026         SG(request_info).path_translated = path_translated;
1027         SG(request_info).content_type = content_type;
1028         SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
1029         SG(sapi_headers).http_response_code = (error_directive) ? rq->status_num : 200;
1030         
1031         nsapi_php_ini_entries(NSLS_C TSRMLS_CC);
1032 
1033         php_handle_auth_data(pblock_findval("authorization", rq->headers) TSRMLS_CC);
1034 
1035         file_handle.type = ZEND_HANDLE_FILENAME;
1036         file_handle.filename = SG(request_info).path_translated;
1037         file_handle.free_filename = 0;
1038         file_handle.opened_path = NULL;
1039 
1040         fst = request_stat_path(SG(request_info).path_translated, rq);
1041         if (fst && S_ISREG(fst->st_mode)) {
1042                 if (php_request_startup(TSRMLS_C) == SUCCESS) {
1043                         php_execute_script(&file_handle TSRMLS_CC);
1044                         php_request_shutdown(NULL);
1045                         retval=REQ_PROCEED;
1046                 } else {
1047                         /* send 500 internal server error */
1048                         log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot prepare PHP engine!");
1049                         if (error_directive) {
1050                                 retval=REQ_NOACTION;
1051                         } else {
1052                                 protocol_status(sn, rq, 500, NULL);
1053                                 retval=REQ_ABORTED;
1054                         }
1055                 }
1056         } else {
1057                 /* send 404 because file not found */
1058                 log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot execute PHP script: %s (File not found)", SG(request_info).path_translated);
1059                 if (error_directive) {
1060                         retval=REQ_NOACTION;
1061                 } else {
1062                         protocol_status(sn, rq, 404, NULL);
1063                         retval=REQ_ABORTED;
1064                 }
1065         }
1066 
1067         pool_free(sn->pool, request_context);
1068         SG(server_context) = NULL;
1069 
1070         return retval;
1071 }
1072 
1073 /*********************************************************
1074 / authentication
1075 /
1076 / we have to make a 'fake' authenticator for netscape so it
1077 / will pass authentication through to php, and allow us to
1078 / check authentication with our scripts.
1079 /
1080 / php5_auth_trans
1081 /   main function called from netscape server to authenticate
1082 /   a line in obj.conf:
1083 /               funcs=php5_auth_trans shlib="path/to/this/phpnsapi.dll"
1084 /       and:
1085 /               <Object ppath="path/to/be/authenticated/by/php/*">
1086 /               AuthTrans fn="php5_auth_trans"
1087 /*********************************************************/
1088 int NSAPI_PUBLIC php5_auth_trans(pblock * pb, Session * sn, Request * rq)
1089 {
1090         /* This is a DO NOTHING function that allows authentication
1091          * information
1092          * to be passed through to PHP scripts.
1093          */
1094         return REQ_PROCEED;
1095 }
1096 
1097 /*
1098  * Local variables:
1099  * tab-width: 4
1100  * c-basic-offset: 4
1101  * End:
1102  * vim600: sw=4 ts=4 fdm=marker
1103  * vim<600: sw=4 ts=4
1104  */

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