1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 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: php5isapi.c,v 1.1.1.2 2012/05/29 12:34:35 misho Exp $ */
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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: */
826: BOOL exceptionhandler(LPEXCEPTION_POINTERS *e, LPEXCEPTION_POINTERS ep)
827: {
828: *e=ep;
829: return TRUE;
830: }
831: #endif
832:
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:
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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>