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.
1203 lines
34 KiB
1203 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
faxapi.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the Win32 FAX APIs.
|
|
The function implemented here are simply very
|
|
thin wrappers around the RPC stubs. The wrappers
|
|
are necessary so that the last error value
|
|
is set properly.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 16-Jan-1996
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "faxapi.h"
|
|
#pragma hdrstop
|
|
|
|
static
|
|
DWORD
|
|
ConnectToFaxServer(
|
|
PHANDLE_ENTRY pHandleEntry,
|
|
PFAX_HANDLE_DATA pFaxData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function that wrap RPC call for connecting to the fax service.
|
|
|
|
The function first attempt to call FAX_ConnectFaxServer in order to connect to .NET or XP fax servers,
|
|
if the call fails with RPC_S_PROCNUM_OUT_OF_RANGE, that indicates that we are dealing with BOS 2000, we try
|
|
to connect to BOS fax server with FAX_ConnectionRefCount.
|
|
|
|
Arguments:
|
|
|
|
pHandleEntry - [in/out] pointer to fax service handle entry.
|
|
the function will use the binding handle and update the context handle.
|
|
pFaxData - [in/out] pointer to fax handle data.
|
|
the function will update the server's API version within this handle data
|
|
|
|
Return Value:
|
|
|
|
Win32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
DEBUG_FUNCTION_NAME(TEXT("ConnectToFaxServer"));
|
|
|
|
Assert (pHandleEntry);
|
|
Assert (pFaxData);
|
|
|
|
__try
|
|
{
|
|
dwRes = FAX_ConnectFaxServer( FH_FAX_HANDLE(pHandleEntry), // Binding handle
|
|
CURRENT_FAX_API_VERSION, // Our API version
|
|
&(pFaxData->dwReportedServerAPIVersion), // Server's API version
|
|
&FH_CONTEXT_HANDLE(pHandleEntry)); // Server's context handle
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we crashed.
|
|
//
|
|
dwRes = GetExceptionCode();
|
|
}
|
|
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
if (RPC_S_PROCNUM_OUT_OF_RANGE == dwRes)
|
|
{
|
|
//
|
|
// Got "The procedure number is out of range.".
|
|
// This is because we're trying to call an RPC function which doesn't exist in BOS 2000 Fax server.
|
|
// Try the 'old' FaxConnectionRefCount() call
|
|
//
|
|
DWORD dwShare; // Igonred
|
|
__try
|
|
{
|
|
dwRes = FAX_ConnectionRefCount( FH_FAX_HANDLE(pHandleEntry),
|
|
&FH_CONTEXT_HANDLE(pHandleEntry),
|
|
1,
|
|
&dwShare);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we crashed.
|
|
//
|
|
dwRes = GetExceptionCode();
|
|
}
|
|
if (ERROR_SUCCESS == dwRes)
|
|
{
|
|
//
|
|
// Hooray!!! This is a BOS 2000 Fax Server
|
|
//
|
|
pFaxData->dwReportedServerAPIVersion = FAX_API_VERSION_0;
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_ConnectionRefCount. (ec: %lu)"),
|
|
dwRes);
|
|
|
|
DumpRPCExtendedStatus ();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_ConnectFaxServer. (ec: %lu)"),
|
|
dwRes);
|
|
|
|
DumpRPCExtendedStatus ();
|
|
}
|
|
}
|
|
return dwRes;
|
|
|
|
} // ConnectToFaxServer
|
|
|
|
|
|
|
|
|
|
//
|
|
// Note: the name of this function is actually a macro that expands to FaxConnectFaxServerW
|
|
// or FaxConnectFaxServerA depnding on the UNICODE macro.
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
FaxConnectFaxServer(
|
|
IN LPCTSTR lpMachineName OPTIONAL,
|
|
OUT LPHANDLE FaxHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a connection to a FAX server. The binding handle that is
|
|
returned is used for all subsequent FAX API calls.
|
|
|
|
Arguments:
|
|
|
|
lpMachineName - Machine name, NULL, or "."
|
|
FaxHandle - Pointer to a FAX handle
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure, call GetLastError() for more error information.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFAX_HANDLE_DATA pFaxData = NULL;
|
|
PHANDLE_ENTRY pHandleEntry = NULL;
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
BOOL bLocalConnection = IsLocalMachineName (lpMachineName);
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxConnectFaxServer"));
|
|
|
|
if (!FaxHandle)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
DebugPrintEx(DEBUG_ERR, _T("FaxHandle is NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
pFaxData = (PFAX_HANDLE_DATA)MemAlloc( sizeof(FAX_HANDLE_DATA) );
|
|
if (!pFaxData)
|
|
{
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
DebugPrintEx(DEBUG_ERR, _T("MemAlloc is failed."));
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory (pFaxData, sizeof(FAX_HANDLE_DATA));
|
|
|
|
pFaxData->bLocalConnection = bLocalConnection;
|
|
InitializeListHead( &pFaxData->HandleTableListHead );
|
|
|
|
//
|
|
// Create new Service handle, in case of an error
|
|
// after this function succeeded cleanup code must call CloseFaxHandle()
|
|
//
|
|
pHandleEntry = CreateNewServiceHandle( pFaxData );
|
|
if (!pHandleEntry)
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR, _T("CreateNewServiceHandle() failed."));
|
|
|
|
MemFree(pFaxData);
|
|
return FALSE;
|
|
}
|
|
|
|
dwRes = FaxClientBindToFaxServer( lpMachineName, FAX_RPC_ENDPOINT, NULL, &pFaxData->FaxHandle );
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, _T("FaxClientBindToFaxServer() failed with %ld."), dwRes);
|
|
pFaxData->FaxHandle = NULL;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!bLocalConnection)
|
|
{
|
|
//
|
|
// This is not the local machine, Remove all \\ from machine name
|
|
//
|
|
LPCTSTR lpctstrDelim = _tcsrchr(lpMachineName, TEXT('\\'));
|
|
if (NULL == lpctstrDelim)
|
|
{
|
|
lpctstrDelim = lpMachineName;
|
|
}
|
|
else
|
|
{
|
|
lpctstrDelim = _tcsinc(lpctstrDelim);
|
|
}
|
|
|
|
pFaxData->MachineName = StringDup (lpctstrDelim);
|
|
if (!pFaxData->MachineName)
|
|
{
|
|
dwRes = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ask for the highest level of privacy (autnetication + encryption)
|
|
//
|
|
dwRes = RpcBindingSetAuthInfo (
|
|
FH_FAX_HANDLE(pHandleEntry), // RPC binding handle
|
|
RPC_SERVER_PRINCIPAL_NAME, // Server principal name
|
|
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Authentication level - fullest
|
|
// Authenticates, verifies, and privacy-encrypts the arguments passed
|
|
// to every remote call.
|
|
RPC_C_AUTHN_WINNT, // Authentication service (NTLMSSP)
|
|
NULL, // Authentication identity - use currently logged on user
|
|
0); // Unused when Authentication service == RPC_C_AUTHN_WINNT
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
//
|
|
// Couldn't set RPC authentication mode
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcBindingSetAuthInfo (RPC_C_AUTHN_LEVEL_PKT_PRIVACY) failed. (ec: %ld)"),
|
|
dwRes);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// On local connections make sure that the fax service is up
|
|
//
|
|
if (bLocalConnection)
|
|
{
|
|
if (!EnsureFaxServiceIsStarted (NULL))
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("EnsureFaxServiceIsStarted failed (ec = %ld"),
|
|
dwRes);
|
|
goto ErrorExit;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Wait till the RPC service is up an running
|
|
//
|
|
if (!WaitForServiceRPCServer (60 * 1000))
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("WaitForServiceRPCServer failed (ec = %ld"),
|
|
dwRes);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Here we tries to connect to the Fax service.
|
|
//
|
|
// We try to connect three times, two times using RPC_C_AUTHN_LEVEL_PKT_PRIVACY Authentication level
|
|
// and if we fail we drop to RPC_C_AUTHN_LEVEL_NONE Authentication level.
|
|
//
|
|
// We try twice with RPC_C_AUTHN_LEVEL_PKT_PRIVACY authentication level, because RPC runtime infrastructure might cache
|
|
// the service handle, and if the service was restarted the first RPC call will use the old cached data, and will fail.
|
|
// RPC cannot internally retry because we dealling with privacy authentication and thus we do the retry.
|
|
//
|
|
// If we fail to connect twice we drop the authentication level and retry. This is done to allow .NET clients to connect to
|
|
// Fax servers that does not use a secure channel.
|
|
// We do not need to retry the connection, beacuse RPC will do that internally.
|
|
//
|
|
dwRes = ConnectToFaxServer(pHandleEntry,pFaxData);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
{
|
|
DebugPrintEx (DEBUG_WRN,
|
|
TEXT("fisrt call to ConnectToFaxServer failed with - %lu"),
|
|
dwRes);
|
|
|
|
dwRes = ConnectToFaxServer(pHandleEntry,pFaxData);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We failed twice, Drop authentication level and retry.
|
|
//
|
|
|
|
DebugPrintEx (DEBUG_WRN,
|
|
TEXT("second call to ConnectToFaxServer failed with - %lu"),
|
|
dwRes);
|
|
|
|
DebugPrintEx (DEBUG_WRN,
|
|
TEXT("Warning!!! not using encryption anymore against remote server %s"),
|
|
lpMachineName);
|
|
|
|
dwRes = RpcBindingSetAuthInfo (
|
|
FH_FAX_HANDLE(pHandleEntry), // RPC binding handle
|
|
RPC_SERVER_PRINCIPAL_NAME, // Server principal name
|
|
RPC_C_AUTHN_LEVEL_NONE, // Authentication level - none
|
|
RPC_C_AUTHN_WINNT, // Authentication service (NTLMSSP)
|
|
NULL, // Authentication identity - use currently logged on user
|
|
0); // Unused when Authentication service == RPC_C_AUTHN_WINNT
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
//
|
|
// Couldn't set RPC authentication mode
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcBindingSetAuthInfo (RPC_C_AUTHN_LEVEL_NONE) failed. (ec: %lu)"),
|
|
dwRes);
|
|
goto ErrorExit;
|
|
}
|
|
dwRes = ConnectToFaxServer(pHandleEntry,pFaxData);
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
DebugPrintEx (DEBUG_ERR,
|
|
TEXT("third call to ConnectToFaxServer failed with - %lu"),
|
|
dwRes);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwRes)
|
|
{
|
|
//
|
|
// Succeeded to connect
|
|
//
|
|
pFaxData->dwServerAPIVersion = pFaxData->dwReportedServerAPIVersion;
|
|
if (pFaxData->dwReportedServerAPIVersion > CURRENT_FAX_API_VERSION)
|
|
{
|
|
//
|
|
// This is the filtering.
|
|
// Assume we're talking to a Windows XP server since we have no knowledge of future servers.
|
|
//
|
|
pFaxData->dwServerAPIVersion = CURRENT_FAX_API_VERSION;
|
|
}
|
|
|
|
*FaxHandle = (LPHANDLE) pHandleEntry;
|
|
return TRUE;
|
|
}
|
|
|
|
ErrorExit:
|
|
Assert (ERROR_SUCCESS != dwRes);
|
|
|
|
if (NULL != pFaxData)
|
|
{
|
|
if (NULL != pFaxData->FaxHandle)
|
|
{
|
|
RpcBindingFree(&pFaxData->FaxHandle);
|
|
}
|
|
}
|
|
|
|
//
|
|
// clean up for CreateNewServiceHandle
|
|
//
|
|
CloseFaxHandle ( pHandleEntry );
|
|
|
|
SetLastError(dwRes);
|
|
return FALSE;
|
|
} // FaxConnectFaxServer
|
|
|
|
|
|
|
|
#ifdef UNICODE
|
|
BOOL
|
|
WINAPI
|
|
FaxConnectFaxServerA(
|
|
IN LPCSTR lpMachineName OPTIONAL,
|
|
OUT LPHANDLE FaxHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a connection to a FAX server. The binding handle that is
|
|
returned is used for all subsequent FAX API calls.
|
|
|
|
Arguments:
|
|
|
|
MachineName - Machine name, NULL, or "."
|
|
FaxHandle - Pointer to a FAX handle
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure, call GetLastError() for more error information.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWCHAR lpwstrMachineName = NULL;
|
|
BOOL bRes;
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxConnectFaxServerA"));
|
|
|
|
if (lpMachineName)
|
|
{
|
|
//
|
|
// Create Unicode machine name
|
|
//
|
|
lpwstrMachineName = AnsiStringToUnicodeString (lpMachineName);
|
|
if (!lpwstrMachineName)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
bRes = FaxConnectFaxServerW (lpwstrMachineName, FaxHandle);
|
|
MemFree (lpwstrMachineName);
|
|
return bRes;
|
|
} // FaxConnectFaxServerA
|
|
|
|
|
|
|
|
#else
|
|
//
|
|
// When compiling this code to ANSI we do not want to support the Unicode version.
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
FaxConnectFaxServerW(
|
|
IN LPCWSTR lpMachineName OPTIONAL,
|
|
OUT LPHANDLE FaxHandle
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(lpMachineName);
|
|
UNREFERENCED_PARAMETER(FaxHandle);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxGetDeviceStatusW(
|
|
IN const HANDLE FaxHandle,
|
|
OUT PFAX_DEVICE_STATUSW *DeviceStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obtains a status report for the FAX devices being
|
|
used by the FAX server.
|
|
|
|
Arguments:
|
|
|
|
FaxHandle - FAX handle obtained from FaxConnectFaxServer.
|
|
StatusBuffer - Buffer for the status data
|
|
BufferSize - Size of the StatusBuffer
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure, call GetLastError() for more error information.
|
|
|
|
--*/
|
|
|
|
{
|
|
#define FixupString(_s) FixupStringPtrW(DeviceStatus,_s)
|
|
error_status_t ec;
|
|
DWORD BufferSize = 0;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxGetDeviceStatusW"));
|
|
|
|
if (!ValidateFaxHandle(FaxHandle, FHT_PORT)) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
DebugPrintEx(DEBUG_ERR, _T("ValidateFaxHandle() is failed."));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!DeviceStatus) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
DebugPrintEx(DEBUG_ERR, _T("DeviceStatus is NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
*DeviceStatus = NULL;
|
|
|
|
__try
|
|
{
|
|
ec = FAX_GetDeviceStatus(
|
|
FH_PORT_HANDLE(FaxHandle),
|
|
(LPBYTE*)DeviceStatus,
|
|
&BufferSize
|
|
);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we crashed.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_GetDeviceStatus. (ec: %ld)"),
|
|
ec);
|
|
}
|
|
|
|
if (ec)
|
|
{
|
|
DumpRPCExtendedStatus ();
|
|
SetLastError( ec );
|
|
return FALSE;
|
|
}
|
|
|
|
FixupString( (*DeviceStatus)->CallerId );
|
|
FixupString( (*DeviceStatus)->Csid );
|
|
FixupString( (*DeviceStatus)->DeviceName );
|
|
FixupString( (*DeviceStatus)->DocumentName );
|
|
FixupString( (*DeviceStatus)->PhoneNumber );
|
|
FixupString( (*DeviceStatus)->RoutingString );
|
|
FixupString( (*DeviceStatus)->SenderName );
|
|
FixupString( (*DeviceStatus)->RecipientName );
|
|
FixupString( (*DeviceStatus)->StatusString );
|
|
FixupString( (*DeviceStatus)->Tsid );
|
|
FixupString( (*DeviceStatus)->UserName );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxGetDeviceStatusA(
|
|
IN const HANDLE FaxHandle,
|
|
OUT PFAX_DEVICE_STATUSA *DeviceStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obtains a status report for the FAX devices being
|
|
used by the FAX server.
|
|
|
|
Arguments:
|
|
|
|
FaxHandle - FAX handle obtained from FaxConnectFaxServer.
|
|
StatusBuffer - Buffer for the status data
|
|
BufferSize - Size of the StatusBuffer
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure, call GetLastError() for more error information.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// no need to validate parameters, FaxGetDeviceStatusW() will do that
|
|
//
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxGetDeviceStatusA"));
|
|
if (!FaxGetDeviceStatusW( FaxHandle, (PFAX_DEVICE_STATUSW *)DeviceStatus ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->CallerId ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->Csid ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->DeviceName ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->DocumentName ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->PhoneNumber ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->RoutingString ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->SenderName ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->RecipientName ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->StatusString ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->Tsid ) ||
|
|
!ConvertUnicodeStringInPlace( (LPWSTR) (*DeviceStatus)->UserName ))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, _T("ConvertUnicodeStringInPlace failed, ec = %ld."), GetLastError());
|
|
MemFree (*DeviceStatus);
|
|
return FALSE;
|
|
}
|
|
(*DeviceStatus)->SizeOfStruct = sizeof(FAX_DEVICE_STATUSA);
|
|
return TRUE;
|
|
} // FaxGetDeviceStatusA
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxClose(
|
|
IN const HANDLE FaxHandle
|
|
)
|
|
{
|
|
error_status_t ec;
|
|
PHANDLE_ENTRY pHandleEntry = (PHANDLE_ENTRY) FaxHandle;
|
|
HANDLE TmpFaxPortHandle;
|
|
DWORD CanShare;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxClose"));
|
|
|
|
if (!FaxHandle || IsBadReadPtr ((LPVOID)FaxHandle, sizeof (HANDLE_ENTRY)))
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
DebugPrintEx(DEBUG_ERR, _T("!FaxHandle || IsBadReadPtr(FaxHandle)."));
|
|
return FALSE;
|
|
}
|
|
|
|
switch (pHandleEntry->Type)
|
|
{
|
|
case FHT_SERVICE:
|
|
|
|
__try
|
|
{
|
|
ec = FAX_ConnectionRefCount( FH_FAX_HANDLE(FaxHandle), &FH_CONTEXT_HANDLE(FaxHandle), 0, &CanShare );
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we crashed.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_ConnectionRefCount. (ec: %ld)"),
|
|
ec);
|
|
}
|
|
if (ERROR_SUCCESS != ec)
|
|
{
|
|
DumpRPCExtendedStatus ();
|
|
}
|
|
|
|
__try
|
|
{
|
|
ec = FaxClientUnbindFromFaxServer( (RPC_BINDING_HANDLE *) pHandleEntry->FaxData->FaxHandle );
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
ec = GetExceptionCode();
|
|
}
|
|
EnterCriticalSection( &pHandleEntry->FaxData->CsHandleTable );
|
|
//
|
|
// Zero the binding handle so that no further RPC calls will be made with floating handles
|
|
// that still hold the FAX_HANDLE_DATA (e.g. from FaxOpenPort).
|
|
//
|
|
pHandleEntry->FaxData->FaxHandle = 0;
|
|
#if DBG
|
|
if (pHandleEntry->FaxData->dwRefCount > 1)
|
|
{
|
|
//
|
|
// The user closed the binding handle (called FaxClose (hFax)) before closing all context
|
|
// handles (e.g. FaxClose (hPort)).
|
|
// This is not a real problem - the reference count mechanism will take care of it.
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_WRN,
|
|
TEXT("User called FaxClose with a service handle but still has live context handles (port or message enum)"));
|
|
}
|
|
#endif
|
|
LeaveCriticalSection( &pHandleEntry->FaxData->CsHandleTable );
|
|
|
|
CloseFaxHandle ( pHandleEntry );
|
|
return TRUE;
|
|
|
|
case FHT_PORT:
|
|
TmpFaxPortHandle = pHandleEntry->hGeneric;
|
|
CloseFaxHandle( pHandleEntry );
|
|
__try
|
|
{
|
|
ec = FAX_ClosePort( &TmpFaxPortHandle );
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we crashed.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_ClosePort. (ec: %ld)"),
|
|
ec);
|
|
}
|
|
if (ec)
|
|
{
|
|
DumpRPCExtendedStatus ();
|
|
SetLastError( ec );
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxGetSecurityEx(
|
|
IN HANDLE hFaxHandle,
|
|
IN SECURITY_INFORMATION SecurityInformation,
|
|
OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine name : FaxGetSecurityEx
|
|
|
|
Routine description:
|
|
|
|
Gets the server's security descriptor
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Nov, 1999
|
|
|
|
Arguments:
|
|
|
|
hFaxHandle [in ] - Handle to fax server
|
|
SECURITY_INFORMATION [in ] - Defines the desired entries in the security descriptor (Bit wise OR )
|
|
ppSecurityDescriptor [out] - Pointer to receive buffer
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure, call GetLastError() for more error information.
|
|
|
|
--*/
|
|
{
|
|
error_status_t ec;
|
|
DWORD BufferSize = 0;
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxGetSecurityEx"));
|
|
DWORD dwSecInfo = ( OWNER_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION |
|
|
DACL_SECURITY_INFORMATION |
|
|
SACL_SECURITY_INFORMATION );
|
|
|
|
|
|
if (!ValidateFaxHandle(hFaxHandle,FHT_SERVICE))
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
DebugPrintEx(DEBUG_ERR, _T("ValidateFaxHandle() is failed."));
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 == (SecurityInformation & dwSecInfo))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
DebugPrintEx(DEBUG_ERR, _T("SecurityInformation is invalid - No valid bit type indicated"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 != (SecurityInformation & ~dwSecInfo))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
DebugPrintEx(DEBUG_ERR, _T("SecurityInformation is invalid - contains invalid securtiy information bits"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ppSecurityDescriptor)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
DebugPrintEx(DEBUG_ERR, _T("ppSecurityDescriptor is NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
if (FAX_API_VERSION_1 > FH_SERVER_VER(hFaxHandle))
|
|
{
|
|
//
|
|
// Servers of API version 0 don't support FAX_GetSecurityEx
|
|
//
|
|
DebugPrintEx(DEBUG_MSG,
|
|
_T("Server version is %ld - doesn't support FAX_GetSecurityEx."),
|
|
FH_SERVER_VER(hFaxHandle));
|
|
__try
|
|
{
|
|
ec = FAX_GetSecurity (
|
|
FH_FAX_HANDLE(hFaxHandle),
|
|
(LPBYTE *)ppSecurityDescriptor,
|
|
&BufferSize
|
|
);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we got an exception.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_GetSecurity. (ec: %ld)"),
|
|
ec);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
__try
|
|
{
|
|
ec = FAX_GetSecurityEx (
|
|
FH_FAX_HANDLE(hFaxHandle),
|
|
SecurityInformation,
|
|
(LPBYTE *)ppSecurityDescriptor,
|
|
&BufferSize
|
|
);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we got an exception.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_GetSecurityEx. (ec: %ld)"),
|
|
ec);
|
|
}
|
|
}
|
|
if (ERROR_SUCCESS != ec)
|
|
{
|
|
DumpRPCExtendedStatus ();
|
|
SetLastError(ec);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} // FaxGetSecurityEx
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxGetSecurity(
|
|
IN HANDLE hFaxHandle,
|
|
OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine name : FaxGetSecurity
|
|
|
|
Routine description:
|
|
|
|
Gets the server's security descriptor
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Nov, 1999
|
|
|
|
Arguments:
|
|
|
|
hFaxHandle [in ] - Handle to fax server
|
|
ppSecurityDescriptor [out] - Pointer to receive buffer
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure, call GetLastError() for more error information.
|
|
|
|
--*/
|
|
{
|
|
error_status_t ec;
|
|
DWORD BufferSize = 0;
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxGetSecurity"));
|
|
|
|
if (!ValidateFaxHandle(hFaxHandle,FHT_SERVICE))
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
DebugPrintEx(DEBUG_ERR, _T("ValidateFaxHandle() is failed."));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ppSecurityDescriptor)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
DebugPrintEx(DEBUG_ERR, _T("ppSecurityDescriptor is NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
__try
|
|
{
|
|
ec = FAX_GetSecurity (
|
|
FH_FAX_HANDLE(hFaxHandle),
|
|
(LPBYTE *)ppSecurityDescriptor,
|
|
&BufferSize
|
|
);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we got an exception.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_GetSecurity. (ec: %ld)"),
|
|
ec);
|
|
}
|
|
|
|
if (ERROR_SUCCESS != ec)
|
|
{
|
|
DumpRPCExtendedStatus ();
|
|
SetLastError(ec);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
} // FaxGetSecurity
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxSetSecurity(
|
|
IN HANDLE hFaxHandle,
|
|
SECURITY_INFORMATION SecurityInformation,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine name : FaxGetSecurity
|
|
|
|
Routine description:
|
|
|
|
Sets the server's security descriptor
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Nov, 1999
|
|
|
|
Arguments:
|
|
|
|
hFaxHandle [in] - Handle to fax server
|
|
SecurityInformation [in] - Defines the valid entries in the security descriptor (Bit wise OR )
|
|
pSecurityDescriptor [in] - New security descriptor to set.
|
|
Must be self-relative.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure, call GetLastError() for more error information.
|
|
|
|
--*/
|
|
{
|
|
error_status_t ec;
|
|
DWORD dwBufferSize;
|
|
DWORD dwRevision;
|
|
SECURITY_DESCRIPTOR_CONTROL sdControl;
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxSetSecurity"));
|
|
|
|
DWORD dwSecInfo = ( OWNER_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION |
|
|
DACL_SECURITY_INFORMATION |
|
|
SACL_SECURITY_INFORMATION );
|
|
|
|
if (!ValidateFaxHandle(hFaxHandle,FHT_SERVICE))
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
DebugPrintEx(DEBUG_ERR, _T("ValidateFaxHandle() is failed."));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pSecurityDescriptor)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
DebugPrintEx(DEBUG_ERR, _T("pSecurityDescriptor is NULL."));
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 == (SecurityInformation & dwSecInfo))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
DebugPrintEx(DEBUG_ERR, _T("SecurityInformation is invalid - No valid bit type indicated"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 != (SecurityInformation & ~dwSecInfo))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
DebugPrintEx(DEBUG_ERR, _T("SecurityInformation is invalid - contains invalid securtiy information bits"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!IsValidSecurityDescriptor(pSecurityDescriptor))
|
|
{
|
|
SetLastError( ERROR_INVALID_SECURITY_DESCR );
|
|
DebugPrintEx(DEBUG_ERR, _T("Got invalid security descriptor"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetSecurityDescriptorControl (
|
|
pSecurityDescriptor,
|
|
&sdControl,
|
|
&dwRevision
|
|
))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Error on GetSecurityDescriptorControl (ec = %ld)"),
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(sdControl & SE_SELF_RELATIVE))
|
|
{
|
|
//
|
|
// Got a non-self-relative security descriptor - bad!!!
|
|
//
|
|
DebugPrintEx(DEBUG_ERR, _T("Got non-self-relative security descriptor"));
|
|
SetLastError( ERROR_INVALID_SECURITY_DESCR );
|
|
return FALSE;
|
|
}
|
|
|
|
dwBufferSize = GetSecurityDescriptorLength(pSecurityDescriptor);
|
|
|
|
__try
|
|
{
|
|
ec = FAX_SetSecurity(
|
|
FH_FAX_HANDLE(hFaxHandle),
|
|
SecurityInformation,
|
|
(LPBYTE)pSecurityDescriptor,
|
|
dwBufferSize
|
|
);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we got an exception.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("Exception on RPC call to FAX_SetSecurity. (ec: %ld)"),
|
|
ec);
|
|
}
|
|
|
|
if (ec != ERROR_SUCCESS)
|
|
{
|
|
DumpRPCExtendedStatus ();
|
|
SetLastError(ec);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
} // FaxSetSecurity
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxRelease(
|
|
IN const HANDLE FaxHandle
|
|
)
|
|
/*++
|
|
|
|
Routine name : FaxRelease
|
|
|
|
Routine description:
|
|
|
|
The Fax Service counts all the clients connected to it. When this reference count reaches zero,
|
|
the Fax Service can download itself.
|
|
There are some connections that do not want to prevent from the service to download,
|
|
like Task Bar Monitor.
|
|
These clients should call this function.
|
|
It adds the indication on the handle that it is "Released" and decrements the total reference count.
|
|
|
|
Author:
|
|
|
|
Iv Garber (IvG), Jan, 2001
|
|
|
|
Arguments:
|
|
|
|
FaxHandle [in] - the client connection handle that do not want to prevent the service from downloading.
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if operation is successfull, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
error_status_t ec;
|
|
DWORD CanShare;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxRelease"));
|
|
|
|
if (!ValidateFaxHandle(FaxHandle,FHT_SERVICE))
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
DebugPrintEx(DEBUG_ERR, _T("ValidateFaxHandle() is failed."));
|
|
return FALSE;
|
|
}
|
|
if (FAX_API_VERSION_1 > FH_SERVER_VER(FaxHandle))
|
|
{
|
|
//
|
|
// Servers of API version 0 don't support FAX_ConnectionRefCount(...,2,...)
|
|
//
|
|
DebugPrintEx(DEBUG_ERR,
|
|
_T("Server version is %ld - doesn't support this call"),
|
|
FH_SERVER_VER(FaxHandle));
|
|
SetLastError(FAX_ERR_VERSION_MISMATCH);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Decrement the Reference Count
|
|
//
|
|
__try
|
|
{
|
|
ec = FAX_ConnectionRefCount( FH_FAX_HANDLE(FaxHandle), &FH_CONTEXT_HANDLE(FaxHandle), 2, &CanShare );
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
//
|
|
// For some reason we crashed.
|
|
//
|
|
ec = GetExceptionCode();
|
|
DebugPrintEx(DEBUG_ERR, _T("Exception on RPC call to FAX_ConnectionRefCount. (ec: %ld)"), ec);
|
|
}
|
|
|
|
if (ec != ERROR_SUCCESS)
|
|
{
|
|
DumpRPCExtendedStatus ();
|
|
SetLastError(ec);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
WINFAXAPI
|
|
BOOL
|
|
WINAPI
|
|
FaxGetReportedServerAPIVersion (
|
|
IN HANDLE hFaxHandle,
|
|
OUT LPDWORD lpdwReportedServerAPIVersion
|
|
)
|
|
/*++
|
|
|
|
Routine name : FaxGetReportedServerAPIVersion
|
|
|
|
Routine description:
|
|
|
|
Extracts the reported (non-filtered) fax server API version from an active connection handle
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Mar, 2001
|
|
|
|
Arguments:
|
|
|
|
hFaxHandle [in] - Connection handle
|
|
lpdwReportedServerAPIVersion [out] - Fax server API version
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if operation is successfull, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxGetReportedServerAPIVersion"));
|
|
|
|
if (!ValidateFaxHandle(hFaxHandle, FHT_SERVICE))
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
DebugPrintEx(DEBUG_ERR, _T("ValidateFaxHandle() is failed."));
|
|
return FALSE;
|
|
}
|
|
*lpdwReportedServerAPIVersion = FH_REPORTED_SERVER_VER(hFaxHandle);
|
|
return TRUE;
|
|
} // FaxGetReportedServerAPIVersion
|