summaryrefslogtreecommitdiff
path: root/APACHE_1_3_42/src/os/win32/mod_isapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'APACHE_1_3_42/src/os/win32/mod_isapi.c')
-rw-r--r--APACHE_1_3_42/src/os/win32/mod_isapi.c891
1 files changed, 891 insertions, 0 deletions
diff --git a/APACHE_1_3_42/src/os/win32/mod_isapi.c b/APACHE_1_3_42/src/os/win32/mod_isapi.c
new file mode 100644
index 0000000000..9a8a04afbf
--- /dev/null
+++ b/APACHE_1_3_42/src/os/win32/mod_isapi.c
@@ -0,0 +1,891 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * mod_isapi.c - Internet Server Application (ISA) module for Apache
+ * by Alexei Kosut <akosut@apache.org>
+ *
+ * This module implements Microsoft's ISAPI, allowing Apache (when running
+ * under Windows) to load Internet Server Applications (ISAPI extensions).
+ * It implements all of the ISAPI 2.0 specification, except for the
+ * "Microsoft-only" extensions dealing with asynchronous I/O. All ISAPI
+ * extensions that use only synchronous I/O and are compatible with the
+ * ISAPI 2.0 specification should work (most ISAPI 1.0 extensions should
+ * function as well).
+ *
+ * To load, simply place the ISA in a location in the document tree.
+ * Then add an "AddHandler isapi-isa dll" into your config file.
+ * You should now be able to load ISAPI DLLs just be reffering to their
+ * URLs. Make sure the ExecCGI option is active in the directory
+ * the ISA is in.
+ */
+
+#ifdef WIN32
+
+/* A lousy hack to include ap_check_cmd_context(): */
+#define CORE_PRIVATE
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "http_log.h"
+#include "util_script.h"
+#include <stdlib.h>
+/* We use the exact same header file as the original */
+#include <HttpExt.h>
+
+/* Seems IIS does not enforce the requirement for \r\n termination on HSE_REQ_SEND_RESPONSE_HEADER,
+ define this to conform */
+#define RELAX_HEADER_RULE
+
+#if !defined(HSE_REQ_SEND_RESPONSE_HEADER_EX) \
+ || !defined(HSE_REQ_MAP_URL_TO_PATH_EX)
+#pragma message("WARNING: This build of Apache is missing the recent changes")
+#pragma message("in the Microsoft Win32 Platform SDK; some mod_isapi features")
+#pragma message("will be disabled. To obtain the latest Platform SDK files,")
+#pragma message("please refer to:")
+#pragma message("http://msdn.microsoft.com/downloads/sdks/platform/platform.asp")
+#endif
+
+module isapi_module;
+
+static DWORD ReadAheadBuffer = 49152;
+static int LogNotSupported = -1;
+static int AppendLogToErrors = 0;
+static int AppendLogToQuery = 0;
+
+/* Our "Connection ID" structure */
+
+typedef struct {
+ LPEXTENSION_CONTROL_BLOCK ecb;
+ request_rec *r;
+ int status;
+} isapi_cid;
+
+/* Declare the ISAPI functions */
+
+BOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName,
+ LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer);
+BOOL WINAPI WriteClient (HCONN ConnID, LPVOID Buffer, LPDWORD lpwdwBytes,
+ DWORD dwReserved);
+BOOL WINAPI ReadClient (HCONN ConnID, LPVOID lpvBuffer, LPDWORD lpdwSize);
+BOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest,
+ LPVOID lpvBuffer, LPDWORD lpdwSize,
+ LPDWORD lpdwDataType);
+
+/*
+ The optimiser blows it totally here. What happens is that autos are addressed relative to the
+ stack pointer, which, of course, moves around. The optimiser seems to lose track of it somewhere
+ between setting isapi_entry and calling through it. We work around the problem by forcing it to
+ use frame pointers.
+*/
+#pragma optimize("y",off)
+
+int isapi_handler (request_rec *r) {
+ LPEXTENSION_CONTROL_BLOCK ecb =
+ ap_pcalloc(r->pool, sizeof(struct _EXTENSION_CONTROL_BLOCK));
+ HSE_VERSION_INFO *pVer = ap_pcalloc(r->pool, sizeof(HSE_VERSION_INFO));
+
+ HINSTANCE isapi_handle;
+ BOOL (*isapi_version)(HSE_VERSION_INFO *); /* entry point 1 */
+ DWORD (*isapi_entry)(LPEXTENSION_CONTROL_BLOCK); /* entry point 2 */
+ BOOL (*isapi_term)(DWORD); /* optional entry point 3 */
+
+ isapi_cid *cid = ap_pcalloc(r->pool, sizeof(isapi_cid));
+ table *e = r->subprocess_env;
+ DWORD read;
+ char *p;
+ int retval;
+ int res;
+
+ /* Use similar restrictions as CGIs */
+
+ if (!(ap_allow_options(r) & OPT_EXECCGI))
+ return FORBIDDEN;
+
+ if (r->finfo.st_mode == 0)
+ return NOT_FOUND;
+
+ if (S_ISDIR(r->finfo.st_mode))
+ return FORBIDDEN;
+
+ if (!(isapi_handle = ap_os_dso_load(r->filename))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
+ "ISAPI Could not load DLL: %s", r->filename);
+ return SERVER_ERROR;
+ }
+
+ if (!(isapi_version =
+ (void *)(ap_os_dso_sym(isapi_handle, "GetExtensionVersion")))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
+ "DLL could not load GetExtensionVersion(): %s",
+ r->filename);
+ ap_os_dso_unload(isapi_handle);
+ return SERVER_ERROR;
+ }
+
+ if (!(isapi_entry =
+ (void *)(ap_os_dso_sym(isapi_handle, "HttpExtensionProc")))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
+ "DLL could not load HttpExtensionProc(): %s",
+ r->filename);
+ ap_os_dso_unload(isapi_handle);
+ return SERVER_ERROR;
+ }
+
+ isapi_term = (void *)(ap_os_dso_sym(isapi_handle, "TerminateExtension"));
+
+ /* Run GetExtensionVersion() */
+
+ if (!(*isapi_version)(pVer)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
+ "ISAPI GetExtensionVersion() failed: %s", r->filename);
+ ap_os_dso_unload(isapi_handle);
+ return SERVER_ERROR;
+ }
+
+ /* Set up variables. There are a couple of special cases for ISAPI.
+ * XXX: These were taken verbatim from GetServerVariable, and should
+ * be reviewed carefully.
+ */
+ ap_add_common_vars(r);
+ ap_add_cgi_vars(r);
+ ap_table_setn(r->subprocess_env, "UNMAPPED_REMOTE_USER", "REMOTE_USER");
+ ap_table_setn(r->subprocess_env, "SERVER_PORT_SECURE", "0");
+ ap_table_setn(r->subprocess_env, "URL", r->uri);
+
+ /* Set up connection ID */
+ ecb->ConnID = (HCONN)cid;
+ cid->ecb = ecb;
+ cid->r = r;
+ cid->status = 0;
+
+ ecb->cbSize = sizeof(struct _EXTENSION_CONTROL_BLOCK);
+ ecb->dwVersion = MAKELONG(0, 2);
+ ecb->dwHttpStatusCode = 0;
+ strcpy(ecb->lpszLogData, "");
+ ecb->lpszMethod = ap_pstrdup(r->pool, r->method);
+ ecb->lpszQueryString = ap_pstrdup(r->pool, ap_table_get(e, "QUERY_STRING"));
+ ecb->lpszPathInfo = ap_pstrdup(r->pool, ap_table_get(e, "PATH_INFO"));
+ ecb->lpszPathTranslated = ap_pstrdup(r->pool, ap_table_get(e, "PATH_TRANSLATED"));
+ ecb->lpszContentType = ap_pstrdup(r->pool, ap_table_get(e, "CONTENT_TYPE"));
+
+ /* Set up client input */
+ if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
+ if (isapi_term) (*isapi_term)( 2 /* HSE_TERM_MUST_UNLOAD */);
+ ap_os_dso_unload(isapi_handle);
+ return retval;
+ }
+
+ if (ap_should_client_block(r)) {
+ /* Time to start reading the appropriate amount of data,
+ * and allow the administrator to tweak the number
+ * TODO: add the httpd.conf option for ReadAheadBuffer.
+ */
+ if (r->remaining) {
+ ecb->cbTotalBytes = r->remaining;
+ if (ecb->cbTotalBytes > ReadAheadBuffer)
+ ecb->cbAvailable = ReadAheadBuffer;
+ else
+ ecb->cbAvailable = ecb->cbTotalBytes;
+ }
+ else
+ {
+ ecb->cbTotalBytes = 0xffffffff;
+ ecb->cbAvailable = ReadAheadBuffer;
+ }
+
+ ecb->lpbData = ap_pcalloc(r->pool, ecb->cbAvailable + 1);
+
+ p = ecb->lpbData;
+ read = 0;
+ while (read < ecb->cbAvailable &&
+ ((res = ap_get_client_block(r, ecb->lpbData + read,
+ ecb->cbAvailable - read)) > 0)) {
+ read += res;
+ }
+
+ if (res < 0) {
+ if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
+ ap_os_dso_unload(isapi_handle);
+ return SERVER_ERROR;
+ }
+
+ /* Although its not to spec, IIS seems to null-terminate
+ * its lpdData string. So we will too.
+ *
+ * XXX: This must be an issue... backing out the null
+ * from the count of bytes.
+ */
+ if (res == 0)
+ ecb->cbAvailable = ecb->cbTotalBytes = read;
+ else
+ ecb->cbAvailable = read;
+ ecb->lpbData[read] = '\0';
+ }
+ else {
+ ecb->cbTotalBytes = 0;
+ ecb->cbAvailable = 0;
+ ecb->lpbData = NULL;
+ }
+
+ /* Set up the callbacks */
+
+ ecb->GetServerVariable = &GetServerVariable;
+ ecb->WriteClient = &WriteClient;
+ ecb->ReadClient = &ReadClient;
+ ecb->ServerSupportFunction = &ServerSupportFunction;
+
+ /* All right... try and load the sucker */
+ retval = (*isapi_entry)(ecb);
+
+ /* Set the status (for logging) */
+ if (ecb->dwHttpStatusCode)
+ r->status = ecb->dwHttpStatusCode;
+
+ /* Check for a log message - and log it */
+ if (ecb->lpszLogData && strcmp(ecb->lpszLogData, ""))
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "ISAPI: %s: %s", ecb->lpszLogData, r->filename);
+
+ /* Soak up any remaining input */
+ if (r->remaining > 0) {
+ char argsbuffer[HUGE_STRING_LEN];
+ while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0);
+ }
+
+ /* All done with the DLL... get rid of it */
+ if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
+ ap_os_dso_unload(isapi_handle);
+
+ switch(retval) {
+ case 0: /* Strange, but MS isapi accepts this as success */
+ case HSE_STATUS_SUCCESS:
+ case HSE_STATUS_SUCCESS_AND_KEEP_CONN:
+ /* Ignore the keepalive stuff; Apache handles it just fine without
+ * the ISA's "advice".
+ */
+
+ if (cid->status) /* We have a special status to return */
+ return cid->status;
+
+ return OK;
+ case HSE_STATUS_PENDING: /* We don't support this */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI asynchronous I/O not supported: %s",
+ r->filename);
+ case HSE_STATUS_ERROR:
+ default:
+ return SERVER_ERROR;
+ }
+
+}
+#pragma optimize("",on)
+
+BOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName,
+ LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer) {
+ request_rec *r = ((isapi_cid *)hConn)->r;
+ const char *result;
+ DWORD len;
+
+ if (!strcmp(lpszVariableName, "ALL_HTTP")) {
+ /* lf delimited, colon split, comma seperated and
+ * null terminated list of HTTP_ vars
+ */
+ char **env = (char**) ap_table_elts(r->subprocess_env)->elts;
+ int nelts = 2 * ap_table_elts(r->subprocess_env)->nelts;
+ int i;
+
+ for (len = 0, i = 0; i < nelts; i += 2)
+ if (!strncmp(env[i], "HTTP_", 5))
+ len += strlen(env[i]) + strlen(env[i + 1]) + 2;
+
+ if (*lpdwSizeofBuffer < len + 1) {
+ *lpdwSizeofBuffer = len + 1;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+
+ for (i = 0; i < nelts; i += 2)
+ if (!strncmp(env[i], "HTTP_", 5)) {
+ strcpy(lpvBuffer, env[i]);
+ ((char*)lpvBuffer) += strlen(env[i]);
+ *(((char*)lpvBuffer)++) = ':';
+ strcpy(lpvBuffer, env[i + 1]);
+ ((char*)lpvBuffer) += strlen(env[i + 1]);
+ *(((char*)lpvBuffer)++) = '\n';
+ }
+ *(((char*)lpvBuffer)++) = '\0';
+ *lpdwSizeofBuffer = len;
+ return TRUE;
+ }
+
+ if (!strcmp(lpszVariableName, "ALL_RAW")) {
+ /* lf delimited, colon split, comma seperated and
+ * null terminated list of the raw request header
+ */
+ char **raw = (char**) ap_table_elts(r->headers_in)->elts;
+ int nelts = 2 * ap_table_elts(r->headers_in)->nelts;
+ int i;
+
+ for (len = 0, i = 0; i < nelts; i += 2)
+ len += strlen(raw[i]) + strlen(raw[i + 1]) + 2;
+
+ if (*lpdwSizeofBuffer < len + 1) {
+ *lpdwSizeofBuffer = len + 1;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+
+ for (i = 0; i < nelts; i += 2) {
+ strcpy(lpvBuffer, raw[i]);
+ ((char*)lpvBuffer) += strlen(raw[i]);
+ *(((char*)lpvBuffer)++) = ':';
+ *(((char*)lpvBuffer)++) = ' ';
+ strcpy(lpvBuffer, raw[i + 1]);
+ ((char*)lpvBuffer) += strlen(raw[i + 1]);
+ *(((char*)lpvBuffer)++) = '\n';
+ i += 2;
+ }
+ *(((char*)lpvBuffer)++) = '\0';
+ *lpdwSizeofBuffer = len;
+ return TRUE;
+ }
+
+ /* Not a special case */
+ result = ap_table_get(r->subprocess_env, lpszVariableName);
+ if (result) {
+ len = strlen(result);
+ if (*lpdwSizeofBuffer < len + 1) {
+ *lpdwSizeofBuffer = len + 1;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ strcpy(lpvBuffer, result);
+ *lpdwSizeofBuffer = len;
+ return TRUE;
+ }
+
+ /* Not Found */
+ SetLastError(ERROR_INVALID_INDEX);
+ return FALSE;
+}
+
+BOOL WINAPI WriteClient (HCONN ConnID, LPVOID Buffer, LPDWORD lpwdwBytes,
+ DWORD dwReserved) {
+ request_rec *r = ((isapi_cid *)ConnID)->r;
+
+ /* We only support synchronous writing */
+ if (dwReserved && dwReserved != HSE_IO_SYNC) {
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI asynchronous I/O not supported: %s",
+ r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if ((*lpwdwBytes = ap_rwrite(Buffer, *lpwdwBytes, r)) <= 0) {
+ if (!GetLastError())
+ SetLastError(ERROR); /* XXX: Find the right error code */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL WINAPI ReadClient (HCONN ConnID, LPVOID lpvBuffer, LPDWORD lpdwSize) {
+ request_rec *r = ((isapi_cid *)ConnID)->r;
+ DWORD read = 0;
+ int res;
+
+ if (r->remaining < (long) *lpdwSize)
+ *lpdwSize = r->remaining;
+
+ while (read < *lpdwSize &&
+ ((res = ap_get_client_block(r, (char*)lpvBuffer + read,
+ *lpdwSize - read)) > 0)) {
+ if (res < 0) {
+ *lpdwSize = 0;
+ if (!GetLastError())
+ SetLastError(ERROR); /* XXX: Find the right error code */
+ return FALSE;
+ }
+
+ read += res;
+ }
+
+ *lpdwSize = read;
+ return TRUE;
+}
+
+static BOOL SendResponseHeaderEx(isapi_cid *cid, const char *stat,
+ const char *head, DWORD statlen,
+ DWORD headlen)
+{
+ int termarg;
+ char *termch;
+
+ if (!stat || statlen == 0 || !*stat) {
+ stat = "Status: 200 OK";
+ }
+ else {
+ char *newstat;
+ newstat = ap_palloc(cid->r->pool, statlen + 9);
+ strcpy(newstat, "Status: ");
+ ap_cpystrn(newstat + 8, stat, statlen + 1);
+ stat = newstat;
+ }
+
+ if (!head || headlen == 0 || !*head) {
+ head = "\r\n";
+ }
+ else
+ {
+ if (head[headlen]) {
+ /* Whoops... not NULL terminated */
+ head = ap_pstrndup(cid->r->pool, head, headlen);
+ }
+ }
+
+ /* Parse them out, or die trying */
+ cid->status = ap_scan_script_header_err_strs(cid->r, NULL, &termch,
+ &termarg, stat, head, NULL);
+ cid->ecb->dwHttpStatusCode = cid->r->status;
+
+ /* All the headers should be set now */
+ ap_send_http_header(cid->r);
+
+ /* Any data left should now be sent directly,
+ * it may be raw if headlen was provided.
+ */
+ if (termch && (termarg == 1)) {
+ if (headlen == -1 && *termch)
+ ap_rputs(termch, cid->r);
+ else if (headlen > (size_t) (termch - head))
+ ap_rwrite(termch, headlen - (termch - head), cid->r);
+ }
+
+ if (cid->status == HTTP_INTERNAL_SERVER_ERROR)
+ return FALSE;
+ return TRUE;
+}
+
+/* XXX: Is there is still an O(n^2) attack possible here? Please detail. */
+BOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest,
+ LPVOID lpvBuffer, LPDWORD lpdwSize,
+ LPDWORD lpdwDataType) {
+ isapi_cid *cid = (isapi_cid *)hConn;
+ request_rec *r = cid->r;
+ request_rec *subreq;
+
+ switch (dwHSERequest) {
+ case 1: /* HSE_REQ_SEND_URL_REDIRECT_RESP */
+ /* Set the status to be returned when the HttpExtensionProc()
+ * is done.
+ * WARNING: Microsoft now advertises HSE_REQ_SEND_URL_REDIRECT_RESP
+ * and HSE_REQ_SEND_URL as equivalant per the Jan 2000 SDK.
+ * They most definately are not, even in their own samples.
+ */
+ ap_table_set(r->headers_out, "Location", lpvBuffer);
+ cid->status = cid->r->status
+ = cid->ecb->dwHttpStatusCode = HTTP_MOVED_TEMPORARILY;
+ return TRUE;
+
+ case 2: /* HSE_REQ_SEND_URL */
+ /* Soak up remaining input (there should be none) */
+ if (r->remaining > 0) {
+ char argsbuffer[HUGE_STRING_LEN];
+ while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0);
+ }
+
+ /* Reset the method to GET */
+ r->method = ap_pstrdup(r->pool, "GET");
+ r->method_number = M_GET;
+
+ /* Don't let anyone think there's still data */
+ ap_table_unset(r->headers_in, "Content-Length");
+
+ /* AV fault per PR3598 - redirected path is lost! */
+ (char*)lpvBuffer = ap_pstrdup(r->pool, (char*)lpvBuffer);
+ ap_internal_redirect((char*)lpvBuffer, r);
+ return TRUE;
+
+ case 3: /* HSE_REQ_SEND_RESPONSE_HEADER */
+ {
+ /* Parse them out, or die trying */
+ DWORD statlen = 0, headlen = 0;
+ if (lpvBuffer)
+ statlen = strlen((char*) lpvBuffer);
+ if (lpdwDataType)
+ headlen = strlen((char*) lpdwDataType);
+ return SendResponseHeaderEx(cid, (char*) lpvBuffer, (char*) lpdwDataType,
+ statlen, headlen);
+ }
+
+ case 4: /* HSE_REQ_DONE_WITH_SESSION */
+ /* Do nothing... since we don't support async I/O, they'll
+ * return from HttpExtensionProc soon
+ */
+ return TRUE;
+
+ case 1001: /* HSE_REQ_MAP_URL_TO_PATH */
+ {
+ /* Map a URL to a filename */
+ char *file = (char *)lpvBuffer;
+ DWORD len;
+ subreq = ap_sub_req_lookup_uri(ap_pstrndup(r->pool, file, *lpdwSize), r);
+
+ len = ap_cpystrn(file, subreq->filename, *lpdwSize) - file;
+
+ /* IIS puts a trailing slash on directories, Apache doesn't */
+ if (S_ISDIR (subreq->finfo.st_mode)) {
+ if (len < *lpdwSize - 1) {
+ file[len++] = '\\';
+ file[len] = '\0';
+ }
+ }
+ *lpdwSize = len;
+ return TRUE;
+ }
+
+ case 1002: /* HSE_REQ_GET_SSPI_INFO */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction HSE_REQ_GET_SSPI_INFO "
+ "is not supported: %s", r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+ case 1003: /* HSE_APPEND_LOG_PARAMETER */
+ /* Log lpvBuffer, of lpdwSize bytes, in the URI Query (cs-uri-query) field
+ * This code will do for now...
+ */
+ ap_table_set(r->notes, "isapi-parameter", (char*) lpvBuffer);
+ if (AppendLogToQuery) {
+ if (r->args)
+ r->args = ap_pstrcat(r->pool, r->args, (char*) lpvBuffer, NULL);
+ else
+ r->args = ap_pstrdup(r->pool, (char*) lpvBuffer);
+ }
+ if (AppendLogToErrors)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
+ "ISAPI %s: %s", cid->r->filename,
+ (char*) lpvBuffer);
+ return TRUE;
+
+ /* We don't support all this async I/O, Microsoft-specific stuff */
+ case 1005: /* HSE_REQ_IO_COMPLETION */
+ case 1006: /* HSE_REQ_TRANSMIT_FILE */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI asynchronous I/O not supported: %s",
+ r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+ case 1007: /* HSE_REQ_REFRESH_ISAPI_ACL */
+ /* Since we don't override the user ID and access, we can't reset.
+ */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction "
+ "HSE_REQ_REFRESH_ISAPI_ACL "
+ "is not supported: %s", r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+ case 1008: /* HSE_REQ_IS_KEEP_CONN */
+ *((LPBOOL) lpvBuffer) = (r->connection->keepalive == 1);
+ return TRUE;
+
+ case 1010: /* HSE_REQ_ASYNC_READ_CLIENT */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI asynchronous I/O not supported: %s",
+ r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+ case 1011: /* HSE_REQ_GET_IMPERSONATION_TOKEN Added in ISAPI 4.0 */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction "
+ "HSE_REQ_GET_IMPERSONATION_TOKEN "
+ "is not supported: %s", r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+#ifdef HSE_REQ_MAP_URL_TO_PATH_EX
+ case 1012: /* HSE_REQ_MAP_URL_TO_PATH_EX */
+ {
+ /* Map a URL to a filename */
+ LPHSE_URL_MAPEX_INFO info = (LPHSE_URL_MAPEX_INFO) lpdwDataType;
+ char* test_uri = ap_pstrndup(r->pool, (char *)lpvBuffer, *lpdwSize);
+
+ subreq = ap_sub_req_lookup_uri(test_uri, r);
+ info->cchMatchingURL = strlen(test_uri);
+ info->cchMatchingPath = ap_cpystrn(info->lpszPath, subreq->filename,
+ MAX_PATH) - info->lpszPath;
+
+ /* Mapping started with assuming both strings matched.
+ * Now roll on the path_info as a mismatch and handle
+ * terminating slashes for directory matches.
+ */
+ if (subreq->path_info && *subreq->path_info) {
+ ap_cpystrn(info->lpszPath + info->cchMatchingPath,
+ subreq->path_info, MAX_PATH - info->cchMatchingPath);
+ info->cchMatchingURL -= strlen(subreq->path_info);
+ if (S_ISDIR(subreq->finfo.st_mode)
+ && info->cchMatchingPath < MAX_PATH - 1) {
+ /* roll forward over path_info's first slash */
+ ++info->cchMatchingPath;
+ ++info->cchMatchingURL;
+ }
+ }
+ else if (S_ISDIR(subreq->finfo.st_mode)
+ && info->cchMatchingPath < MAX_PATH - 1) {
+ /* Add a trailing slash for directory */
+ info->lpszPath[info->cchMatchingPath++] = '/';
+ info->lpszPath[info->cchMatchingPath] = '\0';
+ }
+
+ /* If the matched isn't a file, roll match back to the prior slash */
+ if (!subreq->finfo.st_mode) {
+ while (info->cchMatchingPath && info->cchMatchingURL) {
+ if (info->lpszPath[info->cchMatchingPath - 1] == '/')
+ break;
+ --info->cchMatchingPath;
+ --info->cchMatchingURL;
+ }
+ }
+
+ /* Paths returned with back slashes */
+ for (test_uri = info->lpszPath; *test_uri; ++test_uri)
+ if (*test_uri == '/')
+ *test_uri = '\\';
+
+ /* is a combination of:
+ * HSE_URL_FLAGS_READ 0x001 Allow read
+ * HSE_URL_FLAGS_WRITE 0x002 Allow write
+ * HSE_URL_FLAGS_EXECUTE 0x004 Allow execute
+ * HSE_URL_FLAGS_SSL 0x008 Require SSL
+ * HSE_URL_FLAGS_DONT_CACHE 0x010 Don't cache (VRoot only)
+ * HSE_URL_FLAGS_NEGO_CERT 0x020 Allow client SSL cert
+ * HSE_URL_FLAGS_REQUIRE_CERT 0x040 Require client SSL cert
+ * HSE_URL_FLAGS_MAP_CERT 0x080 Map client SSL cert to account
+ * HSE_URL_FLAGS_SSL128 0x100 Require 128-bit SSL cert
+ * HSE_URL_FLAGS_SCRIPT 0x200 Allow script execution
+ *
+ * XxX: As everywhere, EXEC flags could use some work...
+ * and this could go further with more flags, as desired.
+ */
+ info->dwFlags = (subreq->finfo.st_mode & _S_IREAD ? 0x001 : 0)
+ | (subreq->finfo.st_mode & _S_IWRITE ? 0x002 : 0)
+ | (subreq->finfo.st_mode & _S_IEXEC ? 0x204 : 0);
+ return TRUE;
+ }
+#endif
+
+ case 1014: /* HSE_REQ_ABORTIVE_CLOSE */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction HSE_REQ_ABORTIVE_CLOSE"
+ " is not supported: %s", r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+ case 1015: /* HSE_REQ_GET_CERT_INFO_EX Added in ISAPI 4.0 */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction "
+ "HSE_REQ_GET_CERT_INFO_EX "
+ "is not supported: %s", r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+#ifdef HSE_REQ_SEND_RESPONSE_HEADER_EX
+ case 1016: /* HSE_REQ_SEND_RESPONSE_HEADER_EX Added in ISAPI 4.0 */
+ {
+ LPHSE_SEND_HEADER_EX_INFO shi
+ = (LPHSE_SEND_HEADER_EX_INFO) lpvBuffer;
+ /* XXX: ignore shi->fKeepConn? We shouldn't need the advise */
+ /* r->connection->keepalive = shi->fKeepConn; */
+ return SendResponseHeaderEx(cid, shi->pszStatus, shi->pszHeader,
+ shi->cchStatus, shi->cchHeader);
+ }
+#endif
+
+ case 1017: /* HSE_REQ_CLOSE_CONNECTION Added after ISAPI 4.0 */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction "
+ "HSE_REQ_CLOSE_CONNECTION "
+ "is not supported: %s", r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+ case 1018: /* HSE_REQ_IS_CONNECTED Added after ISAPI 4.0 */
+ /* Returns True if client is connected c.f. MSKB Q188346
+ * XXX: That statement is very ambigious... assuming the
+ * identical return mechanism as HSE_REQ_IS_KEEP_CONN.
+ */
+ *((LPBOOL) lpvBuffer) = (r->connection->aborted == 0);
+ return TRUE;
+
+ case 1020: /* HSE_REQ_EXTENSION_TRIGGER Added after ISAPI 4.0 */
+ /* Undocumented - defined by the Microsoft Jan '00 Platform SDK
+ */
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction "
+ "HSE_REQ_EXTENSION_TRIGGER "
+ "is not supported: %s", r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+
+ default:
+ if (LogNotSupported)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
+ "ISAPI ServerSupportFunction (%d) not supported: "
+ "%s", dwHSERequest, r->filename);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+}
+
+/*
+ * Command handler for the ISAPIReadAheadBuffer directive, which is TAKE1
+ */
+static const char *isapi_cmd_readaheadbuffer(cmd_parms *cmd, void *config,
+ char *arg)
+{
+ long val;
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (((val = ap_strtol(arg, (char **) &err, 10)) <= 0) || *err)
+ return "ISAPIReadAheadBuffer must be a legitimate value.";
+
+ ReadAheadBuffer = val;
+ return NULL;
+}
+
+/*
+ * Command handler for the ISAPIReadAheadBuffer directive, which is TAKE1
+ */
+static const char *isapi_cmd_lognotsupported(cmd_parms *cmd, void *config,
+ char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (strcasecmp(arg, "on") == 0) {
+ LogNotSupported = -1;
+ }
+ else if (strcasecmp(arg, "off") == 0) {
+ LogNotSupported = 0;
+ }
+ else {
+ return "ISAPILogNotSupported must be on or off";
+ }
+ return NULL;
+}
+
+static const char *isapi_cmd_appendlogtoerrors(cmd_parms *cmd, void *config,
+ char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (strcasecmp(arg, "on") == 0) {
+ AppendLogToErrors = -1;
+ }
+ else if (strcasecmp(arg, "off") == 0) {
+ AppendLogToErrors = 0;
+ }
+ else {
+ return "ISAPIAppendLogToErrors must be on or off";
+ }
+ return NULL;
+}
+
+static const char *isapi_cmd_appendlogtoquery(cmd_parms *cmd, void *config,
+ char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (strcasecmp(arg, "on") == 0) {
+ AppendLogToQuery = -1;
+ }
+ else if (strcasecmp(arg, "off") == 0) {
+ AppendLogToQuery = 0;
+ }
+ else {
+ return "ISAPIAppendLogToQuery must be on or off";
+ }
+ return NULL;
+}
+
+static const command_rec isapi_cmds[] = {
+{ "ISAPIReadAheadBuffer", isapi_cmd_readaheadbuffer, NULL, RSRC_CONF, TAKE1,
+ "Maximum bytes to initially pass to the ISAPI handler" },
+{ "ISAPILogNotSupported", isapi_cmd_lognotsupported, NULL, RSRC_CONF, TAKE1,
+ "Log requests not supported by the ISAPI server" },
+{ "ISAPIAppendLogToErrors", isapi_cmd_appendlogtoerrors, NULL, RSRC_CONF, TAKE1,
+ "Send all Append Log requests to the error log" },
+{ "ISAPIAppendLogToQuery", isapi_cmd_appendlogtoquery, NULL, RSRC_CONF, TAKE1,
+ "Append Log requests are concatinated to the query args" },
+{ NULL }
+};
+
+handler_rec isapi_handlers[] = {
+{ "isapi-isa", isapi_handler },
+{ NULL}
+};
+
+module isapi_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ isapi_cmds, /* command table */
+ isapi_handlers, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* logger */
+ NULL /* header parser */
+};
+
+#endif /* WIN32 */