mod_isapi.c revision b4c8a80f7dbfc9b56dbe03bdc28f0b5eb5f23697
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* ====================================================================
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * Redistribution and use in source and binary forms, with or without
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * modification, are permitted provided that the following conditions
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * are met:
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 1. Redistributions of source code must retain the above copyright
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * notice, this list of conditions and the following disclaimer.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 2. Redistributions in binary form must reproduce the above copyright
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * notice, this list of conditions and the following disclaimer in
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * the documentation and/or other materials provided with the
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * distribution.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 3. All advertising materials mentioning features or use of this
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * software must display the following acknowledgment:
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * "This product includes software developed by the Apache Group
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * for use in the Apache HTTP server project (http://www.apache.org/)."
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 4. The names "Apache Server" and "Apache Group" must not be used to
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * endorse or promote products derived from this software without
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * prior written permission. For written permission, please contact
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * apache@apache.org.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 5. Products derived from this software may not be called "Apache"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * nor may "Apache" appear in their names without prior written
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * permission of the Apache Group.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * 6. Redistributions of any form whatsoever must retain the following
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * acknowledgment:
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * "This product includes software developed by the Apache Group
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * for use in the Apache HTTP server project (http://www.apache.org/)."
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * OF THE POSSIBILITY OF SUCH DAMAGE.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ====================================================================
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * This software consists of voluntary contributions made by many
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * individuals on behalf of the Apache Group and was originally based
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * on public domain software written at the National Center for
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * Supercomputing Applications, University of Illinois, Urbana-Champaign.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * For more information on the Apache Group and the Apache HTTP server
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * project, please see <http://www.apache.org/>.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/*
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * mod_isapi.c - Internet Server Application (ISA) module for Apache
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * by Alexei Kosut <akosut@apache.org>
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * This module implements Microsoft's ISAPI, allowing Apache (when running
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * under Windows) to load Internet Server Applications (ISAPI extensions).
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * It implements all of the ISAPI 2.0 specification, except for the
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * "Microsoft-only" extensions dealing with asynchronous I/O. All ISAPI
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * extensions that use only synchronous I/O and are compatible with the
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ISAPI 2.0 specification should work (most ISAPI 1.0 extensions should
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * function as well).
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering *
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering * To load, simply place the ISA in a location in the document tree.
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering * Then add an "AddHandler isapi ap_context_t sa dll" into your config file.
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * You should now be able to load ISAPI DLLs just be reffering to their
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering * URLs. Make sure the ExecCGI option is active in the directory
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering * the ISA is in.
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering */
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "httpd.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "http_config.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "http_core.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "http_protocol.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "http_request.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "http_log.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "util_script.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* We use the exact same header file as the original */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include <HttpExt.h>
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* Seems IIS does not enforce the requirement for \r\n termination on HSE_REQ_SEND_RESPONSE_HEADER,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering define this to conform */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#define RELAX_HEADER_RULE
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringmodule isapi_module;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* Our "Connection ID" structure */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringtypedef struct {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering LPEXTENSION_CONTROL_BLOCK ecb;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering request_rec *r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering int status;
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer} isapi_cid;
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer/* Declare the ISAPI functions */
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName,
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer);
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI WriteClient (HCONN ConnID, LPVOID Buffer, LPDWORD lpwdwBytes,
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer DWORD dwReserved);
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI ReadClient (HCONN ConnID, LPVOID lpvBuffer, LPDWORD lpdwSize);
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest,
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer LPVOID lpvBuffer, LPDWORD lpdwSize,
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer LPDWORD lpdwDataType);
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer/*
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering The optimiser blows it totally here. What happens is that autos are addressed relative to the
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering stack pointer, which, of course, moves around. The optimiser seems to lose track of it somewhere
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering between setting isapi_entry and calling through it. We work around the problem by forcing it to
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering use frame pointers.
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering*/
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering#pragma optimize("y",off)
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poetteringint isapi_handler (request_rec *r) {
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering LPEXTENSION_CONTROL_BLOCK ecb =
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ap_pcalloc(r->pool, sizeof(struct _EXTENSION_CONTROL_BLOCK));
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering HSE_VERSION_INFO *pVer = ap_pcalloc(r->pool, sizeof(HSE_VERSION_INFO));
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering HINSTANCE isapi_handle;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering BOOL (*isapi_version)(HSE_VERSION_INFO *); /* entry point 1 */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering DWORD (*isapi_entry)(LPEXTENSION_CONTROL_BLOCK); /* entry point 2 */
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering BOOL (*isapi_term)(DWORD); /* optional entry point 3 */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering isapi_cid *cid = ap_pcalloc(r->pool, sizeof(isapi_cid));
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering ap_table_t *e = r->subprocess_env;
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering int retval;
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering /* Use similar restrictions as CGIs */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (!(ap_allow_options(r) & OPT_EXECCGI))
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return FORBIDDEN;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (r->finfo.st_mode == 0)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return NOT_FOUND;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (S_ISDIR(r->finfo.st_mode))
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return FORBIDDEN;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Load the module */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!(isapi_handle = LoadLibraryEx(r->filename, NULL,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering LOAD_WITH_ALTERED_SEARCH_PATH))) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering "Could not load DLL: %s", r->filename);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return SERVER_ERROR;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!(isapi_version =
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering (void *)(GetProcAddress(isapi_handle, "GetExtensionVersion")))) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering "DLL could not load GetExtensionVersion(): %s", r->filename);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering FreeLibrary(isapi_handle);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return SERVER_ERROR;
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek }
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek if (!(isapi_entry =
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek (void *)(GetProcAddress(isapi_handle, "HttpExtensionProc")))) {
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering "DLL could not load HttpExtensionProc(): %s", r->filename);
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering FreeLibrary(isapi_handle);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return SERVER_ERROR;
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering }
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering isapi_term = (void *)(GetProcAddress(isapi_handle, "TerminateExtension"));
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering /* Run GetExtensionVersion() */
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if ((*isapi_version)(pVer) != TRUE) {
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek "ISAPI GetExtensionVersion() failed: %s", r->filename);
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek FreeLibrary(isapi_handle);
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek return SERVER_ERROR;
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering }
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering /* Set up variables */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ap_add_common_vars(r);
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering ap_add_cgi_vars(r);
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek /* Set up connection ID */
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->ConnID = (HCONN)cid;
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek cid->ecb = ecb;
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering cid->r = r;
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering cid->status = 0;
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ecb->cbSize = sizeof(struct _EXTENSION_CONTROL_BLOCK);
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering ecb->dwVersion = MAKELONG(0, 2);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ecb->dwHttpStatusCode = 0;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering strcpy(ecb->lpszLogData, "");
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering ecb->lpszMethod = r->method;
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszQueryString = ap_table_get(e, "QUERY_STRING");
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszPathInfo = ap_table_get(e, "PATH_INFO");
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszPathTranslated = ap_table_get(e, "PATH_TRANSLATED");
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszContentType = ap_table_get(e, "CONTENT_TYPE");
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering /* Set up client input */
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering FreeLibrary(isapi_handle);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering return retval;
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering }
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering if (ap_should_client_block(r)) {
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering /* Unlike IIS, which limits this to 48k, we read the whole
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering * sucker in. I suppose this could be bad for memory if someone
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering * uploaded the complete works of Shakespeare. Well, WebSite
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering * does the same thing.
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering */
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering long to_read = atol(ap_table_get(e, "CONTENT_LENGTH"));
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering long read;
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek /* Actually, let's cap it at 48k, until we figure out what
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek * to do with this... we don't want a Content-Length: 1000000000
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek * taking out the machine.
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek */
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (to_read > 49152) {
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering FreeLibrary(isapi_handle);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering return HTTP_REQUEST_ENTITY_TOO_LARGE;
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering }
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering ecb->lpbData = ap_pcalloc(r->pool, 1 + to_read);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering if ((read = ap_get_client_block(r, ecb->lpbData, to_read)) < 0) {
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering FreeLibrary(isapi_handle);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return SERVER_ERROR;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering /* Although its not to spec, IIS seems to null-terminate
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * its lpdData string. So we will too. To make sure
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * cbAvailable matches cbTotalBytes, we'll up the latter
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * and equalize them.
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->cbAvailable = ecb->cbTotalBytes = read + 1;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->lpbData[read] = '\0';
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering else {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->cbTotalBytes = 0;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->cbAvailable = 0;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->lpbData = NULL;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Set up the callbacks */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->GetServerVariable = &GetServerVariable;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->WriteClient = &WriteClient;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->ReadClient = &ReadClient;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->ServerSupportFunction = &ServerSupportFunction;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* All right... try and load the sucker */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering retval = (*isapi_entry)(ecb);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Set the status (for logging) */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (ecb->dwHttpStatusCode)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering r->status = ecb->dwHttpStatusCode;
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Check for a log message - and log it */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (ecb->lpszLogData && strcmp(ecb->lpszLogData, ""))
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "%s: %s", ecb->lpszLogData, r->filename);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* All done with the DLL... get rid of it */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering FreeLibrary(isapi_handle);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering switch(retval) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering case HSE_STATUS_SUCCESS:
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering case HSE_STATUS_SUCCESS_AND_KEEP_CONN:
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Ignore the keepalive stuff; Apache handles it just fine without
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * the ISA's "advice".
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering */
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (cid->status) /* We have a special status to return */
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering return cid->status;
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering return OK;
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering case HSE_STATUS_PENDING: /* We don't support this */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_WARNING, r,
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering "ISAPI asynchronous I/O not supported: %s", r->filename);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering case HSE_STATUS_ERROR:
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering default:
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering return SERVER_ERROR;
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering }
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering}
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering#pragma optimize("",on)
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart PoetteringBOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName,
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer) {
request_rec *r = ((isapi_cid *)hConn)->r;
ap_table_t *e = r->subprocess_env;
const char *result;
/* Mostly, we just grab it from the environment, but there are
* a couple of special cases
*/
if (!strcasecmp(lpszVariableName, "UNMAPPED_REMOTE_USER")) {
/* We don't support NT users, so this is always the same as
* REMOTE_USER
*/
result = ap_table_get(e, "REMOTE_USER");
}
else if (!strcasecmp(lpszVariableName, "SERVER_PORT_SECURE")) {
/* Apache doesn't support secure requests inherently, so
* we have no way of knowing. We'll be conservative, and say
* all requests are insecure.
*/
result = "0";
}
else if (!strcasecmp(lpszVariableName, "URL")) {
result = r->uri;
}
else {
result = ap_table_get(e, lpszVariableName);
}
if (result) {
if (strlen(result) > *lpdwSizeofBuffer) {
*lpdwSizeofBuffer = strlen(result);
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
strncpy(lpvBuffer, result, *lpdwSizeofBuffer);
return TRUE;
}
/* Didn't find it */
SetLastError(ERROR_INVALID_INDEX);
return FALSE;
}
BOOL WINAPI WriteClient (HCONN ConnID, LPVOID Buffer, LPDWORD lpwdwBytes,
DWORD dwReserved) {
request_rec *r = ((isapi_cid *)ConnID)->r;
int writ; /* written, actually, but why shouldn't I make up words? */
/* We only support synchronous writing */
if (dwReserved && dwReserved != HSE_IO_SYNC) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, r,
"ISAPI asynchronous I/O not supported: %s", r->filename);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((writ = ap_rwrite(Buffer, *lpwdwBytes, r)) == EOF) {
SetLastError(ERROR); /* XXX: Find the right error code */
return FALSE;
}
*lpwdwBytes = writ;
return TRUE;
}
BOOL WINAPI ReadClient (HCONN ConnID, LPVOID lpvBuffer, LPDWORD lpdwSize) {
/* Doesn't need to do anything; we've read all the data already */
return TRUE;
}
/* XXX: There is an O(n^2) attack possible here. */
BOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest,
LPVOID lpvBuffer, LPDWORD lpdwSize,
LPDWORD lpdwDataType) {
isapi_cid *cid = (isapi_cid *)hConn;
request_rec *subreq, *r = cid->r;
char *data;
switch (dwHSERequest) {
case HSE_REQ_SEND_URL_REDIRECT_RESP:
/* Set the status to be returned when the HttpExtensionProc()
* is done.
*/
ap_table_set (r->headers_out, "Location", lpvBuffer);
cid->status = cid->r->status = cid->ecb->dwHttpStatusCode = REDIRECT;
return TRUE;
case HSE_REQ_SEND_URL:
/* Read any additional input */
if (r->remaining > 0) {
char argsbuffer[HUGE_STRING_LEN];
while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN));
}
/* 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");
ap_internal_redirect((char *)lpvBuffer, r);
return TRUE;
case HSE_REQ_SEND_RESPONSE_HEADER:
r->status_line = lpvBuffer ? lpvBuffer : ap_pstrdup(r->pool, "200 OK");
sscanf(r->status_line, "%d", &r->status);
cid->ecb->dwHttpStatusCode = r->status;
/* Now fill in the HTTP headers, and the rest of it. Ick.
* lpdwDataType contains a string that has headers (in MIME
* format), a blank like, then (possibly) data. We need
* to parse it.
*
* Easy case first:
*/
if (!lpdwDataType) {
ap_send_http_header(r);
return TRUE;
}
/* Make a copy - don't disturb the original */
data = ap_pstrdup(r->pool, (char *)lpdwDataType);
/* We *should* break before this while loop ends */
while (*data) {
char *value, *lf = strchr(data, '\n');
int p;
#ifdef RELAX_HEADER_RULE
if (lf)
*lf = '\0';
#else
if (!lf) { /* Huh? Invalid data, I think */
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
"ISA sent invalid headers: %s", r->filename);
SetLastError(ERROR); /* XXX: Find right error */
return FALSE;
}
/* Get rid of \n and \r */
*lf = '\0';
#endif
p = strlen(data);
if (p > 0 && data[p-1] == '\r') data[p-1] = '\0';
/* End of headers */
if (*data == '\0') {
#ifdef RELAX_HEADER_RULE
if (lf)
#endif
data = lf + 1; /* Reset data */
break;
}
if (!(value = strchr(data, ':'))) {
SetLastError(ERROR); /* XXX: Find right error */
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
"ISA sent invalid headers", r->filename);
return FALSE;
}
*value++ = '\0';
while (*value && ap_isspace(*value)) ++value;
/* Check all the special-case headers. Similar to what
* ap_scan_script_header_err() does (see that function for
* more detail)
*/
if (!strcasecmp(data, "Content-Type")) {
char *tmp;
/* Nuke trailing whitespace */
char *endp = value + strlen(value) - 1;
while (endp > value && ap_isspace(*endp)) *endp-- = '\0';
tmp = ap_pstrdup (r->pool, value);
ap_str_tolower(tmp);
r->content_type = tmp;
}
else if (!strcasecmp(data, "Content-Length")) {
ap_table_set(r->headers_out, data, value);
}
else if (!strcasecmp(data, "Transfer-Encoding")) {
ap_table_set(r->headers_out, data, value);
}
else if (!strcasecmp(data, "Set-Cookie")) {
ap_table_add(r->err_headers_out, data, value);
}
else {
ap_table_merge(r->err_headers_out, data, value);
}
/* Reset data */
#ifdef RELAX_HEADER_RULE
if (!lf) {
data += p;
break;
}
#endif
data = lf + 1;
}
/* All the headers should be set now */
ap_send_http_header(r);
/* Any data left should now be sent directly */
ap_rputs(data, r);
return TRUE;
case HSE_REQ_MAP_URL_TO_PATH:
/* Map a URL to a filename */
subreq = ap_sub_req_lookup_uri(ap_pstrndup(r->pool, (char *)lpvBuffer,
*lpdwSize), r);
GetFullPathName(subreq->filename, *lpdwSize - 1, (char *)lpvBuffer, NULL);
/* IIS puts a trailing slash on directories, Apache doesn't */
if (S_ISDIR (subreq->finfo.st_mode)) {
int l = strlen((char *)lpvBuffer);
((char *)lpvBuffer)[l] = '\\';
((char *)lpvBuffer)[l + 1] = '\0';
}
return TRUE;
case HSE_REQ_DONE_WITH_SESSION:
/* Do nothing... since we don't support async I/O, they'll
* return from HttpExtensionProc soon
*/
return TRUE;
/* We don't support all this async I/O, Microsoft-specific stuff */
case HSE_REQ_IO_COMPLETION:
case HSE_REQ_TRANSMIT_FILE:
ap_log_rerror(APLOG_MARK, APLOG_WARNING, r,
"ISAPI asynchronous I/O not supported: %s", r->filename);
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
handler_rec isapi_handlers[] = {
{ "isapi ap_context_t sa", 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 */
NULL, /* command ap_table_t */
isapi_handlers, /* handlers */
NULL, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* logger */
NULL /* header parser */
};