Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1393 lines
41 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
clirpc.c
Abstract:
This module contains the client side RPC
functions. These functions are used when the
WINFAX client runs as an RPC server too. These
functions are the ones available for the RPC
clients to call. Currently the only client
of these functions is the fax service.
Author:
Wesley Witt (wesw) 29-Nov-1996
Revision History:
--*/
#include "faxapi.h"
#include "CritSec.h"
#pragma hdrstop
extern CFaxCriticalSection g_CsFaxAssyncInfo; // used to synchronize access to the assync info structures (notification context)
extern DWORD g_dwFaxClientRpcNumInst;
extern TCHAR g_tszEndPoint[MAX_ENDPOINT_LEN];
static const ASYNC_EVENT_INFO g_scBadAsyncInfo = {0}; // this ASYNC_EVENT_INFO structure will be used as a return value for
// malicious RPC calls.
BOOL
ValidAsyncInfoSignature (PASYNC_EVENT_INFO pAsyncInfo);
VOID
WINAPI
FaxFreeBuffer(
LPVOID Buffer
)
{
MemFree( Buffer );
}
void *
MIDL_user_allocate(
IN size_t NumBytes
)
{
return MemAlloc( NumBytes );
}
void
MIDL_user_free(
IN void *MemPointer
)
{
MemFree( MemPointer );
}
BOOL
WINAPI
FaxStartServerNotification (
IN HANDLE hFaxHandle,
IN DWORD dwEventTypes,
IN HANDLE hCompletionPort,
IN ULONG_PTR upCompletionKey,
IN HWND hWnd,
IN DWORD dwMessage,
IN BOOL bEventEx,
OUT LPHANDLE lphEvent
)
{
PASYNC_EVENT_INFO AsyncInfo = NULL;
error_status_t ec = ERROR_SUCCESS;
TCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
WCHAR ComputerNameW[MAX_COMPUTERNAME_LENGTH + 1];
WCHAR wszEndPoint[MAX_ENDPOINT_LEN] = {0};
DWORD Size;
BOOL RpcServerStarted = FALSE;
HANDLE hServerContext;
DEBUG_FUNCTION_NAME(TEXT("FaxStartServerNotification"));
if (!ValidateFaxHandle(hFaxHandle, FHT_SERVICE))
{
SetLastError(ERROR_INVALID_HANDLE);
DebugPrintEx(DEBUG_ERR, _T("ValidateFaxHandle() failed."));
return FALSE;
}
if ((hCompletionPort && hWnd) || (!hCompletionPort && !hWnd))
{
SetLastError( ERROR_INVALID_PARAMETER );
DebugPrintEx(DEBUG_ERR, _T("(hCompletionPort && hWnd) || (!hCompletionPort && !hWnd)."));
return FALSE;
}
#ifdef WIN95
if (NULL != hCompletionPort)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Win95 does not support completion port"));
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
#endif // WIN95
if (hWnd && dwMessage < WM_USER)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("dwMessage must be equal to/greater than WM_USER"));
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (TRUE == bEventEx)
{
if (!((dwEventTypes & FAX_EVENT_TYPE_IN_QUEUE) ||
(dwEventTypes & FAX_EVENT_TYPE_OUT_QUEUE) ||
(dwEventTypes & FAX_EVENT_TYPE_CONFIG) ||
(dwEventTypes & FAX_EVENT_TYPE_ACTIVITY) ||
(dwEventTypes & FAX_EVENT_TYPE_QUEUE_STATE) ||
(dwEventTypes & FAX_EVENT_TYPE_IN_ARCHIVE) ||
(dwEventTypes & FAX_EVENT_TYPE_OUT_ARCHIVE) ||
(dwEventTypes & FAX_EVENT_TYPE_FXSSVC_ENDED) ||
(dwEventTypes & FAX_EVENT_TYPE_DEVICE_STATUS) ||
(dwEventTypes & FAX_EVENT_TYPE_NEW_CALL)))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("dwEventTypes is invalid - No valid event type indicated"));
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if ( 0 != (dwEventTypes & ~(FAX_EVENT_TYPE_IN_QUEUE |
FAX_EVENT_TYPE_OUT_QUEUE |
FAX_EVENT_TYPE_CONFIG |
FAX_EVENT_TYPE_ACTIVITY |
FAX_EVENT_TYPE_QUEUE_STATE |
FAX_EVENT_TYPE_IN_ARCHIVE |
FAX_EVENT_TYPE_OUT_ARCHIVE |
FAX_EVENT_TYPE_FXSSVC_ENDED |
FAX_EVENT_TYPE_DEVICE_STATUS|
FAX_EVENT_TYPE_NEW_CALL ) ))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("dwEventTypes is invalid - contains invalid event type bits"));
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
else
{
Assert (FAX_EVENT_TYPE_LEGACY == dwEventTypes);
}
//
// Get host name
//
Size = sizeof(ComputerName) / sizeof(TCHAR);
if (!GetComputerName( ComputerName, &Size ))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("GetComputerName failed (ec = %ld)"),
GetLastError());
return FALSE;
}
AsyncInfo = (PASYNC_EVENT_INFO) MemAlloc( sizeof(ASYNC_EVENT_INFO) );
if (!AsyncInfo)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Can't allocate ASTNC_EVENT_INFO"));
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
_tcscpy (AsyncInfo->tszSignature, ASYNC_EVENT_INFO_SIGNATURE);
AsyncInfo->bEventEx = bEventEx;
AsyncInfo->CompletionPort = NULL;
AsyncInfo->hWindow = NULL;
AsyncInfo->hBinding = NULL;
AsyncInfo->bLocalNotificationsOnly = FH_DATA(hFaxHandle)->bLocalConnection; // Fax client asked for notification from local or remote fax service.
AsyncInfo->bInUse = FALSE;
AsyncInfo->dwServerAPIVersion = FH_DATA(hFaxHandle)->dwServerAPIVersion; // Fax server API version.
if (hCompletionPort != NULL)
{
//
// Completion port notifications
//
AsyncInfo->CompletionPort = hCompletionPort;
AsyncInfo->CompletionKey = upCompletionKey;
}
else
{
//
// Window messages notifications
//
AsyncInfo->hWindow = hWnd;
AsyncInfo->MessageStart = dwMessage;
}
Assert ((NULL != AsyncInfo->CompletionPort && NULL == AsyncInfo->hWindow) ||
(NULL == AsyncInfo->CompletionPort && NULL != AsyncInfo->hWindow));
//
// We rely on the above assertion when validating the 'Context' parameter (points to this AssyncInfo structure) in
// Fax_OpenConnection.
//
//
// timing: get the server thread up and running before
// registering with the fax service (our client)
//
ec = StartFaxClientRpcServer();
if (ERROR_SUCCESS != ec)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StartFaxClientRpcServer failed (ec = %ld)"),
ec);
goto error_exit;
}
RpcServerStarted = TRUE;
Assert (_tcslen(g_tszEndPoint));
#ifdef UNICODE
wcscpy(ComputerNameW,ComputerName);
wcscpy(wszEndPoint, g_tszEndPoint);
#else // !UNICODE
if (0 == MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
ComputerName,
-1,
ComputerNameW,
sizeof(ComputerNameW)/sizeof(ComputerNameW[0])))
{
ec = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("MultiByteToWideChar failed (ec = %ld)"),
ec);
goto error_exit;
}
if (0 == MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
g_tszEndPoint,
-1,
wszEndPoint,
sizeof(wszEndPoint)/sizeof(wszEndPoint[0])))
{
ec = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("MultiByteToWideChar failed (ec = %ld)"),
ec);
goto error_exit;
}
#endif // UNICODE
//
// Register at the fax server for events
//
__try
{
ec = FAX_StartServerNotificationEx(
FH_FAX_HANDLE(hFaxHandle),
ComputerNameW, // Passed to create RPC binding
(LPCWSTR)wszEndPoint, // Passed to create RPC binding
(ULONG64) AsyncInfo, // Passed to the server,
// the server passes it back to the client with FAX_OpenConnection,
// and the client returns it back to the server as a context handle.
L"ncacn_ip_tcp", // For BOS interoperability it must be set to "ncacn_ip_tcp"
bEventEx, // flag to use FAX_EVENT_EX
dwEventTypes, // used in FAX_EVENT_EX
&hServerContext // returns a context handle to the client.
);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
//
// For some reason we got an exception.
//
ec = GetExceptionCode();
DebugPrintEx(
DEBUG_ERR,
TEXT("Exception on RPC call to FAX_StartServerNotification/Ex. (ec: %ld)"),
ec);
}
if (ERROR_SUCCESS != ec)
{
DumpRPCExtendedStatus ();
DebugPrintEx(
DEBUG_ERR,
TEXT("FAX_StartServerNotification/Ex failed (ec = %ld)"),
ec);
goto error_exit;
}
if (TRUE == bEventEx)
{
*lphEvent = hServerContext;
}
return TRUE;
error_exit:
MemFree(AsyncInfo);
AsyncInfo = NULL;
if (RpcServerStarted)
{
//
// this should also terminate FaxServerThread
//
StopFaxClientRpcServer();
}
SetLastError(ec);
return FALSE;
}
BOOL
WINAPI
FaxRegisterForServerEvents (
IN HANDLE hFaxHandle,
IN DWORD dwEventTypes,
IN HANDLE hCompletionPort,
IN ULONG_PTR upCompletionKey,
IN HWND hWnd,
IN DWORD dwMessage,
OUT LPHANDLE lphEvent
)
{
return FaxStartServerNotification ( hFaxHandle,
dwEventTypes,
hCompletionPort,
upCompletionKey,
hWnd,
dwMessage,
TRUE, // extended API
lphEvent
);
}
BOOL
WINAPI
FaxInitializeEventQueue(
IN HANDLE FaxHandle,
IN HANDLE CompletionPort,
IN ULONG_PTR upCompletionKey,
IN HWND hWnd,
IN UINT MessageStart
)
/*++
Routine Description:
Initializes the client side event queue. There can be one event
queue initialized for each fax server that the client app is
connected to.
Arguments:
FaxHandle - FAX handle obtained from FaxConnectFaxServer.
CompletionPort - Handle of an existing completion port opened using CreateIoCompletionPort.
upCompletionKey - A value that will be returned through the upCompletionKey parameter of GetQueuedCompletionStatus.
hWnd - Window handle to post events to
MessageStart - Starting message number, message range used is MessageStart + FEI_NEVENTS
Return Value:
TRUE - Success
FALSE - Failure, call GetLastError() for more error information.
--*/
{
if (hWnd && (upCompletionKey == -1))
//
// Backwards compatibility only.
// See "Receiving Notification Messages from the Fax Service" on MSDN
//
{
return TRUE;
}
return FaxStartServerNotification ( FaxHandle,
FAX_EVENT_TYPE_LEGACY, //Event type
CompletionPort,
upCompletionKey,
hWnd,
MessageStart,
FALSE, // Event Ex
NULL // Context handle
);
}
BOOL
WINAPI
FaxUnregisterForServerEvents (
IN HANDLE hEvent
)
/*++
Routine name : FaxUnregisterForServerEvents
Routine description:
A fax client application calls the FaxUnregisterForServerEvents function to stop
recieving notification.
Author:
Oded Sacher (OdedS), Dec, 1999
Arguments:
hEvent [in] - The enumeration handle value.
This value is obtained by calling FaxRegisterForServerEvents.
Return Value:
TRUE - Success
FALSE - Failure, call GetLastError() for more error information.
--*/
{
error_status_t ec = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("FaxUnregisterForServerEvents"));
if (NULL == hEvent)
{
SetLastError(ERROR_INVALID_HANDLE);
DebugPrintEx(DEBUG_ERR, _T("hEvent is NULL."));
return FALSE;
}
__try
{
//
// Attempt to tell the server we are shutting down this notification context
//
ec = FAX_EndServerNotification (&hEvent); // this will free Assync info
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
//
// For some reason we got an exception.
//
ec = GetExceptionCode();
DebugPrintEx(
DEBUG_ERR,
TEXT("Exception on RPC call to FAX_EndServerNotification. (ec: %ld)"),
ec);
}
if (ERROR_SUCCESS != ec)
{
DumpRPCExtendedStatus ();
DebugPrintEx(DEBUG_ERR, _T("FAX_EndServerNotification failed. (ec: %ld)"), ec);
}
ec = StopFaxClientRpcServer();
if (ERROR_SUCCESS != ec)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StopFaxClientRpcServer failed. (ec: %ld)"),
ec);
}
if (ERROR_SUCCESS != ec)
{
SetLastError(ec);
return FALSE;
}
return TRUE;
} // FaxUnregisterForServerEvents
BOOL
ValidAsyncInfoSignature (PASYNC_EVENT_INFO pAsyncInfo)
{
if (NULL == pAsyncInfo)
{
return FALSE;
}
if (&g_scBadAsyncInfo == pAsyncInfo)
{
//
// We are under attack!
//
return FALSE;
}
if (_tcscmp (pAsyncInfo->tszSignature, ASYNC_EVENT_INFO_SIGNATURE))
{
return FALSE;
}
return TRUE;
} // ValidAsyncInfoSignature
error_status_t
FAX_OpenConnection(
IN handle_t hBinding,
IN ULONG64 Context,
OUT LPHANDLE FaxHandle
)
{
PASYNC_EVENT_INFO pAsyncInfo = (PASYNC_EVENT_INFO) Context;
DWORD ec = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("FAX_OpenConnection"));
EnterCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
//
// Try to access the AssyncInfo structure pointed by 'Context' to verify it is not corrupted.
//
if (IsBadReadPtr(
pAsyncInfo, // memory address,
sizeof(ASYNC_EVENT_INFO) // size of block
))
{
//
// We are under attack!!!
//
DebugPrintEx(
DEBUG_ERR,
TEXT("Invalid AssyncInfo structure pointed by 'Context'. We are under attack!!!!"));
ec = ERROR_INVALID_PARAMETER;
goto exit;
}
//
// Looks good, Let's do some more verifications.
//
__try
{
if ((NULL == pAsyncInfo->CompletionPort && NULL == pAsyncInfo->hWindow) ||
(NULL != pAsyncInfo->CompletionPort && NULL != pAsyncInfo->hWindow))
{
//
// Invalid AssyncInfo structure pointed by 'Context'. We are under attack!!!!
//
ec = ERROR_INVALID_PARAMETER;
DebugPrintEx(
DEBUG_ERR,
TEXT("Invalid AssyncInfo structure pointed by 'Context'. We are under attack!!!!"));
goto exit;
}
if (!ValidAsyncInfoSignature(pAsyncInfo))
{
//
// Signature mismatch. We are under attack!!!!
//
ec = ERROR_INVALID_PARAMETER;
DebugPrintEx(
DEBUG_ERR,
TEXT("Invalid AssyncInfo siganture pointed by 'Context'. We are under attack!!!!"));
goto exit;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
//
// For some reason we got an exception.
//
ec = GetExceptionCode();
DebugPrintEx(
DEBUG_ERR,
TEXT("Exception when trying to access the AssyncInfo structure (ec: %ld)"),
ec);
goto exit;
}
Assert (ERROR_SUCCESS == ec);
if (pAsyncInfo->bInUse)
{
//
// This AsynchInfo is already used by another notifier (server). We are under attack!!!!
//
ec = ERROR_INVALID_PARAMETER;
DebugPrintEx(
DEBUG_ERR,
TEXT("This AsynchInfo is already used by another notifier (server). We are under attack!!!!"));
goto exit;
}
//
// Mark this AsynchInfo as being used.
//
pAsyncInfo->bInUse = TRUE;
if (IsWinXPOS() &&
pAsyncInfo->dwServerAPIVersion > FAX_API_VERSION_1)
{
// We are running on XP or later OS, and
// talking to fax server running on OS later then XP (.NET and later),
// we require at least packet-level privacy (RPC_C_AUTHN_LEVEL_PKT_PRIVACY).
//
RPC_AUTHZ_HANDLE hPrivs;
DWORD dwAuthn;
RPC_STATUS status = RPC_S_OK;
//
// Query the client's authentication level
//
status = RpcBindingInqAuthClient(
hBinding,
&hPrivs,
NULL,
&dwAuthn,
NULL,
NULL);
if (status != RPC_S_OK)
{
DebugPrintEx(DEBUG_ERR,
TEXT("RpcBindingInqAuthClient returned: 0x%x"),
status);
ec = ERROR_ACCESS_DENIED;
goto exit;
}
//
// Now check the authentication level.
// We require at least packet-level privacy (RPC_C_AUTHN_LEVEL_PKT_PRIVACY).
//
if (dwAuthn < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
{
DebugPrintEx(DEBUG_ERR,
TEXT("Attempt by client to use weak authentication. - 0x%x"),
dwAuthn);
ec = ERROR_ACCESS_DENIED;
goto exit;
}
}
else
{
//
// Talking to Fax service running on pre .NET OS, allow anonymous connection
//
DebugPrintEx(DEBUG_WRN,
TEXT("Talking to Fax server, with anonymous RPC connection."));
}
//
// hBinding is a valid context handle pointing to a real ASYNC_EVENT_INFO object.
// Save the binding handle for other RPC calls.
//
pAsyncInfo->hBinding = hBinding;
if ( pAsyncInfo->bLocalNotificationsOnly )
{
//
// Client asked for local events only
//
BOOL bIsLocal = FALSE;
ec = IsLocalRPCConnectionIpTcp(hBinding,&bIsLocal);
if (ERROR_SUCCESS != ec)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("IsLocalRPCConnectionIpTcp failed. (ec: %lu)"),
ec);
*FaxHandle = NULL;
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
return ec;
}
else
{
if (FALSE == bIsLocal)
{
//
// Client asked for local events only but the call is from remote location. We are under attack!!!!
//
ec = ERROR_INVALID_PARAMETER;
DebugPrintEx(
DEBUG_ERR,
TEXT("Client asked for local events only. We are under attack!!!!"));
goto exit;
}
}
}
Assert (ERROR_SUCCESS == ec);
exit:
if (ERROR_SUCCESS == ec)
{
*FaxHandle = (HANDLE) Context;
}
else
{
//
// Probably we are under attack, The notification RPC functions should not fail if a wrong (read: malicious)
// notification context arrives.
// Instead, it should report success but not process notifications from that AsyncInfo object.
//
// This will make it very hard for an attacker to scan the 4G context range and detect the
// right context for bogus notifications.
//
*FaxHandle = (HANDLE)&g_scBadAsyncInfo ;
ec = ERROR_SUCCESS;
}
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
return ec;
}
error_status_t
FAX_CloseConnection(
OUT LPHANDLE pFaxHandle
)
{
PASYNC_EVENT_INFO pAsyncInfo = (PASYNC_EVENT_INFO) *pFaxHandle;
error_status_t ec = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("FAX_CloseConnection"));
EnterCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
if (!ValidAsyncInfoSignature(pAsyncInfo))
{
//
// Probably we are under attack, The notification RPC functions should not fail if a wrong (read: malicious)
// notification context arrives.
// Instead, it should report success but not process notifications from that AsyncInfo object.
//
// This will make it very hard for an attacker to scan the 4G context range and detect the
// right context for bogus notifications.
//
DebugPrintEx(DEBUG_ERR, TEXT("Invalid AssyncInfo signature. We are under attack!!!!"));
//
// Don't report the error to the malicious user!
//
ec = ERROR_SUCCESS;
goto exit;
}
if ( pAsyncInfo->bLocalNotificationsOnly)
{
//
// Client asked for local events only
//
BOOL bIsLocal = FALSE;
ec = IsLocalRPCConnectionIpTcp(pAsyncInfo->hBinding,&bIsLocal);
if (ERROR_SUCCESS != ec)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("IsLocalRPCConnectionIpTcp failed. (ec: %lu)"),
ec);
goto exit;
}
else
{
if (FALSE == bIsLocal)
{
//
// Client asked for local events only but the call is from remote location. We are under attack!!!!
//
DebugPrintEx(
DEBUG_ERR,
TEXT("Client asked for local events only. We are under attack!!!!"));
//
// Don't report the error to the malicious user!
//
ec = ERROR_SUCCESS;
goto exit;
}
}
}
ZeroMemory (*pFaxHandle, sizeof(ASYNC_EVENT_INFO));
MemFree (*pFaxHandle); // Assync info
*pFaxHandle = NULL; // prevent rundown
exit:
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
return ec;
}
error_status_t
FAX_ClientEventQueue(
IN HANDLE FaxHandle,
IN FAX_EVENT FaxEvent
)
/*++
Routine Description:
This function is called when the a fax server wants
to deliver a fax event to this client.
Arguments:
FaxHandle - FAX handle obtained from FaxConnectFaxServer.
FaxEvent - FAX event structure.
Context - Context token, really a ASYNC_EVENT_INFO structure pointer
Return Value:
Win32 error code.
--*/
{
PASYNC_EVENT_INFO AsyncInfo = (PASYNC_EVENT_INFO) FaxHandle;
error_status_t ec = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("FAX_ClientEventQueue"));
EnterCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
if (!ValidAsyncInfoSignature(AsyncInfo))
{
//
// Probably we are under attack, The notification RPC functions should not fail if a wrong (read: malicious)
// notification context arrives.
// Instead, it should report success but not process notifications from that AsyncInfo object.
//
// This will make it very hard for an attacker to scan the 4G context range and detect the
// right context for bogus notifications.
//
DebugPrintEx(DEBUG_ERR, TEXT("Invalid AssyncInfo signature"));
//
// Don't report the error to the malicious user!
//
ec = ERROR_SUCCESS;
goto exit;
}
if ( AsyncInfo->bLocalNotificationsOnly)
{
//
// Client asked for local events only
//
BOOL bIsLocal = FALSE;
ec = IsLocalRPCConnectionIpTcp(AsyncInfo->hBinding,&bIsLocal);
if (ERROR_SUCCESS != ec)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("IsLocalRPCConnectionIpTcp failed. (ec: %lu)"),
ec);
goto exit;
}
else
{
if (FALSE == bIsLocal)
{
//
// Client asked for local events only but the call is from remote location. We are under attack!!!!
//
DebugPrintEx(
DEBUG_ERR,
TEXT("Client asked for local events only. We are under attack!!!!"));
//
// Don't report the error to the malicious user!
//
ec = ERROR_SUCCESS;
goto exit;
}
}
}
if (AsyncInfo->CompletionPort != NULL)
{
//
// Use completion port
//
PFAX_EVENT FaxEventPost = NULL;
FaxEventPost = (PFAX_EVENT) LocalAlloc( LMEM_FIXED, sizeof(FAX_EVENT) );
if (!FaxEventPost)
{
ec = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
CopyMemory( FaxEventPost, &FaxEvent, sizeof(FAX_EVENT) );
if (!PostQueuedCompletionStatus(
AsyncInfo->CompletionPort,
sizeof(FAX_EVENT),
AsyncInfo->CompletionKey,
(LPOVERLAPPED) FaxEventPost))
{
ec = GetLastError();
DebugPrint(( TEXT("PostQueuedCompletionStatus failed, ec = %d\n"), ec ));
LocalFree (FaxEventPost);
goto exit;
}
goto exit;
}
Assert (AsyncInfo->hWindow != NULL)
//
// Use window messages
//
if (! PostMessage( AsyncInfo->hWindow,
AsyncInfo->MessageStart + FaxEvent.EventId,
(WPARAM)FaxEvent.DeviceId,
(LPARAM)FaxEvent.JobId ))
{
ec = GetLastError();
DebugPrint(( TEXT("PostMessage failed, ec = %d\n"), ec ));
goto exit;
}
exit:
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
return ec;
}
DWORD
DispatchEvent (
const ASYNC_EVENT_INFO* pAsyncInfo,
const FAX_EVENT_EX* pEvent,
DWORD dwEventSize
)
{
DWORD dwRes = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("DispatchEvent"));
Assert (pAsyncInfo && pEvent && dwEventSize);
if (pAsyncInfo->CompletionPort != NULL)
{
//
// Use completion port
//
if (!PostQueuedCompletionStatus( pAsyncInfo->CompletionPort,
dwEventSize,
pAsyncInfo->CompletionKey,
(LPOVERLAPPED) pEvent))
{
dwRes = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("PostQueuedCompletionStatus failed (ec: %ld)"),
dwRes);
goto exit;
}
}
else
{
Assert (pAsyncInfo->hWindow != NULL)
//
// Use window messages
//
if (! PostMessage( pAsyncInfo->hWindow,
pAsyncInfo->MessageStart,
(WPARAM)NULL,
(LPARAM)pEvent ))
{
dwRes = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("PostMessage failed (ec: %ld)"),
dwRes);
goto exit;
}
}
Assert (ERROR_SUCCESS == dwRes);
exit:
return dwRes;
} // DispatchEvent
void
PostRundownEventEx (
PASYNC_EVENT_INFO pAsyncInfo
)
{
PFAX_EVENT_EX pEvent = NULL;
DWORD dwRes = ERROR_SUCCESS;
DWORD dwEventSize = sizeof(FAX_EVENT_EX);
DEBUG_FUNCTION_NAME(TEXT("PostRundownEventEx"));
Assert (pAsyncInfo);
pEvent = (PFAX_EVENT_EX)MemAlloc (dwEventSize);
if (NULL == pEvent)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("PostRundownEventEx failed , Error allocatin FAX_EVENT_EX"));
return;
}
ZeroMemory(pEvent, dwEventSize);
pEvent->dwSizeOfStruct = sizeof(FAX_EVENT_EX);
GetSystemTimeAsFileTime( &(pEvent->TimeStamp) );
pEvent->EventType = FAX_EVENT_TYPE_FXSSVC_ENDED;
dwRes = DispatchEvent (pAsyncInfo, pEvent, dwEventSize);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(DEBUG_ERR, _T("DispatchEvent failed , ec = %ld"), dwRes);
MemFree (pEvent);
}
} // PostRundownEventEx
VOID
RPC_FAX_HANDLE_rundown(
IN HANDLE FaxHandle
)
{
PASYNC_EVENT_INFO pAsyncInfo = (PASYNC_EVENT_INFO) FaxHandle;
DWORD dwRes = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("RPC_FAX_HANDLE_rundown"));
EnterCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
if (!ValidAsyncInfoSignature(pAsyncInfo))
{
DebugPrintEx(DEBUG_ERR, TEXT("Invalid AssyncInfo signature"));
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
return;
}
Assert (pAsyncInfo->CompletionPort || pAsyncInfo->hWindow);
if (pAsyncInfo->bEventEx == TRUE)
{
PostRundownEventEx(pAsyncInfo);
}
else
{
// legacy event - FAX_EVENT
if (pAsyncInfo->CompletionPort != NULL)
{
PFAX_EVENT pFaxEvent;
pFaxEvent = (PFAX_EVENT) LocalAlloc( LMEM_FIXED, sizeof(FAX_EVENT) );
if (!pFaxEvent)
{
goto exit;
}
pFaxEvent->SizeOfStruct = sizeof(ASYNC_EVENT_INFO);
GetSystemTimeAsFileTime( &pFaxEvent->TimeStamp );
pFaxEvent->DeviceId = 0;
pFaxEvent->EventId = FEI_FAXSVC_ENDED;
pFaxEvent->JobId = 0;
if( !PostQueuedCompletionStatus (pAsyncInfo->CompletionPort,
sizeof(FAX_EVENT),
pAsyncInfo->CompletionKey,
(LPOVERLAPPED) pFaxEvent
) )
{
dwRes = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("PostQueuedCompletionStatus failed (ec: %ld)"),
dwRes);
LocalFree (pFaxEvent);
goto exit;
}
}
if (pAsyncInfo->hWindow != NULL)
{
PostMessage (pAsyncInfo->hWindow,
pAsyncInfo->MessageStart + FEI_FAXSVC_ENDED,
0,
0);
}
}
exit:
ZeroMemory(pAsyncInfo, sizeof(ASYNC_EVENT_INFO));
MemFree (pAsyncInfo);
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
return;
}
BOOL
ValidateAndFixupEventStringPtr (
PFAX_EVENT_EXW pEventEx,
LPCWSTR *lpptstrString,
DWORD dwDataSize
)
/*++
Routine Description:
This function validates that the string offest in a FAX_EVENT_EXW structure
is completely contained within the event structure data range.
Once this is validated, the function converts the offest to a valid string pointer.
Arguments:
pEventEx [in] - Pointer to the fax event structure.
lpptstrString [in / out] - Pointer to string offset, later converted to the string itself.
dwDataSize [in] - Size of the event blob (bytes)
Return Value:
Win32 error code.
--*/
{
LPCWSTR lpcwstrString = *lpptstrString;
if (!lpcwstrString)
{
return TRUE;
}
//
// Make sure the offest falls within the structure size
//
if ((ULONG_PTR)lpcwstrString >= dwDataSize)
{
return FALSE;
}
//
// Convert offset to string
//
*lpptstrString = (LPCWSTR)((LPBYTE)pEventEx + (ULONG_PTR)lpcwstrString);
lpcwstrString = *lpptstrString;
if ((ULONG_PTR)lpcwstrString < (ULONG_PTR)pEventEx)
{
return FALSE;
}
//
// Make sure string ends within the event structure bounds
//
while (*lpcwstrString != TEXT('\0'))
{
lpcwstrString++;
if (lpcwstrString >= (LPCWSTR)((LPBYTE)pEventEx + dwDataSize))
{
//
// Going to exceed structure - corrupted offset
//
return FALSE;
}
}
return TRUE;
} // ValidateAndFixupEventStringPtr
error_status_t
FAX_ClientEventQueueEx(
IN RPC_FAX_HANDLE hClientContext,
IN const LPBYTE lpbData,
IN DWORD dwDataSize
)
{
PASYNC_EVENT_INFO pAsyncInfo = (PASYNC_EVENT_INFO) hClientContext;
PFAX_EVENT_EXW pEvent = NULL;
PFAX_EVENT_EXA pEventA = NULL;
DWORD dwRes = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("FAX_ClientEventQueueEx"));
Assert (pAsyncInfo && lpbData && dwDataSize);
EnterCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
if (!ValidAsyncInfoSignature(pAsyncInfo))
{
//
// Probably we are under attack, The notification RPC functions should not fail if a wrong (read: malicious)
// notification context arrives.
// Instead, it should report success but not process notifications from that AsyncInfo object.
//
// This will make it very hard for an attacker to scan the 4G context range and detect the
// right context for bogus notifications.
//
DebugPrintEx(DEBUG_ERR, TEXT("Invalid AssyncInfo signature"));
//
// Don't report the error to the malicious user!
//
dwRes = ERROR_SUCCESS;
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
goto exit;
}
if ( pAsyncInfo->bLocalNotificationsOnly )
{
//
// Client asked for local events only
//
BOOL bIsLocal = FALSE;
dwRes = IsLocalRPCConnectionIpTcp(pAsyncInfo->hBinding,&bIsLocal);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("IsLocalRPCConnectionIpTcp failed. (ec: %lu)"),
dwRes);
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
goto exit;
}
else
{
if (FALSE == bIsLocal)
{
//
// Client asked for local events only but the call is from remote location. We are under attack!!!!
//
DebugPrintEx(
DEBUG_ERR,
TEXT("Client asked for local events only. We are under attack!!!!"));
//
// Don't report the error to the malicious user!
//
dwRes = ERROR_SUCCESS;
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
goto exit;
}
}
}
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
//
// IMPORTANT - Do not use pAsyncInfo before validating it again with ValidAsyncInfoSignature().
//
pEvent = (PFAX_EVENT_EXW)MemAlloc (dwDataSize);
if (NULL == pEvent)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Error allocatin FAX_EVENT_EX"));
return ERROR_OUTOFMEMORY;
}
CopyMemory (pEvent, lpbData, dwDataSize);
if(pEvent->EventType == FAX_EVENT_TYPE_NEW_CALL)
{
if (!ValidateAndFixupEventStringPtr (pEvent,
(LPCWSTR *)&(pEvent->EventInfo).NewCall.lptstrCallerId,
dwDataSize))
{
dwRes = ERROR_INVALID_DATA;
goto exit;
}
}
if ( (pEvent->EventType == FAX_EVENT_TYPE_IN_QUEUE ||
pEvent->EventType == FAX_EVENT_TYPE_OUT_QUEUE) &&
((pEvent->EventInfo).JobInfo.Type == FAX_JOB_EVENT_TYPE_STATUS) )
{
//
// Unpack FAX_EVENT_EX
//
Assert ((pEvent->EventInfo).JobInfo.pJobData);
(pEvent->EventInfo).JobInfo.pJobData = (PFAX_JOB_STATUSW)
((LPBYTE)pEvent +
(ULONG_PTR)((pEvent->EventInfo).JobInfo.pJobData));
if (!ValidateAndFixupEventStringPtr (pEvent,
&((pEvent->EventInfo).JobInfo.pJobData->lpctstrExtendedStatus),
dwDataSize) ||
!ValidateAndFixupEventStringPtr (pEvent,
&((pEvent->EventInfo).JobInfo.pJobData->lpctstrTsid),
dwDataSize) ||
!ValidateAndFixupEventStringPtr (pEvent,
&((pEvent->EventInfo).JobInfo.pJobData->lpctstrCsid),
dwDataSize) ||
!ValidateAndFixupEventStringPtr (pEvent,
&((pEvent->EventInfo).JobInfo.pJobData->lpctstrDeviceName),
dwDataSize) ||
!ValidateAndFixupEventStringPtr (pEvent,
&((pEvent->EventInfo).JobInfo.pJobData->lpctstrCallerID),
dwDataSize) ||
!ValidateAndFixupEventStringPtr (pEvent,
&((pEvent->EventInfo).JobInfo.pJobData->lpctstrRoutingInfo),
dwDataSize))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("ValidateAndFixupEventStringPtr failed"));
dwRes = ERROR_INVALID_DATA;
goto exit;
}
#ifndef UNICODE
(pEvent->EventInfo).JobInfo.pJobData->dwSizeOfStruct = sizeof(FAX_JOB_STATUSA);
if (!ConvertUnicodeStringInPlace( (LPWSTR) (pEvent->EventInfo).JobInfo.pJobData->lpctstrExtendedStatus ) ||
!ConvertUnicodeStringInPlace( (LPWSTR) (pEvent->EventInfo).JobInfo.pJobData->lpctstrTsid ) ||
!ConvertUnicodeStringInPlace( (LPWSTR) (pEvent->EventInfo).JobInfo.pJobData->lpctstrCsid ) ||
!ConvertUnicodeStringInPlace( (LPWSTR) (pEvent->EventInfo).JobInfo.pJobData->lpctstrDeviceName ) ||
!ConvertUnicodeStringInPlace( (LPWSTR) (pEvent->EventInfo).JobInfo.pJobData->lpctstrCallerID ) ||
!ConvertUnicodeStringInPlace( (LPWSTR) (pEvent->EventInfo).JobInfo.pJobData->lpctstrRoutingInfo ))
{
dwRes = GetLastError ();
DebugPrintEx(
DEBUG_ERR,
TEXT("ConvertUnicodeStringInPlace failed with %ld"),
dwRes);
goto exit;
}
#endif // ifndef UNICODE
}
EnterCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
if (!ValidAsyncInfoSignature(pAsyncInfo))
{
DebugPrintEx(DEBUG_ERR, TEXT("Invalid AssyncInfo signature"));
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
//
// if we got here and pAsyncInfo is invalid, it must be that
// Fax_CloseConnection or rundown was called and the pAsyncInfo
// become invalid.
//
dwRes = ERROR_INVALID_DATA;
goto exit;
}
#ifdef UNICODE
dwRes = DispatchEvent (pAsyncInfo, pEvent, dwDataSize);
#else
pEvent->dwSizeOfStruct = sizeof(FAX_EVENT_EXA);
pEventA = (PFAX_EVENT_EXA)pEvent;
dwRes = DispatchEvent (pAsyncInfo, pEventA, dwDataSize);
#endif
LeaveCriticalSection(&g_CsFaxAssyncInfo); // Protect AsyncInfo
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("DispatchEvent failed , errro %ld"),
dwRes);
goto exit;
}
Assert (ERROR_SUCCESS == dwRes);
exit:
if (ERROR_SUCCESS != dwRes)
{
MemFree (pEvent);
}
return dwRes;
} // FAX_ClientEventQueueEx