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.
844 lines
25 KiB
844 lines
25 KiB
//-----------------------------------------------------------------------------
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// rpcisapi.cxx
|
|
//
|
|
// IIS ISAPI extension part of the RPC proxy over HTTP.
|
|
//
|
|
// Exports:
|
|
//
|
|
// BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer )
|
|
//
|
|
// Returns the version of the spec that this server was built with.
|
|
//
|
|
// BOOL WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB )
|
|
//
|
|
// This function does all of the work.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Includes:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <sysinc.h>
|
|
#include <winsock2.h>
|
|
#include <rpc.h>
|
|
#include <rpcdcep.h>
|
|
#include <rpcerrp.h>
|
|
#include <httpfilt.h>
|
|
#include <httpext.h>
|
|
#include <mbstring.h>
|
|
#include <ecblist.h>
|
|
#include <filter.h>
|
|
#include <olist.h>
|
|
#include <server.h>
|
|
#include <RpcIsapi.h>
|
|
#include <registry.h>
|
|
#include <StrSafe.h>
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Globals:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
extern SERVER_INFO *g_pServerInfo;
|
|
extern BOOL g_fIsIIS6;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetExtensionVersion()
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer )
|
|
{
|
|
HRESULT hr;
|
|
|
|
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR, HSE_VERSION_MAJOR );
|
|
|
|
ASSERT( sizeof(EXTENSION_DESCRIPTION) <= HSE_MAX_EXT_DLL_NAME_LEN );
|
|
|
|
hr = StringCchCopyNA (pVer->lpszExtensionDesc,
|
|
sizeof(pVer->lpszExtensionDesc),
|
|
EXTENSION_DESCRIPTION,
|
|
sizeof(EXTENSION_DESCRIPTION)
|
|
);
|
|
|
|
// this cannot fail as the strings are constant
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
// if the filter data structures are not initialized yet, initialize them
|
|
if (g_pServerInfo == NULL)
|
|
{
|
|
if (InitializeGlobalDataStructures(FALSE /* IsFromFilter */) == FALSE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
LogEventStartupSuccess (fIsIISInCompatibilityMode ? "5" : "6");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ReplyToClient()
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ReplyToClient( EXTENSION_CONTROL_BLOCK *pECB,
|
|
const char *pBuffer,
|
|
DWORD *pdwSize,
|
|
DWORD *pdwStatus )
|
|
{
|
|
DWORD dwFlags = (HSE_IO_SYNC | HSE_IO_NODELAY);
|
|
|
|
if (!pECB->WriteClient(pECB->ConnID, (char *)pBuffer, pdwSize, dwFlags))
|
|
{
|
|
*pdwStatus = GetLastError();
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("ReplyToClient(): failed: %d\n",*pdwStatus);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
*pdwStatus = HSE_STATUS_SUCCESS;
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
ReplyToClientWithStatus (
|
|
IN EXTENSION_CONTROL_BLOCK *pECB,
|
|
IN RPC_STATUS RpcStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends a reply to the client with the given error code as error.
|
|
|
|
Arguments:
|
|
|
|
pECB - extension control block
|
|
RpcStatus - error code to be returned to client
|
|
|
|
Return Value:
|
|
|
|
Return value appropriate for return to IIS (i.e. HSE_STATUS_*)
|
|
|
|
--*/
|
|
{
|
|
// size is the error string + 20 space for the error code
|
|
char Buffer[sizeof(ServerErrorString) + 20];
|
|
ULONG Size;
|
|
ULONG Status;
|
|
BOOL Result;
|
|
HRESULT hr;
|
|
|
|
hr = StringCbPrintfA (Buffer,
|
|
sizeof(Buffer),
|
|
ServerErrorString,
|
|
RpcStatus
|
|
);
|
|
|
|
// this should never fail as the strings are constant
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
Size = strlen(Buffer);
|
|
Result = ReplyToClient (
|
|
pECB,
|
|
Buffer,
|
|
&Size,
|
|
&Status
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ParseQueryString()
|
|
//
|
|
// The query string is in the format:
|
|
//
|
|
// <Index_of_pOverlapped>
|
|
//
|
|
// Where the index is in ASCII Hex. The index is read and converted back
|
|
// to a DWORD then used to locate the SERVER_OVERLAPPED. If its found,
|
|
// return TRUE, else return FALSE.
|
|
//
|
|
// NOTE: "&" is the parameter separator if multiple parameters are passed.
|
|
//-----------------------------------------------------------------------------
|
|
BOOL ParseQueryString( unsigned char *pszQuery,
|
|
SERVER_OVERLAPPED **ppOverlapped,
|
|
DWORD *pdwStatus )
|
|
{
|
|
DWORD dwIndex = 0;
|
|
|
|
pszQuery = AnsiHexToDWORD(pszQuery,&dwIndex,pdwStatus);
|
|
if (!pszQuery)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*ppOverlapped = GetOverlapped(dwIndex);
|
|
if (*ppOverlapped == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
ParseHTTP2QueryString (
|
|
IN char *Query,
|
|
IN OUT USHORT *ServerAddressBuffer,
|
|
IN ULONG ServerAddressBufferLength,
|
|
IN OUT USHORT *ServerPortBuffer,
|
|
IN ULONG ServerPortBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses an HTTP2 format query string into a server address and
|
|
server port.
|
|
|
|
Arguments:
|
|
|
|
Query - the raw query string as received by the extension
|
|
ServerAddressBuffer - the buffer where the server address will be
|
|
stored. Undefined upon failure. Upon success it will be 0 terminated.
|
|
ServerAddressBufferLengh - the length of ServerAddressBuffer in unicode chars.
|
|
ServerPortBuffer - the buffer where the server port will be
|
|
stored. Undefined upon failure. Upon success it will be 0 terminated.
|
|
ServerPortBufferLengh - the length of ServerAddressBuffer in unicode chars.
|
|
|
|
Return Value:
|
|
|
|
non-zero for success and 0 for failure.
|
|
|
|
--*/
|
|
{
|
|
char *ColonPosition;
|
|
int CharactersConverted;
|
|
|
|
ColonPosition = _mbschr(Query, ServerAddressAndPortSeparator);
|
|
|
|
if (ColonPosition == NULL)
|
|
return FALSE;
|
|
|
|
CharactersConverted = MultiByteToWideChar (
|
|
CP_ACP,
|
|
MB_ERR_INVALID_CHARS,
|
|
Query,
|
|
ColonPosition - Query,
|
|
ServerAddressBuffer,
|
|
ServerAddressBufferLength
|
|
);
|
|
|
|
// did we convert successfully?
|
|
if (CharactersConverted == 0)
|
|
return FALSE;
|
|
|
|
// do we have space for the terminating null?
|
|
if (CharactersConverted + 1 > ServerAddressBufferLength)
|
|
return FALSE;
|
|
|
|
// null terminate the server address string. Since we gave the length
|
|
// explicitly to MultiByteToWideChar it will not add null for us
|
|
ServerAddressBuffer[CharactersConverted] = 0;
|
|
|
|
CharactersConverted = MultiByteToWideChar (
|
|
CP_ACP,
|
|
MB_ERR_INVALID_CHARS,
|
|
ColonPosition + 1,
|
|
-1, // have MultiByteToWideChar calculate the length
|
|
ServerPortBuffer,
|
|
ServerPortBufferLength
|
|
);
|
|
|
|
// did we convert successfully?
|
|
if (CharactersConverted == 0)
|
|
return FALSE;
|
|
|
|
// since we had MultiByteToWideChar calculate the string length,
|
|
// it has null terminated the resulting string. We're all done.
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GetRemoteUserString (
|
|
IN EXTENSION_CONTROL_BLOCK *pECB,
|
|
OUT char **FinalRemoteUser
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the remote user name from IIS. If anonymous, an empty
|
|
string will be returned.
|
|
|
|
Arguments:
|
|
|
|
pECB - the extension control block given to us by IIS.
|
|
FinalRemoteUser - on output a pointer to the remote user name allocated by this
|
|
routine. Muts be freed by caller using MemFree. Undefined on failure.
|
|
|
|
Return Value:
|
|
|
|
non-zero for success or 0 for failure/
|
|
|
|
--*/
|
|
{
|
|
ULONG ActualServerVariableLength;
|
|
char *TempRemoteUser;
|
|
BOOL Result;
|
|
|
|
ActualServerVariableLength = 0;
|
|
TempRemoteUser = NULL;
|
|
Result = pECB->GetServerVariable(pECB->ConnID,
|
|
"REMOTE_USER",
|
|
TempRemoteUser,
|
|
&ActualServerVariableLength
|
|
);
|
|
ASSERT(Result == FALSE);
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
TempRemoteUser = (char *)MemAllocate(ActualServerVariableLength + 1);
|
|
if (TempRemoteUser == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Result = pECB->GetServerVariable(pECB->ConnID,
|
|
"REMOTE_USER",
|
|
TempRemoteUser,
|
|
&ActualServerVariableLength
|
|
);
|
|
|
|
if (Result == FALSE)
|
|
{
|
|
MemFree(TempRemoteUser);
|
|
return FALSE;
|
|
}
|
|
|
|
*FinalRemoteUser = TempRemoteUser;
|
|
return TRUE;
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY I_RpcProxyIsValidMachine (
|
|
IN char *pszMachine,
|
|
IN char *pszDotMachine,
|
|
IN ULONG dwPortNumber
|
|
)
|
|
{
|
|
BOOL Result;
|
|
|
|
Result = HttpProxyIsValidMachine(g_pServerInfo,
|
|
pszMachine,
|
|
pszDotMachine,
|
|
dwPortNumber
|
|
);
|
|
|
|
if (Result)
|
|
return RPC_S_OK;
|
|
else
|
|
return RPC_S_ACCESS_DENIED;
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY I_RpcProxyGetClientAddress (
|
|
IN void *Context,
|
|
OUT char *Buffer,
|
|
OUT ULONG *BufferLength
|
|
)
|
|
{
|
|
BOOL Result;
|
|
EXTENSION_CONTROL_BLOCK *pECB = (EXTENSION_CONTROL_BLOCK *) Context;
|
|
|
|
Result = pECB->GetServerVariable(pECB->ConnID,
|
|
"REMOTE_ADDR",
|
|
Buffer,
|
|
BufferLength
|
|
);
|
|
|
|
if (Result)
|
|
return RPC_S_OK;
|
|
else
|
|
return GetLastError();
|
|
}
|
|
|
|
RPC_STATUS
|
|
RPC_ENTRY I_RpcProxyGetConnectionTimeout (
|
|
OUT ULONG *ConnectionTimeout
|
|
)
|
|
{
|
|
*ConnectionTimeout = IISConnectionTimeout;
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
const I_RpcProxyCallbackInterface ProxyCallbackInterface =
|
|
{
|
|
I_RpcProxyIsValidMachine,
|
|
I_RpcProxyGetClientAddress,
|
|
I_RpcProxyGetConnectionTimeout
|
|
};
|
|
|
|
|
|
// uncomment this to see why connections are being rejected
|
|
// by AllowAnonymous
|
|
// #define DEBUG_ALLOW_ANONYMOUS
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HttpExtensionProc()
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB )
|
|
{
|
|
DWORD dwStatus;
|
|
DWORD dwFlags;
|
|
DWORD dwSize;
|
|
SERVER_INFO *pServerInfo = g_pServerInfo;
|
|
SERVER_OVERLAPPED *pOverlapped = NULL;
|
|
HSE_SEND_HEADER_EX_INFO HeaderEx;
|
|
CHAR *pLegacyVerb;
|
|
RPC_STATUS RpcStatus;
|
|
ULONG VerbLength;
|
|
USHORT ServerAddress[MaxServerAddressLength];
|
|
USHORT ServerPort[MaxServerPortLength];
|
|
BOOL Result;
|
|
ULONG ProxyType;
|
|
BOOL ConnectionEstablishmentRequest;
|
|
char EchoResponse[sizeof(EchoResponseHeader2) + 2]; // 2 is for
|
|
// the size of the Echo RTS which goes instead of ContentLength
|
|
int BytesWritten;
|
|
ULONG BufferSize;
|
|
const BYTE *EchoRTS;
|
|
char ServerVariable[20];
|
|
ULONG ActualServerVariableLength;
|
|
ULONG NumContentLength;
|
|
BOOL AnonymousConnection;
|
|
char *RemoteUser = NULL;
|
|
RPC_CHAR *ActualServerName;
|
|
DWORD ExtensionProcResult;
|
|
DWORD HttpStatusCode;
|
|
char *DestinationEnd;
|
|
HRESULT hr;
|
|
|
|
if (g_pServerInfo->dwEnabled == FALSE)
|
|
{
|
|
dwSize = sizeof(STATUS_PROXY_DISABLED) - 1; // don't want to count trailing 0.
|
|
|
|
ReplyToClient(pECB,STATUS_PROXY_DISABLED, &dwSize, &dwStatus);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
if (g_pServerInfo->AllowAnonymous == FALSE)
|
|
{
|
|
// if we are not allowing anonymous connections, check that a secure
|
|
// channel and authentication are used
|
|
|
|
// assume anonymous for now
|
|
AnonymousConnection = TRUE;
|
|
|
|
ActualServerVariableLength = sizeof(ServerVariable);
|
|
|
|
Result = pECB->GetServerVariable(pECB->ConnID,
|
|
"HTTPS",
|
|
ServerVariable,
|
|
&ActualServerVariableLength
|
|
);
|
|
|
|
if (!Result)
|
|
{
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
if (RpcpStringCompareIntA(ServerVariable, "on") == 0)
|
|
{
|
|
Result = GetRemoteUserString (pECB,
|
|
&RemoteUser
|
|
);
|
|
if (!Result)
|
|
{
|
|
#ifdef DEBUG_ALLOW_ANONYMOUS
|
|
DbgPrint("Connection rejected getting the remote user failed\n");
|
|
#endif // #ifdef DEBUG_ALLOW_ANONYMOUS
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
// if non-empty string, it is authenticated
|
|
if (RemoteUser[0] != 0)
|
|
{
|
|
AnonymousConnection = FALSE;
|
|
#ifdef DEBUG_ALLOW_ANONYMOUS
|
|
DbgPrint("Connection rejected because user could not be retrieved\n");
|
|
#endif // #ifdef DEBUG_ALLOW_ANONYMOUS
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_ALLOW_ANONYMOUS
|
|
DbgPrint("Connection accepted for user %s\n", RemoteUser);
|
|
#endif // #ifdef DEBUG_ALLOW_ANONYMOUS
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_ALLOW_ANONYMOUS
|
|
DbgPrint("Connection rejected because it is not SSL\n");
|
|
#endif // #ifdef DEBUG_ALLOW_ANONYMOUS
|
|
}
|
|
|
|
// if empty string, it is not authenticated
|
|
if (AnonymousConnection)
|
|
{
|
|
dwSize = sizeof(AnonymousAccessNotAllowedString) - 1; // don't want to count trailing 0.
|
|
|
|
ReplyToClient(pECB, AnonymousAccessNotAllowedString, &dwSize, &dwStatus);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = dwStatus;
|
|
goto AbortAndExit;
|
|
}
|
|
}
|
|
|
|
pECB->dwHttpStatusCode = STATUS_CONNECTION_OK;
|
|
|
|
if (g_fIsIIS6)
|
|
{
|
|
pLegacyVerb = RPC_CONNECT;
|
|
}
|
|
else
|
|
{
|
|
pLegacyVerb = POST_STR;
|
|
}
|
|
|
|
VerbLength = strlen(pECB->lpszMethod);
|
|
ConnectionEstablishmentRequest = FALSE;
|
|
|
|
// get the verb and depending on that we will determine our course of
|
|
// action
|
|
if ((VerbLength == InChannelEstablishmentMethodLength)
|
|
&& (lstrcmpi(pECB->lpszMethod, InChannelEstablishmentMethod) == 0))
|
|
{
|
|
ConnectionEstablishmentRequest = TRUE;
|
|
ProxyType = RPC_PROXY_CONNECTION_TYPE_IN_PROXY;
|
|
}
|
|
else if ((VerbLength == OutChannelEstablishmentMethodLength)
|
|
&& (lstrcmpi(pECB->lpszMethod, OutChannelEstablishmentMethod) == 0))
|
|
{
|
|
ConnectionEstablishmentRequest = TRUE;
|
|
ProxyType = RPC_PROXY_CONNECTION_TYPE_OUT_PROXY;
|
|
}
|
|
|
|
if (ConnectionEstablishmentRequest)
|
|
{
|
|
// check if this is echo request or a true connection
|
|
// establishment
|
|
ActualServerVariableLength = sizeof(ServerVariable);
|
|
|
|
Result = pECB->GetServerVariable(pECB->ConnID,
|
|
"CONTENT_LENGTH",
|
|
ServerVariable,
|
|
&ActualServerVariableLength
|
|
);
|
|
|
|
if (!Result)
|
|
{
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
NumContentLength = atol(ServerVariable);
|
|
if (NumContentLength <= MaxEchoRequestSize)
|
|
{
|
|
// too small for a channel. Must be an echo
|
|
EchoRTS = GetEchoRTS(&BufferSize);
|
|
|
|
// Echo back the RTS packet + headers
|
|
hr = StringCbPrintfExA(EchoResponse,
|
|
sizeof(EchoResponse),
|
|
&DestinationEnd, // ppszDestEnd
|
|
NULL, // pcbRemaining
|
|
0, // Flags
|
|
EchoResponseHeader2,
|
|
BufferSize
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
// calculate the number of bytes written as the
|
|
// distance from the end of the written buffer to the
|
|
// beginning
|
|
BytesWritten = DestinationEnd - EchoResponse;
|
|
|
|
// send back headers
|
|
dwSize = sizeof(HeaderEx);
|
|
dwFlags = 0;
|
|
memset(&HeaderEx, 0, dwSize);
|
|
HeaderEx.fKeepConn = TRUE;
|
|
HeaderEx.pszStatus = EchoResponseHeader1;
|
|
HeaderEx.cchStatus = sizeof(EchoResponseHeader1);
|
|
HeaderEx.pszHeader = EchoResponse;
|
|
HeaderEx.cchHeader = BytesWritten;
|
|
Result = pECB->ServerSupportFunction(pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER_EX,
|
|
&HeaderEx,
|
|
&dwSize,
|
|
&dwFlags);
|
|
if (!Result)
|
|
{
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
// send back Echo RTS
|
|
dwSize = BufferSize;
|
|
dwFlags = 0;
|
|
Result = pECB->WriteClient(pECB->ConnID, (char *)EchoRTS, &dwSize, dwFlags);
|
|
if (!Result)
|
|
{
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
return HSE_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
// a channel
|
|
Result = ParseHTTP2QueryString (
|
|
pECB->lpszQueryString,
|
|
ServerAddress,
|
|
sizeof(ServerAddress) / sizeof(ServerAddress[0]),
|
|
ServerPort,
|
|
sizeof(ServerPort) / sizeof(ServerPort[0])
|
|
);
|
|
|
|
if (Result == FALSE)
|
|
{
|
|
dwSize = sizeof(CannotParseQueryString) - 1; // don't want to count trailing 0.
|
|
|
|
ReplyToClient(pECB, CannotParseQueryString, &dwSize, &dwStatus);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = dwStatus;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
if (g_pServerInfo->RpcNewHttpProxyChannel)
|
|
{
|
|
// get the remote user (if not available yet) and call
|
|
// the redirector dll
|
|
if (RemoteUser == NULL)
|
|
{
|
|
Result = GetRemoteUserString (pECB,
|
|
&RemoteUser
|
|
);
|
|
if (Result == FALSE)
|
|
{
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
}
|
|
|
|
ASSERT(g_pServerInfo->RpcHttpProxyFreeString);
|
|
|
|
RpcStatus = g_pServerInfo->RpcNewHttpProxyChannel (
|
|
ServerAddress,
|
|
ServerPort,
|
|
RemoteUser,
|
|
&ActualServerName
|
|
);
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
}
|
|
else
|
|
ActualServerName = ServerAddress;
|
|
|
|
RpcStatus = I_RpcProxyNewConnection (
|
|
ProxyType,
|
|
ActualServerName,
|
|
ServerPort,
|
|
pECB,
|
|
(I_RpcProxyCallbackInterface *)&ProxyCallbackInterface
|
|
);
|
|
|
|
if (g_pServerInfo->RpcNewHttpProxyChannel
|
|
&& (ActualServerName != ServerAddress))
|
|
{
|
|
// get the remote user and call the redirector dll
|
|
ASSERT(g_pServerInfo->RpcHttpProxyFreeString);
|
|
g_pServerInfo->RpcHttpProxyFreeString(ActualServerName);
|
|
}
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
ReplyToClientWithStatus(pECB, RpcStatus);
|
|
HttpStatusCode = STATUS_CONNECTION_OK;
|
|
ExtensionProcResult = HSE_STATUS_SUCCESS;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint("RPCPROXY: %d: Connection type %d to %S:%S\n", GetCurrentProcessId(),
|
|
ProxyType, ServerAddress, ServerPort);
|
|
#endif
|
|
HttpStatusCode = STATUS_CONNECTION_OK;
|
|
ExtensionProcResult = HSE_STATUS_PENDING;
|
|
goto AbortAndExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The RPC request must be a post (or RPC_CONNECT for 6.0):
|
|
//
|
|
if (_mbsicmp(pECB->lpszMethod,pLegacyVerb))
|
|
{
|
|
dwSize = sizeof(STATUS_MUST_BE_POST_STR) - 1; // don't want to count trailing 0.
|
|
|
|
ReplyToClient(pECB,STATUS_MUST_BE_POST_STR,&dwSize,&dwStatus);
|
|
HttpStatusCode = STATUS_CONNECTION_OK;
|
|
ExtensionProcResult = HSE_STATUS_SUCCESS;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
//
|
|
// Make sure there is no data from the initial BIND in the ECB data buffer:
|
|
//
|
|
// ASSERT(pECB->cbTotalBytes == 0);
|
|
|
|
//
|
|
// Get the connect parameters:
|
|
//
|
|
if (!ParseQueryString(pECB->lpszQueryString,&pOverlapped,&dwStatus))
|
|
{
|
|
dwSize = sizeof(STATUS_POST_BAD_FORMAT_STR) - 1; // don't want to count trailing 0.
|
|
|
|
ReplyToClient(pECB,STATUS_POST_BAD_FORMAT_STR,&dwSize,&dwStatus);
|
|
HttpStatusCode = STATUS_CONNECTION_OK;
|
|
ExtensionProcResult = HSE_STATUS_SUCCESS;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
pOverlapped->pECB = pECB;
|
|
|
|
//
|
|
// Add the new ECB to the Active ECB List:
|
|
//
|
|
if (!AddToECBList(g_pServerInfo->pActiveECBList,pECB))
|
|
{
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("HttpExtensionProc(): AddToECBList() failed\n");
|
|
#endif
|
|
FreeOverlapped(pOverlapped);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
//
|
|
// Submit the first client async read:
|
|
//
|
|
if (!StartAsyncClientRead(pECB,pOverlapped->pConn,&dwStatus))
|
|
{
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("HttpExtensionProc(): StartAsyncClientRead() failed %d\n",dwStatus);
|
|
#endif
|
|
FreeOverlapped(pOverlapped);
|
|
CleanupECB(pECB);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
//
|
|
// Post the first server read on the new socket:
|
|
//
|
|
IncrementECBRefCount(pServerInfo->pActiveECBList,pECB);
|
|
|
|
if (!SubmitNewRead(pServerInfo,pOverlapped,&dwStatus))
|
|
{
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("HttpExtensionProc(): SubmitNewRead() failed %d\n",dwStatus);
|
|
#endif
|
|
FreeOverlapped(pOverlapped);
|
|
CleanupECB(pECB);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
//
|
|
// Make sure the server receive thread is up and running:
|
|
//
|
|
if (!CheckStartReceiveThread(g_pServerInfo,&dwStatus))
|
|
{
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("HttpExtensionProc(): CheckStartReceiveThread() failed %d\n",dwStatus);
|
|
#endif
|
|
FreeOverlapped(pOverlapped);
|
|
CleanupECB(pECB);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
//
|
|
// Send back connection Ok to client, and also set fKeepConn to FALSE.
|
|
//
|
|
dwSize = sizeof(HeaderEx);
|
|
dwFlags = 0;
|
|
memset(&HeaderEx,0,dwSize);
|
|
HeaderEx.fKeepConn = FALSE;
|
|
if (!pECB->ServerSupportFunction(pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER_EX,
|
|
&HeaderEx,
|
|
&dwSize,
|
|
&dwFlags))
|
|
{
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("HttpExtensionProc(): SSF(HSE_REQ_SEND_RESPONSE_HEADER_EX) failed %d\n",dwStatus);
|
|
#endif
|
|
FreeOverlapped(pOverlapped);
|
|
CleanupECB(pECB);
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_ERROR;
|
|
goto AbortAndExit;
|
|
}
|
|
|
|
HttpStatusCode = STATUS_SERVER_ERROR;
|
|
ExtensionProcResult = HSE_STATUS_PENDING;
|
|
// fall through
|
|
|
|
AbortAndExit:
|
|
if (RemoteUser)
|
|
MemFree(RemoteUser);
|
|
|
|
pECB->dwHttpStatusCode = HttpStatusCode;
|
|
|
|
return ExtensionProcResult;
|
|
}
|
|
|