php5isapi.c 32 KB

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