1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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: Zeev Suraski <zeev@zend.com> |
16 | Ben Mansell <ben@zeus.com> (Zeus Support) |
17 +----------------------------------------------------------------------+
18 */
19 /* $Id$ */
20
21 #include "php.h"
22 #include <httpext.h>
23 #include <httpfilt.h>
24 #include <httpext.h>
25 #include "php_main.h"
26 #include "SAPI.h"
27 #include "php_globals.h"
28 #include "ext/standard/info.h"
29 #include "php_variables.h"
30 #include "php_ini.h"
31
32 #ifdef PHP_WIN32
33 # include <process.h>
34 #else
35 # define __try
36 # define __except(val)
37 # define __declspec(foo)
38 #endif
39
40
41 #ifdef WITH_ZEUS
42 # include "httpext.h"
43 # include <errno.h>
44 # define GetLastError() errno
45 #endif
46
47 #ifdef PHP_WIN32
48 #define PHP_ENABLE_SEH
49 #endif
50
51 /*
52 uncomment the following lines to turn off
53 exception trapping when running under a debugger
54
55 #ifdef _DEBUG
56 #undef PHP_ENABLE_SEH
57 #endif
58 */
59
60 #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST POSSIBLE STATUS DESCRIPTION")
61 #define ISAPI_SERVER_VAR_BUF_SIZE 1024
62 #define ISAPI_POST_DATA_BUF 1024
63
64 static zend_bool bFilterLoaded=0;
65 static zend_bool bTerminateThreadsOnError=0;
66
67 static char *isapi_special_server_variable_names[] = {
68 "ALL_HTTP",
69 "HTTPS",
70 #ifndef WITH_ZEUS
71 "SCRIPT_NAME",
72 #endif
73 NULL
74 };
75
76 #define NUM_SPECIAL_VARS (sizeof(isapi_special_server_variable_names)/sizeof(char *))
77 #define SPECIAL_VAR_ALL_HTTP 0
78 #define SPECIAL_VAR_HTTPS 1
79 #define SPECIAL_VAR_PHP_SELF 2
80
81 static char *isapi_server_variable_names[] = {
82 "AUTH_PASSWORD",
83 "AUTH_TYPE",
84 "AUTH_USER",
85 "CONTENT_LENGTH",
86 "CONTENT_TYPE",
87 "PATH_TRANSLATED",
88 "QUERY_STRING",
89 "REMOTE_ADDR",
90 "REMOTE_HOST",
91 "REMOTE_USER",
92 "REQUEST_METHOD",
93 "SERVER_NAME",
94 "SERVER_PORT",
95 "SERVER_PROTOCOL",
96 "SERVER_SOFTWARE",
97 #ifndef WITH_ZEUS
98 "APPL_MD_PATH",
99 "APPL_PHYSICAL_PATH",
100 "INSTANCE_ID",
101 "INSTANCE_META_PATH",
102 "LOGON_USER",
103 "REQUEST_URI",
104 "URL",
105 #else
106 "DOCUMENT_ROOT",
107 #endif
108 NULL
109 };
110
111
112 static char *isapi_secure_server_variable_names[] = {
113 "CERT_COOKIE",
114 "CERT_FLAGS",
115 "CERT_ISSUER",
116 "CERT_KEYSIZE",
117 "CERT_SECRETKEYSIZE",
118 "CERT_SERIALNUMBER",
119 "CERT_SERVER_ISSUER",
120 "CERT_SERVER_SUBJECT",
121 "CERT_SUBJECT",
122 "HTTPS_KEYSIZE",
123 "HTTPS_SECRETKEYSIZE",
124 "HTTPS_SERVER_ISSUER",
125 "HTTPS_SERVER_SUBJECT",
126 "SERVER_PORT_SECURE",
127 #ifdef WITH_ZEUS
128 "SSL_CLIENT_CN",
129 "SSL_CLIENT_EMAIL",
130 "SSL_CLIENT_OU",
131 "SSL_CLIENT_O",
132 "SSL_CLIENT_L",
133 "SSL_CLIENT_ST",
134 "SSL_CLIENT_C",
135 "SSL_CLIENT_I_CN",
136 "SSL_CLIENT_I_EMAIL",
137 "SSL_CLIENT_I_OU",
138 "SSL_CLIENT_I_O",
139 "SSL_CLIENT_I_L",
140 "SSL_CLIENT_I_ST",
141 "SSL_CLIENT_I_C",
142 #endif
143 NULL
144 };
145
146
php_info_isapi(ZEND_MODULE_INFO_FUNC_ARGS)147 static void php_info_isapi(ZEND_MODULE_INFO_FUNC_ARGS)
148 {
149 char **p;
150 char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
151 DWORD variable_len;
152 char **all_variables[] = {
153 isapi_server_variable_names,
154 isapi_special_server_variable_names,
155 isapi_secure_server_variable_names,
156 NULL
157 };
158 char ***server_variable_names;
159 LPEXTENSION_CONTROL_BLOCK lpECB;
160
161 lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
162
163 php_info_print_table_start();
164 php_info_print_table_header(2, "Server Variable", "Value");
165 server_variable_names = all_variables;
166 while (*server_variable_names) {
167 p = *server_variable_names;
168 while (*p) {
169 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
170 if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len)
171 && variable_buf[0]) {
172 php_info_print_table_row(2, *p, variable_buf);
173 } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
174 char *tmp_variable_buf;
175
176 tmp_variable_buf = (char *) emalloc(variable_len);
177 if (lpECB->GetServerVariable(lpECB->ConnID, *p, tmp_variable_buf, &variable_len)
178 && variable_buf[0]) {
179 php_info_print_table_row(2, *p, tmp_variable_buf);
180 }
181 efree(tmp_variable_buf);
182 }
183 p++;
184 }
185 server_variable_names++;
186 }
187 php_info_print_table_end();
188 }
189
190
191 static zend_module_entry php_isapi_module = {
192 STANDARD_MODULE_HEADER,
193 "ISAPI",
194 NULL,
195 NULL,
196 NULL,
197 NULL,
198 NULL,
199 php_info_isapi,
200 NULL,
201 STANDARD_MODULE_PROPERTIES
202 };
203
204
sapi_isapi_ub_write(const char * str,uint str_length TSRMLS_DC)205 static int sapi_isapi_ub_write(const char *str, uint str_length TSRMLS_DC)
206 {
207 DWORD num_bytes = str_length;
208 LPEXTENSION_CONTROL_BLOCK ecb;
209
210 ecb = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
211 if (ecb->WriteClient(ecb->ConnID, (char *) str, &num_bytes, HSE_IO_SYNC) == FALSE) {
212 php_handle_aborted_connection();
213 }
214 return num_bytes;
215 }
216
217
sapi_isapi_header_handler(sapi_header_struct * sapi_header,sapi_header_op_enum op,sapi_headers_struct * sapi_headers TSRMLS_DC)218 static int sapi_isapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
219 {
220 return SAPI_HEADER_ADD;
221 }
222
223
224
accumulate_header_length(sapi_header_struct * sapi_header,uint * total_length TSRMLS_DC)225 static void accumulate_header_length(sapi_header_struct *sapi_header, uint *total_length TSRMLS_DC)
226 {
227 *total_length += sapi_header->header_len+2;
228 }
229
230
concat_header(sapi_header_struct * sapi_header,char ** combined_headers_ptr TSRMLS_DC)231 static void concat_header(sapi_header_struct *sapi_header, char **combined_headers_ptr TSRMLS_DC)
232 {
233 memcpy(*combined_headers_ptr, sapi_header->header, sapi_header->header_len);
234 *combined_headers_ptr += sapi_header->header_len;
235 **combined_headers_ptr = '\r';
236 (*combined_headers_ptr)++;
237 **combined_headers_ptr = '\n';
238 (*combined_headers_ptr)++;
239 }
240
241
sapi_isapi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)242 static int sapi_isapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
243 {
244 uint total_length = 2; /* account for the trailing \r\n */
245 char *combined_headers, *combined_headers_ptr;
246 LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
247 HSE_SEND_HEADER_EX_INFO header_info;
248 sapi_header_struct default_content_type;
249 char *status_buf = NULL;
250
251 /* Obtain headers length */
252 if (SG(sapi_headers).send_default_content_type) {
253 sapi_get_default_content_type_header(&default_content_type TSRMLS_CC);
254 accumulate_header_length(&default_content_type, (void *) &total_length TSRMLS_CC);
255 }
256 zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) accumulate_header_length, (void *) &total_length TSRMLS_CC);
257
258 /* Generate headers */
259 combined_headers = (char *) emalloc(total_length+1);
260 combined_headers_ptr = combined_headers;
261 if (SG(sapi_headers).send_default_content_type) {
262 concat_header(&default_content_type, (void *) &combined_headers_ptr TSRMLS_CC);
263 sapi_free_header(&default_content_type); /* we no longer need it */
264 }
265 zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) concat_header, (void *) &combined_headers_ptr TSRMLS_CC);
266 *combined_headers_ptr++ = '\r';
267 *combined_headers_ptr++ = '\n';
268 *combined_headers_ptr = 0;
269
270 switch (SG(sapi_headers).http_response_code) {
271 case 200:
272 header_info.pszStatus = "200 OK";
273 break;
274 case 302:
275 header_info.pszStatus = "302 Moved Temporarily";
276 break;
277 case 401:
278 header_info.pszStatus = "401 Authorization Required";
279 break;
280 default: {
281 const char *sline = SG(sapi_headers).http_status_line;
282 int sline_len;
283
284 /* httpd requires that r->status_line is set to the first digit of
285 * the status-code: */
286 if (sline && ((sline_len = strlen(sline)) > 12) && strncmp(sline, "HTTP/1.", 7) == 0 && sline[8] == ' ') {
287 if ((sline_len - 9) > MAX_STATUS_LENGTH) {
288 status_buf = estrndup(sline + 9, MAX_STATUS_LENGTH);
289 } else {
290 status_buf = estrndup(sline + 9, sline_len - 9);
291 }
292 } else {
293 status_buf = emalloc(MAX_STATUS_LENGTH + 1);
294 snprintf(status_buf, MAX_STATUS_LENGTH, "%d Undescribed", SG(sapi_headers).http_response_code);
295 }
296 header_info.pszStatus = status_buf;
297 break;
298 }
299 }
300 header_info.cchStatus = strlen(header_info.pszStatus);
301 header_info.pszHeader = combined_headers;
302 header_info.cchHeader = total_length;
303 header_info.fKeepConn = FALSE;
304 lpECB->dwHttpStatusCode = SG(sapi_headers).http_response_code;
305
306 lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
307
308 efree(combined_headers);
309 if (status_buf) {
310 efree(status_buf);
311 }
312 return SAPI_HEADER_SENT_SUCCESSFULLY;
313 }
314
315
php_isapi_startup(sapi_module_struct * sapi_module)316 static int php_isapi_startup(sapi_module_struct *sapi_module)
317 {
318 if (php_module_startup(sapi_module, &php_isapi_module, 1)==FAILURE) {
319 return FAILURE;
320 } else {
321 bTerminateThreadsOnError = (zend_bool) INI_INT("isapi.terminate_threads_on_error");
322 return SUCCESS;
323 }
324 }
325
326
sapi_isapi_read_post(char * buffer,uint count_bytes TSRMLS_DC)327 static int sapi_isapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
328 {
329 LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
330 DWORD read_from_buf=0;
331 DWORD read_from_input=0;
332 DWORD total_read=0;
333
334 if ((DWORD) SG(read_post_bytes) < lpECB->cbAvailable) {
335 read_from_buf = MIN(lpECB->cbAvailable-SG(read_post_bytes), count_bytes);
336 memcpy(buffer, lpECB->lpbData+SG(read_post_bytes), read_from_buf);
337 total_read += read_from_buf;
338 }
339 if (read_from_buf<count_bytes
340 && (SG(read_post_bytes)+read_from_buf) < lpECB->cbTotalBytes) {
341 DWORD cbRead=0, cbSize;
342
343 read_from_input = MIN(count_bytes-read_from_buf, lpECB->cbTotalBytes-SG(read_post_bytes)-read_from_buf);
344 while (cbRead < read_from_input) {
345 cbSize = read_from_input - cbRead;
346 if (!lpECB->ReadClient(lpECB->ConnID, buffer+read_from_buf+cbRead, &cbSize) || cbSize==0) {
347 break;
348 }
349 cbRead += cbSize;
350 }
351 total_read += cbRead;
352 }
353 return total_read;
354 }
355
356
sapi_isapi_read_cookies(TSRMLS_D)357 static char *sapi_isapi_read_cookies(TSRMLS_D)
358 {
359 LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
360 char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
361 DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
362
363 if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", variable_buf, &variable_len)) {
364 return estrndup(variable_buf, variable_len);
365 } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
366 char *tmp_variable_buf = (char *) emalloc(variable_len+1);
367
368 if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", tmp_variable_buf, &variable_len)) {
369 tmp_variable_buf[variable_len] = 0;
370 return tmp_variable_buf;
371 } else {
372 efree(tmp_variable_buf);
373 }
374 }
375 return STR_EMPTY_ALLOC();
376 }
377
378
379 #ifdef WITH_ZEUS
380
sapi_isapi_register_zeus_ssl_variables(LPEXTENSION_CONTROL_BLOCK lpECB,zval * track_vars_array TSRMLS_DC)381 static void sapi_isapi_register_zeus_ssl_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC)
382 {
383 char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
384 DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
385 char static_cons_buf[ISAPI_SERVER_VAR_BUF_SIZE];
386 /*
387 * We need to construct the /C=.../ST=...
388 * DN's for SSL_CLIENT_DN and SSL_CLIENT_I_DN
389 */
390 strcpy( static_cons_buf, "/C=" );
391 if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
392 strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE);
393 }
394 strlcat( static_cons_buf, "/ST=", ISAPI_SERVER_VAR_BUF_SIZE);
395 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
396 if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
397 strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE );
398 }
399 php_register_variable( "SSL_CLIENT_DN", static_cons_buf, track_vars_array TSRMLS_CC );
400
401 strcpy( static_cons_buf, "/C=" );
402 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
403 if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
404 strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE );
405 }
406 strlcat( static_cons_buf, "/ST=", ISAPI_SERVER_VAR_BUF_SIZE);
407 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
408 if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
409 strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE );
410 }
411 php_register_variable( "SSL_CLIENT_I_DN", static_cons_buf, track_vars_array TSRMLS_CC );
412 }
413
sapi_isapi_register_zeus_variables(LPEXTENSION_CONTROL_BLOCK lpECB,zval * track_vars_array TSRMLS_DC)414 static void sapi_isapi_register_zeus_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC)
415 {
416 char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
417 DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
418 DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE;
419 DWORD pathinfo_len = 0;
420 char *strtok_buf = NULL;
421
422 /* Get SCRIPT_NAME, we use this to work out which bit of the URL
423 * belongs in PHP's version of PATH_INFO
424 */
425 lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len);
426
427 /* Adjust Zeus' version of PATH_INFO, set PHP_SELF,
428 * and generate REQUEST_URI
429 */
430 if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
431
432 /* PHP_SELF is just PATH_INFO */
433 php_register_variable( "PHP_SELF", static_variable_buf, track_vars_array TSRMLS_CC );
434
435 /* Chop off filename to get just the 'real' PATH_INFO' */
436 pathinfo_len = variable_len - scriptname_len;
437 php_register_variable( "PATH_INFO", static_variable_buf + scriptname_len - 1, track_vars_array TSRMLS_CC );
438 /* append query string to give url... extra byte for '?' */
439 if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) {
440 /* append query string only if it is present... */
441 if ( strlen(lpECB->lpszQueryString) ) {
442 static_variable_buf[ variable_len - 1 ] = '?';
443 strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString );
444 }
445 php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC );
446 php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC );
447 }
448 }
449
450 /* Get and adjust PATH_TRANSLATED to what PHP wants */
451 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
452 if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
453 static_variable_buf[ variable_len - pathinfo_len - 1 ] = '\0';
454 php_register_variable( "PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC );
455 }
456
457 /* Bring in the AUTHENTICATION stuff as needed */
458 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
459 if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_USER", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
460 php_register_variable( "PHP_AUTH_USER", static_variable_buf, track_vars_array TSRMLS_CC );
461 }
462 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
463 if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_PASSWORD", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
464 php_register_variable( "PHP_AUTH_PW", static_variable_buf, track_vars_array TSRMLS_CC );
465 }
466 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
467 if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_TYPE", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
468 php_register_variable( "AUTH_TYPE", static_variable_buf, track_vars_array TSRMLS_CC );
469 }
470
471 /* And now, for the SSL variables (if applicable) */
472 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
473 if ( lpECB->GetServerVariable(lpECB->ConnID, "CERT_COOKIE", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
474 sapi_isapi_register_zeus_ssl_variables( lpECB, track_vars_array TSRMLS_CC );
475 }
476 /* Copy some of the variables we need to meet Apache specs */
477 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
478 if ( lpECB->GetServerVariable(lpECB->ConnID, "SERVER_SOFTWARE", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
479 php_register_variable( "SERVER_SIGNATURE", static_variable_buf, track_vars_array TSRMLS_CC );
480 }
481 }
482 #else
483
sapi_isapi_register_iis_variables(LPEXTENSION_CONTROL_BLOCK lpECB,zval * track_vars_array TSRMLS_DC)484 static void sapi_isapi_register_iis_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC)
485 {
486 char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
487 char path_info_buf[ISAPI_SERVER_VAR_BUF_SIZE];
488 DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
489 DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE;
490 DWORD pathinfo_len = 0;
491 HSE_URL_MAPEX_INFO humi;
492
493 /* Get SCRIPT_NAME, we use this to work out which bit of the URL
494 * belongs in PHP's version of PATH_INFO. SCRIPT_NAME also becomes PHP_SELF.
495 */
496 lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len);
497 php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
498
499 /* Adjust IIS' version of PATH_INFO, set PHP_SELF,
500 * and generate REQUEST_URI
501 * Get and adjust PATH_TRANSLATED to what PHP wants
502 */
503 if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
504
505 /* Chop off filename to get just the 'real' PATH_INFO' */
506 php_register_variable( "ORIG_PATH_INFO", static_variable_buf, track_vars_array TSRMLS_CC );
507 pathinfo_len = variable_len - scriptname_len;
508 strncpy(path_info_buf, static_variable_buf + scriptname_len - 1, sizeof(path_info_buf)-1);
509 php_register_variable( "PATH_INFO", path_info_buf, track_vars_array TSRMLS_CC );
510 /* append query string to give url... extra byte for '?' */
511 if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) {
512 /* append query string only if it is present... */
513 if ( strlen(lpECB->lpszQueryString) ) {
514 static_variable_buf[ variable_len - 1 ] = '?';
515 strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString );
516 }
517 php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC );
518 php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC );
519 }
520 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
521 if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
522 php_register_variable( "ORIG_PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC );
523 }
524 if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, path_info_buf, &pathinfo_len, (LPDWORD) &humi)) {
525 /* Remove trailing \ */
526 if (humi.lpszPath[variable_len-2] == '\\') {
527 humi.lpszPath[variable_len-2] = 0;
528 }
529 php_register_variable("PATH_TRANSLATED", humi.lpszPath, track_vars_array TSRMLS_CC);
530 }
531 }
532
533 static_variable_buf[0] = '/';
534 static_variable_buf[1] = 0;
535 variable_len = 2;
536 if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) {
537 /* Remove trailing \ */
538 if (humi.lpszPath[variable_len-2] == '\\') {
539 humi.lpszPath[variable_len-2] = 0;
540 }
541 php_register_variable("DOCUMENT_ROOT", humi.lpszPath, track_vars_array TSRMLS_CC);
542 }
543
544 if (!SG(request_info).auth_user || !SG(request_info).auth_password ||
545 !SG(request_info).auth_user[0] || !SG(request_info).auth_password[0]) {
546 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
547 if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_AUTHORIZATION", static_variable_buf, &variable_len)
548 && static_variable_buf[0]) {
549 php_handle_auth_data(static_variable_buf TSRMLS_CC);
550 }
551 }
552
553 if (SG(request_info).auth_user) {
554 php_register_variable("PHP_AUTH_USER", SG(request_info).auth_user, track_vars_array TSRMLS_CC );
555 }
556 if (SG(request_info).auth_password) {
557 php_register_variable("PHP_AUTH_PW", SG(request_info).auth_password, track_vars_array TSRMLS_CC );
558 }
559 }
560 #endif
561
sapi_isapi_register_server_variables2(char ** server_variables,LPEXTENSION_CONTROL_BLOCK lpECB,zval * track_vars_array,char ** recorded_values TSRMLS_DC)562 static void sapi_isapi_register_server_variables2(char **server_variables, LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array, char **recorded_values TSRMLS_DC)
563 {
564 char **p=server_variables;
565 DWORD variable_len;
566 char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
567 char *variable_buf;
568
569 while (*p) {
570 variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
571 if (lpECB->GetServerVariable(lpECB->ConnID, *p, static_variable_buf, &variable_len)
572 && static_variable_buf[0]) {
573 php_register_variable(*p, static_variable_buf, track_vars_array TSRMLS_CC);
574 if (recorded_values) {
575 recorded_values[p-server_variables] = estrndup(static_variable_buf, variable_len);
576 }
577 } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
578 variable_buf = (char *) emalloc(variable_len+1);
579 if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len)
580 && variable_buf[0]) {
581 php_register_variable(*p, variable_buf, track_vars_array TSRMLS_CC);
582 }
583 if (recorded_values) {
584 recorded_values[p-server_variables] = variable_buf;
585 } else {
586 efree(variable_buf);
587 }
588 } else { /* for compatibility with Apache SAPIs */
589 php_register_variable(*p, "", track_vars_array TSRMLS_CC);
590 }
591 p++;
592 }
593 }
594
595
sapi_isapi_register_server_variables(zval * track_vars_array TSRMLS_DC)596 static void sapi_isapi_register_server_variables(zval *track_vars_array TSRMLS_DC)
597 {
598 DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
599 char *variable;
600 char *strtok_buf = NULL;
601 char *isapi_special_server_variables[NUM_SPECIAL_VARS];
602 LPEXTENSION_CONTROL_BLOCK lpECB;
603
604 lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
605
606 /* Register the special ISAPI variables */
607 memset(isapi_special_server_variables, 0, sizeof(isapi_special_server_variables));
608 sapi_isapi_register_server_variables2(isapi_special_server_variable_names, lpECB, track_vars_array, isapi_special_server_variables TSRMLS_CC);
609 if (SG(request_info).cookie_data) {
610 php_register_variable("HTTP_COOKIE", SG(request_info).cookie_data, track_vars_array TSRMLS_CC);
611 }
612
613 /* Register the standard ISAPI variables */
614 sapi_isapi_register_server_variables2(isapi_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC);
615
616 if (isapi_special_server_variables[SPECIAL_VAR_HTTPS]
617 && (atoi(isapi_special_server_variables[SPECIAL_VAR_HTTPS])
618 || !strcasecmp(isapi_special_server_variables[SPECIAL_VAR_HTTPS], "on"))
619 ) {
620 /* Register SSL ISAPI variables */
621 sapi_isapi_register_server_variables2(isapi_secure_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC);
622 }
623
624 if (isapi_special_server_variables[SPECIAL_VAR_HTTPS]) {
625 efree(isapi_special_server_variables[SPECIAL_VAR_HTTPS]);
626 }
627
628
629 #ifdef WITH_ZEUS
630 sapi_isapi_register_zeus_variables(lpECB, track_vars_array TSRMLS_CC);
631 #else
632 sapi_isapi_register_iis_variables(lpECB, track_vars_array TSRMLS_CC);
633 #endif
634
635 /* PHP_SELF support */
636 if (isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]) {
637 php_register_variable("PHP_SELF", isapi_special_server_variables[SPECIAL_VAR_PHP_SELF], track_vars_array TSRMLS_CC);
638 efree(isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]);
639 }
640
641 if (isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]) {
642 /* Register the internal bits of ALL_HTTP */
643 variable = php_strtok_r(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP], "\r\n", &strtok_buf);
644 while (variable) {
645 char *colon = strchr(variable, ':');
646
647 if (colon) {
648 char *value = colon+1;
649
650 while (*value==' ') {
651 value++;
652 }
653 *colon = 0;
654 php_register_variable(variable, value, track_vars_array TSRMLS_CC);
655 *colon = ':';
656 }
657 variable = php_strtok_r(NULL, "\r\n", &strtok_buf);
658 }
659 efree(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]);
660 }
661 }
662
663
664 static sapi_module_struct isapi_sapi_module = {
665 "isapi", /* name */
666 "ISAPI", /* pretty name */
667
668 php_isapi_startup, /* startup */
669 php_module_shutdown_wrapper, /* shutdown */
670
671 NULL, /* activate */
672 NULL, /* deactivate */
673
674 sapi_isapi_ub_write, /* unbuffered write */
675 NULL, /* flush */
676 NULL, /* get uid */
677 NULL, /* getenv */
678
679 php_error, /* error handler */
680
681 sapi_isapi_header_handler, /* header handler */
682 sapi_isapi_send_headers, /* send headers handler */
683 NULL, /* send header handler */
684
685 sapi_isapi_read_post, /* read POST data */
686 sapi_isapi_read_cookies, /* read Cookies */
687
688 sapi_isapi_register_server_variables, /* register server variables */
689 NULL, /* Log message */
690 NULL, /* Get request time */
691 NULL, /* Child terminate */
692
693 STANDARD_SAPI_MODULE_PROPERTIES
694 };
695
696
GetFilterVersion(PHTTP_FILTER_VERSION pFilterVersion)697 BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pFilterVersion)
698 {
699 bFilterLoaded = 1;
700 pFilterVersion->dwFilterVersion = HTTP_FILTER_REVISION;
701 strcpy(pFilterVersion->lpszFilterDesc, isapi_sapi_module.pretty_name);
702 pFilterVersion->dwFlags= (SF_NOTIFY_AUTHENTICATION | SF_NOTIFY_PREPROC_HEADERS);
703 return TRUE;
704 }
705
706
HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,DWORD notificationType,LPVOID pvNotification)707 DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification)
708 {
709 TSRMLS_FETCH();
710
711 switch (notificationType) {
712 case SF_NOTIFY_PREPROC_HEADERS:
713 SG(request_info).auth_user = NULL;
714 SG(request_info).auth_password = NULL;
715 SG(request_info).auth_digest = NULL;
716 break;
717 case SF_NOTIFY_AUTHENTICATION: {
718 char *auth_user = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszUser;
719 char *auth_password = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszPassword;
720
721 if (auth_user && auth_user[0]) {
722 SG(request_info).auth_user = estrdup(auth_user);
723 }
724 if (auth_password && auth_password[0]) {
725 SG(request_info).auth_password = estrdup(auth_password);
726 }
727 return SF_STATUS_REQ_HANDLED_NOTIFICATION;
728 }
729 break;
730 }
731 return SF_STATUS_REQ_NEXT_NOTIFICATION;
732 }
733
734
init_request_info(LPEXTENSION_CONTROL_BLOCK lpECB TSRMLS_DC)735 static void init_request_info(LPEXTENSION_CONTROL_BLOCK lpECB TSRMLS_DC)
736 {
737 DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
738 char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
739 #ifndef WITH_ZEUS
740 HSE_URL_MAPEX_INFO humi;
741 #endif
742
743 SG(request_info).request_method = lpECB->lpszMethod;
744 SG(request_info).query_string = lpECB->lpszQueryString;
745 SG(request_info).request_uri = lpECB->lpszPathInfo;
746 SG(request_info).content_type = lpECB->lpszContentType;
747 SG(request_info).content_length = lpECB->cbTotalBytes;
748 SG(sapi_headers).http_response_code = 200; /* I think dwHttpStatusCode is invalid at this stage -RL */
749 if (!bFilterLoaded) { /* we don't have valid ISAPI Filter information */
750 SG(request_info).auth_user = SG(request_info).auth_password = SG(request_info).auth_digest = NULL;
751 }
752
753 #ifdef WITH_ZEUS
754 /* PATH_TRANSLATED can contain extra PATH_INFO stuff after the
755 * file being loaded, so we must use SCRIPT_FILENAME instead
756 */
757 if(lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_FILENAME", static_variable_buf, &variable_len)) {
758 SG(request_info).path_translated = estrdup(static_variable_buf);
759 } else
760 #else
761 /* happily, IIS gives us SCRIPT_NAME which is correct (without PATH_INFO stuff)
762 so we can just map that to the physical path and we have our filename */
763
764 lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &variable_len);
765 if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) {
766 SG(request_info).path_translated = estrdup(humi.lpszPath);
767 } else
768 #endif
769 /* if mapping fails, default to what the server tells us */
770 SG(request_info).path_translated = estrdup(lpECB->lpszPathTranslated);
771
772 /* some server configurations allow '..' to slip through in the
773 translated path. We'll just refuse to handle such a path. */
774 if (strstr(SG(request_info).path_translated,"..")) {
775 SG(sapi_headers).http_response_code = 404;
776 efree(SG(request_info).path_translated);
777 SG(request_info).path_translated = NULL;
778 }
779 }
780
781
php_isapi_report_exception(char * message,int message_len TSRMLS_DC)782 static void php_isapi_report_exception(char *message, int message_len TSRMLS_DC)
783 {
784 if (!SG(headers_sent)) {
785 HSE_SEND_HEADER_EX_INFO header_info;
786 LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
787
788 header_info.pszStatus = "500 Internal Server Error";
789 header_info.cchStatus = strlen(header_info.pszStatus);
790 header_info.pszHeader = "Content-Type: text/html\r\n\r\n";
791 header_info.cchHeader = strlen(header_info.pszHeader);
792
793 lpECB->dwHttpStatusCode = 500;
794 lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
795 SG(headers_sent)=1;
796 }
797 sapi_isapi_ub_write(message, message_len TSRMLS_CC);
798 }
799
800
GetExtensionVersion(HSE_VERSION_INFO * pVer)801 BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
802 {
803 pVer->dwExtensionVersion = HSE_VERSION;
804 #ifdef WITH_ZEUS
805 strncpy( pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN);
806 #else
807 lstrcpyn(pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN);
808 #endif
809 return TRUE;
810 }
811
812
my_endthread()813 static void my_endthread()
814 {
815 #ifdef PHP_WIN32
816 if (bTerminateThreadsOnError) {
817 _endthread();
818 }
819 #endif
820 }
821
822 #ifdef PHP_WIN32
823 /* ep is accessible only in the context of the __except expression,
824 * so we have to call this function to obtain it.
825 */
exceptionhandler(LPEXCEPTION_POINTERS * e,LPEXCEPTION_POINTERS ep)826 BOOL exceptionhandler(LPEXCEPTION_POINTERS *e, LPEXCEPTION_POINTERS ep)
827 {
828 *e=ep;
829 return TRUE;
830 }
831 #endif
832
HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)833 DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
834 {
835 zend_file_handle file_handle;
836 zend_bool stack_overflown=0;
837 int retval = FAILURE;
838 #ifdef PHP_ENABLE_SEH
839 LPEXCEPTION_POINTERS e;
840 #endif
841 TSRMLS_FETCH();
842
843 zend_first_try {
844 #ifdef PHP_ENABLE_SEH
845 __try {
846 #endif
847 init_request_info(lpECB TSRMLS_CC);
848 SG(server_context) = lpECB;
849
850 php_request_startup(TSRMLS_C);
851
852 file_handle.filename = SG(request_info).path_translated;
853 file_handle.free_filename = 0;
854 file_handle.type = ZEND_HANDLE_FILENAME;
855 file_handle.opened_path = NULL;
856
857 /* open the script here so we can 404 if it fails */
858 if (file_handle.filename)
859 retval = php_fopen_primary_script(&file_handle TSRMLS_CC);
860
861 if (!file_handle.filename || retval == FAILURE) {
862 SG(sapi_headers).http_response_code = 404;
863 PUTS("No input file specified.\n");
864 } else {
865 php_execute_script(&file_handle TSRMLS_CC);
866 }
867
868 if (SG(request_info).cookie_data) {
869 efree(SG(request_info).cookie_data);
870 }
871 if (SG(request_info).path_translated)
872 efree(SG(request_info).path_translated);
873 #ifdef PHP_ENABLE_SEH
874 } __except(exceptionhandler(&e, GetExceptionInformation())) {
875 char buf[1024];
876 if (_exception_code()==EXCEPTION_STACK_OVERFLOW) {
877 LPBYTE lpPage;
878 static SYSTEM_INFO si;
879 static MEMORY_BASIC_INFORMATION mi;
880 static DWORD dwOldProtect;
881
882 GetSystemInfo(&si);
883
884 /* Get page ESP is pointing to */
885 _asm mov lpPage, esp;
886
887 /* Get stack allocation base */
888 VirtualQuery(lpPage, &mi, sizeof(mi));
889
890 /* Go to the page below the current page */
891 lpPage = (LPBYTE) (mi.BaseAddress) - si.dwPageSize;
892
893 /* Free pages below current page */
894 if (!VirtualFree(mi.AllocationBase, (LPBYTE)lpPage - (LPBYTE) mi.AllocationBase, MEM_DECOMMIT)) {
895 _endthread();
896 }
897
898 /* Restore the guard page */
899 if (!VirtualProtect(lpPage, si.dwPageSize, PAGE_GUARD | PAGE_READWRITE, &dwOldProtect)) {
900 _endthread();
901 }
902
903 CG(unclean_shutdown)=1;
904 _snprintf(buf, sizeof(buf)-1,"PHP has encountered a Stack overflow");
905 php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC);
906 } else if (_exception_code()==EXCEPTION_ACCESS_VIOLATION) {
907 _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Access Violation at %p", e->ExceptionRecord->ExceptionAddress);
908 php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC);
909 my_endthread();
910 } else {
911 _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Unhandled Exception Code %d at %p", e->ExceptionRecord->ExceptionCode , e->ExceptionRecord->ExceptionAddress);
912 php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC);
913 my_endthread();
914 }
915 }
916 #endif
917 #ifdef PHP_ENABLE_SEH
918 __try {
919 php_request_shutdown(NULL);
920 } __except(EXCEPTION_EXECUTE_HANDLER) {
921 my_endthread();
922 }
923 #else
924 php_request_shutdown(NULL);
925 #endif
926 } zend_catch {
927 zend_try {
928 php_request_shutdown(NULL);
929 } zend_end_try();
930 return HSE_STATUS_ERROR;
931 } zend_end_try();
932
933 return HSE_STATUS_SUCCESS;
934 }
935
936
937
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)938 __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
939 {
940 switch (fdwReason) {
941 case DLL_PROCESS_ATTACH:
942 #ifdef WITH_ZEUS
943 tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "TSRM.log");
944 #else
945 tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "C:\\TSRM.log");
946 #endif
947 sapi_startup(&isapi_sapi_module);
948 if (isapi_sapi_module.startup) {
949 isapi_sapi_module.startup(&sapi_module);
950 }
951 break;
952 case DLL_THREAD_ATTACH:
953 break;
954 case DLL_THREAD_DETACH:
955 ts_free_thread();
956 break;
957 case DLL_PROCESS_DETACH:
958 if (isapi_sapi_module.shutdown) {
959 isapi_sapi_module.shutdown(&sapi_module);
960 }
961 sapi_shutdown();
962 tsrm_shutdown();
963 break;
964 }
965 return TRUE;
966 }
967
968 /*
969 * Local variables:
970 * tab-width: 4
971 * c-basic-offset: 4
972 * End:
973 */
974