Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2228 lines
58 KiB

/*++
Copyright (c) 1995-1996 Microsoft Corporation
Module Name :
isplocal.cxx
Abstract:
This module declares the functions for Local ISAPI handler
as well as the global table of all ISAPI applications loaded
Author:
Murali R. Krishnan ( MuraliK ) 17-July-1996
Environment:
User Mode - Win32
Project:
W3 Services DLL
--*/
/************************************************************
* Include Headers
************************************************************/
# include <isapip.hxx>
# include <irtlmisc.h>
# include "isapidll.hxx"
# include "setable.hxx"
# include "gip.h"
# include "iwr.h"
# include "WamW3.hxx"
/************************************************************
* Global Data
************************************************************/
//
// Generic mapping for Application access check
//
GENERIC_MAPPING sg_FileGenericMapping =
{
FILE_GENERIC_READ,
FILE_GENERIC_WRITE,
FILE_GENERIC_EXECUTE,
FILE_ALL_ACCESS
};
/************************************************************
* Functions
************************************************************/
BOOL
CallChildCompletionProc(
IN WAM_EXEC_INFO * pWamExecInfo,
DWORD dwBytes,
DWORD dwLastError
)
/*++
Routine Description:
Call the async IO completion routine of the child ISA.
Arguments:
pWamExecInfo - WAM_EXEC_INFO of the child
dwBytes - Bytes for read/write
dwLastError - Last error (used for status of IO request)
Return Value:
TRUE on success, FALSE on failure
--*/
{
BOOL fRet = TRUE;
DBG_ASSERT( pWamExecInfo->_AsyncIoInfo._pfnHseIO != NULL);
__try
{
(*pWamExecInfo->_AsyncIoInfo._pfnHseIO)( &(pWamExecInfo->ecb),
pWamExecInfo->_AsyncIoInfo._pvHseIOContext,
dwBytes,
dwLastError );
}
__except ( g_fEnableTryExcept ?
WAMExceptionFilter( GetExceptionInformation(),
WAM_EVENT_EXTENSION_EXCEPTION,
pWamExecInfo ) :
EXCEPTION_CONTINUE_SEARCH )
{
fRet = FALSE;
}
return fRet;
}
/**************************************************
* Member functions of HSE_APPDLL
**************************************************/
/* class static */
PHSE
HSE_APPDLL::LoadModule( IN const char * pchModuleName,
IN HANDLE hImpersonation,
IN BOOL fCache )
{
PFN_HTTPEXTENSIONPROC pfnSEProc;
HMODULE hMod;
PFN_GETEXTENSIONVERSION pfnGetExtVer;
PFN_TERMINATEEXTENSION pfnTerminate;
HSE_VERSION_INFO ExtensionVersion;
HSE_APPDLL * pExtension = NULL;
hMod = LoadLibraryEx( pchModuleName,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH );
if ( hMod == NULL ) {
DBGPRINTF(( DBG_CONTEXT,
"[SEGetEntryPoint] LoadLibrary %s failed with error %d\n",
pchModuleName, GetLastError()));
return NULL;
}
//
// check machine type from header
//
LPBYTE pImg = (LPBYTE)hMod;
//
// skip possible DOS header
//
if ( ((IMAGE_DOS_HEADER*)pImg)->e_magic == IMAGE_DOS_SIGNATURE )
{
pImg += ((IMAGE_DOS_HEADER*)pImg)->e_lfanew;
}
//
// test only if NT header detected
//
if ( !TsIsWindows95() ) {
if ( *(DWORD*)pImg == IMAGE_NT_SIGNATURE
&& ( ((IMAGE_FILE_HEADER*)(pImg+sizeof(DWORD)))->Machine
< USER_SHARED_DATA->ImageNumberLow
|| ((IMAGE_FILE_HEADER*)(pImg+sizeof(DWORD)))->Machine
> USER_SHARED_DATA->ImageNumberHigh ) )
{
DBGPRINTF(( DBG_CONTEXT,
"[SEGetEntryPoint] LoadLibrary loaded bad "
" format exe type %d, valid range %d-%d\n",
((IMAGE_FILE_HEADER*)(pImg+sizeof(DWORD)))->Machine,
USER_SHARED_DATA->ImageNumberLow,
USER_SHARED_DATA->ImageNumberHigh
));
SetLastError( ERROR_BAD_EXE_FORMAT );
FreeLibrary( hMod );
return NULL;
}
}
//
// Retrieve the entry points
//
pfnSEProc = (PFN_HTTPEXTENSIONPROC) GetProcAddress(
hMod,
SE_DEFAULT_ENTRY );
pfnGetExtVer = (PFN_GETEXTENSIONVERSION) GetProcAddress(
hMod,
SE_INIT_ENTRY );
//
// Note that there is no harm done
// even if ISAPI is old and does not have TerminateExtension
//
pfnTerminate =
(PFN_TERMINATEEXTENSION) GetProcAddress( hMod, SE_TERM_ENTRY );
//
// Revert our security context, so that GetExtensionVersion()
// can be called in the system context
//
RevertToSelf();
if ( !pfnSEProc ||
!pfnGetExtVer ||
!pfnGetExtVer( &ExtensionVersion )) {
DBGPRINTF(( DBG_CONTEXT,
"SE_TABLE::LoadModule() GetExtVer failed, Error %d\n",
GetLastError() ));
FreeLibrary( hMod );
return NULL;
}
//
// Re-impersonate before for Loading ACLs which is called in
// the constructor of HSE_APPDLL
//
if ( !ImpersonateLoggedOnUser( hImpersonation )) {
DWORD dwError = GetLastError();
//
// since this call is not implemented on win95, ignore it.
//
if ( !TsIsWindows95() ) {
DBGPRINTF(( DBG_CONTEXT,
"SE_TABLE::LoadModule() Re-impersonation failed,"
" Error %d\n",
GetLastError() ));
//
// tell the extension that we are shutting down :(
//
if ( pfnTerminate ) {
pfnTerminate( HSE_TERM_MUST_UNLOAD );
}
FreeLibrary( hMod);
SetLastError( dwError);
return ( NULL);
}
}
pExtension = new HSE_APPDLL( pchModuleName,
hMod,
pfnSEProc,
pfnTerminate,
fCache );
if ( !pExtension || !pExtension->IsValid()) {
if ( pfnTerminate ) {
pfnTerminate( HSE_TERM_MUST_UNLOAD );
}
if ( pExtension != NULL) {
delete pExtension;
pExtension = NULL;
}
FreeLibrary( hMod );
return NULL;
}
DBGPRINTF(( DBG_CONTEXT,
"SE_TABLE::LoadModule() Loaded extension %s, "
" description \"%s\"\n",
pchModuleName,
ExtensionVersion.lpszExtensionDesc ));
return ( (HSE_BASE * ) pExtension);
} // HSE_APPDLL::LoadModule()
HSE_APPDLL::~HSE_APPDLL(VOID)
{
Unload();
if ( _hMod) {
DBG_REQUIRE( FreeLibrary( _hMod ) );
_hMod = NULL;
}
} // HSE_APPDLL::~HSE_APPDLL()
BOOL
HSE_APPDLL::LoadAcl(VOID)
{
DWORD cbSecDesc = _buffSD.QuerySize();
DBG_ASSERT( IsValid());
//
// Force an access check on the next request
//
SetLastSuccessfulUser( NULL );
//
// Chicago does not have GetFileSecurity call
//
if ( TsIsWindows95() ) {
return(TRUE);
}
if ( GetFileSecurity( QueryModuleName(),
(OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION),
NULL,
0,
&cbSecDesc ))
{
return TRUE;
}
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
{
return FALSE;
}
TryAgain:
if ( !_buffSD.Resize( cbSecDesc ) ||
!GetFileSecurity( QueryModuleName(),
(OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION),
_buffSD.QueryPtr(),
cbSecDesc,
&cbSecDesc ))
{
//
// A new ACL may have been written since we checked the old
// one, so try it again
//
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
goto TryAgain;
}
return FALSE;
}
return TRUE;
} // HSE_APPDLL::LoadAcl()
BOOL
HSE_APPDLL::AccessCheck( IN HANDLE hImpersonation,
IN BOOL fCacheImpersonation
)
{
BOOL fRet = TRUE;
// NOTE we call IsKindaValid() because caller may dereference before calling us
// (causing IsValid() to return false).
DBG_ASSERT( IsKindaValid() );
//
// Optimize for the anonymous user and only do the access
// check if this is a different user then the last successful
// user
//
if ( !TsIsWindows95() ) {
if ( !fCacheImpersonation ||
(hImpersonation != QueryLastSuccessfulUser()) ) {
DWORD dwGrantedAccess;
BYTE PrivSet[400];
DWORD cbPrivilegeSet = sizeof(PrivSet);
BOOL fAccessGranted;
fRet = ( ::AccessCheck( QuerySecDesc(),
hImpersonation,
FILE_GENERIC_EXECUTE,
&sg_FileGenericMapping,
(PRIVILEGE_SET *) &PrivSet,
&cbPrivilegeSet,
&dwGrantedAccess,
&fAccessGranted )
&& fAccessGranted);
if ( fRet && fCacheImpersonation ) {
SetLastSuccessfulUser( hImpersonation );
}
}
}
return ( fRet);
} // HSE_APPDLL::AccessCheck()
DWORD
HSE_APPDLL::ExecuteRequest(
WAM_EXEC_INFO * pWamExecInfo
)
{
DWORD dwIsaRet; // return value from ISA
DBG_ASSERT( pWamExecInfo );
EXTENSION_CONTROL_BLOCK * pecb = &(pWamExecInfo->ecb);
pecb->GetServerVariable= GetServerVariable;
pecb->WriteClient = WriteClient;
pecb->ReadClient = ReadClient;
pecb->ServerSupportFunction = ServerSupportFunction;
DBG_ASSERT( IsValid());
// addref the context before we hand it to ISA
pWamExecInfo->AddRef();
IF_DEBUG( WAM_FILENAMES ) {
DBGPRINTF(( DBG_CONTEXT, "Dll: %s\tScript: %s\n",
WRC_GET_SZ( WRC_I_ISADLLPATH ),
WRC_GET_SZ( WRC_I_PATHINFO ) ));
}
DBG_WAMREQ_REFCOUNTS(( "HSE_APPDLL::ExecuteRequest before ISA call ...", pWamExecInfo ));
// call the extension proc ...
dwIsaRet = ( _pfnEntryPoint( pecb ) );
// release the context upon return from ISA
pWamExecInfo->Release( );
DBG_WAMREQ_REFCOUNTS(( "HSE_APPDLL::ExecuteRequest after ISA call ...", pWamExecInfo ));
return dwIsaRet;
} // HSE_APPDLL::ExecuteRequest()
BOOL
HSE_APPDLL::Cleanup(VOID)
{
return (TRUE);
} // HSE_APPDLL::Cleanup()
DWORD
HSE_APPDLL::Unload(VOID)
{
// Unload can be called before the ref count hits zero
// This will force all the requests inside ISAPI DLL to exit
// DBG_ASSERT( RefCount() == 0);
DBG_REQUIRE( Cleanup());
if ( _pfnTerminate ) {
//
// From the old code :(
// The return value from Terminate() is ignored!
//
_pfnTerminate( HSE_TERM_MUST_UNLOAD );
_pfnTerminate = NULL;
}
SetValid( FALSE);
return (NO_ERROR);
} // HSE_APPDLL::Unload()
/*-----------------------------------------------------------------------------*
Support for ISAPI Callback Functions
*/
/*-----------------------------------------------------------------------------*
GetISAContext
Gets the ISA context from the ISA-supplied connection handle.
NOTE caller must balance calls to GetISAContext and ReleaseISAContext
Arguments:
See below
Returns:
BOOL
*/
BOOL
GetISAContext(
IN HCONN hConn,
OUT EXTENSION_CONTROL_BLOCK ** ppecb,
OUT WAM_EXEC_INFO ** ppWamExecInfo,
OUT IWamRequest ** ppIWamRequest
)
{
IF_DEBUG( MISC ) {
DBGPRINTF(( DBG_CONTEXT, "GetISAContext(%08x)\n", hConn ));
}
*ppecb = (EXTENSION_CONTROL_BLOCK *) hConn;
*ppWamExecInfo = (WAM_EXEC_INFO *) hConn;
DBG_ASSERT( *ppecb );
DBG_ASSERT( *ppWamExecInfo );
if ( !*ppecb || (*ppecb)->cbSize != sizeof(EXTENSION_CONTROL_BLOCK) ) {
DBGPRINTF(( DBG_CONTEXT,
"[GetISAContext]: Invalid ECB\r\n"));
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if ( !( (*ppWamExecInfo)->IsValid() ) ) {
DBGPRINTF(( DBG_CONTEXT,
"[GetISAContext]: Invalid WAM_EXEC_INFO.\r\n"));
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
//
// Get iwamreq
//
if ( FAILED( (*ppWamExecInfo)->GetIWamRequest( ppIWamRequest ) ) ) {
DBGPRINTF(( DBG_CONTEXT,
"[GetISAContext]: GetIWamRequest failed.\r\n"));
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
//
// Addref wamexec-info
//
(*ppWamExecInfo)->AddRef();
DBG_ASSERT( *ppIWamRequest );
return TRUE;
} // GetISAContext
/*-----------------------------------------------------------------------------*
ReleaseISAContext
Releases the ISA context.
NOTE caller must balance calls to GetISAContext and ReleaseISAContext
Arguments:
See below
Returns:
Nothing
*/
VOID
ReleaseISAContext(
OUT EXTENSION_CONTROL_BLOCK ** ppecb,
OUT WAM_EXEC_INFO ** ppWamExecInfo,
OUT IWamRequest ** ppIWamRequest
)
{
IF_DEBUG( MISC ) {
DBGPRINTF((
DBG_CONTEXT
, "ReleaseISAContext(%08x)\n"
, *ppecb
));
}
DBG_ASSERT( *ppecb );
DBG_ASSERT( *ppWamExecInfo );
DBG_ASSERT( *ppIWamRequest );
//
// Release iwamreq - balances Get in GetISAContext
//
(*ppWamExecInfo)->ReleaseIWamRequest( *ppIWamRequest );
//
// Release wamexec-info - balances Addref in GetISAContext
//
(*ppWamExecInfo)->Release();
*ppIWamRequest = NULL;
*ppWamExecInfo = NULL;
*ppecb = NULL;
return;
} // ReleaseISAContext
/************************************************************
* ISAPI Callback Functions
************************************************************/
/*-----------------------------------------------------------------------------*
ServerSupportFunction
Routine Description:
This method handles a gateway request to a server extension DLL
Arguments:
hConn - Connection context (pointer to WAM_EXEC_INFO)
dwHSERequest - Request type
lpvBuffer - Buffer for request
lpdwSize -
lpdwDataType
Return Value:
TRUE on success, FALSE on failure
*/
BOOL
WINAPI
ServerSupportFunction(
HCONN hConn,
DWORD dwHSERequest,
LPVOID lpvBuffer,
LPDWORD lpdwSize,
LPDWORD lpdwDataType
)
{
BOOL fReturn = FALSE; // this function's return value
BOOL fNotSupportedOOP = FALSE; // is the hse request supported OOP?
EXTENSION_CONTROL_BLOCK * pecb = NULL;
WAM_EXEC_INFO * pWamExecInfo = NULL;
IWamRequest * pIWamRequest = NULL;
HANDLE hCurrentUser = NULL;
IF_DEBUG( WAM_ISA_CALLS ) {
DBGPRINTF(( DBG_CONTEXT,
"ServerSupportFunction:\n\t"
"hConn = (%p)\t"
"dwHSERequest = (%p)\t"
"lpvBuffer = (%p)\t"
"lpdwSize = (%p)\t"
"lpdwDataType = (%p)\t"
"\n"
,
hConn,
dwHSERequest,
lpvBuffer,
lpdwSize,
lpdwDataType
));
}
//
// Get ISA context from connection handle - bail if bogus
// - if this succeeds, we have usable WAM_EXEC_INFO and IWamRequest ptrs
// - if this fails, GetISAContext calls SetLastError so we don't need to
//
if( !GetISAContext( hConn,
&pecb,
&pWamExecInfo,
&pIWamRequest ) ) {
return FALSE;
}
if ( !pWamExecInfo->QueryPWam()->FInProcess() )
{
hCurrentUser = INVALID_HANDLE_VALUE;
}
//
// Fast path send response headers - will be called on almost every
// request
//
//
// New send-header api. Fixes send-header/keep-alive bug.
// Also recommended for best performance.
//
if ( dwHSERequest == HSE_REQ_SEND_RESPONSE_HEADER_EX ) {
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
goto LExit;
}
if ( pWamExecInfo->NoHeaders() ) {
fReturn = TRUE;
goto LExit;
}
HSE_SEND_HEADER_EX_INFO * pSendHeaderExInfo =
reinterpret_cast<HSE_SEND_HEADER_EX_INFO *>( lpvBuffer );
//
// null strings are permitted
// (preserves semantics of old send-header api)
//
DWORD cchStatus = (
pSendHeaderExInfo->cchStatus
? pSendHeaderExInfo->cchStatus + 1
: pSendHeaderExInfo->pszStatus
? lstrlen( pSendHeaderExInfo->pszStatus ) + 1
: 0
);
DWORD cchHeader = (
pSendHeaderExInfo->cchHeader
? pSendHeaderExInfo->cchHeader + 1
: pSendHeaderExInfo->pszHeader
? lstrlen( pSendHeaderExInfo->pszHeader ) + 1
: 0
);
//
// set keep-conn state explicitly based on caller's boolean
// (since boolean itself is explicit)
//
if ( pSendHeaderExInfo->fKeepConn == FALSE ) {
pWamExecInfo->_dwIsaKeepConn = KEEPCONN_FALSE;
} else {
pWamExecInfo->_dwIsaKeepConn = KEEPCONN_TRUE;
}
DoRevertHack( &hCurrentUser );
fReturn =
BoolFromHresult( pIWamRequest->SendHeader(
(unsigned char *) pSendHeaderExInfo->pszStatus
, cchStatus
, (unsigned char *) pSendHeaderExInfo->pszHeader
, cchHeader
, pWamExecInfo->_dwIsaKeepConn
));
UndoRevertHack( &hCurrentUser );
goto LExit;
}
//
// Old send-header api, exists purely for back-compatibility
//
// Not recommended because ISA has no way to communicate
// its keep-conn strategy to us before we send headers.
// We infer it from header string, which is slow.
//
if ( dwHSERequest == HSE_REQ_SEND_RESPONSE_HEADER ) {
if ( pWamExecInfo->NoHeaders() ) {
fReturn = TRUE;
goto LExit;
}
//
// lpvBuffer points to status string
// status string is optional (null is permitted)
//
DWORD cchStatus = (
lpvBuffer
? lstrlen( (char *) lpvBuffer ) + 1
: 0
);
//
// lpdwDataType points to header string
// header string is optional (null is permitted)
//
DWORD cchHeader = (
lpdwDataType
? lstrlen( (char *) lpdwDataType ) + 1
: 0
);
//
// if status or header string contains "Content-Length:",
// we assume ISA wants connection kept alive.
//
// NOTE we don't set keep-conn state false in opposite case,
// since old caller may not intend to close connection.
//
//
if ( (lpvBuffer && stristr((const char *)lpvBuffer, "Content-Length:"))
||
(lpdwDataType
&& stristr((const char *)lpdwDataType, "Content-Length:"))
) {
pWamExecInfo->_dwIsaKeepConn = KEEPCONN_TRUE;
} else {
pWamExecInfo->_dwIsaKeepConn = KEEPCONN_FALSE;
}
IF_DEBUG( WAM_ISA_CALLS ) {
DBGPRINTF(( DBG_CONTEXT,
"SSF SendHeader: "
"Status = %s "
"Header = %s "
"Keep-conn = %d "
"\n"
, (unsigned char *) lpvBuffer
, (unsigned char *) lpdwDataType
, pWamExecInfo->_dwIsaKeepConn
));
}
DoRevertHack( &hCurrentUser );
fReturn =
BoolFromHresult( pIWamRequest->SendHeader(
(unsigned char *) lpvBuffer
, cchStatus
, (unsigned char *) lpdwDataType
, cchHeader
, pWamExecInfo->_dwIsaKeepConn
));
UndoRevertHack( &hCurrentUser );
goto LExit;
}
//
// Handle the server extension's request
//
switch ( dwHSERequest ) {
//
// IO Completion routine is provided.
//
case HSE_REQ_IO_COMPLETION:
//
// We don't check the pointer because we dont' want to mask
// application coding errors
//
if ( lpvBuffer != NULL) {
//
// Set the callback function and its ecb ptr argument
// NOTE setting the ptr seems a bit cheesy, but is probably the quickest way
// to make new out-of-proc wam suport our old code path
//
pWamExecInfo->_AsyncIoInfo._pfnHseIO = (PFN_HSE_IO_COMPLETION ) lpvBuffer;
}
pWamExecInfo->_AsyncIoInfo._pvHseIOContext = (PVOID ) lpdwDataType;
fReturn = TRUE;
break;
case HSE_REQ_TRANSMIT_FILE:
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
// NOTE lpvBuffer == pHseTfInfo
fReturn = pWamExecInfo->TransmitFile((LPHSE_TF_INFO ) lpvBuffer);
break;
case HSE_REQ_ASYNC_READ_CLIENT: {
DWORD dwFlags;
if ( lpvBuffer == NULL || lpdwSize == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
dwFlags = lpdwDataType ? *lpdwDataType : HSE_IO_ASYNC;
fReturn = pWamExecInfo->AsyncReadClient( lpvBuffer,
lpdwSize,
dwFlags );
break;
}
case HSE_REQ_SEND_URL_REDIRECT_RESP: {
//
// Descrption:
// Send an URL redirect message to the browser client
//
// Input:
// lpvBuffer - pointer to buffer that contains the location to
// redirect the client to.
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - Unused
//
// Return:
// None
//
// Notes:
// Works In-Process and Out-Of-Process
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
//
// bug 117107: don't change keep-conn setting
// on redirected responses.
//
// NOTE old behavior had been that we closed
// the connection by default
//
pWamExecInfo->_dwIsaKeepConn = KEEPCONN_DONT_CHANGE;
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult(
pIWamRequest->SendURLRedirectResponse(
(unsigned char *) lpvBuffer
) );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_SEND_URL_REDIRECT_RESP:
//
// HSE_REQ_SEND_URL functionality is broken (especially if the URL
// to be sent is another ISA. In this case, we are overwriting state of
// the parent ISA by the child )
//
// For now, just treat HSE_REQ_SEND_URL as a redirect. If enough people
// complain, then a new HTTP_REQUEST object must be created in order to
// handle the new request.
//
case HSE_REQ_SEND_URL: {
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
//
// bug 117107: don't change keep-conn setting
// on redirected responses.
//
// NOTE old behavior had been that we closed
// the connection by default
//
pWamExecInfo->_dwIsaKeepConn = KEEPCONN_DONT_CHANGE;
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->SendRedirectMessage( (unsigned char *) lpvBuffer ) );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_SEND_URL:
//
// This is an async callback from the extension dll indicating
// they are done with the socket
//
case HSE_REQ_DONE_WITH_SESSION: {
DBG_WAMREQ_REFCOUNTS(( "ServerSupportFunction DONE_WITH_SESSION",
pWamExecInfo));
// DBG_ASSERT( pWamExecInfo->_AsyncIoInfo._dwOutstandingIO == FALSE);
//
// A multi-threaded extension may indicate they
// are done before returning pending.
// Thus, we always return success.
//
fReturn = TRUE;
//
// Remember if the ISA wanted to keep the session open
//
if ( lpvBuffer &&
*((DWORD *) lpvBuffer) == HSE_STATUS_SUCCESS_AND_KEEP_CONN ) {
pWamExecInfo->_dwIsaKeepConn = KEEPCONN_TRUE;
}
//
// FDisconnected is only true for ASP when it is sending a buffered
// oop response. That call has already been made when we
// get here and the flag is either set (cleanup has already
// happened) or not (cleanup needs to happen here)
//
if( !pWamExecInfo->FDisconnected() )
{
//
// Figure out whether mainline thread or this callback thread
// hit its cleanup code first.
//
// This protects somewhat against isapis that disobey the async
// rules. The isapi should be in one of two modes:
//
// 1. It return HSE_STATUS_PENDING in the mainline thread and
// always calls HSE_DONE_WITH_SESSION.
//
// 2. It returns any other status code from the mainline and
// NEVER calls HSE_DONE_WITH_SESSION.
//
// Unfortunately isapi writers frequently do bad things to good
// servers. This code will prevent an AV (accessing a deleted
// ecb when the isapi calls HSE_DONE_WITH_SESSION from the
// the mainline thread. If the call occurs on another thread
// then all bets are off and only thread scheduling can save
// us.
//
// This protection was disabled for a while, but some internal
// ISAPI writers were having problems.
//
// NOTE return value is initial value of the destination
//
LONG FirstThread = INTERLOCKED_COMPARE_EXCHANGE(
(LONG *) &pWamExecInfo->_FirstThread
, (LONG) FT_CALLBACK
, (LONG) FT_NULL
);
if( FirstThread == (LONG) FT_NULL )
{
// Do nothing. Save the final release for the
// mainline thread.
;
}
else
{
//
// Mainline thread executed first, so this callback thread
// now must cleanup the wamreq and release wamexecinfo.
//
DoRevertHack( &hCurrentUser );
pIWamRequest->CleanupWamRequest(
(unsigned char*) pecb->lpszLogData
, lstrlen( pecb->lpszLogData ) + 1
, pecb->dwHttpStatusCode
, pWamExecInfo->_dwIsaKeepConn
);
UndoRevertHack( &hCurrentUser );
pWamExecInfo->Release( );
}
}
else
{
// we do need to release even if asp is disconnected
pWamExecInfo->Release( );
}
break;
} // case HSE_REQ_DONE_WITH_SESSION:
case HSE_REQ_EXECUTE_CHILD: {
//
// Descrption:
// SSI Execute functions
//
// Input:
// lpvBuffer - pointer to the URL (or Command string)
// to be executed.
// lpdwSize - NULL or points to verb to do request under
// lpdwDataType - Points to DWORD containing flags
//
// Flags (OR'd) and their meanings:
//
// HSE_EXEC_NO_HEADERS - When set, suppresses sending of the
// child request's headers. Needed to
// be set if the parent request sends
// its own headers.
//
// HSE_EXEC_COMMAND - When set, lpvBuffer contains command
// string to execute, as opposed to URL.
// SSINC uses it for <!--#EXEC CMD=...
//
// HSE_EXEC_NO_ISA_WILDCARDS
// - When set, disables wildcard ISAPI
// file extension mapping during the
// child execution. DAVFS sets this flag
// to avoid recursions.
//
// HSE_EXEC_CUSTOM_ERROR
// - Set to indicate that this is a custom
// error URL. DAV code uses this junk.
//
// Return:
// TRUE = SUCCESS
//
// Notes:
// Works In-Process and Out-Of-Process
//
if ( lpvBuffer == NULL || lpdwDataType == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DWORD dwExecFlags = *lpdwDataType;
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->SSIncExec(
(unsigned char *)lpvBuffer,
dwExecFlags,
lpdwSize ?
(unsigned char *)lpdwSize : NULL ) );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_EXECUTE_CHILD
//
// These are Microsoft specific extensions
//
case HSE_REQ_MAP_URL_TO_PATH: {
//
// Descrption:
// Simple api for looking up path-translated for a vroot
//
// Input:
// lpvBuffer - ptr to buffer which contains URL
// (will contain path-translated on return)
// lpdwDataType - ignored
// lpdwSize - ptr to buffer size
//
// Return:
// lpvBuffer - contains path-translated on return
// lpdwDataType - ignored, unchanged
// lpdwSize - unchanged
//
DWORD cchRequired = 0;
if ( lpvBuffer == NULL || lpdwSize == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->LookupVirtualRoot(
(unsigned char *) lpvBuffer,
(*lpdwSize),
&cchRequired ) );
UndoRevertHack( &hCurrentUser );
*lpdwSize = cchRequired;
break;
} // case HSE_REQ_MAP_URL_TO_PATH:
case HSE_REQ_MAP_URL_TO_PATH_EX: {
//
// Descrption:
// Extended api for looking up path-translated for a vroot
//
// Input:
// lpvBuffer - ptr to buffer which contains URL
// lpdwDataType - ptr to HSE_URL_MAPEX_INFO struct (see iisext.x)
// lpdwSize - (optional) ptr to buffer size
//
// Return:
// lpvBuffer - unchanged
// lpdwDataType - ptr to HSE_URL_MAPEX_INFO struct, which now has
// its parameters filled in
// lpdwSize - if supplied, ptr to size of returned buffer
// within HSE_URL_MAPEX_INFO struct
//
DWORD cchRequired = 0;
HSE_URL_MAPEX_INFO * purlmap = (HSE_URL_MAPEX_INFO *) lpdwDataType;
if ( lpvBuffer == NULL || lpdwDataType == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->LookupVirtualRootEx(
(unsigned char *) lpvBuffer, // [in] szURL
(unsigned char *)purlmap->lpszPath, // [out] pchBuffer
sizeof( purlmap->lpszPath ),
&cchRequired,
&purlmap->cchMatchingPath,
&purlmap->cchMatchingURL,
&purlmap->dwFlags ) );
UndoRevertHack( &hCurrentUser );
if ( lpdwSize != NULL )
{
*lpdwSize = cchRequired;
}
if ( fReturn )
{
//
// Bug38264 - Don't reflect a trailing backslash
// in the URL in the cchMatchingURL value. This
// check must be done against the original URL in
// lpvBuffer because the string doesn't exist in
// any of the HSE_URL_MAPEX_INFO members.
//
DWORD cchOriginalURL = lstrlen( (LPSTR)lpvBuffer );
if ( cchOriginalURL < purlmap->cchMatchingURL )
{
purlmap->cchMatchingURL = cchOriginalURL;
}
purlmap->dwFlags &= HSE_URL_FLAGS_MASK;
purlmap->dwReserved1 = 0;
purlmap->dwReserved2 = 0;
}
break;
} // case HSE_REQ_MAP_URL_TO_PATH_EX:
case HSE_REQ_ABORTIVE_CLOSE: {
//
// Descrption:
// request an abortive close on disconnect for this connection
//
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->RequestAbortiveClose() );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_ABORTIVE_CLOSE
case HSE_REQ_CLOSE_CONNECTION: {
//
// Descrption:
// close the connection socket
//
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->CloseConnection() );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_CLOSE_CONNECTION
case HSE_REQ_GET_CERT_INFO: {
//
// this call is obsolete - use HSE_REQ_GET_CERT_INFO_EX instead
//
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
fReturn = FALSE;
break;
} // case HSE_REQ_GET_CERT_INFO:
case HSE_REQ_GET_CERT_INFO_EX: {
//
// Descrption:
// Returns the first cert in the request's cert-chain,
// only used if using an SSPI package
//
// Input:
// lpvBuffer - ISA-provided struct
// NOTE ISA must allocate buffer within struct
//
// Notes:
// Works in-proc or out-of-proc
//
//
// cast ISA-provided ptr to our cert struct
//
CERT_CONTEXT_EX * pCertContextEx = reinterpret_cast
<CERT_CONTEXT_EX *>
( lpvBuffer );
if ( lpvBuffer == NULL ) {
DBG_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
//
// pass struct members as individual parameters
//
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->GetClientCertInfoEx(
pCertContextEx->cbAllocated,
&( pCertContextEx->CertContext.dwCertEncodingType ),
pCertContextEx->CertContext.pbCertEncoded,
&( pCertContextEx->CertContext.cbCertEncoded ),
&( pCertContextEx->dwCertificateFlags ) ) );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_GET_CERT_INFO_EX:
case HSE_REQ_GET_SSPI_INFO: {
//
// Descrption:
// Retrieves the SSPI context and credential handles, only used if
// using an SSPI package
//
// Input:
// lpvBuffer - pointer to buffer that will contain the CtxtHandle
// on return
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - pointer to buffer that will contain the
// CredHandle on return
//
// Return:
// CtxtHandle - in *lpvBuffer
// CredHandle - in *lpdwDataType
//
// Notes:
// Works In-Process
// Fails out-of-process, by design
// (security 'handles' won't duplicate cross-process)
//
//
// NOTE: ISA must ensure that lpvBuffer & lpdwDataType point to buffers
// of appropriate sizes sizeof(CtxtHandle) & sizeof(CredHandle)
//
if( !pWamExecInfo->QueryPWam()->FInProcess() ) {
fNotSupportedOOP = TRUE;
break;
}
if ( lpvBuffer == NULL || lpdwDataType == NULL ) {
DBG_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult(
pIWamRequest->GetSspiInfo(
8 /* UNDONE sizeof( CtxtHandle) */
, (PBYTE ) lpvBuffer
, 8 /* UNDONE sizeof( CredHandle) */
, (PBYTE ) lpdwDataType
));
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_GET_SSPI_INFO:
case HSE_APPEND_LOG_PARAMETER: {
//
// Descrption:
// Appends a certain string to the log record written out.
//
// Input:
// lpvBuffer - string containing the log data to be appended
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - pointer to Data type value (Unused)
//
// Return:
// None
//
// Notes:
// Works Out-Of-Process & In-Process
// Good candidate for being marshalled into calling process.
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->AppendLogParameter( (unsigned char *) lpvBuffer ) );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_APPEND_LOG_PARAMETER:
case HSE_REQ_REFRESH_ISAPI_ACL: {
//
// Descrption:
// Refreshes the ACLs for the ISAPI dll specified
// It forces the server to re-read the ACL for the ISAPI dll
//
// Input:
// lpvBuffer - string containing the name of the ISAPI dll
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - pointer to Data type value (Unused)
//
// Return:
// None
//
// Notes:
// This is local to the WAM process
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
fReturn = (g_psextensions->RefreshAcl( (LPSTR) lpvBuffer ));
break;
} // case HSE_REQ_REFRESH_ISAPI_ACL:
case HSE_REQ_IS_KEEP_CONN: {
//
// Descrption:
// Obtains the state if this connection is keep-alive or not.
//
// Input:
// lpvBuffer - pointer to BOOL which will contain the state on return
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - pointer to Data type value (Unused)
//
// Return:
// *lpvBuffer contains the value (TRUE=>keep-alive, FALSE=>non-KA)
//
// Notes:
// Works Out-Of-Process & In-Process
// Good candidate for being marshalled into calling process.
//
// We need this function here in ServerSupportFunction
// (vs. fetching the BOOL up front) because a script, for example,
// could change the state of keep-conn then later query it.
//
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DBG_ASSERT( NULL != lpvBuffer );
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->IsKeepConnSet( (LPBOOL)lpvBuffer ) );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_REQ_IS_KEEP_CONN:
case HSE_REQ_GET_IMPERSONATION_TOKEN: {
//
// Descrption:
// Obtains the impersonation token for the current user
//
// Input:
// lpvBuffer - pointer to HANDLE that will contain the impersonation
// token on return
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - pointer to Data type value (Unused)
//
// Return:
// *lpvBuffer contains the value
//
if ( lpvBuffer == NULL ) {
DBG_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
*((HANDLE *)lpvBuffer) = WRC_GET_FIX.m_hUserToken;
fReturn = TRUE;
break;
} // case HSE_REQ_GET_IMPERSONATION_TOKEN:
case HSE_REQ_GET_VIRTUAL_PATH_TOKEN:
//
// Descrption:
// Obtains the impersonation token for the specified virtual path
//
// Input:
// lpvBuffer - points to virtual path for which UNC impersonation
// token is sought
// lpdwSize - points to a HANDLE which will be set on return
// lpdwDataType - pointer to Data type value (Unused)
//
// Return:
// *lpdwSize contains the token
//
if( lpvBuffer == NULL || lpdwSize == NULL ) {
DBG_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
}
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->GetVirtualPathToken(
(unsigned char *) lpvBuffer,
#ifdef _WIN64
(UINT64 *)lpdwSize ) );
#else
(ULONG_PTR *)lpdwSize ) );
#endif
UndoRevertHack( &hCurrentUser );
break;
case HSE_REQ_IS_CONNECTED:
//
// Description:
// Attempts to determine if the if the client is still connected.
// Works by doing a "peek" on the socket.
//
// Input:
// lpvBuffer - pointer to BOOL which will contain the state on return
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - pointer to Data type value (Unused)
//
// Return:
// *lpvBuffer contains the value
// TRUE connected
// FALSE socket closed or unreadable
//
if ( lpvBuffer == NULL ) {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DBG_ASSERT( NULL != lpvBuffer );
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->TestConnection( (LPBOOL)lpvBuffer ) );
UndoRevertHack( &hCurrentUser );
break;
case HSE_REQ_GET_EXECUTE_FLAGS:
//
// Descrption:
// Gets the execute descriptor flags used for this request
//
// Input:
// None
//
// Return:
// *lpdwDataType contains the flags
//
if ( lpdwDataType == NULL )
{
DBG_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
*lpdwDataType = pWamExecInfo->_dwChildExecFlags;
fReturn = TRUE;
break;
case HSE_REQ_EXTENSION_TRIGGER:
//
// Description:
// Notify any filters waiting on SF_NOTIFY_EXTENSION_TRIGGER
//
// Input:
// lpvBuffer - Context pointer
// lpdwDataType - Points to trigger type
//
//
// Only works in-proc.
//
if ( !lpdwDataType )
{
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
if ( !pWamExecInfo->QueryPWam()->FInProcess() )
{
SetLastError( ERROR_NOT_SUPPORTED );
fReturn = FALSE;
break;
}
fReturn = BoolFromHresult( pIWamRequest->ExtensionTrigger(
(unsigned char*) lpvBuffer,
*lpdwDataType ) );
break;
//
// These are private services
//
//
// Descrption:
// Following is a list of options that only work in-process
// and are mostly backdoor hand-off of pointers to ill-behaved
// applications! A big hack!
//
// Input:
// lpvBuffer - pointer to location that will contain the returned value
// lpdwSize - pointer to DWORD containing size (UnUsed)
// lpdwDataType - pointer to Data type value (Unused)
//
// Return:
// *lpvBuffer contains the value
//
// Notes:
// Works In-Process
// Fails gracefully Out-Of-Process
case HSE_PRIV_REQ_TSVCINFO:
case HSE_PRIV_REQ_HTTP_REQUEST:
case HSE_PRIV_REQ_VROOT_TABLE:
case HSE_PRIV_REQ_TSVC_CACHE: {
if( !pWamExecInfo->QueryPWam()->FInProcess() ) {
fNotSupportedOOP = TRUE;
break;
}
if ( lpvBuffer == NULL ) {
DBG_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
}
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->GetPrivatePtr( dwHSERequest, (unsigned char **) &lpvBuffer ) );
UndoRevertHack( &hCurrentUser );
break;
} // case HSE_PRIV_REQ_TSVCINFO: et al
default: {
SetLastError( ERROR_INVALID_PARAMETER );
fReturn = FALSE;
break;
} // case default:
} // switch ( dwHSERequest )
if (fNotSupportedOOP) {
SetLastError( ERROR_INVALID_FUNCTION );
fReturn = FALSE;
}
LExit:
//
// Release isa context
// Balances GetISAContext at top of this function
//
ReleaseISAContext(
&pecb
, &pWamExecInfo
, &pIWamRequest
);
return ( fReturn );
} // ServerSupportFunction()
BOOL
WINAPI
GetServerVariable(
HCONN hConn,
LPSTR szVarName,
LPVOID lpvBuffer,
LPDWORD lpdwSize
)
{
BOOL fReturn = FALSE;
EXTENSION_CONTROL_BLOCK * pecb = NULL;
WAM_EXEC_INFO * pWamExecInfo = NULL;
IWamRequest * pIWamRequest = NULL;
IF_DEBUG( WAM_ISA_CALLS ) {
DBGPRINTF(( DBG_CONTEXT,
"GetServerVariable:\n\t"
"hConn = (%08x)\t"
"szVarName = %s\t"
"lpvBuffer = (%08x)\t"
"*lpdwSize = %d\t"
"\n"
,
hConn,
szVarName,
lpvBuffer,
lpdwSize ? *lpdwSize : -1
));
}
//
// Validate ISA-supplied input parameters
//
if ( szVarName == NULL || lpdwSize == NULL ) {
DBG_ASSERT( FALSE );
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
//
// Get ISA context from connection handle - bail if bogus
// - if this succeeds, we have usable WAM_EXEC_INFO and IWamRequest ptrs
// - if this fails, GetISAContext calls SetLastError so we don't need to
//
if( !GetISAContext( hConn,
&pecb,
&pWamExecInfo,
&pIWamRequest ) ) {
return FALSE;
}
fReturn = BoolFromHresult( pWamExecInfo->GetInfoForName(
pIWamRequest,
(unsigned char *) szVarName,
(unsigned char *) lpvBuffer,
*lpdwSize,
lpdwSize ) );
//
// Release isa context
// Balances GetISAContext at top of this function
//
ReleaseISAContext(
&pecb
, &pWamExecInfo
, &pIWamRequest
);
return ( fReturn );
} // GetServerVariable()
/*-----------------------------------------------------------------------------*
WriteClient
Routine Description:
Writes to the http client on behalf of the ISA
Arguments:
hConn - Connection context (pointer to WAM_EXEC_INFO)
Buffer - pointer to the buffer containing the data to be sent to the client
lpdwBytes - pointer to DWORD that contains the size of data to be
sent out to client when this function is called.
On return, if this is a synchronous write, then this location
will contain the number of bytes actually sent out.
dwReserved - Reserved set of flags
For now,
HSE_IO_ASYNC - indicates that Async Write should be done
HSE_IO_SYNC - (default) indicates that Sync. Write should be done.
Return Value:
TRUE on success, FALSE on failure
See GetLastError() for error code
Note:
Atmost one async IO operation is permitted at a given time.
Atmost one sync IO operation should be made. Multiple sync IO operations
may result in unpredictable result.
Enforcing one sync IO operation would make every single ISAPI to pay a
penalty for a very few insane ones. So we don't do it.
*/
BOOL
WINAPI
WriteClient(
HCONN hConn,
LPVOID Buffer,
LPDWORD lpdwBytes,
DWORD dwReserved
)
{
BOOL fReturn = FALSE;
EXTENSION_CONTROL_BLOCK * pecb = NULL;
WAM_EXEC_INFO * pWamExecInfo = NULL;
IWamRequest * pIWamRequest = NULL;
HANDLE hCurrentUser = NULL;
IF_DEBUG( WAM_ISA_CALLS ) {
DBGPRINTF(( DBG_CONTEXT,
"WriteClient:\n\t"
"hConn = (%08x)\t"
"Buffer = (%08x)\t"
"*lpdwBytes = %d\t"
"\n"
,
hConn,
Buffer,
lpdwBytes ? *lpdwBytes : -1
));
}
//
// Return failure when invalid Buffer is supplied
//
// NOTE we do this before validating ecb
//
if ( (NULL == Buffer) || (NULL == lpdwBytes) ) {
SetLastError( ERROR_INVALID_PARAMETER);
return ( FALSE);
}
//
// Ignore zero length sends
//
// NOTE we do this before validating ecb
// so we don't need to release iwamreq ptr
//
if ( *lpdwBytes == 0 ) {
return TRUE;
}
//
// Get ISA context from connection handle - bail if bogus
// - if this succeeds, we have usable WAM_EXEC_INFO and IWamRequest ptrs
// - if this fails, GetISAContext calls SetLastError so we don't need to
//
if( !GetISAContext( hConn,
&pecb,
&pWamExecInfo,
&pIWamRequest ) ) {
return FALSE;
}
if ( !pWamExecInfo->QueryPWam()->FInProcess() )
{
hCurrentUser = INVALID_HANDLE_VALUE;
}
//
// Branch based on Async IO or Synchronous IO operation
//
if ( (dwReserved & HSE_IO_ASYNC) ) {
//
// Check for error condition in the AsyncIO callback path
//
if ((pWamExecInfo->_AsyncIoInfo._pfnHseIO == NULL) ||
(pWamExecInfo->_AsyncIoInfo._dwOutstandingIO)
) {
DBGPRINTF(( DBG_CONTEXT,
"%08x::Async WriteClient() requested when IO in progress"
" or when Context not supplied.\n",
pWamExecInfo));
//
// Set error code and fall-through
// - so that we will properly release pWamExecInfo
// and WamRequest pointers
//
SetLastError( ERROR_INVALID_PARAMETER);
fReturn = (FALSE);
} else {
//
// 1. Set Request state to be async IO from ISAPI client
// 2. Submit Async IOP
// 3. Return to the ISAPI application
//
pWamExecInfo->InitAsyncIO( ASYNC_IO_TYPE_WRITE );
pWamExecInfo->_AsyncIoInfo._cbLastAsyncIO = *lpdwBytes;
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult(
pIWamRequest->AsyncWriteClient(
#ifdef _WIN64
(UINT64) pWamExecInfo,
#else
(ULONG_PTR) pWamExecInfo,
#endif
(unsigned char *) Buffer,
*lpdwBytes,
dwReserved
) );
UndoRevertHack( &hCurrentUser );
if ( !fReturn ) {
pWamExecInfo->UninitAsyncIO();
}
}
} else {
//
// Submit synchronous IO operation
//
DWORD cbToWrite = *lpdwBytes;
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->
SyncWriteClient( cbToWrite,
(unsigned char *) Buffer,
lpdwBytes,
dwReserved ) );
UndoRevertHack( &hCurrentUser );
}
//
// Release isa context
// Balances GetISAContext at top of this function
//
ReleaseISAContext(
&pecb
, &pWamExecInfo
, &pIWamRequest
);
return ( fReturn );
} // WriteClient()
BOOL
WINAPI
ReadClient(
HCONN hConn,
LPVOID Buffer,
LPDWORD lpdwBytes
)
{
BOOL fReturn = FALSE;
EXTENSION_CONTROL_BLOCK * pecb = NULL;
WAM_EXEC_INFO * pWamExecInfo = NULL;
IWamRequest * pIWamRequest = NULL;
HANDLE hCurrentUser = NULL;
IF_DEBUG( WAM_ISA_CALLS ) {
DBGPRINTF(( DBG_CONTEXT,
"ReadClient:\n\t"
"hConn = (%08x)\t"
"Buffer = (%08x)\t"
"*lpdwBytes = %d\t"
"\n"
,
hConn,
Buffer,
lpdwBytes ? *lpdwBytes : -1
));
}
//
// Return failure when invalid Buffer is supplied
//
// NOTE we do this before validating ecb
//
if ( (NULL == Buffer) || (NULL == lpdwBytes) ) {
SetLastError( ERROR_INVALID_PARAMETER);
return ( FALSE);
}
//
// Get ISA context from connection handle - bail if bogus
// - if this succeeds, we have usable WAM_EXEC_INFO and IWamRequest ptrs
// - if this fails, GetISAContext calls SetLastError so we don't need to
//
if( !GetISAContext( hConn,
&pecb,
&pWamExecInfo,
&pIWamRequest ) ) {
return FALSE;
}
if ( !pWamExecInfo->QueryPWam()->FInProcess() )
{
hCurrentUser = INVALID_HANDLE_VALUE;
}
DoRevertHack( &hCurrentUser );
fReturn = BoolFromHresult( pIWamRequest->SyncReadClient(
(unsigned char *) Buffer,
*lpdwBytes,
lpdwBytes) );
UndoRevertHack( &hCurrentUser );
//
// Release isa context
// Balances GetISAContext at top of this function
//
ReleaseISAContext(
&pecb
, &pWamExecInfo
, &pIWamRequest
);
return ( fReturn );
} // ReadClient()