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.
7530 lines
212 KiB
7530 lines
212 KiB
/*************************************************************************
|
|
*
|
|
* winsta.c
|
|
*
|
|
* Client side APIs for window stations objects
|
|
*
|
|
* Copyright Microsoft Corporation, 1998
|
|
*
|
|
*************************************************************************/
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntddkbd.h>
|
|
#include <ntddmou.h>
|
|
#include <windows.h>
|
|
#include <winbase.h>
|
|
#include <winerror.h>
|
|
#include <allproc.h>
|
|
|
|
#include <winsta.h>
|
|
#include <winwlx.h>
|
|
#include <malloc.h>
|
|
#include <stdio.h>
|
|
#include <dbt.h>
|
|
#include <lm.h>
|
|
|
|
/*
|
|
* Include the RPC generated common header
|
|
*/
|
|
|
|
#include "tsrpc.h"
|
|
|
|
#include "rpcwire.h"
|
|
|
|
#ifdef NTSDDEBUG
|
|
#define NTSDDBGPRINT(x) DbgPrint x
|
|
#else
|
|
#define NTSDDBGPRINT(x)
|
|
#endif
|
|
|
|
#if DBG
|
|
#define VERIFY(x) ASSERT(x) // we already have ASSERT;
|
|
#else
|
|
#define VERIFY(x) (x)
|
|
#endif
|
|
|
|
|
|
#if DBG
|
|
ULONG
|
|
DbgPrint(
|
|
PCH Format,
|
|
...
|
|
);
|
|
#define DBGPRINT(x) DbgPrint x
|
|
#if DBGTRACE
|
|
#define TRACE0(x) DbgPrint x
|
|
#define TRACE1(x) DbgPrint x
|
|
#else
|
|
#define TRACE0(x)
|
|
#define TRACE1(x)
|
|
#endif
|
|
#else
|
|
#define DBGPRINT(x)
|
|
#define TRACE0(x)
|
|
#define TRACE1(x)
|
|
#endif
|
|
|
|
/*
|
|
* This handle is returned when there is no terminal
|
|
* server present on the system. (Non-Hydra)
|
|
*/
|
|
#define RPC_HANDLE_NO_SERVER (HANDLE)IntToPtr( 0xFFFFFFFD )
|
|
|
|
|
|
/*
|
|
* Private Procedures defined here
|
|
*/
|
|
|
|
BOOLEAN DllInitialize(IN PVOID, IN ULONG, IN PCONTEXT OPTIONAL);
|
|
|
|
RPC_STATUS
|
|
RpcWinStationBind(
|
|
LPWSTR pszUuid,
|
|
LPWSTR pszProtocolSequence,
|
|
LPWSTR pszNetworkAddress,
|
|
LPWSTR pszEndPoint,
|
|
LPWSTR pszOptions,
|
|
RPC_BINDING_HANDLE *pHandle
|
|
);
|
|
|
|
RPC_STATUS
|
|
RpcWinStationBindSecure(
|
|
LPWSTR pszUuid,
|
|
LPWSTR pszProtocolSequence,
|
|
LPWSTR pszNetworkAddress,
|
|
LPWSTR pszEndPoint,
|
|
LPWSTR pszOptions,
|
|
RPC_BINDING_HANDLE *pHandle
|
|
);
|
|
|
|
BOOLEAN
|
|
RpcLocalAutoBind(
|
|
VOID
|
|
);
|
|
|
|
/*
|
|
* Global data
|
|
*/
|
|
|
|
// Critical section to protect the handlelist from multiple threads
|
|
RTL_CRITICAL_SECTION WstHandleLock;
|
|
|
|
/*
|
|
* RPC program identifier and security options
|
|
*/
|
|
LPWSTR pszUuid = L"5ca4a760-ebb1-11cf-8611-00a0245420ed"; // From ICAAPI.IDL
|
|
LPWSTR pszOptions = L"Security=Impersonation Dynamic False";
|
|
|
|
/*
|
|
* RPC over LPC binding information
|
|
*/
|
|
LPWSTR pszProtocolSequence = L"ncalrpc"; // RPC over LPC
|
|
LPWSTR pszEndPoint = L"IcaApi";
|
|
|
|
/*
|
|
* RPC over named pipes binding information
|
|
*/
|
|
LPWSTR pszRemoteProtocolSequence = L"ncacn_np"; // RPC over Named pipes
|
|
LPWSTR pszRemoteEndPoint = L"\\pipe\\Ctx_WinStation_API_service";
|
|
|
|
|
|
/*
|
|
* other internal Procedures used (not defined here)
|
|
*/
|
|
VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
|
|
VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
|
|
VOID PdConfig2U2A( PPDCONFIG2A, PPDCONFIG2W );
|
|
VOID PdConfig2A2U( PPDCONFIG2W, PPDCONFIG2A );
|
|
VOID PdParamsU2A( PPDPARAMSA, PPDPARAMSW );
|
|
VOID PdParamsA2U( PPDPARAMSW, PPDPARAMSA );
|
|
VOID WdConfigU2A( PWDCONFIGA, PWDCONFIGW );
|
|
VOID WdConfigA2U( PWDCONFIGW, PWDCONFIGA );
|
|
VOID WinStationCreateU2A( PWINSTATIONCREATEA, PWINSTATIONCREATEW );
|
|
VOID WinStationCreateA2U( PWINSTATIONCREATEW, PWINSTATIONCREATEA );
|
|
VOID WinStationConfigU2A( PWINSTATIONCONFIGA, PWINSTATIONCONFIGW );
|
|
VOID WinStationConfigA2U( PWINSTATIONCONFIGW, PWINSTATIONCONFIGA );
|
|
VOID WinStationPrinterU2A( PWINSTATIONPRINTERA, PWINSTATIONPRINTERW );
|
|
VOID WinStationPrinterA2U( PWINSTATIONPRINTERW, PWINSTATIONPRINTERA );
|
|
VOID WinStationInformationU2A( PWINSTATIONINFORMATIONA,
|
|
PWINSTATIONINFORMATIONW );
|
|
VOID WinStationInformationA2U( PWINSTATIONINFORMATIONW,
|
|
PWINSTATIONINFORMATIONA );
|
|
VOID WinStationClientU2A( PWINSTATIONCLIENTA, PWINSTATIONCLIENTW );
|
|
VOID WinStationProductIdU2A( PWINSTATIONPRODIDA, PWINSTATIONPRODIDW );
|
|
|
|
ULONG CheckUserBuffer(WINSTATIONINFOCLASS,
|
|
PVOID,
|
|
ULONG,
|
|
PVOID *,
|
|
PULONG,
|
|
BOOLEAN *);
|
|
BOOLEAN CloseContextHandle(HANDLE *pHandle, DWORD *pdwResult);
|
|
|
|
/*
|
|
* Check to see that caller does not hold the loader critsec.
|
|
* WinStation APIs must NOT be called while holding the loader critsec
|
|
* since deadlock may occur.
|
|
*/
|
|
#define CheckLoaderLock() \
|
|
ASSERT( NtCurrentTeb()->ClientId.UniqueThread != \
|
|
((PRTL_CRITICAL_SECTION)(NtCurrentPeb()->LoaderLock))->OwningThread );
|
|
|
|
|
|
/*
|
|
* Handle the SERVERNAME_CURRENT for auto local binding.
|
|
*/
|
|
#define HANDLE_CURRENT_BINDING( hServer ) \
|
|
CheckLoaderLock(); \
|
|
if( hServer == SERVERNAME_CURRENT ) { \
|
|
if( IcaApi_IfHandle == NULL ) { \
|
|
if( !RpcLocalAutoBind() ) { \
|
|
return FALSE; \
|
|
} \
|
|
} \
|
|
hServer = IcaApi_IfHandle; \
|
|
} \
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) { \
|
|
SetLastError( ERROR_APP_WRONG_OS ); \
|
|
return FALSE; \
|
|
}
|
|
|
|
|
|
#define HANDLE_CURRENT_BINDING_BUFFER( hServer, pBuffer ) \
|
|
CheckLoaderLock(); \
|
|
if( hServer == SERVERNAME_CURRENT ) { \
|
|
if( IcaApi_IfHandle == NULL ) { \
|
|
if( !RpcLocalAutoBind() ) { \
|
|
if (pBuffer != NULL) { \
|
|
LocalFree(pBuffer); \
|
|
} \
|
|
return FALSE; \
|
|
} \
|
|
} \
|
|
hServer = IcaApi_IfHandle; \
|
|
} \
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) { \
|
|
if (pBuffer != NULL) { \
|
|
LocalFree(pBuffer); \
|
|
} \
|
|
SetLastError( ERROR_APP_WRONG_OS ); \
|
|
return FALSE; \
|
|
}
|
|
|
|
|
|
/*
|
|
* Handle the SERVERNAME_CURRENT for auto local binding that
|
|
* allows the RPC_HANDLE_NO_SERVER handle.
|
|
*/
|
|
#define HANDLE_CURRENT_BINDING_NO_SERVER( hServer ) \
|
|
CheckLoaderLock(); \
|
|
if( hServer == SERVERNAME_CURRENT ) { \
|
|
if( IcaApi_IfHandle == NULL ) { \
|
|
if( !RpcLocalAutoBind() ) { \
|
|
return FALSE; \
|
|
} \
|
|
} \
|
|
hServer = IcaApi_IfHandle; \
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* DllInitialize
|
|
*
|
|
* Function is called when the DLL is loaded. The only work we do here
|
|
* is initialize our CriticalSection.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* DllHandle
|
|
* Loaded handle to our DLL image
|
|
*
|
|
* Reason
|
|
* Reason for notifying us
|
|
*
|
|
* Context
|
|
* Reason specific parameter from NT
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN
|
|
DllInitialize(
|
|
IN PVOID DllHandle,
|
|
IN ULONG Reason,
|
|
IN PCONTEXT Context OPTIONAL
|
|
)
|
|
{
|
|
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
RPC_STATUS Status;
|
|
BOOLEAN Success;
|
|
NTSTATUS ntStatus;
|
|
static BOOLEAN sbIniOK = FALSE;
|
|
|
|
(VOID)Context;
|
|
|
|
Success = TRUE;
|
|
|
|
switch ( Reason ) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
|
|
/*
|
|
// some instrumentation for catching the bug #
|
|
// 145378 TRACKING: Winsta.dll getting loaded into csrss
|
|
|
|
DBGPRINT(("Checking if winsta is being loaded into csrss.exe\n"));
|
|
if(NULL != wcsstr(GetCommandLine(), TEXT("csrss.exe")))
|
|
{
|
|
DBGPRINT(("**** will break because csrss.exe loaded winsta.dll ***** \n"));
|
|
DebugBreak();
|
|
}
|
|
*/
|
|
ntStatus = RtlInitializeCriticalSection( &WstHandleLock );
|
|
IcaApi_IfHandle = NULL;
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
Success = FALSE;
|
|
}else {
|
|
sbIniOK = TRUE;
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
if (sbIniOK) {
|
|
|
|
if( (IcaApi_IfHandle != NULL) && (IcaApi_IfHandle != RPC_HANDLE_NO_SERVER) )
|
|
{
|
|
HANDLE hTmp = InterlockedExchangePointer(&IcaApi_IfHandle,NULL);
|
|
if( hTmp && !IcaApi_IfHandle )
|
|
{
|
|
|
|
//
|
|
// making RPC call in DLL_PROCESS_DETACH is bad.
|
|
// threrefore we cannot do CloseContextHandle(&hTmp, &Result);
|
|
// lets just call RpcSsDestroyClientContext, which will cause
|
|
// rundown to run at server end.
|
|
|
|
RpcTryExcept {
|
|
|
|
RpcSsDestroyClientContext(&hTmp);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
ASSERT(FALSE);
|
|
}
|
|
RpcEndExcept
|
|
|
|
}
|
|
}
|
|
|
|
RtlDeleteCriticalSection( &WstHandleLock );
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* RpcWinStationBind
|
|
*
|
|
* Perform the RPC binding sequence.
|
|
*
|
|
* This is an internal function.
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
RPC_STATUS
|
|
RpcWinStationBind(
|
|
LPWSTR pszUuid,
|
|
LPWSTR pszProtocolSequence,
|
|
LPWSTR pszNetworkAddress,
|
|
LPWSTR pszEndPoint,
|
|
LPWSTR pszOptions,
|
|
RPC_BINDING_HANDLE *pHandle
|
|
)
|
|
{
|
|
RPC_STATUS Status;
|
|
LPWSTR pszString = NULL;
|
|
|
|
/*
|
|
* Compose the binding string using the helper routine
|
|
* and our protocol sequence, security options, UUID, etc.
|
|
*/
|
|
Status = RpcStringBindingCompose(
|
|
pszUuid,
|
|
pszProtocolSequence,
|
|
pszNetworkAddress,
|
|
pszEndPoint,
|
|
pszOptions,
|
|
&pszString
|
|
);
|
|
|
|
if( Status != RPC_S_OK ) {
|
|
DBGPRINT(("Error %d in RpcStringBindingCompose\n",Status));
|
|
return( Status );
|
|
}
|
|
|
|
/*
|
|
* Now generate the RPC binding from the cononical RPC
|
|
* binding string.
|
|
*/
|
|
Status = RpcBindingFromStringBinding(
|
|
pszString,
|
|
pHandle
|
|
);
|
|
|
|
if( Status != RPC_S_OK ) {
|
|
DBGPRINT(("Error %d in RpcBindingFromStringBinding\n",Status));
|
|
RpcStringFree( &pszString );
|
|
return( Status );
|
|
}
|
|
|
|
/*
|
|
* Free the memory returned from RpcStringBindingCompose()
|
|
*/
|
|
RpcStringFree( &pszString );
|
|
|
|
return( Status );
|
|
}
|
|
|
|
BOOL
|
|
PrepareServerSPN(
|
|
LPWSTR pszNetworkAddress,
|
|
LPWSTR *wszServerSPN)
|
|
{
|
|
PWKSTA_INFO_100 pwi;
|
|
NET_API_STATUS net_status;
|
|
LPWSTR wszTemplate = L"%s\\%s$";
|
|
*wszServerSPN = NULL;
|
|
|
|
net_status = NetWkstaGetInfo(
|
|
pszNetworkAddress,
|
|
100,
|
|
(LPBYTE *)&pwi);
|
|
|
|
if(net_status == NERR_Success)
|
|
{
|
|
if(pwi->wki100_computername &&
|
|
pwi->wki100_langroup)
|
|
{
|
|
*wszServerSPN = (LPWSTR)LocalAlloc(LPTR,
|
|
(wcslen(wszTemplate)+wcslen(pwi->wki100_computername)+wcslen(pwi->wki100_langroup))*sizeof(WCHAR));
|
|
|
|
if(*wszServerSPN)
|
|
{
|
|
swprintf(*wszServerSPN, wszTemplate, pwi->wki100_langroup, pwi->wki100_computername);
|
|
NetApiBufferFree(pwi);
|
|
return TRUE;
|
|
}
|
|
}
|
|
NetApiBufferFree(pwi);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* RpcWinStationBindSecure
|
|
*
|
|
* Performs the RPC binding sequence.
|
|
* It also specifies authentication level and SSP used.
|
|
*
|
|
* This is an internal function.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
RPC_STATUS
|
|
RpcWinStationBindSecure(
|
|
LPWSTR pszUuid,
|
|
LPWSTR pszProtocolSequence,
|
|
LPWSTR pszNetworkAddress,
|
|
LPWSTR pszEndPoint,
|
|
LPWSTR pszOptions,
|
|
RPC_BINDING_HANDLE *pHandle
|
|
)
|
|
{
|
|
RPC_STATUS Status;
|
|
RPC_SECURITY_QOS qos;
|
|
LPWSTR wszServerSPN = NULL;
|
|
|
|
Status = RpcWinStationBind(
|
|
pszUuid,
|
|
pszProtocolSequence,
|
|
pszNetworkAddress,
|
|
pszEndPoint,
|
|
pszOptions,
|
|
pHandle);
|
|
|
|
if( Status != RPC_S_OK ) {
|
|
DBGPRINT(("Error %d in RpcWinStationBind\n",Status));
|
|
return Status;
|
|
}
|
|
|
|
qos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
|
|
qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
|
|
qos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
|
|
qos.Version = RPC_C_SECURITY_QOS_VERSION;
|
|
|
|
if(PrepareServerSPN(pszNetworkAddress,&wszServerSPN))
|
|
{
|
|
Status = RpcBindingSetAuthInfoEx(
|
|
*pHandle,
|
|
wszServerSPN,
|
|
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_AUTHN_GSS_NEGOTIATE,
|
|
NULL,
|
|
RPC_C_AUTHZ_NAME,
|
|
&qos);
|
|
|
|
LocalFree(wszServerSPN);
|
|
}
|
|
else
|
|
{
|
|
Status = RpcBindingSetAuthInfoEx(
|
|
*pHandle,
|
|
pszNetworkAddress,
|
|
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_AUTHN_GSS_NEGOTIATE,
|
|
NULL,
|
|
RPC_C_AUTHZ_NAME,
|
|
&qos);
|
|
}
|
|
|
|
if(Status != RPC_S_OK)
|
|
{
|
|
DBGPRINT(("Error %d in RpcBindingSetAuthInfoEx\n",Status));
|
|
RpcBindingFree(pHandle);
|
|
return Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationOpenLocalServer (Private)
|
|
*
|
|
* Connect to the local RPC over LPC server for WINSTATION API's.
|
|
*
|
|
* On non-terminal server machines, it returns a handle that allows
|
|
* a subset of the DLL's functions to operate locally.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
*
|
|
****************************************************************************/
|
|
|
|
HANDLE WINAPI
|
|
WinStationOpenLocalServer(
|
|
)
|
|
{
|
|
RPC_STATUS Status;
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
RPC_BINDING_HANDLE RpcHandle;
|
|
HANDLE ContextHandle;
|
|
RPC_SECURITY_QOS RpcSecQos;
|
|
|
|
if( !(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer)) ) {
|
|
return( RPC_HANDLE_NO_SERVER );
|
|
}
|
|
|
|
/*
|
|
* Do the RPC bind to the local server.
|
|
*
|
|
* We use explict binding handles since we want
|
|
* to allow a single application to talk to multiple
|
|
* WinFrame servers at a time.
|
|
*
|
|
* NOTE: We use the auto handle from the .ACF file
|
|
* for our local connections.
|
|
*/
|
|
Status = RpcWinStationBind(
|
|
NULL,
|
|
pszProtocolSequence,
|
|
NULL, // ServerName
|
|
pszEndPoint,
|
|
pszOptions,
|
|
&RpcHandle
|
|
);
|
|
|
|
if( Status != RPC_S_OK ) {
|
|
SetLastError( RtlNtStatusToDosError(RPC_NT_SERVER_UNAVAILABLE) );
|
|
return( NULL );
|
|
}
|
|
|
|
//
|
|
//Demand mutual authentication
|
|
//We only want to work with service running by LocalSystem
|
|
//
|
|
RpcSecQos.Capabilities= RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
|
|
RpcSecQos.IdentityTracking= RPC_C_QOS_IDENTITY_DYNAMIC;
|
|
RpcSecQos.ImpersonationType= RPC_C_IMP_LEVEL_IMPERSONATE;
|
|
RpcSecQos.Version= RPC_C_SECURITY_QOS_VERSION;
|
|
|
|
Status= RpcBindingSetAuthInfoExW(RpcHandle,
|
|
L"NT AUTHORITY\\SYSTEM",
|
|
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_AUTHN_WINNT,
|
|
NULL,
|
|
RPC_C_AUTHZ_NONE,
|
|
&RpcSecQos);
|
|
if( Status != RPC_S_OK ) {
|
|
RpcBindingFree( &RpcHandle );
|
|
SetLastError( Status );
|
|
DBGPRINT(("RpcBindingSetAuthInfoExW failed %d\n", Status));
|
|
return( NULL );
|
|
}
|
|
|
|
//
|
|
// Get a context handle from the server so it can
|
|
// manage the connections state
|
|
//
|
|
// NOTE: This can fail due to authentication failure.
|
|
//
|
|
RpcTryExcept {
|
|
rc = RpcWinStationOpenServer( RpcHandle, &Result, &ContextHandle );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
rc = FALSE;
|
|
#if DBG
|
|
if ( Result != RPC_S_SERVER_UNAVAILABLE ) {
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
}
|
|
#endif
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( rc ) {
|
|
//
|
|
// Close the server binding handle now that we
|
|
// have a client specific context handle
|
|
//
|
|
RpcBindingFree( &RpcHandle );
|
|
|
|
return( (HANDLE)ContextHandle );
|
|
}
|
|
else {
|
|
#if DBG
|
|
if ( Result != RPC_S_SERVER_UNAVAILABLE ) {
|
|
DBGPRINT(("WinStationOpenLocalServer: Error %d getting context handle\n",Result));
|
|
}
|
|
#endif
|
|
|
|
RpcBindingFree( &RpcHandle );
|
|
|
|
SetLastError( Result );
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* RpcLocalAutoBind
|
|
*
|
|
* Handle auto binding to the local server.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
* TRUE - Success
|
|
* FALSE - Error, Use GetLastError() to retrieve reason.
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN
|
|
RpcLocalAutoBind(void)
|
|
{
|
|
if( IcaApi_IfHandle == NULL ) {
|
|
|
|
DWORD Result;
|
|
HANDLE hTmp = WinStationOpenLocalServer();
|
|
|
|
if( hTmp == NULL ) {
|
|
SetLastError( RPC_S_INVALID_BINDING );
|
|
return( FALSE );
|
|
}
|
|
|
|
InterlockedCompareExchangePointer(&IcaApi_IfHandle,hTmp,NULL);
|
|
|
|
if(IcaApi_IfHandle != hTmp) {
|
|
CloseContextHandle(&hTmp, &Result);
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationOpenServerA
|
|
*
|
|
* Connect to a WinFrame computer in order to issue
|
|
* ICA API's
|
|
*
|
|
* NULL for machine name means local system.
|
|
*
|
|
* ENTRY:
|
|
* Machine (input)
|
|
* Name of WinFrame computer to connect to
|
|
*
|
|
* EXIT:
|
|
* handle to server (or NULL on error)
|
|
*
|
|
****************************************************************************/
|
|
|
|
HANDLE WINAPI
|
|
WinStationOpenServerA(
|
|
LPSTR pServerName
|
|
)
|
|
{
|
|
HANDLE hServer;
|
|
ULONG NameLength;
|
|
PWCHAR pServerNameW = NULL;
|
|
|
|
if( pServerName == NULL ) {
|
|
return( WinStationOpenServerW( NULL ) );
|
|
}
|
|
|
|
NameLength = strlen( pServerName ) + 1;
|
|
|
|
pServerNameW = LocalAlloc( 0, NameLength * sizeof(WCHAR) );
|
|
if( pServerNameW == NULL ) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
return( NULL );
|
|
}
|
|
|
|
AnsiToUnicode( pServerNameW, NameLength*sizeof(WCHAR), pServerName );
|
|
|
|
hServer = WinStationOpenServerW( pServerNameW );
|
|
|
|
LocalFree( pServerNameW );
|
|
|
|
return( hServer );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationOpenServerW
|
|
*
|
|
* Connect to a WinFrame computer in order to issue
|
|
* ICA API's
|
|
*
|
|
* NULL for machine name means local system.
|
|
*
|
|
* ENTRY:
|
|
* Machine (input)
|
|
* Name of WinFrame computer to connect to
|
|
*
|
|
* EXIT:
|
|
* handle to server (or NULL on error)
|
|
*
|
|
****************************************************************************/
|
|
|
|
HANDLE WINAPI
|
|
WinStationOpenServerW(
|
|
LPWSTR pServerName
|
|
)
|
|
{
|
|
DWORD Result = ERROR_ACCESS_DENIED;
|
|
BOOLEAN rc;
|
|
RPC_STATUS Status;
|
|
RPC_BINDING_HANDLE RpcHandle;
|
|
HANDLE ContextHandle;
|
|
BOOL bTryAgain = TRUE;
|
|
/*
|
|
* If the server name is NULL, attempt to open
|
|
* the local machines ICA server over LPC.
|
|
*/
|
|
if( pServerName == NULL ) {
|
|
return( WinStationOpenLocalServer() );
|
|
}
|
|
|
|
/*
|
|
* Do the RPC bind to the server.
|
|
*
|
|
* We use explict binding handles since we want
|
|
* to allow a single application to talk to multiple
|
|
* WinFrame servers at a time.
|
|
*/
|
|
Status = RpcWinStationBindSecure(
|
|
pszUuid,
|
|
pszRemoteProtocolSequence,
|
|
pServerName,
|
|
pszRemoteEndPoint,
|
|
pszOptions,
|
|
&RpcHandle
|
|
);
|
|
|
|
if( Status != RPC_S_OK ) {
|
|
SetLastError( RtlNtStatusToDosError(RPC_NT_SERVER_UNAVAILABLE) );
|
|
return( NULL );
|
|
}
|
|
|
|
for(;;)
|
|
{
|
|
//
|
|
// Get a context handle from the server so it can
|
|
// manage the connections state
|
|
//
|
|
// NOTE: This can fail due to authentication failure.
|
|
//
|
|
RpcTryExcept {
|
|
rc = RpcWinStationOpenServer( RpcHandle, &Result, &ContextHandle );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
rc = FALSE;
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
}
|
|
RpcEndExcept
|
|
|
|
//
|
|
// Close the server binding handle now that we
|
|
// have a client specific context handle
|
|
//
|
|
RpcBindingFree( &RpcHandle );
|
|
|
|
//RPC_S_UNKNOWN_AUTHN_SERVICE - it's an old server and does not use Kerberos
|
|
//for authentication
|
|
//We get ERROR_ACCESS_DENIED if the client runs under wrong (local) user account,
|
|
//but we can still succeed if we drop authentication if we have a net session
|
|
//opened on the target computer
|
|
if( !rc &&
|
|
(Result == RPC_S_UNKNOWN_AUTHN_SERVICE || Result == ERROR_ACCESS_DENIED) &&
|
|
bTryAgain ) {
|
|
|
|
bTryAgain = FALSE;
|
|
|
|
//Try again with no security set
|
|
Status = RpcWinStationBind(
|
|
pszUuid,
|
|
pszRemoteProtocolSequence,
|
|
pServerName,
|
|
pszRemoteEndPoint,
|
|
pszOptions,
|
|
&RpcHandle
|
|
);
|
|
|
|
if(Status == RPC_S_OK){
|
|
DBGPRINT(("Using nonsecure connection!!!\n"));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if( rc ) {
|
|
return( (HANDLE)ContextHandle );
|
|
}
|
|
else {
|
|
DBGPRINT(("WinStationOpenServerW: Error %d getting context handle\n",Result));
|
|
SetLastError( Result );
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationCloseServer
|
|
*
|
|
* Close a connection to a WinFrame computer.
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Handle to close
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationCloseServer(
|
|
HANDLE hServer
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
//
|
|
// Do not close the implicit handles
|
|
//
|
|
if( (hServer == IcaApi_IfHandle) ||
|
|
(hServer == RPC_HANDLE_NO_SERVER) ) {
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//
|
|
// Send the close to the remote side so it clean
|
|
// cleanup its context
|
|
//
|
|
rc = CloseContextHandle(&hServer, &Result);
|
|
|
|
if( rc ) {
|
|
return( TRUE );
|
|
}
|
|
else {
|
|
DBGPRINT(("WinStationCloseServer: Error %d closing context handle\n",Result));
|
|
SetLastError( Result );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* MIDL_user_allocate
|
|
*
|
|
* Handles RPC's allocation of argument data structures
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
void __RPC_FAR * __RPC_USER
|
|
MIDL_user_allocate(
|
|
size_t Size
|
|
)
|
|
{
|
|
return( LocalAlloc(LMEM_FIXED,Size) );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* MIDL_user_allocate
|
|
*
|
|
* Handles RPC's de-allocation of argument data structures
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
void __RPC_USER
|
|
MIDL_user_free(
|
|
void __RPC_FAR *p
|
|
)
|
|
{
|
|
LocalFree( p );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationServerPing
|
|
*
|
|
* Ping the given WinFrame server handle to see if it is still up.
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Open RPC server handle
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationServerPing(
|
|
HANDLE hServer
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
/*
|
|
* Do the RPC
|
|
*
|
|
* NOTE: This must be done under an RPC exception handler,
|
|
* since the RPC runtime code throws exceptions if
|
|
* network errors occur, or the server can not be
|
|
* reached.
|
|
*/
|
|
RpcTryExcept {
|
|
|
|
rc = RpcIcaServerPing(
|
|
hServer,
|
|
&Result
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
|
|
TRACE0(("RpcIcaServerPing rc 0x%x, Result 0x%x\n",rc, Result));
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationEnumerateA (ANSI stub)
|
|
*
|
|
* Returns a list of window station objects.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationEnumerateW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationEnumerateW, plus
|
|
*
|
|
* ERROR_NOT_ENOUGH_MEMORY - the LocalAlloc failed
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationEnumerateA(
|
|
HANDLE hServer,
|
|
PLOGONIDA *ppLogonId,
|
|
PULONG pEntries
|
|
)
|
|
{
|
|
PLOGONIDW pLogonIdW, pLogonIdBaseW;
|
|
PLOGONIDA pLogonIdA;
|
|
BOOLEAN Status;
|
|
ULONG Count;
|
|
|
|
/*
|
|
* Call UNICODE WinStationEnumerateW first.
|
|
*/
|
|
*pEntries = 0;
|
|
*ppLogonId = NULL;
|
|
Status = WinStationEnumerateW( hServer, &pLogonIdBaseW, &Count );
|
|
if ( !Status )
|
|
goto badenumerate;
|
|
|
|
/*
|
|
* Allocate buffer and perform conversion from UNICODE to ANSI.
|
|
*/
|
|
if ( !(pLogonIdA = (PLOGONIDA)LocalAlloc( 0, Count * sizeof(LOGONIDA) )) ) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
Status = FALSE;
|
|
goto nomemory;
|
|
}
|
|
|
|
*pEntries = Count;
|
|
*ppLogonId = pLogonIdA;
|
|
|
|
for ( pLogonIdW = pLogonIdBaseW; Count; Count-- ) {
|
|
|
|
pLogonIdA->LogonId = pLogonIdW->LogonId;
|
|
|
|
UnicodeToAnsi( pLogonIdA->WinStationName,
|
|
sizeof(WINSTATIONNAMEA),
|
|
pLogonIdW->WinStationName );
|
|
|
|
pLogonIdA->State = pLogonIdW->State;
|
|
|
|
pLogonIdA++;
|
|
pLogonIdW++;
|
|
}
|
|
|
|
nomemory:
|
|
/*
|
|
* Free the UNICODE enumerate buffer.
|
|
*/
|
|
WinStationFreeMemory( pLogonIdBaseW );
|
|
|
|
badenumerate:
|
|
return(Status);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationEnumerateW (UNICODE)
|
|
*
|
|
* Returns a list of window station objects.
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* ppLogonId (output)
|
|
* Points to a pointer to a buffer to receive the enumeration results,
|
|
* which are returned as an array of LOGONID structures. The buffer is
|
|
* allocated within this API and is disposed of using
|
|
* WinStationFreeMemory.
|
|
* pEntries (output)
|
|
* Points to a variable specifying the number of entries read.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The enumerate operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationEnumerateW(
|
|
HANDLE hServer,
|
|
PLOGONIDW *ppLogonId,
|
|
PULONG pEntries
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
ULONG LogonIdCount = 50;
|
|
PLOGONIDW pLogonId, pLogonIdTemp;
|
|
ULONG Length;
|
|
ULONG Index = 0;
|
|
ULONG ByteCount = 0;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
*pEntries = 0;
|
|
*ppLogonId = NULL;
|
|
Length = LogonIdCount * sizeof(LOGONIDW);
|
|
if ( !(pLogonId = (PLOGONIDW)LocalAlloc( 0, Length)) ) {
|
|
Result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto nomemexit;
|
|
}
|
|
|
|
/*
|
|
* get list of all WinStations
|
|
*/
|
|
for (;;) {
|
|
|
|
if ( Index ) {
|
|
|
|
ByteCount = *pEntries * sizeof(LOGONIDW);
|
|
*pEntries += LogonIdCount;
|
|
if ( !(pLogonIdTemp = (PSESSIONIDW)LocalAlloc( 0,
|
|
(*pEntries * sizeof(LOGONIDW)))) ) {
|
|
|
|
Result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto errexit;
|
|
}
|
|
|
|
if ( *ppLogonId ) {
|
|
|
|
MoveMemory( pLogonIdTemp, *ppLogonId, ByteCount );
|
|
LocalFree(*ppLogonId);
|
|
}
|
|
|
|
MoveMemory( ((PBYTE)pLogonIdTemp + ByteCount), pLogonId,
|
|
(LogonIdCount * sizeof(LOGONIDW)) );
|
|
*ppLogonId = pLogonIdTemp;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationEnumerate(
|
|
hServer,
|
|
&Result,
|
|
&LogonIdCount,
|
|
(PCHAR)pLogonId,
|
|
&Length,
|
|
&Index
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if ( Result == ERROR_NO_MORE_ITEMS) {
|
|
Result = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
goto nomemexit;
|
|
}
|
|
RpcEndExcept
|
|
}
|
|
|
|
errexit:
|
|
LocalFree( pLogonId );
|
|
|
|
nomemexit:
|
|
if ( Result ) {
|
|
|
|
if ( *ppLogonId ) {
|
|
|
|
LocalFree( *ppLogonId );
|
|
*ppLogonId = NULL;
|
|
}
|
|
|
|
SetLastError(Result);
|
|
return(FALSE);
|
|
|
|
} else {
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationEnumerate_IndexedA (ANSI stub)
|
|
*
|
|
* Returns a list of window station objects (multi-call indexed).
|
|
*
|
|
* NOTE: this API used to be WinStationEnumerateA in WinFrame 1.6 and
|
|
* earlier. It is provided now for backward compatibility with
|
|
* Citrix code built around the indexed enumeration procedure.
|
|
* New code should use the WinStationEnumerateA call.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationEnumerate_IndexedW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationEnumerate_IndexedW, plus
|
|
*
|
|
* ERROR_NOT_ENOUGH_MEMORY - the LocalAlloc failed
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationEnumerate_IndexedA(
|
|
HANDLE hServer,
|
|
PULONG pEntries,
|
|
PLOGONIDA pLogonId,
|
|
PULONG pByteCount,
|
|
PULONG pIndex
|
|
)
|
|
{
|
|
PLOGONIDW pBuffer = NULL, pLogonIdW;
|
|
BOOLEAN Status;
|
|
ULONG Count, ByteCountW = (*pByteCount << 1);
|
|
|
|
/*
|
|
* If the caller supplied a buffer and the length is not 0,
|
|
* allocate a corresponding (*2) buffer for UNICODE strings.
|
|
*/
|
|
if ( pLogonId && ByteCountW ) {
|
|
if ( !(pBuffer = LocalAlloc(0, ByteCountW)) ) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Enumerate WinStations
|
|
*/
|
|
pLogonIdW = pBuffer;
|
|
Status = WinStationEnumerate_IndexedW( hServer, pEntries, pLogonIdW,
|
|
&ByteCountW, pIndex );
|
|
|
|
/*
|
|
* Always /2 the resultant ByteCount (whether sucessful or not).
|
|
*/
|
|
*pByteCount = (ByteCountW >> 1);
|
|
|
|
/*
|
|
* If the function completed sucessfully and caller
|
|
* (and stub) defined a buffer to copy into, perform conversion
|
|
* from UNICODE to ANSI.
|
|
*/
|
|
if ( Status && pLogonIdW && pLogonId ) {
|
|
|
|
for ( Count = *pEntries; Count; Count-- ) {
|
|
|
|
pLogonId->LogonId = pLogonIdW->LogonId;
|
|
|
|
UnicodeToAnsi( pLogonId->WinStationName,
|
|
sizeof(WINSTATIONNAMEA),
|
|
pLogonIdW->WinStationName );
|
|
|
|
pLogonId->State = pLogonIdW->State;
|
|
|
|
(char*)pLogonId += sizeof(LOGONIDA);
|
|
(char*)pLogonIdW += sizeof(LOGONIDW);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we defined a buffer, free it now, then return the status of
|
|
* the WinStationEnumerateW call.
|
|
*/
|
|
if ( pBuffer )
|
|
LocalFree(pBuffer);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationEnumerate_IndexedW (UNICODE)
|
|
*
|
|
* Returns a list of window station objects (multi-call indexed).
|
|
*
|
|
* NOTE: this API used to be WinStationEnumerateW in WinFrame 1.6 and
|
|
* earlier. It is provided now for backward compatibility with
|
|
* Citrix code built around the indexed enumeration procedure.
|
|
* New code should use the WinStationEnumerateW call.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* pEntries (input/output)
|
|
* Points to a variable specifying the number of entries requested.
|
|
* If the number requested is 0xFFFFFFFF, the function returns as
|
|
* many entries as possible. When the function finishes successfully,
|
|
* the variable pointed to by the pEntries parameter contains the
|
|
* number of entries actually read.
|
|
*
|
|
* pLogonId (output)
|
|
* Points to the buffer to receive the enumeration results, which are
|
|
* returned as an array of LOGONID structures. If the window
|
|
* station is disconnected the name is null.
|
|
*
|
|
* pByteCount (input/output)
|
|
* Points to a variable that specifies the size, in bytes, of the
|
|
* pLogonId parameter. If the buffer is too small to receive even
|
|
* one entry, this variable receives the required size of the buffer.
|
|
*
|
|
* pIndex (input/output)
|
|
* Points to a ULONG that specifies where to start the enumeration.
|
|
* The only user visible value is 0, for starting at the begining.
|
|
* Each call will update this so that the next call will return the
|
|
* next WinStation in the list, till end of list.
|
|
* The user should not interpret, or use the internal values, other
|
|
* than the special case 0.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE - The enumeration succeeded, and the buffer contains the
|
|
* requested data. The calling application can continue to call
|
|
* the WinStationEnumerate function to complete the enumeration.
|
|
*
|
|
* FALSE - The operation failed. Extended error status is available using
|
|
* GetLastError. Possible return values from GetLastError include
|
|
* the following:
|
|
*
|
|
* ERROR_NO_MORE_ITEMS - There are no more entries. The buffer
|
|
* contents are undefined.
|
|
* ERROR_MORE_DATA - The buffer is too small for even one entry.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationEnumerate_IndexedW(
|
|
HANDLE hServer,
|
|
PULONG pEntries,
|
|
PLOGONIDW pLogonId,
|
|
PULONG pByteCount,
|
|
PULONG pIndex
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationEnumerate(
|
|
hServer,
|
|
&Result,
|
|
pEntries,
|
|
(PCHAR)pLogonId,
|
|
pByteCount,
|
|
pIndex
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationGetAllProcesses (UNICODE)
|
|
*
|
|
* Returns a structure containing TS_SYS_PROCESS_INFORMATION structures
|
|
* for each process on the specified server.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
* TRUE - The enumeration succeeded, and the buffer contains the
|
|
* requested data.
|
|
* FALSE - The operation failed. Extended error status is available using
|
|
* GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationGetAllProcesses(
|
|
HANDLE hServer,
|
|
ULONG Level,
|
|
ULONG *pNumberOfProcesses,
|
|
PVOID *ppProcessArray
|
|
)
|
|
{
|
|
BOOLEAN bGetAllProcessesOk = FALSE;
|
|
DWORD dwResult;
|
|
|
|
if (Level != GAP_LEVEL_BASIC)
|
|
{
|
|
dwResult = RtlNtStatusToDosError( STATUS_NOT_IMPLEMENTED );
|
|
SetLastError(dwResult);
|
|
return FALSE;
|
|
}
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
// The Win2K server uses PTS_ALL_PROCESSES_INFO structure for the process information.
|
|
// And the whistler server uses PTS_SYS_PROCESS_INFORMATION_NT6 structure for the same.
|
|
// So, we have to try two different RPC APIs. Assume initially that the server is a
|
|
// Whistler server and use RpcWinStationGetAllProcesses_NT6. If it is Win2K server, this
|
|
// call will fail, because this API does not exist on Win2K server. In that case we will
|
|
// use RpcWinStationGetAllProcesses.
|
|
|
|
// Try out Whistler interface first.
|
|
|
|
RpcTryExcept {
|
|
bGetAllProcessesOk = RpcWinStationGetAllProcesses_NT6(hServer,
|
|
(ULONG *)&dwResult,
|
|
Level,
|
|
pNumberOfProcesses,
|
|
(PTS_ALL_PROCESSES_INFO_NT6 *)ppProcessArray);
|
|
if( !bGetAllProcessesOk )
|
|
{
|
|
dwResult = RtlNtStatusToDosError( dwResult );
|
|
SetLastError(dwResult);
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
dwResult = RpcExceptionCode();
|
|
if (dwResult == RPC_S_PROCNUM_OUT_OF_RANGE)
|
|
// Whistler interface failed.
|
|
goto TryW2KInterface;
|
|
SetLastError( dwResult );
|
|
DBGPRINT(("RPC Exception %d\n",dwResult));
|
|
bGetAllProcessesOk = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( bGetAllProcessesOk );
|
|
|
|
TryW2KInterface:
|
|
// Try out Win2K interface now.
|
|
RpcTryExcept {
|
|
bGetAllProcessesOk = RpcWinStationGetAllProcesses(hServer,
|
|
(ULONG *)&dwResult,
|
|
Level,
|
|
pNumberOfProcesses,
|
|
(PTS_ALL_PROCESSES_INFO *)ppProcessArray);
|
|
if( !bGetAllProcessesOk )
|
|
{
|
|
dwResult = RtlNtStatusToDosError( dwResult );
|
|
SetLastError(dwResult);
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
dwResult = RpcExceptionCode();
|
|
SetLastError( dwResult );
|
|
DBGPRINT(("RPC Exception %d\n",dwResult));
|
|
bGetAllProcessesOk = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( bGetAllProcessesOk );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* WinStationGetProcessSid()
|
|
* username for the requested process
|
|
* For identifying correct process processid and start
|
|
* time are required
|
|
*
|
|
* hServer - input, Handle of the server to find info about,
|
|
* if NULL use local.
|
|
* ProcessId - input, ProcessID
|
|
* ProcessStartTime- input, Process start time, (identifies unique process
|
|
* together with ProcessID)
|
|
* pProcessUserSid - output, process user sid
|
|
* dwSidSize - input, memory allocated for pProcessUserSid
|
|
*
|
|
* returns TURE if succeeded, FALSE if failed. in case of failure
|
|
* GetLastError() will gives more infromation about failure.
|
|
*
|
|
******************************************************************************/
|
|
BOOLEAN WINAPI
|
|
WinStationGetProcessSid(
|
|
HANDLE hServer,
|
|
DWORD ProcessId,
|
|
FILETIME ProcessStartTime,
|
|
PBYTE pProcessUserSid,
|
|
DWORD *pdwSidSize
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
LARGE_INTEGER CreateTime;
|
|
DWORD Result;
|
|
NTSTATUS Status;
|
|
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
CreateTime.LowPart = ProcessStartTime.dwLowDateTime;
|
|
CreateTime.HighPart = ProcessStartTime.dwHighDateTime;
|
|
|
|
RpcTryExcept
|
|
{
|
|
rc = RpcWinStationGetProcessSid(
|
|
hServer,
|
|
ProcessId,
|
|
CreateTime,
|
|
&Status,
|
|
pProcessUserSid,
|
|
*pdwSidSize,
|
|
pdwSidSize
|
|
);
|
|
|
|
if( !rc )
|
|
{
|
|
Result = RtlNtStatusToDosError( Status );
|
|
SetLastError(Result);
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Result = RpcExceptionCode();
|
|
SetLastError(Result);
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationGetLanAdapterNameW (UNICODE)
|
|
*
|
|
* Returns a Network Adapter name
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
* TRUE - The Query succeeded, and the buffer contains the
|
|
* requested data.
|
|
* FALSE - The operation failed. Extended error status is available using
|
|
* GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationGetLanAdapterNameW(
|
|
HANDLE hServer,
|
|
ULONG LanAdapter,
|
|
ULONG pdNameLength,
|
|
PWCHAR pPdName,
|
|
ULONG *pLength,
|
|
PWCHAR *ppLanAdapter
|
|
)
|
|
{
|
|
BOOLEAN bGetLanAdapter = FALSE;
|
|
DWORD dwResult;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept
|
|
{
|
|
bGetLanAdapter = RpcWinStationGetLanAdapterName(hServer,
|
|
&dwResult,
|
|
pdNameLength,
|
|
pPdName,
|
|
LanAdapter,
|
|
pLength,
|
|
ppLanAdapter
|
|
);
|
|
|
|
if( !bGetLanAdapter )
|
|
{
|
|
dwResult = RtlNtStatusToDosError( dwResult );
|
|
SetLastError(dwResult);
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
dwResult = RpcExceptionCode();
|
|
SetLastError( dwResult );
|
|
DBGPRINT(("RPC Exception %d\n",dwResult));
|
|
bGetLanAdapter = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( bGetLanAdapter );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationGetLanAdapterNameA
|
|
*
|
|
* Returns a Network Adapter name - Ansi equivalent for WinStationGetLanAdapterNameW
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
* TRUE - The Query succeeded, and the buffer contains the
|
|
* requested data.
|
|
* FALSE - The operation failed. Extended error status is available using
|
|
* GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationGetLanAdapterNameA(
|
|
HANDLE hServer,
|
|
ULONG LanAdapter,
|
|
ULONG pdNameLength,
|
|
PCHAR pPdName,
|
|
ULONG *pLength,
|
|
PCHAR *ppLanAdapter
|
|
)
|
|
{
|
|
BOOLEAN bGetLanAdapter = FALSE;
|
|
PWCHAR pPdNameW = NULL;
|
|
PWCHAR pLanAdapterW = NULL;
|
|
ULONG Size = 0;
|
|
|
|
|
|
*ppLanAdapter = NULL;
|
|
*pLength = 0;
|
|
|
|
pPdNameW = LocalAlloc(0,pdNameLength * sizeof(WCHAR));
|
|
if (NULL == pPdNameW)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
AnsiToUnicode(pPdNameW, pdNameLength * sizeof(WCHAR), pPdName );
|
|
|
|
bGetLanAdapter = WinStationGetLanAdapterNameW(hServer,LanAdapter,pdNameLength * sizeof(WCHAR),pPdNameW,&Size,&pLanAdapterW);
|
|
if(bGetLanAdapter )
|
|
{
|
|
*ppLanAdapter = LocalAlloc(0,lstrlen(pLanAdapterW) + 1);
|
|
if(NULL == *ppLanAdapter)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
bGetLanAdapter = FALSE;
|
|
|
|
}
|
|
else
|
|
{
|
|
UnicodeToAnsi(*ppLanAdapter,lstrlen(pLanAdapterW) + 1,pLanAdapterW);
|
|
*pLength = lstrlen(pLanAdapterW) + 1;
|
|
}
|
|
WinStationFreeMemory(pLanAdapterW);
|
|
|
|
|
|
}
|
|
|
|
LocalFree(pPdNameW);
|
|
|
|
return( bGetLanAdapter );
|
|
}
|
|
|
|
#if defined(_WIN64)
|
|
void ConvertFromX86(PTS_SYS_PROCESS_INFORMATION pTSProcessInfo)
|
|
{
|
|
|
|
//
|
|
// this function is called from WinStationEnumerateProcesses, which is used only for TS4 machines.
|
|
// This structure has to be marshalled correctly to convert from x86 to ia64 when running on ia64.
|
|
//
|
|
typedef struct _WIRE_UNICODE_STRING
|
|
{
|
|
USHORT Length;
|
|
USHORT MaximumLength;
|
|
ULONG Buffer;
|
|
} X86_UNICODE_STRING, *PX86_UNICODE_STRING;
|
|
|
|
typedef struct TS_SYS_PROCESS_INFORMATION_X86
|
|
{
|
|
ULONG NextEntryOffset;
|
|
ULONG NumberOfThreads;
|
|
LARGE_INTEGER SpareLi1;
|
|
LARGE_INTEGER SpareLi2;
|
|
LARGE_INTEGER SpareLi3;
|
|
LARGE_INTEGER CreateTime;
|
|
LARGE_INTEGER UserTime;
|
|
LARGE_INTEGER KernelTime;
|
|
X86_UNICODE_STRING ImageName;
|
|
LONG BasePriority; // KPRIORITY in ntexapi.h
|
|
DWORD UniqueProcessId; // HANDLE in ntexapi.h
|
|
DWORD InheritedFromUniqueProcessId; // HANDLE in ntexapi.h
|
|
ULONG HandleCount;
|
|
ULONG SessionId;
|
|
ULONG SpareUl3;
|
|
ULONG PeakVirtualSize;
|
|
ULONG VirtualSize;
|
|
ULONG PageFaultCount;
|
|
ULONG PeakWorkingSetSize;
|
|
ULONG WorkingSetSize;
|
|
ULONG QuotaPeakPagedPoolUsage;
|
|
ULONG QuotaPagedPoolUsage;
|
|
ULONG QuotaPeakNonPagedPoolUsage;
|
|
ULONG QuotaNonPagedPoolUsage;
|
|
ULONG PagefileUsage;
|
|
ULONG PeakPagefileUsage;
|
|
ULONG PrivatePageCount;
|
|
}
|
|
TS_SYS_PROCESS_INFORMATION_X86, *PTS_SYS_PROCESS_INFORMATION_X86;
|
|
|
|
TS_SYS_PROCESS_INFORMATION_X86 TSProcInfoX86;
|
|
|
|
TSProcInfoX86 = * (PTS_SYS_PROCESS_INFORMATION_X86) pTSProcessInfo;
|
|
|
|
pTSProcessInfo->NextEntryOffset = TSProcInfoX86.NextEntryOffset ;
|
|
pTSProcessInfo->NumberOfThreads = TSProcInfoX86.NumberOfThreads ;
|
|
pTSProcessInfo->SpareLi1 = TSProcInfoX86.SpareLi1 ;
|
|
pTSProcessInfo->SpareLi2 = TSProcInfoX86.SpareLi2 ;
|
|
pTSProcessInfo->SpareLi3 = TSProcInfoX86.SpareLi3 ;
|
|
pTSProcessInfo->CreateTime = TSProcInfoX86.CreateTime ;
|
|
pTSProcessInfo->UserTime = TSProcInfoX86.UserTime ;
|
|
pTSProcessInfo->KernelTime = TSProcInfoX86.KernelTime ;
|
|
pTSProcessInfo->ImageName.Length = TSProcInfoX86.ImageName.Length;
|
|
pTSProcessInfo->ImageName.MaximumLength = TSProcInfoX86.ImageName.MaximumLength;
|
|
pTSProcessInfo->ImageName.Buffer = UlongToPtr(TSProcInfoX86.ImageName.Buffer);
|
|
pTSProcessInfo->BasePriority = TSProcInfoX86.BasePriority ;
|
|
pTSProcessInfo->UniqueProcessId = TSProcInfoX86.UniqueProcessId ;
|
|
pTSProcessInfo->InheritedFromUniqueProcessId = TSProcInfoX86.InheritedFromUniqueProcessId ;
|
|
pTSProcessInfo->HandleCount = TSProcInfoX86.HandleCount ;
|
|
pTSProcessInfo->SessionId = TSProcInfoX86.SessionId ;
|
|
|
|
//
|
|
// Following members are not used so we dont need to copy their values.
|
|
// if we did so, we overwrite data past the original structure, as the strucutre comes from x86
|
|
// its smaller than the WIN64 version.
|
|
//
|
|
|
|
//pTSProcessInfo->SpareUl3 = TSProcInfoX86.SpareUl3 ;
|
|
//pTSProcessInfo->PeakVirtualSize = TSProcInfoX86.PeakVirtualSize ;
|
|
//pTSProcessInfo->VirtualSize = TSProcInfoX86.VirtualSize ;
|
|
//pTSProcessInfo->PageFaultCount = TSProcInfoX86.PageFaultCount ;
|
|
//pTSProcessInfo->PeakWorkingSetSize = TSProcInfoX86.PeakWorkingSetSize ;
|
|
//pTSProcessInfo->WorkingSetSize = TSProcInfoX86.WorkingSetSize ;
|
|
//pTSProcessInfo->QuotaPeakPagedPoolUsage = TSProcInfoX86.QuotaPeakPagedPoolUsage ;
|
|
//pTSProcessInfo->QuotaPagedPoolUsage = TSProcInfoX86.QuotaPagedPoolUsage ;
|
|
//pTSProcessInfo->QuotaPeakNonPagedPoolUsage = TSProcInfoX86.QuotaPeakNonPagedPoolUsage ;
|
|
//pTSProcessInfo->QuotaNonPagedPoolUsage = TSProcInfoX86.QuotaNonPagedPoolUsage ;
|
|
//pTSProcessInfo->PagefileUsage = TSProcInfoX86.PagefileUsage ;
|
|
//pTSProcessInfo->PeakPagefileUsage = TSProcInfoX86.PeakPagefileUsage ;
|
|
//pTSProcessInfo->PrivatePageCount = TSProcInfoX86.PrivatePageCount ;
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationEnumerateProcesses (UNICODE)
|
|
*
|
|
* Returns a buffer containing SYSTEM_PROCESS_INFORMATION structures
|
|
* for each process on the specified server.
|
|
*
|
|
* IMPORTANT: This API can ONLY be used to access TS 4.0 servers.
|
|
* The process structure has changed in Windows 2000 !
|
|
*
|
|
* ENTRY:
|
|
* ppProcessBuffer (output)
|
|
* Points to a variable that will be set to the beginning of the
|
|
* process buffer on success. The buffer is allocated within this
|
|
* API and is disposed of using WinStationFreeMemory.
|
|
*
|
|
* EXIT:
|
|
* TRUE - The enumeration succeeded, and the buffer contains the
|
|
* requested data.
|
|
* FALSE - The operation failed. Extended error status is available using
|
|
* GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationEnumerateProcesses(
|
|
HANDLE hServer,
|
|
PVOID *ppProcessBuffer
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
PBYTE pBuffer;
|
|
ULONG ByteCount;
|
|
|
|
// From pstat.c
|
|
#define BUFFER_SIZE 32*1024
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
ByteCount = BUFFER_SIZE;
|
|
*ppProcessBuffer = NULL;
|
|
|
|
for(;;) {
|
|
|
|
if ( (pBuffer = LocalAlloc( 0, ByteCount )) == NULL ) {
|
|
Result = (DWORD)STATUS_NO_MEMORY;
|
|
rc = FALSE;
|
|
break;
|
|
}
|
|
|
|
//#ifdef notdef
|
|
/*
|
|
* get process info from server
|
|
*/
|
|
rc = RpcWinStationEnumerateProcesses(
|
|
hServer,
|
|
&Result,
|
|
pBuffer,
|
|
ByteCount
|
|
);
|
|
//#else
|
|
#ifdef notdef
|
|
Result = NtQuerySystemInformation( SystemProcessInformation,
|
|
(PVOID)pBuffer,
|
|
ByteCount,
|
|
NULL );
|
|
|
|
rc = (Result == STATUS_SUCCESS) ? TRUE : FALSE;
|
|
#endif
|
|
|
|
if ( rc || (Result != STATUS_INFO_LENGTH_MISMATCH) )
|
|
break;
|
|
|
|
LocalFree( pBuffer );
|
|
ByteCount *= 2;
|
|
}
|
|
|
|
if( !rc ) {
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
SetLastError(Result);
|
|
LocalFree( pBuffer );
|
|
*ppProcessBuffer = NULL;
|
|
|
|
} else {
|
|
|
|
//#ifdef notdef
|
|
PTS_SYS_PROCESS_INFORMATION ProcessInfo;
|
|
PCITRIX_PROCESS_INFORMATION CitrixInfo;
|
|
|
|
ULONG TotalOffset;
|
|
|
|
/*
|
|
* Walk the returned buffer (it's in PTS_SYS_PROCESS_INFORMATION
|
|
* format) and fixup the addresses (now containing
|
|
* offsets) to pointers in our address space within pBuffer.
|
|
*/
|
|
ProcessInfo = (PTS_SYS_PROCESS_INFORMATION)pBuffer;
|
|
TotalOffset = 0;
|
|
for(;;) {
|
|
|
|
|
|
#if defined(_WIN64)
|
|
ConvertFromX86(ProcessInfo);
|
|
#endif
|
|
|
|
/*
|
|
* Fixup image name buffer address
|
|
*/
|
|
if ( ProcessInfo->ImageName.Buffer )
|
|
ProcessInfo->ImageName.Buffer =
|
|
(PWSTR)&pBuffer[(ULONG_PTR)(ProcessInfo->ImageName.Buffer)];
|
|
|
|
|
|
/*
|
|
* Fixup ProcessSid address
|
|
*/
|
|
//
|
|
// Note: this is necessary because we may access to a Hydra 4 server
|
|
// the MagicNumber should prevent us from doing wrong.
|
|
//
|
|
CitrixInfo = (PCITRIX_PROCESS_INFORMATION)
|
|
(((PUCHAR)ProcessInfo) +
|
|
SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION +
|
|
(SIZEOF_TS4_SYSTEM_THREAD_INFORMATION * (int)ProcessInfo->NumberOfThreads));
|
|
|
|
#if defined(_WIN64)
|
|
//The pointer to SID came from x86 machine, so upper
|
|
//32 bits contain garbage. Set them to 0.
|
|
//This overrides original Pad value, bu it's okay,
|
|
//because it is not used.
|
|
(ULONG_PTR)CitrixInfo->ProcessSid &=0x00000000FFFFFFFF;
|
|
#endif
|
|
|
|
if( (CitrixInfo->MagicNumber == CITRIX_PROCESS_INFO_MAGIC) &&
|
|
(CitrixInfo->ProcessSid) ) {
|
|
|
|
CitrixInfo->ProcessSid =
|
|
(PVOID)&pBuffer[(ULONG_PTR)(CitrixInfo->ProcessSid)];
|
|
}
|
|
|
|
if( ProcessInfo->NextEntryOffset == 0 )
|
|
break;
|
|
else
|
|
TotalOffset += ProcessInfo->NextEntryOffset;
|
|
|
|
ProcessInfo = (PTS_SYS_PROCESS_INFORMATION)&pBuffer[TotalOffset];
|
|
}
|
|
//#endif
|
|
*ppProcessBuffer = (PVOID)pBuffer;
|
|
}
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationRenameA (ANSI stub)
|
|
*
|
|
* Renames a window station object in the session manager.
|
|
* (see WinStationRenameW)
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationRenameW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationRenameW
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationRenameA(
|
|
HANDLE hServer,
|
|
PWINSTATIONNAMEA pWinStationNameOld,
|
|
PWINSTATIONNAMEA pWinStationNameNew
|
|
)
|
|
{
|
|
WINSTATIONNAMEW WinStationNameOldW;
|
|
WINSTATIONNAMEW WinStationNameNewW;
|
|
|
|
/*
|
|
* Convert ANSI WinStationNames to UNICODE.
|
|
*/
|
|
AnsiToUnicode( WinStationNameOldW, sizeof(WINSTATIONNAMEW), pWinStationNameOld );
|
|
AnsiToUnicode( WinStationNameNewW, sizeof(WINSTATIONNAMEW), pWinStationNameNew );
|
|
|
|
/*
|
|
* Call WinStationRenameW & return it's status.
|
|
*/
|
|
return ( WinStationRenameW( hServer, WinStationNameOldW, WinStationNameNewW ) );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationRenameW (UNICODE)
|
|
*
|
|
* Renames a window station object in the session manager.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* pWinStationNameOld (input)
|
|
* Old name of window station.
|
|
*
|
|
* pWinStationNameNew (input)
|
|
* New name of window station.
|
|
*
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The rename operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationRenameW(
|
|
HANDLE hServer,
|
|
PWINSTATIONNAMEW pWinStationNameOld,
|
|
PWINSTATIONNAMEW pWinStationNameNew
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
WCHAR* rpcBufferOld;
|
|
WCHAR* rpcBufferNew;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
// Since, due to legacy clients, we cannot change the interface,
|
|
// as a workarround to bug#265954, we double the size of RPC Buffers.
|
|
|
|
#pragma prefast(suppress:260, legacy servers expect this behaviour (http://searchraid/ntbug/265954.asp))
|
|
rpcBufferOld = LocalAlloc(LPTR, sizeof(WINSTATIONNAMEW) * sizeof(WCHAR));
|
|
if (rpcBufferOld != NULL) {
|
|
CopyMemory(rpcBufferOld, pWinStationNameOld, sizeof(WINSTATIONNAMEW));
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
#pragma prefast(suppress:260, legacy clients expect this behaviour (http://searchraid/ntbug/229753.asp))
|
|
rpcBufferNew = LocalAlloc(LPTR, sizeof(WINSTATIONNAMEW) * sizeof(WCHAR));
|
|
if (rpcBufferNew != NULL) {
|
|
CopyMemory(rpcBufferNew, pWinStationNameNew, sizeof(WINSTATIONNAMEW));
|
|
} else {
|
|
LocalFree(rpcBufferOld);
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationRename(
|
|
hServer,
|
|
&Result,
|
|
(PWCHAR)rpcBufferOld,
|
|
sizeof(WINSTATIONNAMEW),
|
|
(PWCHAR)rpcBufferNew,
|
|
sizeof(WINSTATIONNAMEW)
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
LocalFree(rpcBufferOld);
|
|
LocalFree(rpcBufferNew);
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationQueryInformationA (ANSI stub)
|
|
*
|
|
* Queries configuration information about a window station object.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationQueryInformationW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationQueryInformationW
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationQueryInformationA(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
WINSTATIONINFOCLASS WinStationInformationClass,
|
|
PVOID pWinStationInformation,
|
|
ULONG WinStationInformationLength,
|
|
PULONG pReturnLength
|
|
)
|
|
{
|
|
PVOID pInfo;
|
|
ULONG InfoLength, ValidInputLength;
|
|
struct {
|
|
union {
|
|
WINSTATIONCREATEW CreateData;
|
|
WINSTATIONCONFIGW Configuration;
|
|
PDPARAMSW PdParams;
|
|
WDCONFIGW Wd;
|
|
PDCONFIGW Pd;
|
|
WINSTATIONPRINTERW Printer;
|
|
WINSTATIONINFORMATIONW Information;
|
|
WINSTATIONCLIENTW Client;
|
|
WINSTATIONPRODIDW DigProdId;
|
|
};
|
|
} Info;
|
|
|
|
/*
|
|
* Validate the caller supplied buffer length and set up for
|
|
* call to WinStationQueryInformationW.
|
|
*/
|
|
switch ( WinStationInformationClass ) {
|
|
|
|
case WinStationCreateData:
|
|
pInfo = &Info.CreateData;
|
|
InfoLength = sizeof(Info.CreateData);
|
|
ValidInputLength = sizeof(WINSTATIONCREATEA);
|
|
break;
|
|
|
|
case WinStationConfiguration:
|
|
pInfo = &Info.Configuration;
|
|
InfoLength = sizeof(Info.Configuration);
|
|
ValidInputLength = sizeof(WINSTATIONCONFIGA);
|
|
break;
|
|
|
|
case WinStationPdParams:
|
|
pInfo = &Info.PdParams;
|
|
((PPDPARAMSW)pInfo)->SdClass = ((PPDPARAMSA)pWinStationInformation)->SdClass;
|
|
InfoLength = sizeof(Info.PdParams);
|
|
ValidInputLength = sizeof(PDPARAMSA);
|
|
break;
|
|
|
|
case WinStationWd:
|
|
pInfo = &Info.Wd;
|
|
InfoLength = sizeof(Info.Wd);
|
|
ValidInputLength = sizeof(WDCONFIGA);
|
|
break;
|
|
|
|
case WinStationPd:
|
|
pInfo = &Info.Pd;
|
|
InfoLength = sizeof(Info.Pd);
|
|
ValidInputLength = sizeof(PDCONFIGA);
|
|
break;
|
|
|
|
case WinStationPrinter:
|
|
pInfo = &Info.Printer;
|
|
InfoLength = sizeof(Info.Printer);
|
|
ValidInputLength = sizeof(WINSTATIONPRINTERA);
|
|
break;
|
|
|
|
case WinStationInformation:
|
|
pInfo = &Info.Information;
|
|
InfoLength = sizeof(Info.Information);
|
|
ValidInputLength = sizeof(WINSTATIONINFORMATIONA);
|
|
break;
|
|
|
|
case WinStationClient:
|
|
pInfo = &Info.Client;
|
|
InfoLength = sizeof(Info.Client);
|
|
ValidInputLength = sizeof(WINSTATIONCLIENTA);
|
|
break;
|
|
case WinStationDigProductId:
|
|
pInfo = &Info.DigProdId;
|
|
InfoLength = sizeof(Info.DigProdId);
|
|
ValidInputLength = sizeof(WINSTATIONPRODIDA);
|
|
break;
|
|
|
|
/*
|
|
* The other WINSTATIONINFOCLASSes don't need converting.
|
|
*/
|
|
default:
|
|
pInfo = pWinStationInformation;
|
|
ValidInputLength = InfoLength = WinStationInformationLength;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If the caller-supplied buffer is not the proper size, set error
|
|
* and return FALSE.
|
|
*/
|
|
if ( WinStationInformationLength != ValidInputLength )
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* Call the WinStationQueryInformationW function, returning if
|
|
* failure.
|
|
*/
|
|
if ( !WinStationQueryInformationW( hServer, LogonId,
|
|
WinStationInformationClass,
|
|
pInfo, InfoLength, pReturnLength ) )
|
|
return(FALSE);
|
|
|
|
|
|
/*
|
|
* Convert the returned UNICODE information to ANSI, if needed.
|
|
*/
|
|
switch ( WinStationInformationClass ) {
|
|
|
|
case WinStationCreateData:
|
|
WinStationCreateU2A( (PWINSTATIONCREATEA)pWinStationInformation,
|
|
(PWINSTATIONCREATEW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationConfiguration:
|
|
WinStationConfigU2A( (PWINSTATIONCONFIGA)pWinStationInformation,
|
|
(PWINSTATIONCONFIGW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationPdParams:
|
|
PdParamsU2A( (PPDPARAMSA)pWinStationInformation,
|
|
(PPDPARAMSW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationWd:
|
|
WdConfigU2A( (PWDCONFIGA)pWinStationInformation,
|
|
(PWDCONFIGW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationPd:
|
|
PdConfig2U2A( &((PPDCONFIGA)pWinStationInformation)->Create,
|
|
&((PPDCONFIGW)pInfo)->Create );
|
|
PdParamsU2A( &((PPDCONFIGA)pWinStationInformation)->Params,
|
|
&((PPDCONFIGW)pInfo)->Params );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationPrinter:
|
|
WinStationPrinterU2A( (PWINSTATIONPRINTERA)pWinStationInformation,
|
|
(PWINSTATIONPRINTERW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationInformation:
|
|
WinStationInformationU2A( (PWINSTATIONINFORMATIONA)pWinStationInformation,
|
|
(PWINSTATIONINFORMATIONW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationClient:
|
|
WinStationClientU2A( (PWINSTATIONCLIENTA)pWinStationInformation,
|
|
(PWINSTATIONCLIENTW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
case WinStationDigProductId:
|
|
WinStationProductIdU2A( (PWINSTATIONPRODIDA)pWinStationInformation,
|
|
(PWINSTATIONPRODIDW)pInfo );
|
|
*pReturnLength = ValidInputLength;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationQueryInformationW (UNICODE)
|
|
*
|
|
* Queries configuration information about a window station object.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* WinStationHandle (input)
|
|
* Identifies the window station object. The handle must have
|
|
* WINSTATION_QUERY access.
|
|
*
|
|
* WinStationInformationClass (input)
|
|
* Specifies the type of information to retrieve from the specified
|
|
* window station object.
|
|
*
|
|
* pWinStationInformation (output)
|
|
* A pointer to a buffer that will receive information about the
|
|
* specified window station. The format and contents of the buffer
|
|
* depend on the specified information class being queried.
|
|
*
|
|
* WinStationInformationLength (input)
|
|
* Specifies the length in bytes of the window station information
|
|
* buffer.
|
|
*
|
|
* pReturnLength (output)
|
|
* An optional parameter that if specified, receives the number of
|
|
* bytes placed in the window station information buffer.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query succeeded, and the buffer contains the requested data.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationQueryInformationW(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
WINSTATIONINFOCLASS WinStationInformationClass,
|
|
PVOID pWinStationInformation,
|
|
ULONG WinStationInformationLength,
|
|
PULONG pReturnLength
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
PCHAR RpcBuf;
|
|
ULONG RpcBufLen;
|
|
PVOID WireBuf;
|
|
PVOID AllocatedBuff = NULL;
|
|
ULONG WireBufLen;
|
|
BOOLEAN WireBufAllocated;
|
|
ULONG Status;
|
|
static UINT AlreadyWaitedForTermsrv = 0; // a flag which helps to determine if we already waited for TermSrv to be up
|
|
|
|
if ((Status = CheckUserBuffer(WinStationInformationClass,
|
|
pWinStationInformation,
|
|
WinStationInformationLength,
|
|
&WireBuf,
|
|
&WireBufLen,
|
|
&WireBufAllocated)) != ERROR_SUCCESS) {
|
|
SetLastError(Status);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (WireBufAllocated) {
|
|
AllocatedBuff = WireBuf;
|
|
RpcBuf = (PCHAR) WireBuf;
|
|
RpcBufLen = WireBufLen;
|
|
CopyInWireBuf(WinStationInformationClass,
|
|
pWinStationInformation,
|
|
WireBuf);
|
|
} else {
|
|
RpcBuf = (PCHAR) pWinStationInformation;
|
|
RpcBufLen = WinStationInformationLength;
|
|
}
|
|
|
|
|
|
HANDLE_CURRENT_BINDING_BUFFER( hServer, AllocatedBuff );
|
|
|
|
// First wait for termsrv to get started if User Token is queried
|
|
// This is for Session 0 only where termsrv is started after 60 seconds on Per and Pro
|
|
// Need to do this only for the first time - AlreadyWaitedForTermsrv flag helps to determine this
|
|
|
|
if ( (LogonId == 0) && (WinStationInformationClass == WinStationUserToken) && (AlreadyWaitedForTermsrv == 0) ) {
|
|
|
|
HANDLE ReadyEventHandle ;
|
|
|
|
ReadyEventHandle = OpenEvent(SYNCHRONIZE, FALSE, TEXT("Global\\TermSrvReadyEvent"));
|
|
if (ReadyEventHandle != NULL) {
|
|
DWORD dwTimeOut = 1000*60*3; // 3 minutes
|
|
AlreadyWaitedForTermsrv++;
|
|
// wait until termsrv is actually ready.
|
|
WaitForSingleObject(ReadyEventHandle, dwTimeOut);
|
|
CloseHandle(ReadyEventHandle);
|
|
}
|
|
}
|
|
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationQueryInformation(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
(DWORD)WinStationInformationClass,
|
|
RpcBuf,
|
|
RpcBufLen,
|
|
pReturnLength
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (WireBufAllocated) {
|
|
if (rc) {
|
|
CopyOutWireBuf(WinStationInformationClass,
|
|
pWinStationInformation,
|
|
WireBuf);
|
|
*pReturnLength = WinStationInformationLength;
|
|
}
|
|
LocalFree(WireBuf);
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationSetInformationA (ANSI stub)
|
|
*
|
|
* Sets configuration information for a window station object.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationSetInformationW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationSetInformationW
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationSetInformationA(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
WINSTATIONINFOCLASS WinStationInformationClass,
|
|
PVOID pWinStationInformation,
|
|
ULONG WinStationInformationLength
|
|
)
|
|
{
|
|
PVOID pInfo;
|
|
ULONG InfoLength;
|
|
struct {
|
|
union {
|
|
WINSTATIONCREATEW CreateData;
|
|
WINSTATIONCONFIGW Configuration;
|
|
PDPARAMSW PdParams;
|
|
WDCONFIGW Wd;
|
|
PDCONFIGW Pd;
|
|
WINSTATIONPRINTERW Printer;
|
|
WINSTATIONINFORMATIONW Information;
|
|
};
|
|
} Info;
|
|
|
|
/*
|
|
* Validate the caller supplied buffer length and convert to the
|
|
* appropriate UNICODE buffer for call to WinStationSetInformationW.
|
|
*/
|
|
switch ( WinStationInformationClass ) {
|
|
|
|
case WinStationCreateData:
|
|
pInfo = &Info.CreateData;
|
|
InfoLength = sizeof(Info.CreateData);
|
|
if ( WinStationInformationLength != sizeof(WINSTATIONCREATEA) )
|
|
goto BadBufferLength;
|
|
WinStationCreateA2U( (PWINSTATIONCREATEW)pInfo,
|
|
(PWINSTATIONCREATEA)pWinStationInformation );
|
|
break;
|
|
|
|
case WinStationConfiguration:
|
|
pInfo = &Info.Configuration;
|
|
InfoLength = sizeof(Info.Configuration);
|
|
if ( WinStationInformationLength != sizeof(WINSTATIONCONFIGA) )
|
|
goto BadBufferLength;
|
|
WinStationConfigA2U( (PWINSTATIONCONFIGW)pInfo,
|
|
(PWINSTATIONCONFIGA)pWinStationInformation );
|
|
break;
|
|
|
|
case WinStationPdParams:
|
|
pInfo = &Info.PdParams;
|
|
InfoLength = sizeof(Info.PdParams);
|
|
if ( WinStationInformationLength != sizeof(PDPARAMSA) )
|
|
goto BadBufferLength;
|
|
PdParamsA2U( (PPDPARAMSW)pInfo,
|
|
(PPDPARAMSA)pWinStationInformation );
|
|
break;
|
|
|
|
case WinStationWd:
|
|
pInfo = &Info.Wd;
|
|
InfoLength = sizeof(Info.Wd);
|
|
if ( WinStationInformationLength != sizeof(WDCONFIGA) )
|
|
goto BadBufferLength;
|
|
WdConfigA2U( (PWDCONFIGW)pInfo,
|
|
(PWDCONFIGA)pWinStationInformation );
|
|
break;
|
|
|
|
case WinStationPd:
|
|
pInfo = &Info.Pd;
|
|
InfoLength = sizeof(Info.Pd);
|
|
if ( WinStationInformationLength != sizeof(PDCONFIGA) )
|
|
goto BadBufferLength;
|
|
PdConfig2A2U( &((PPDCONFIGW)pInfo)->Create,
|
|
&((PPDCONFIGA)pWinStationInformation)->Create );
|
|
PdParamsA2U( &((PPDCONFIGW)pInfo)->Params,
|
|
&((PPDCONFIGA)pWinStationInformation)->Params );
|
|
break;
|
|
|
|
case WinStationPrinter:
|
|
pInfo = &Info.Printer;
|
|
InfoLength = sizeof(Info.Printer);
|
|
if ( WinStationInformationLength != sizeof(WINSTATIONPRINTERA) )
|
|
goto BadBufferLength;
|
|
WinStationPrinterA2U( (PWINSTATIONPRINTERW)pInfo,
|
|
(PWINSTATIONPRINTERA)pWinStationInformation );
|
|
break;
|
|
|
|
case WinStationInformation:
|
|
pInfo = &Info.Information;
|
|
InfoLength = sizeof(Info.Information);
|
|
if ( WinStationInformationLength != sizeof(WINSTATIONINFORMATIONA) )
|
|
goto BadBufferLength;
|
|
WinStationInformationA2U( (PWINSTATIONINFORMATIONW)pInfo,
|
|
(PWINSTATIONINFORMATIONA)pWinStationInformation );
|
|
break;
|
|
|
|
/*
|
|
* The other WINSTATIONINFOCLASSes don't need converting.
|
|
*/
|
|
default:
|
|
pInfo = pWinStationInformation;
|
|
InfoLength = WinStationInformationLength;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Call the WinStationSetInformationW function and return it's
|
|
* status.
|
|
*/
|
|
return ( WinStationSetInformationW( hServer, LogonId,
|
|
WinStationInformationClass,
|
|
pInfo, InfoLength ) );
|
|
|
|
/*--------------------------------------
|
|
* Error clean-up and return...
|
|
*/
|
|
BadBufferLength:
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return(FALSE);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationSetInformationW (UNICODE)
|
|
*
|
|
* Sets configuration information for a window station object.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* WinStationHandle (input)
|
|
* Identifies the window station object. The handle must have
|
|
* WINSTATION_SET access.
|
|
*
|
|
* WinStationInformationClass (input)
|
|
* Specifies the type of information to retrieve from the specified
|
|
* window station object.
|
|
*
|
|
* pWinStationInformation (input)
|
|
* A pointer to a buffer that contains information to set for the
|
|
* specified window station. The format and contents of the buffer
|
|
* depend on the specified information class being set.
|
|
*
|
|
* WinStationInformationLength (input)
|
|
* Specifies the length in bytes of the window station information
|
|
* buffer.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The set operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationSetInformationW(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
WINSTATIONINFOCLASS WinStationInformationClass,
|
|
PVOID pWinStationInformation,
|
|
ULONG WinStationInformationLength
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
PCHAR RpcBuf;
|
|
ULONG RpcBufLen;
|
|
PVOID WireBuf;
|
|
PVOID AllocatedBuff = NULL;
|
|
ULONG WireBufLen;
|
|
BOOLEAN WireBufAllocated;
|
|
ULONG Status;
|
|
|
|
if ((Status = CheckUserBuffer(WinStationInformationClass,
|
|
pWinStationInformation,
|
|
WinStationInformationLength,
|
|
&WireBuf,
|
|
&WireBufLen,
|
|
&WireBufAllocated)) != ERROR_SUCCESS) {
|
|
SetLastError(Status);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (WireBufAllocated) {
|
|
AllocatedBuff = WireBuf;
|
|
RpcBuf = (PCHAR) WireBuf;
|
|
RpcBufLen = WireBufLen;
|
|
CopyInWireBuf(WinStationInformationClass,
|
|
pWinStationInformation,
|
|
WireBuf);
|
|
} else {
|
|
RpcBuf = (PCHAR) pWinStationInformation;
|
|
RpcBufLen = WinStationInformationLength;
|
|
}
|
|
|
|
HANDLE_CURRENT_BINDING_BUFFER( hServer, AllocatedBuff );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationSetInformation(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
(DWORD)WinStationInformationClass,
|
|
RpcBuf,
|
|
RpcBufLen
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (WireBufAllocated) {
|
|
LocalFree(WireBuf);
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationSendMessageA (ANSI stub)
|
|
*
|
|
* Sends a message to the specified window station object and optionally
|
|
* waits for a reply. The reply is returned to the caller of
|
|
* WinStationSendMessage.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationSendMessageW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationSendMessageW, plus
|
|
*
|
|
* ERROR_NOT_ENOUGH_MEMORY - the LocalAlloc failed
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationSendMessageA(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
LPSTR pTitle,
|
|
ULONG TitleLength,
|
|
LPSTR pMessage,
|
|
ULONG MessageLength,
|
|
ULONG Style,
|
|
ULONG Timeout,
|
|
PULONG pResponse,
|
|
BOOLEAN DoNotWait
|
|
)
|
|
{
|
|
BOOLEAN status;
|
|
LPWSTR pTitleW, pMessageW;
|
|
ULONG TitleLengthW, MessageLengthW;
|
|
|
|
/*
|
|
* Allocate a buffer for UNICODE version of Title and convert.
|
|
*/
|
|
if ( !(pTitleW = LocalAlloc( 0,
|
|
TitleLengthW =
|
|
(TitleLength*sizeof(WCHAR)) )) ) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
AnsiToUnicode( pTitleW, TitleLengthW, pTitle );
|
|
|
|
/*
|
|
* Allocate a buffer for UNICODE version of Message and convert.
|
|
*/
|
|
if ( !(pMessageW = LocalAlloc( 0,
|
|
MessageLengthW =
|
|
(MessageLength*sizeof(WCHAR)) )) ) {
|
|
LocalFree(pTitleW);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
AnsiToUnicode( pMessageW, MessageLengthW, pMessage );
|
|
|
|
/*
|
|
* Call WinStationSendMessageW
|
|
*/
|
|
status = WinStationSendMessageW( hServer,
|
|
LogonId,
|
|
pTitleW,
|
|
TitleLengthW,
|
|
pMessageW,
|
|
MessageLengthW,
|
|
Style,
|
|
Timeout,
|
|
pResponse,
|
|
DoNotWait );
|
|
|
|
/*
|
|
* Free allocated buffers and return status.
|
|
*/
|
|
LocalFree(pTitleW);
|
|
LocalFree(pMessageW);
|
|
return(status);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationSendMessageW (UNICODE)
|
|
*
|
|
* Sends a message to the specified window station object and optionally
|
|
* waits for a reply. The reply is returned to the caller of
|
|
* WinStationSendMessage.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* WinStationHandle (input)
|
|
* Specifies the window station object to send a message to.
|
|
*
|
|
* pTitle (input)
|
|
* Pointer to title for message box to display.
|
|
*
|
|
* TitleLength (input)
|
|
* Length of title to display in bytes.
|
|
*
|
|
* pMessage (input)
|
|
* Pointer to message to display.
|
|
*
|
|
* MessageLength (input)
|
|
* Length of message in bytes to display at the specified window station.
|
|
*
|
|
* Style (input)
|
|
* Standard Windows MessageBox() style parameter.
|
|
*
|
|
* Timeout (input)
|
|
* Response timeout in seconds. If message is not responded to in
|
|
* Timeout seconds then a response code of IDTIMEOUT (cwin.h) is
|
|
* returned to signify the message timed out.
|
|
*
|
|
* pResponse (output)
|
|
* Address to return selected response.
|
|
*
|
|
* DoNotWait (input)
|
|
* Do not wait for the response. Causes pResponse to be set to
|
|
* IDASYNC (cwin.h) if no errors queueing the message.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The send message operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationSendMessageW(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
LPWSTR pTitle,
|
|
ULONG TitleLength,
|
|
LPWSTR pMessage,
|
|
ULONG MessageLength,
|
|
ULONG Style,
|
|
ULONG Timeout,
|
|
PULONG pResponse,
|
|
BOOLEAN DoNotWait
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
WCHAR* rpcBuffer1;
|
|
WCHAR* rpcBuffer2;
|
|
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
// Since, due to legacy clients, we cannot change the interface,
|
|
// as a workarround to bug#265954, we double the size of RPC Buffers.
|
|
|
|
rpcBuffer1 = LocalAlloc(LPTR, MessageLength * sizeof(WCHAR));
|
|
if (rpcBuffer1 != NULL) {
|
|
CopyMemory(rpcBuffer1, pMessage, MessageLength);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
rpcBuffer2 = LocalAlloc(LPTR, TitleLength * sizeof(WCHAR));
|
|
if (rpcBuffer2 != NULL) {
|
|
CopyMemory(rpcBuffer2, pTitle, TitleLength);
|
|
} else {
|
|
LocalFree(rpcBuffer1);
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationSendMessage(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
rpcBuffer2,
|
|
TitleLength,
|
|
rpcBuffer1,
|
|
MessageLength,
|
|
Style,
|
|
Timeout,
|
|
pResponse,
|
|
DoNotWait
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
LocalFree(rpcBuffer1);
|
|
LocalFree(rpcBuffer2);
|
|
if (!rc) {
|
|
SetLastError( Result );
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* LogonIdFromWinStationNameA (ANSI stub)
|
|
*
|
|
* Returns the LogonId for the specified window station name.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see LogonIdFromWinStationNameW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see LogonIdFromWinStationNameW
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
LogonIdFromWinStationNameA(
|
|
HANDLE hServer,
|
|
PWINSTATIONNAMEA pWinStationName,
|
|
PULONG pLogonId
|
|
)
|
|
{
|
|
WINSTATIONNAMEW WinStationNameW;
|
|
|
|
/*
|
|
* Convert ANSI WinStationName to UNICODE.
|
|
*/
|
|
AnsiToUnicode( WinStationNameW, sizeof(WINSTATIONNAMEW), pWinStationName );
|
|
|
|
/*
|
|
* Call LogonIdFromWinStationNameW & return it's status.
|
|
*/
|
|
return ( LogonIdFromWinStationNameW( hServer, WinStationNameW, pLogonId ) );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* LogonIdFromWinStationNameW (UNICODE)
|
|
*
|
|
* Returns the LogonId for the specified window station name.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* pWinStationName (input)
|
|
* Window station name.
|
|
*
|
|
* pLogonId (output)
|
|
* Pointer to where to place the LogonId if found
|
|
*
|
|
* EXIT:
|
|
*
|
|
* If the function succeeds, the return value is TRUE, otherwise, it is
|
|
* FALSE.
|
|
* To get extended error information, use the GetLastError function.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
LogonIdFromWinStationNameW(
|
|
HANDLE hServer,
|
|
PWINSTATIONNAMEW pWinStationName,
|
|
PULONG pLogonId
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for bug 229753. The bug can't be fixed
|
|
* completely without breaking TS4 clients.
|
|
*/
|
|
|
|
#pragma prefast(suppress:260, legacy clients expect this (http://searchraid/ntbug/229753.asp))
|
|
rpcBuffer = LocalAlloc(LPTR, sizeof(WINSTATIONNAMEW) * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pWinStationName, sizeof(WINSTATIONNAMEW));
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcLogonIdFromWinStationName(
|
|
hServer,
|
|
&Result,
|
|
rpcBuffer,
|
|
sizeof(WINSTATIONNAMEW),
|
|
pLogonId
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationNameFromLogonIdA (ANSI stub)
|
|
*
|
|
* Returns the WinStation name for the specified LogonId.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationNameFromLogonIdW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationNameFromLogonIdW
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationNameFromLogonIdA(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
PWINSTATIONNAMEA pWinStationName
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
WINSTATIONNAMEW WinStationNameW;
|
|
|
|
/*
|
|
* Call WinStationNameFromLogonIdW
|
|
*/
|
|
Result = WinStationNameFromLogonIdW( hServer, LogonId, WinStationNameW );
|
|
|
|
/*
|
|
* if successful, convert UNICODE WinStationName to ANSI.
|
|
*/
|
|
if ( Result ) {
|
|
UnicodeToAnsi( pWinStationName, sizeof(WINSTATIONNAMEA), WinStationNameW );
|
|
}
|
|
|
|
return( Result );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationNameFromLogonIdW (UNICODE)
|
|
*
|
|
* Returns the WinStation name for the specified LogonId.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* LogonId (input)
|
|
* LogonId to query
|
|
*
|
|
* pWinStationName (output)
|
|
* Location to return WinStation name
|
|
*
|
|
* EXIT:
|
|
*
|
|
* If the function succeeds, the return value is TRUE, otherwise, it is
|
|
* FALSE.
|
|
* To get extended error information, use the GetLastError function.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationNameFromLogonIdW(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
PWINSTATIONNAMEW pWinStationName
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for bug 229753. The bug can't be fixed
|
|
* completely without breaking TS4 clients.
|
|
*/
|
|
|
|
#pragma prefast(suppress:260, legacy clients expect this (http://searchraid/ntbug/229753.asp))
|
|
rpcBuffer = LocalAlloc(LPTR, sizeof(WINSTATIONNAMEW) * sizeof(WCHAR));
|
|
if (rpcBuffer == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationNameFromLogonId(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ?
|
|
NtCurrentPeb()->SessionId : LogonId,
|
|
rpcBuffer,
|
|
sizeof(WINSTATIONNAMEW)
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if (rc) {
|
|
CopyMemory(pWinStationName, rpcBuffer, sizeof(WINSTATIONNAMEW));
|
|
}
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationConnectA (ANSI stub)
|
|
*
|
|
* Connects a window station object to the configured terminal and Pd.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* see WinStationConnectW
|
|
*
|
|
* EXIT:
|
|
*
|
|
* see WinStationConnectW
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationConnectA( HANDLE hServer,
|
|
ULONG LogonId,
|
|
ULONG TargetLogonId,
|
|
PCHAR pPassword,
|
|
BOOLEAN bWait )
|
|
{
|
|
WCHAR PasswordW[ PASSWORD_LENGTH + 1 ];
|
|
|
|
/*
|
|
* Convert ANSI Password to UNICODE.
|
|
*/
|
|
|
|
AnsiToUnicode( PasswordW, sizeof(PasswordW), pPassword );
|
|
|
|
/*
|
|
* Call WinStationConnectW & return it's status.
|
|
*/
|
|
return ( WinStationConnectW( hServer, LogonId, TargetLogonId, PasswordW, bWait ) );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationConnectW (UNICODE)
|
|
*
|
|
* Connects a window station object to the configured terminal and Pd.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* LogonId (input)
|
|
* ID of window station object to connect.
|
|
*
|
|
* TargetLogonId (input)
|
|
* ID of target window station.
|
|
*
|
|
* pPassword (input)
|
|
* password of LogonId window station (not needed if same domain/username)
|
|
*
|
|
* bWait (input)
|
|
* Specifies whether or not to wait for connect to complete
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The connect operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationConnectW(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
ULONG TargetLogonId,
|
|
PWCHAR pPassword,
|
|
BOOLEAN bWait
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
DWORD PasswordLength;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
if( pPassword ) {
|
|
PasswordLength = (lstrlenW( pPassword ) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for bug 229753. The bug can't be
|
|
* fixed completely without breaking TS4 clients.
|
|
*/
|
|
|
|
rpcBuffer = LocalAlloc(LPTR, PasswordLength * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pPassword, PasswordLength);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
PasswordLength = 0;
|
|
rpcBuffer = NULL;
|
|
}
|
|
|
|
rc = RpcWinStationConnect(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
(LogonId == LOGONID_CURRENT) ?
|
|
NtCurrentPeb()->SessionId : LogonId,
|
|
(TargetLogonId == LOGONID_CURRENT) ?
|
|
NtCurrentPeb()->SessionId : TargetLogonId,
|
|
rpcBuffer,
|
|
PasswordLength,
|
|
bWait
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationVirtualOpen
|
|
*
|
|
* Open a virtual channel
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
HANDLE WINAPI
|
|
WinStationVirtualOpen(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
PVIRTUALCHANNELNAME pVirtualName /* ascii name */
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD NameLength;
|
|
ULONG_PTR VirtualHandle = (ULONG_PTR)0;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
if( pVirtualName )
|
|
NameLength = strlen( pVirtualName ) + 1;
|
|
else
|
|
NameLength = 0;
|
|
|
|
rc = RpcWinStationVirtualOpen(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
GetCurrentProcessId(),
|
|
(PCHAR)pVirtualName,
|
|
NameLength,
|
|
&VirtualHandle
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) {
|
|
SetLastError(Result);
|
|
VirtualHandle = (ULONG_PTR)0;
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( (HANDLE) ( VirtualHandle ) );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationBeepOpen
|
|
*
|
|
* Open a beep channel
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
HANDLE WINAPI
|
|
_WinStationBeepOpen(
|
|
ULONG LogonId
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
ULONG_PTR VirtualHandle = (ULONG_PTR)0;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationBeepOpen(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
GetCurrentProcessId(),
|
|
&VirtualHandle
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) {
|
|
SetLastError(Result);
|
|
VirtualHandle = (ULONG_PTR)0;
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( (HANDLE) ( VirtualHandle ) );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationDisconnect
|
|
*
|
|
* Disconects a window station object from the configured terminal and Pd.
|
|
* While disconnected all window station i/o is bit bucketed.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* LogonId (input)
|
|
* ID of window station object to disconnect.
|
|
* bWait (input)
|
|
* Specifies whether or not to wait for disconnect to complete
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The disconnect operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationDisconnect(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
BOOLEAN bWait
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationDisconnect(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
bWait
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationReset
|
|
*
|
|
* Reset the specified window station.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* LogonId (input)
|
|
* Identifies the window station object to reset.
|
|
* bWait (input)
|
|
* Specifies whether or not to wait for reset to complete
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The reset operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationReset(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
BOOLEAN bWait
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationReset(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
bWait
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationShadowStop
|
|
*
|
|
* Stop the shadow on the specified window station.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* LogonId (input)
|
|
* Identifies the window station object to stop the shadow on.
|
|
* bWait (input)
|
|
* Specifies whether or not to wait for reset to complete
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationShadowStop(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
BOOLEAN bWait
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationShadowStop(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
bWait
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationShutdownSystem
|
|
*
|
|
* Shutdown the system and optionally logoff all WinStations
|
|
* and/or reboot the system.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* ShutdownFlags (input)
|
|
* Flags which specify shutdown options.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The shutdown operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationShutdownSystem(
|
|
HANDLE hServer,
|
|
ULONG ShutdownFlags
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationShutdownSystem(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
ShutdownFlags
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationTerminateProcess
|
|
*
|
|
* Terminate the specified process
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* hServer (input)
|
|
* handle to winframe server
|
|
* ProcessId (input)
|
|
* process id of the process to terminate
|
|
* ExitCode (input)
|
|
* Termination status for each thread in the process
|
|
*
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The terminate operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationTerminateProcess(
|
|
HANDLE hServer,
|
|
ULONG ProcessId,
|
|
ULONG ExitCode
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationTerminateProcess(
|
|
hServer,
|
|
&Result,
|
|
ProcessId,
|
|
ExitCode
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationWaitSystemEvent
|
|
*
|
|
* Waits for an event (WinStation create, delete, connect, etc) before
|
|
* returning to the caller.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EventFlags (input)
|
|
* Bit mask that specifies which event(s) to wait for.
|
|
* pEventFlags (output)
|
|
* Bit mask of event(s) that occurred.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The wait event operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationWaitSystemEvent(
|
|
HANDLE hServer,
|
|
ULONG EventMask,
|
|
PULONG pEventFlags
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationWaitSystemEvent(
|
|
hServer,
|
|
&Result,
|
|
EventMask,
|
|
pEventFlags
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationShadow
|
|
*
|
|
* Start a Winstation shadow operation
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* open RPC server handle
|
|
* pTargetServerName (input)
|
|
* name of target WinFrame server
|
|
* TargetLogonId (input)
|
|
* shadow target login id (where the app is running)
|
|
* HotkeyVk (input)
|
|
* virtual key to press to stop shadow
|
|
* HotkeyModifiers (input)
|
|
* virtual modifer to press to stop shadow (i.e. shift, control)
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationShadow(
|
|
HANDLE hServer,
|
|
LPWSTR pTargetServerName,
|
|
ULONG TargetLogonId,
|
|
BYTE HotkeyVk,
|
|
USHORT HotkeyModifiers
|
|
)
|
|
{
|
|
DWORD NameSize;
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
if ( pTargetServerName && *pTargetServerName ) {
|
|
NameSize = (lstrlenW( pTargetServerName ) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for bug 229753. The bug can't be
|
|
* fixed completely without breaking TS4 clients.
|
|
*/
|
|
|
|
rpcBuffer = LocalAlloc(LPTR, NameSize * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pTargetServerName, NameSize);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
NameSize = 0;
|
|
rpcBuffer = NULL;
|
|
}
|
|
|
|
rc = RpcWinStationShadow(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
rpcBuffer,
|
|
NameSize,
|
|
TargetLogonId,
|
|
HotkeyVk,
|
|
HotkeyModifiers
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationShadowTargetSetup
|
|
*
|
|
* private api used to initialize the target size of a shadow
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* target server
|
|
* LogonId (input)
|
|
* target logon id
|
|
* pClientName (input)
|
|
* pointer to client name string (domain/username)
|
|
* ClientNameLength (input)
|
|
* length of client name string
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationShadowTargetSetup(
|
|
HANDLE hServer,
|
|
ULONG LogonId
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationShadowTargetSetup(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId
|
|
);
|
|
|
|
//Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(RtlNtStatusToDosError(Result));
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationShadowTarget
|
|
*
|
|
* private api used to initialize the target size of a shadow
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* target server
|
|
* LogonId (input)
|
|
* target logon id
|
|
* pConfig (input)
|
|
* pointer to WinStation config data (to configure shadow stack)
|
|
* pAddress (input)
|
|
* address of shadow client
|
|
* pModuleData (input)
|
|
* pointer to client module data
|
|
* ModuleDataLength (input)
|
|
* length of client module data
|
|
* pThinwireData (input)
|
|
* pointer to thinwire module data
|
|
* ThinwireDataLength (input)
|
|
* length of thinwire module data
|
|
* pClientName (input)
|
|
* pointer to client name string (domain/username)
|
|
* ClientNameLength (input)
|
|
* length of client name string
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
NTSTATUS WINAPI
|
|
_WinStationShadowTarget(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
PWINSTATIONCONFIG2 pConfig,
|
|
PICA_STACK_ADDRESS pAddress,
|
|
PVOID pModuleData,
|
|
ULONG ModuleDataLength,
|
|
PVOID pThinwireData,
|
|
ULONG ThinwireDataLength,
|
|
PVOID pClientName,
|
|
ULONG ClientNameLength
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationShadowTarget(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
(PBYTE) pConfig,
|
|
sizeof(*pConfig),
|
|
(PBYTE) pAddress,
|
|
sizeof(*pAddress),
|
|
pModuleData,
|
|
ModuleDataLength,
|
|
pThinwireData,
|
|
ThinwireDataLength,
|
|
pClientName,
|
|
ClientNameLength
|
|
);
|
|
|
|
// Since a program has called us, we need to set the last error code such
|
|
// that extended error information is available
|
|
if (!rc)
|
|
SetLastError(RtlNtStatusToDosError(Result));
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationFreeMemory
|
|
*
|
|
* Called to free memory which was allocated by a WinStation API.
|
|
*
|
|
* ENTRY:
|
|
* pBuffer (input)
|
|
*
|
|
* EXIT:
|
|
* TRUE -- The install operation succeeded.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationFreeMemory(
|
|
PVOID pBuffer
|
|
)
|
|
{
|
|
if ( pBuffer )
|
|
LocalFree( pBuffer );
|
|
return( TRUE );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationFreeGAPMemory
|
|
*
|
|
* Called to free memory which was allocated by the WinStationGetAllProcesses API.
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationFreeGAPMemory(ULONG Level,
|
|
PVOID pProcArray,
|
|
ULONG NumberOfProcesses)
|
|
{
|
|
ULONG i;
|
|
PTS_ALL_PROCESSES_INFO pProcessArray = (PTS_ALL_PROCESSES_INFO)pProcArray;
|
|
|
|
if (Level == GAP_LEVEL_BASIC) // only level supported right now
|
|
{
|
|
if ( pProcessArray != NULL)
|
|
{
|
|
for (i=0; i < NumberOfProcesses ; i++)
|
|
{
|
|
if (pProcessArray[i].pTsProcessInfo != NULL)
|
|
{
|
|
if (((pProcessArray[i].pTsProcessInfo)->ImageName).Buffer != NULL)
|
|
{
|
|
//
|
|
// free the ImageName string
|
|
//
|
|
LocalFree(((pProcessArray[i].pTsProcessInfo)->ImageName).Buffer);
|
|
}
|
|
//
|
|
// free the Process Info buffer
|
|
//
|
|
LocalFree(pProcessArray[i].pTsProcessInfo);
|
|
}
|
|
|
|
if (pProcessArray[i].pSid != NULL)
|
|
{
|
|
//
|
|
// free the SID
|
|
//
|
|
LocalFree(pProcessArray[i].pSid);
|
|
}
|
|
}
|
|
|
|
LocalFree(pProcessArray);
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationGenerateLicense
|
|
*
|
|
* Called to generate a license from a given serial number string.
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* pSerialNumberString (input)
|
|
* Pointer to a null-terminated, wide-character Serial Number string
|
|
* pLicense (output)
|
|
* Pointer to a License structure that will be filled in with
|
|
* information based on pSerialNumberString
|
|
* LicenseSize (input)
|
|
* Size in bytes of the structure pointed to by pLicense
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The install operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationGenerateLicense(
|
|
HANDLE hServer,
|
|
PWCHAR pSerialNumberString,
|
|
PVOID pLicense,
|
|
DWORD LicenseSize
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD Length;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
if ( pSerialNumberString ) {
|
|
Length = (lstrlenW( pSerialNumberString ) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for 229753.
|
|
*/
|
|
|
|
rpcBuffer = LocalAlloc(LPTR, Length * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pSerialNumberString, Length);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
Length = 0;
|
|
rpcBuffer = NULL;
|
|
}
|
|
|
|
rc = RpcWinStationGenerateLicense(
|
|
hServer,
|
|
&Result,
|
|
rpcBuffer,
|
|
Length,
|
|
(PCHAR)pLicense,
|
|
LicenseSize
|
|
);
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationInstallLicense
|
|
*
|
|
* Called to install a license.
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* pLicense (input)
|
|
* Pointer to a License structure containing the license to
|
|
* be installed
|
|
* LicenseSize (input)
|
|
* Size in bytes of the structure pointed to by pLicense
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The install operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationInstallLicense(
|
|
HANDLE hServer,
|
|
PVOID pLicense,
|
|
DWORD LicenseSize
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationInstallLicense(
|
|
hServer,
|
|
&Result,
|
|
(PCHAR) pLicense,
|
|
LicenseSize
|
|
);
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationEnumerateLicenses
|
|
*
|
|
* Called to return the list of valid licenses.
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* ppLicense (output)
|
|
* Points to a pointer to a buffer to receive the enumeration results,
|
|
* which are returned as an array of LICENSE structures. The buffer is
|
|
* allocated within this API and is disposed of using
|
|
* WinStationFreeMemory.
|
|
* pEntries (output)
|
|
* Points to a variable specifying the number of entries read.
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The enumerate operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#define _LICENSE_REQUEST_SIZE 10
|
|
#define _LICENSE_SIZE 1024 // This is arbitrary
|
|
BOOLEAN
|
|
WinStationEnumerateLicenses(
|
|
HANDLE hServer,
|
|
PVOID *ppLicense,
|
|
DWORD *pEntries
|
|
)
|
|
{
|
|
ULONG ByteCount;
|
|
ULONG BumpSize;
|
|
ULONG TotalSize;
|
|
LONG Index;
|
|
int i;
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
BumpSize = _LICENSE_SIZE * _LICENSE_REQUEST_SIZE;
|
|
TotalSize = 0;
|
|
*ppLicense = NULL;
|
|
*pEntries = 0;
|
|
Index = 0;
|
|
for ( ;; ) {
|
|
PVOID pNewLicense;
|
|
LONG BumpEntries;
|
|
|
|
/*
|
|
* Allocate a enough memory for _LICENSE_REQUEST_SIZE more
|
|
* entries.
|
|
*/
|
|
pNewLicense = LocalAlloc( 0, TotalSize + BumpSize );
|
|
if ( !pNewLicense ) {
|
|
if ( *ppLicense )
|
|
WinStationFreeMemory( *ppLicense );
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
/*
|
|
* If this is not the first pass through, then copy
|
|
* the previous buffer's contents to the new buffer.
|
|
*/
|
|
if ( TotalSize ) {
|
|
RtlCopyMemory( pNewLicense, *ppLicense, TotalSize );
|
|
WinStationFreeMemory( *ppLicense );
|
|
}
|
|
*ppLicense = pNewLicense;
|
|
|
|
/*
|
|
* Get up to _LICENSE_REQUEST_SIZE Licenses
|
|
*/
|
|
ByteCount = BumpSize;
|
|
BumpEntries = _LICENSE_REQUEST_SIZE;
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationEnumerateLicenses(
|
|
hServer,
|
|
&Result,
|
|
&Index,
|
|
&BumpEntries,
|
|
(PCHAR) (((PCHAR) *ppLicense) + TotalSize),
|
|
ByteCount,
|
|
&ByteCount
|
|
);
|
|
|
|
Result = rc ? ERROR_SUCCESS : Result;
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
}
|
|
RpcEndExcept
|
|
|
|
if ( Result != ERROR_SUCCESS && Result != ERROR_NO_MORE_ITEMS ) {
|
|
|
|
SetLastError( Result );
|
|
return( FALSE );
|
|
|
|
}
|
|
else {
|
|
/*
|
|
* Bump the Total Size of the License buffer by the size of
|
|
* the request
|
|
*/
|
|
TotalSize += BumpSize;
|
|
|
|
/*
|
|
* Include the new Licenses in the entry count
|
|
*/
|
|
*pEntries += BumpEntries;
|
|
|
|
if ( Result == ERROR_NO_MORE_ITEMS ) {
|
|
return( TRUE );
|
|
}
|
|
}
|
|
} // for ( ;; )
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationActivateLicense
|
|
*
|
|
* Called to Activate a license for a given License
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* pLicense (input/output)
|
|
* Pointer to a License structure that will be activated
|
|
* LicenseSize (input)
|
|
* Size in bytes of the structure pointed to by pLicense
|
|
* pActivationCode (input)
|
|
* Pointer to a null-terminated, wide-character Activation Code string
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The install operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationActivateLicense(
|
|
HANDLE hServer,
|
|
PVOID pLicense,
|
|
DWORD LicenseSize,
|
|
PWCHAR pActivationCode
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD Length;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
if ( pActivationCode ) {
|
|
Length = (lstrlenW( pActivationCode ) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for 229753.
|
|
*/
|
|
|
|
rpcBuffer = LocalAlloc(LPTR, Length * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pActivationCode, Length);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
Length = 0;
|
|
rpcBuffer = NULL;
|
|
}
|
|
|
|
rc = RpcWinStationActivateLicense(
|
|
hServer,
|
|
&Result,
|
|
(PCHAR)pLicense,
|
|
LicenseSize,
|
|
rpcBuffer,
|
|
Length
|
|
);
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationQueryLicense
|
|
*
|
|
* Query the license(s) on the WinFrame server and the network
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* pLicenseCounts (output)
|
|
* pointer to buffer to return license count structure
|
|
* ByteCount (input)
|
|
* length of buffer in bytes
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationQueryLicense(
|
|
HANDLE hServer,
|
|
PVOID pLicenseCounts,
|
|
ULONG ByteCount
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
memset( pLicenseCounts, 0, ByteCount );
|
|
|
|
rc = RpcWinStationQueryLicense(
|
|
hServer,
|
|
&Result,
|
|
(PCHAR) pLicenseCounts,
|
|
ByteCount
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationQueryUpdateRequired
|
|
*
|
|
* Query the license(s) on the WinFrame server and determine if an
|
|
* update is required. (worker)
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* pUpdateFlag (output)
|
|
* Update flag, set if an update is required
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationQueryUpdateRequired(
|
|
HANDLE hServer,
|
|
PULONG pUpdateFlag
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationQueryUpdateRequired(
|
|
hServer,
|
|
&Result,
|
|
pUpdateFlag
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationRemoveLicense
|
|
*
|
|
* Called to remove a license diskette.
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* pLicense (input)
|
|
* Pointer to a License structure containing the license to
|
|
* be removed
|
|
* LicenseSize (input)
|
|
* Size in bytes of the structure pointed to by pLicense
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The install operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationRemoveLicense(
|
|
HANDLE hServer,
|
|
PVOID pLicense,
|
|
DWORD LicenseSize
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationRemoveLicense(
|
|
hServer,
|
|
&Result,
|
|
(PCHAR) pLicense,
|
|
LicenseSize
|
|
);
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationSetPoolCount
|
|
*
|
|
* Called to change the PoolCount for a given License
|
|
*
|
|
* ENTRY:
|
|
* hServer (input)
|
|
* Server handle
|
|
* pLicense (input/output)
|
|
* Pointer to a License structure that will be changed
|
|
* LicenseSize (input)
|
|
* Size in bytes of the structure pointed to by pLicense
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The change operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationSetPoolCount(
|
|
HANDLE hServer,
|
|
PVOID pLicense,
|
|
DWORD LicenseSize
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationSetPoolCount(
|
|
hServer,
|
|
&Result,
|
|
(PCHAR) pLicense,
|
|
LicenseSize
|
|
);
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationAnnoyancePopup
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationAnnoyancePopup(
|
|
HANDLE hServer,
|
|
ULONG LogonId
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationAnnoyancePopup(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationCallback
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationCallback(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
LPWSTR pPhoneNumber
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD Length;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
if( pPhoneNumber ) {
|
|
Length = (lstrlenW( pPhoneNumber ) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for 229753.
|
|
*/
|
|
|
|
rpcBuffer = LocalAlloc(LPTR, Length * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pPhoneNumber, Length);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
Length = 0;
|
|
rpcBuffer = NULL;
|
|
}
|
|
|
|
rc = RpcWinStationCallback(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ?
|
|
NtCurrentPeb()->SessionId : LogonId,
|
|
rpcBuffer,
|
|
Length
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationBreakPoint
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationBreakPoint(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
BOOLEAN KernelFlag
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationBreakPoint(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId,
|
|
KernelFlag
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationReadRegistry
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationReadRegistry(
|
|
HANDLE hServer
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationReadRegistry(
|
|
hServer,
|
|
&Result
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationUpdateSettings
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationUpdateSettings(
|
|
HANDLE hServer,
|
|
WINSTATIONUPDATECFGCLASS SettingsClass,
|
|
DWORD SettingsParameters
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationUpdateSettings(
|
|
hServer,
|
|
&Result,
|
|
(DWORD)SettingsClass,
|
|
SettingsParameters
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationReInitializeSecurity
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationReInitializeSecurity(
|
|
HANDLE hServer
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationReInitializeSecurity(
|
|
hServer,
|
|
&Result
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationWaitForConnect
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationWaitForConnect(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
if (NtCurrentPeb()->SessionId != 0) {
|
|
DbgPrint("hServer == RPC_HANDLE_NO_SERVER for SessionId %d\n",NtCurrentPeb()->SessionId);
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationWaitForConnect(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId()
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationNotifyLogon
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationNotifyLogon(
|
|
BOOLEAN fUserIsAdmin,
|
|
HANDLE UserToken,
|
|
PWCHAR pDomain,
|
|
PWCHAR pUserName,
|
|
PWCHAR pPassword,
|
|
UCHAR Seed,
|
|
PUSERCONFIGW pUserConfig,
|
|
BOOLEAN *pfIsRedirected
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD DomainLength;
|
|
DWORD UserNameLength;
|
|
DWORD PasswordLength;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
HANDLE ReadyEventHandle;
|
|
DWORD TermSrvWaitTime = 180 * 1000; // 3 Minutes
|
|
WCHAR* rpcBuffer1 = NULL;
|
|
WCHAR* rpcBuffer2 = NULL;
|
|
WCHAR* rpcBuffer3 = NULL;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Wait for the TermSrvReadyEvent to be set by TERMSRV.EXE. This
|
|
// event indicates that TermSrv is initialized to the point that
|
|
// the data used by _WinStationNotifyLogon() is available.
|
|
//
|
|
ReadyEventHandle = OpenEvent(SYNCHRONIZE, FALSE, TEXT("Global\\TermSrvReadyEvent"));
|
|
if (ReadyEventHandle != NULL)
|
|
{
|
|
if (WaitForSingleObject(ReadyEventHandle, TermSrvWaitTime) != 0)
|
|
{
|
|
DBGPRINT(("WinLogon: Wait for ReadyEventHandle failed\n"));
|
|
}
|
|
CloseHandle(ReadyEventHandle);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(("WinLogon: Create failed for ReadyEventHandle\n"));
|
|
}
|
|
|
|
|
|
RpcTryExcept {
|
|
|
|
if( pDomain ) {
|
|
DomainLength = (lstrlenW( pDomain ) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer[1,2,3] is a workaround for 229753.
|
|
*/
|
|
|
|
rpcBuffer1 = LocalAlloc(LPTR, DomainLength * sizeof(WCHAR));
|
|
if (rpcBuffer1 != NULL) {
|
|
CopyMemory(rpcBuffer1, pDomain, DomainLength);
|
|
} else {
|
|
Result = ERROR_OUTOFMEMORY;
|
|
rc = FALSE;
|
|
goto Error;
|
|
}
|
|
|
|
} else {
|
|
DomainLength = 0;
|
|
rpcBuffer1 = NULL;
|
|
}
|
|
|
|
if( pUserName ) {
|
|
UserNameLength = (lstrlenW( pUserName ) + 1) * sizeof(WCHAR);
|
|
|
|
rpcBuffer2 = LocalAlloc(LPTR, UserNameLength * sizeof(WCHAR));
|
|
if (rpcBuffer2 != NULL) {
|
|
CopyMemory(rpcBuffer2, pUserName, UserNameLength);
|
|
} else {
|
|
Result = ERROR_OUTOFMEMORY;
|
|
rc = FALSE;
|
|
goto Error;
|
|
}
|
|
|
|
} else {
|
|
UserNameLength = 0;
|
|
rpcBuffer2 = NULL;
|
|
}
|
|
|
|
if( pPassword ) {
|
|
PasswordLength = (lstrlenW( pPassword ) + 1) * sizeof(WCHAR);
|
|
|
|
rpcBuffer3 = LocalAlloc(LPTR, PasswordLength * sizeof(WCHAR));
|
|
if (rpcBuffer3 != NULL) {
|
|
CopyMemory(rpcBuffer3, pPassword, PasswordLength);
|
|
} else {
|
|
Result = ERROR_OUTOFMEMORY;
|
|
rc = FALSE;
|
|
goto Error;
|
|
}
|
|
|
|
} else {
|
|
PasswordLength = 0;
|
|
rpcBuffer3 = NULL;
|
|
}
|
|
|
|
rc = RpcWinStationNotifyLogon(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId(),
|
|
fUserIsAdmin,
|
|
(DWORD)(INT_PTR)UserToken,
|
|
rpcBuffer1,
|
|
DomainLength,
|
|
rpcBuffer2,
|
|
UserNameLength,
|
|
rpcBuffer3,
|
|
PasswordLength,
|
|
Seed,
|
|
(PCHAR)pUserConfig,
|
|
sizeof(*pUserConfig),
|
|
pfIsRedirected
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = RtlNtStatusToDosError( Result );
|
|
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
Error:
|
|
if (rpcBuffer1 != NULL) {
|
|
LocalFree(rpcBuffer1);
|
|
}
|
|
|
|
if (rpcBuffer2 != NULL) {
|
|
LocalFree(rpcBuffer2);
|
|
}
|
|
|
|
if (rpcBuffer3 != NULL) {
|
|
LocalFree(rpcBuffer3);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationNotifyLogoff
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationNotifyLogoff(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationNotifyLogoff(
|
|
hServer,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId(),
|
|
&Result
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationNotifyNewSession
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationNotifyNewSession(
|
|
HANDLE hServer,
|
|
ULONG LogonId
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
//
|
|
// If the local machine has no TSRPC interface running, this is most
|
|
// likely the console winlogon attempting to logon before termsrv.exe
|
|
// is running.
|
|
//
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationNotifyNewSession(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _RpcServerNWLogonSetAdmin
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_NWLogonSetAdmin(
|
|
HANDLE hServer,
|
|
PWCHAR pServerName,
|
|
PNWLOGONADMIN pNWLogon
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD ServerNameLength;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
if (pServerName) {
|
|
ServerNameLength = (lstrlenW(pServerName) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for bug 229753. The bug can't be fixed
|
|
* completely without breaking TS4 clients.
|
|
*/
|
|
|
|
rpcBuffer = LocalAlloc(LPTR, ServerNameLength * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pServerName, ServerNameLength);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
ServerNameLength = 0;
|
|
rpcBuffer = NULL;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcServerNWLogonSetAdmin(
|
|
hServer,
|
|
&Result,
|
|
rpcBuffer,
|
|
ServerNameLength,
|
|
(PCHAR)pNWLogon,
|
|
sizeof(NWLOGONADMIN)
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _RpcServerNWLogonQueryAdmin
|
|
*
|
|
* Comment
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_NWLogonQueryAdmin(
|
|
HANDLE hServer,
|
|
PWCHAR pServerName,
|
|
PNWLOGONADMIN pNWLogon
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD ServerNameLength;
|
|
WCHAR* rpcBuffer;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
if (pServerName) {
|
|
ServerNameLength = (lstrlenW(pServerName) + 1) * sizeof(WCHAR);
|
|
|
|
/*
|
|
* rpcBuffer is a workaround for bug 229753. The bug can't be fixed
|
|
* completely without breaking TS4 clients.
|
|
*/
|
|
|
|
rpcBuffer = LocalAlloc(LPTR, ServerNameLength * sizeof(WCHAR));
|
|
if (rpcBuffer != NULL) {
|
|
CopyMemory(rpcBuffer, pServerName, ServerNameLength);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
ServerNameLength = 0;
|
|
rpcBuffer = NULL;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcServerNWLogonQueryAdmin(
|
|
hServer,
|
|
&Result,
|
|
rpcBuffer,
|
|
ServerNameLength,
|
|
(PCHAR)pNWLogon,
|
|
sizeof(NWLOGONADMIN)
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (rpcBuffer != NULL) {
|
|
LocalFree(rpcBuffer);
|
|
}
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _WinStationCheckForApplicationName
|
|
*
|
|
* Handles published applications.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query succeeded, and the buffer contains the requested data.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
_WinStationCheckForApplicationName(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
PWCHAR pUserName,
|
|
DWORD UserNameSize,
|
|
PWCHAR pDomain,
|
|
DWORD DomainSize,
|
|
PWCHAR pPassword,
|
|
DWORD *pPasswordSize,
|
|
DWORD MaxPasswordSize,
|
|
PCHAR pSeed,
|
|
PBOOLEAN pfPublished,
|
|
PBOOLEAN pfAnonymous
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
WCHAR* rpcBufferName;
|
|
WCHAR* rpcBufferDomain;
|
|
WCHAR* rpcBufferPassword;
|
|
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
// Since, due to legacy clients, we cannot change the interface,
|
|
// as a workarround to bug#265954, we double the size of RPC Buffers.
|
|
|
|
rpcBufferName = LocalAlloc(LPTR, UserNameSize * sizeof(WCHAR));
|
|
if (rpcBufferName != NULL) {
|
|
CopyMemory(rpcBufferName, pUserName, UserNameSize);
|
|
} else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
rpcBufferDomain = LocalAlloc(LPTR, DomainSize * sizeof(WCHAR));
|
|
if (rpcBufferDomain != NULL) {
|
|
CopyMemory(rpcBufferDomain, pDomain, DomainSize);
|
|
} else {
|
|
LocalFree(rpcBufferName);
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
rpcBufferPassword = LocalAlloc(LPTR,MaxPasswordSize * sizeof(WCHAR));
|
|
if (rpcBufferPassword != NULL) {
|
|
CopyMemory(rpcBufferPassword, pPassword, MaxPasswordSize);
|
|
} else {
|
|
LocalFree(rpcBufferName);
|
|
LocalFree(rpcBufferDomain);
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationCheckForApplicationName(
|
|
hServer,
|
|
&Result,
|
|
LogonId,
|
|
rpcBufferName,
|
|
UserNameSize,
|
|
rpcBufferDomain,
|
|
DomainSize,
|
|
rpcBufferPassword,
|
|
pPasswordSize,
|
|
MaxPasswordSize,
|
|
pSeed,
|
|
pfPublished,
|
|
pfAnonymous
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
LocalFree(rpcBufferName);
|
|
LocalFree(rpcBufferDomain);
|
|
LocalFree(rpcBufferPassword);
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _WinStationGetApplicationInfo
|
|
*
|
|
* Gets info about published applications.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query succeeded, and the buffer contains the requested data.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
_WinStationGetApplicationInfo(
|
|
HANDLE hServer,
|
|
ULONG LogonId,
|
|
PBOOLEAN pfPublished,
|
|
PBOOLEAN pfAnonymous
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationGetApplicationInfo(
|
|
hServer,
|
|
&Result,
|
|
LogonId,
|
|
pfPublished,
|
|
pfAnonymous
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationNtsdDebug
|
|
*
|
|
* Set up a debug connection for ntsd
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The function succeeds
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationNtsdDebug(
|
|
ULONG LogonId,
|
|
LONG ProcessId,
|
|
ULONG DbgProcessId,
|
|
ULONG DbgThreadId,
|
|
PVOID AttachCompletionRoutine
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
NTSDDBGPRINT(("In WinStationNtsdDebug command\n"));
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationNtsdDebug(
|
|
hServer,
|
|
&Result,
|
|
LogonId,
|
|
ProcessId,
|
|
DbgProcessId,
|
|
DbgThreadId,
|
|
(DWORD_PTR) AttachCompletionRoutine
|
|
);
|
|
|
|
DbgPrint("RpcWinStationNtsdDebug: returned 0x%x\n", rc);
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
NTSDDBGPRINT(("WinStationNtsdDebug returning %d\n", rc));
|
|
return( rc );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationGetTermSrvCountersValue
|
|
*
|
|
* Gets TermSrv Counters value
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The query succeeded, and the buffer contains the requested data.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
WinStationGetTermSrvCountersValue(
|
|
HANDLE hServer,
|
|
ULONG dwEntries,
|
|
PVOID pCounter
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
rc = RpcWinStationGetTermSrvCountersValue(
|
|
hServer,
|
|
&Result,
|
|
dwEntries,
|
|
(PTS_COUNTER)pCounter
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
if( !rc ) SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationBroadcastSystemMessageWorker
|
|
*
|
|
* Perform the the equivalent to Window's standard API BroadcastSystemMessage to
|
|
* all Hydra sessions. This is an exported function, at least used by the PNP manager to
|
|
* send a device change message to all sessions.
|
|
*
|
|
* LIMITATIONS:
|
|
* some messages, such as WM_COPYDATA send an address pointer to some user data as lParam.
|
|
* In this API. the only such case that is currently supported is for WM_DEVICECHANGE
|
|
* No error code will be returned if you try to use such an unsupported message, simply the
|
|
* lParam will be ignored.
|
|
*
|
|
* ENTRY:
|
|
* hServer
|
|
* this is a handle which identifies a Hydra server. For the local server, hServer
|
|
* should be set to SERVERNAME_CURRENT
|
|
*
|
|
* sendToAllWinstations
|
|
* This should be set to TRUE if you want to broadcast message to all winstations
|
|
*
|
|
* sessionID,
|
|
* if sendToAllWinstations = FALSE, then message is only sent to only the
|
|
* winstation with the specified sessionID
|
|
*
|
|
* timeOut
|
|
* set this to the amount of time you are willing to wait to get a response
|
|
* from the specified winstation. Even though Window's SendMessage API
|
|
* is blocking, the call from this side MUST choose how long it is willing to
|
|
* wait for a response.
|
|
*
|
|
* dwFlags
|
|
* see MSDN on BroadcastSystemMessage(). Be aware that POST is not allowed on any
|
|
* where the wparam is a pointer to some user mode data structure.
|
|
* For more info, see ntos\...\client\ntstubs.c
|
|
*
|
|
* lpdwRecipients
|
|
* Pointer to a variable that contains and receives information about the recipients of the message.
|
|
* see MSDN for more info
|
|
*
|
|
* uiMessage
|
|
* the window's message to send, limited to WM_DEVICECHANGE and WM_SETTINGSCHANGE
|
|
* at this time.
|
|
*
|
|
* wParam
|
|
* first message param
|
|
*
|
|
* lParam
|
|
* second message parameter
|
|
*
|
|
* pResponse
|
|
* this is the response to the message sent, see MSDN
|
|
*
|
|
* idOfSessionBeingIgnored
|
|
* if -1, then no sessions are ignored. Else, the id of the session passed in is ignored
|
|
*
|
|
* EXIT:
|
|
* TRUE if all went well or
|
|
* FALSE if something went wrong.
|
|
*
|
|
* WARNINGs:
|
|
* since the RPC call never blocks, you need to specify a reasonable timeOut if you want to wait for
|
|
* a response. Please remember that since this message is being sent to all winstations, the timeOut value
|
|
* will be on per-winstation.
|
|
*
|
|
* Also, Do not use flag BSF_POSTMESSAGE, since an app/window on a
|
|
* winstation is not setup to send back a response to the
|
|
* query in an asynchronous fashion.
|
|
* You must wait for the response (until the time out period).
|
|
*
|
|
* Comments:
|
|
* For more info, please see MSDN for BroadcastSystemMessage()
|
|
*
|
|
****************************************************************************/
|
|
|
|
LONG WinStationBroadcastSystemMessageWorker(
|
|
HANDLE hServer,
|
|
BOOL sendToAllWinstations,
|
|
ULONG sessionID,
|
|
ULONG timeOut,
|
|
DWORD dwFlags,
|
|
DWORD *lpdwRecipients,
|
|
ULONG uiMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LONG *pResponse, // this is the response to the message sent
|
|
DWORD idOfSessionBeingIgnored
|
|
)
|
|
{
|
|
|
|
DWORD Result = ERROR_SUCCESS;
|
|
LONG rc;
|
|
LONG status;
|
|
ULONG i;
|
|
LONG response=0;
|
|
|
|
PLOGONID pWd;
|
|
ULONG ByteCount, Index;
|
|
UINT WdCount;
|
|
|
|
// these are used for PNP messages
|
|
PBYTE rpcBuffer=NULL;
|
|
ULONG bufferSize=0;
|
|
ULONG maxSize;
|
|
|
|
BOOLEAN fBufferHasValidData = FALSE;
|
|
|
|
// Since the PNP message uses the lparam to pass the address of a user memory location, we
|
|
// need to handle this by creating our own copy of that data, and then pass it to
|
|
// termServ
|
|
|
|
// we may want to make this general for the future... hence use switch
|
|
switch( uiMessage )
|
|
{
|
|
// if this is a PNP message
|
|
case WM_DEVICECHANGE:
|
|
|
|
if ( lParam ) // see if the PNP message has a pointer to some user data
|
|
{
|
|
bufferSize = ( (DEV_BROADCAST_HDR *)(lParam))->dbch_size;
|
|
rpcBuffer = LocalAlloc( LPTR, bufferSize );
|
|
if ( rpcBuffer )
|
|
{
|
|
// copy from user-space into our local rpc buffer
|
|
CopyMemory(rpcBuffer, (PBYTE)lParam, bufferSize );
|
|
fBufferHasValidData = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// if this is a settings change message the system-CPL sends out
|
|
// when an Admin changes the system env vars...
|
|
case WM_SETTINGCHANGE:
|
|
if ( lParam ) // see if message has a string data
|
|
{
|
|
// put some artificial limit on how large a buffer we are willing to use
|
|
// in order to protect against malicious use of this api
|
|
maxSize = 4096;
|
|
|
|
bufferSize = lstrlenW( (PWCHAR) lParam ) * sizeof( WCHAR );
|
|
if ( bufferSize < maxSize )
|
|
{
|
|
rpcBuffer = LocalAlloc( LPTR, bufferSize );
|
|
if ( rpcBuffer )
|
|
{
|
|
// copy from user-space into our local rpc buffer
|
|
CopyMemory(rpcBuffer, (PBYTE) lParam, bufferSize );
|
|
fBufferHasValidData = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we have too many
|
|
// vars in the user's profile.
|
|
KdPrint(("lParam length too big = %d \n", bufferSize));
|
|
break;
|
|
SetLastError( ERROR_MESSAGE_EXCEEDS_MAX_SIZE );
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// if the rpcBuffer is still empty (meaning, this was not a PNP message), we must fill it up
|
|
// with some bogus data, otherwise, we will get an RPC error of RPC_X_NULL_REF_POINTER
|
|
// (error code of 1780). It looks like Rpc does not check the
|
|
// bufferSize value, and it just throws an exception if the buffer is NULL.
|
|
//
|
|
if ( !rpcBuffer )
|
|
{
|
|
rpcBuffer = LocalAlloc( LPTR, sizeof(UINT) );
|
|
if (!rpcBuffer)
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return ( FALSE );
|
|
}
|
|
bufferSize = sizeof(UINT);
|
|
fBufferHasValidData = FALSE; // note that this is set to FALSE, which means, the recepient will
|
|
// not use the buffer. We do free the alloc below in either case.
|
|
}
|
|
|
|
HANDLE_CURRENT_BINDING_BUFFER( hServer, rpcBuffer );
|
|
|
|
WdCount = 1000;
|
|
pWd = NULL; // it will be allocated by Winstation Enumerate()
|
|
rc = WinStationEnumerate( hServer, &pWd, &WdCount );
|
|
|
|
/*
|
|
* Do not use this flag, since no process on the session side can respond back to a console process
|
|
* thru the post message mechanism, since there is no session ID abstraction in that call.
|
|
*/
|
|
dwFlags &= ~BSF_POSTMESSAGE;
|
|
|
|
if ( rc != TRUE )
|
|
{
|
|
status = GetLastError();
|
|
DBGPRINT(( "WinstationEnumerate = %d, failed at %s %d\n", status,__FILE__,__LINE__));
|
|
if ( pWd )
|
|
{
|
|
WinStationFreeMemory(pWd);
|
|
}
|
|
|
|
ASSERT(rpcBuffer);
|
|
LocalFree( rpcBuffer );
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// the loop for sending data to each winstation
|
|
//
|
|
for ( i=0; i < WdCount; i++ )
|
|
{
|
|
// id of the session being ignored
|
|
if ( pWd[i].SessionId == idOfSessionBeingIgnored)
|
|
continue;
|
|
|
|
// either send to all winstations, or to a specific winstation
|
|
if ( sendToAllWinstations || pWd[i].SessionId == sessionID )
|
|
{
|
|
// don't send message to any winstation unless it is either Active or in the disconnect state
|
|
if ( pWd[i].State == State_Active ||
|
|
pWd[i].State == State_Disconnected)
|
|
{
|
|
RpcTryExcept
|
|
{
|
|
rc = RpcWinStationBroadcastSystemMessage(
|
|
hServer,
|
|
pWd[i].SessionId,
|
|
timeOut,
|
|
dwFlags,
|
|
lpdwRecipients,
|
|
uiMessage,
|
|
wParam,
|
|
lParam,
|
|
rpcBuffer,
|
|
bufferSize,
|
|
fBufferHasValidData,
|
|
&response );
|
|
|
|
DBGPRINT(("done with call RpcWinStationBroadcastSystemMessage() for sessionID= %d\n", pWd[i].SessionId ));
|
|
*pResponse |= response; // keep an OR of all return values
|
|
|
|
// @@@
|
|
// if response is -1 from any winstation, maybe we should give up and return ?
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d in RpcWinStationBroadcastSystemMessage() for sessionID = %d \n",Result, sessionID));
|
|
rc = FALSE; // change rc to FALSE
|
|
break; // get out of the for-loop, we have a problem with at least one of the winstations
|
|
}
|
|
RpcEndExcept
|
|
|
|
} // end if winstation state check
|
|
|
|
} // if ( sendToAllWinstations || pWd[i].SessionId == sessionID )
|
|
|
|
} // end of the for loop
|
|
|
|
WinStationFreeMemory(pWd);
|
|
|
|
LocalFree( rpcBuffer );
|
|
|
|
SetLastError( Result );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*************************************************************************
|
|
* *
|
|
* This struct is used to pack data passed into a workder thread which is *
|
|
* altimetly passed to WinStationBroadcastSystemMessageWorker() *
|
|
* *
|
|
*************************************************************************/
|
|
typedef struct {
|
|
HANDLE hServer;
|
|
BOOL sendToAllWinstations;
|
|
ULONG sessionID;
|
|
ULONG timeOut;
|
|
DWORD dwFlags;
|
|
DWORD *lpdwRecipients;
|
|
ULONG uiMessage;
|
|
WPARAM wParam;
|
|
LPARAM lParam;
|
|
LONG *pResponse;
|
|
DWORD idOfSessionBeingIgnored ;
|
|
} BSM_DATA_PACKAGE;
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* This is a workder thread used to make a call into WinStationBroadcastSystemMessageWorker() *
|
|
* The reason for this is in certain cases, we don't want to block the caller of this func from *
|
|
* processing window messages *
|
|
* DWORD WINAPI WinStationBSMWorkerThread( LPVOID p ) *
|
|
*
|
|
***********************************************************************************************/
|
|
DWORD WINAPI WinStationBSMWorkerThread( LPVOID p )
|
|
{
|
|
DWORD rc;
|
|
BSM_DATA_PACKAGE *pd = (BSM_DATA_PACKAGE *)p;
|
|
|
|
rc = WinStationBroadcastSystemMessageWorker(
|
|
pd->hServer ,
|
|
pd->sendToAllWinstations ,
|
|
pd->sessionID ,
|
|
pd->timeOut ,
|
|
pd->dwFlags ,
|
|
pd->lpdwRecipients ,
|
|
pd->uiMessage ,
|
|
pd->wParam ,
|
|
pd->lParam ,
|
|
pd->pResponse ,
|
|
pd->idOfSessionBeingIgnored);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/**************************************************************************************************
|
|
* *
|
|
* This func is used to wait on a thread, and still allow the user of this thread (aka the creator *
|
|
* of this thread) to process window messages *
|
|
* *
|
|
**************************************************************************************************/
|
|
DWORD MsgWaitForMultipleObjectsLoop(HANDLE hEvent, DWORD dwTimeout)
|
|
{
|
|
while (1)
|
|
{
|
|
MSG msg;
|
|
|
|
DWORD dwObject = MsgWaitForMultipleObjects(1, &hEvent, FALSE, dwTimeout, QS_ALLEVENTS);
|
|
|
|
// Are we done waiting?
|
|
switch (dwObject)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
case WAIT_FAILED:
|
|
return dwObject;
|
|
|
|
case WAIT_TIMEOUT:
|
|
return WAIT_TIMEOUT;
|
|
|
|
case WAIT_OBJECT_0 + 1:
|
|
// This PeekMessage has the side effect of processing any broadcast messages.
|
|
// It doesn't matter what message we actually peek for but if we don't peek
|
|
// then other threads that have sent broadcast sendmessages will hang until
|
|
// hEvent is signaled. Since the process we're waiting on could be the one
|
|
// that sent the broadcast message that could cause a deadlock otherwise.
|
|
PeekMessage(&msg, NULL, WM_NULL, WM_USER, PM_NOREMOVE);
|
|
break;
|
|
}
|
|
}
|
|
// never gets here
|
|
// return dwObject;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationBroadcastSystemMessage
|
|
*
|
|
* Perform the the equivalent to Window's standard API BroadcastSystemMessage to
|
|
* all Hydra sessions. This is an exported function, at least used by the PNP manager to
|
|
* send a device change message to all sessions.
|
|
*
|
|
* LIMITATIONS:
|
|
* some messages, such as WM_COPYDATA send an address pointer to some user data as lParam.
|
|
* In this API. the only such case that is currently supported is for WM_DEVICECHANGE
|
|
* No error code will be returned if you try to use such an unsupported message, simply the
|
|
* lParam will be ignored.
|
|
*
|
|
* This func will only allow WM_DEVICECHNAGE and WM_SETTINGSCHANGE to go thru.
|
|
*
|
|
* ENTRY:
|
|
* hServer
|
|
* this is a handle which identifies a Hydra server. For the local server, hServer
|
|
* should be set to SERVERNAME_CURRENT
|
|
*
|
|
* sendToAllWinstations
|
|
* This should be set to TRUE if you want to broadcast message to all winstations
|
|
*
|
|
* sessionID,
|
|
* if sendToAllWinstations = FALSE, then message is only sent to only the
|
|
* winstation with the specified sessionID
|
|
*
|
|
* timeOut [ IN SECONDS ]
|
|
* set this to the amount of time you are willing to wait to get a response
|
|
* from the specified winstation. Even though Window's SendMessage API
|
|
* is blocking, the call from this side MUST choose how long it is willing to
|
|
* wait for a response.
|
|
*
|
|
* dwFlags
|
|
* see MSDN on BroadcastSystemMessage(). Be aware that POST is not allowed on any
|
|
* where the wparam is a pointer to some user mode data structure.
|
|
* For more info, see ntos\...\client\ntstubs.c
|
|
*
|
|
* lpdwRecipients
|
|
* Pointer to a variable that contains and receives information about the recipients of the message.
|
|
* see MSDN for more info
|
|
*
|
|
* uiMessage
|
|
* the window's message to send, limited to WM_DEVICECHANGE and WM_SETTINGSCHANGE
|
|
* at this time.
|
|
*
|
|
* wParam
|
|
* first message param
|
|
*
|
|
* lParam
|
|
* second message parameter
|
|
*
|
|
* pResponse
|
|
* this is the response to the message sent, see MSDN
|
|
*
|
|
* EXIT:
|
|
* TRUE if all went well or
|
|
* FALSE if something went wrong.
|
|
*
|
|
* WARNINGs:
|
|
* since the RPC call never blocks, you need to specify a reasonable timeOut if you want to wait for
|
|
* a response. Please remember that since this message is being sent to all winstations, the timeOut value
|
|
* will be on per-winstation.
|
|
*
|
|
* Also, Do not use flag BSF_POSTMESSAGE, since an app/window on a
|
|
* winstation is not setup to send back a response to the
|
|
* query in an asynchronous fashion.
|
|
* You must wait for the response (until the time out period).
|
|
*
|
|
* For WM_SETTINGGSCHNAGE, a second therad is used to allow the caller to still process windows
|
|
* messages.
|
|
* For WM_DEVICECHANGE, no such thread is used.
|
|
*
|
|
* Comments:
|
|
* For more info, please see MSDN for BroadcastSystemMessage()
|
|
*
|
|
****************************************************************************/
|
|
LONG WinStationBroadcastSystemMessage(
|
|
HANDLE hServer,
|
|
BOOL sendToAllWinstations,
|
|
ULONG sessionID,
|
|
ULONG timeOut,
|
|
DWORD dwFlags,
|
|
DWORD *lpdwRecipients,
|
|
ULONG uiMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LONG *pResponse // this is the response to the message sent
|
|
)
|
|
{
|
|
|
|
LONG rc;
|
|
DWORD dwRecipients=0; // caller may be passing null, so use a local var 1st, and then set
|
|
// value passed in by caller if an only if the caller's address is not null.
|
|
|
|
BOOLEAN fBufferHasValidData = FALSE;
|
|
|
|
BOOL bIsTerminalServer = !!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer));
|
|
if (!bIsTerminalServer)
|
|
{
|
|
return TRUE; // all is well, but we are not on a Hydra server
|
|
}
|
|
|
|
if (lpdwRecipients) // if caller passed in a non-NULL pointer for lpdwRec, use it's value
|
|
{
|
|
dwRecipients = *lpdwRecipients ;
|
|
}
|
|
|
|
|
|
// we may want to make this general for the future, but for now...
|
|
// we only let WM_DEVICECHANGE or WM_SETTINGCHANGE messages to go thru
|
|
switch ( uiMessage)
|
|
{
|
|
case WM_DEVICECHANGE:
|
|
rc = WinStationBroadcastSystemMessageWorker(
|
|
hServer,
|
|
sendToAllWinstations,
|
|
sessionID,
|
|
timeOut,
|
|
dwFlags,
|
|
&dwRecipients,
|
|
uiMessage,
|
|
wParam,
|
|
lParam,
|
|
pResponse,
|
|
NtCurrentPeb()->SessionId // ID of the session to be ignored.
|
|
);
|
|
|
|
if (lpdwRecipients) // if caller passed in a non-NULL pointer for lpdwRec, then set value
|
|
{
|
|
*lpdwRecipients = dwRecipients;
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_SETTINGCHANGE:
|
|
|
|
{
|
|
BSM_DATA_PACKAGE d;
|
|
ULONG threadID;
|
|
HANDLE hThread;
|
|
|
|
//pack the data passed to the thread proc
|
|
d.hServer = hServer ;
|
|
d.sendToAllWinstations = sendToAllWinstations;
|
|
d.sessionID = sessionID;
|
|
d.timeOut = timeOut;
|
|
d.dwFlags = dwFlags;
|
|
d.lpdwRecipients = &dwRecipients;
|
|
d.uiMessage = uiMessage;
|
|
d.wParam = wParam;
|
|
d.lParam = lParam;
|
|
d.pResponse = pResponse;
|
|
d.idOfSessionBeingIgnored = NtCurrentPeb()->SessionId ;
|
|
// a remote admin may change env-settings
|
|
// and expect all sessions includin the
|
|
// console session to be updated
|
|
// A -1 means no sessions are ignored
|
|
// Call from shell\cpls\system\envvar.c already sent the message to the current session
|
|
|
|
|
|
hThread = CreateThread( NULL, 0, WinStationBSMWorkerThread,
|
|
(void *) &d, 0 , &threadID );
|
|
|
|
if ( hThread )
|
|
{
|
|
MsgWaitForMultipleObjectsLoop( hThread, INFINITE );
|
|
if (lpdwRecipients) // if caller passed in a non-NULL pointer for lpdwRec, then set value
|
|
{
|
|
*lpdwRecipients = *d.lpdwRecipients ;
|
|
}
|
|
GetExitCodeThread( hThread, &rc );
|
|
CloseHandle( hThread );
|
|
}
|
|
else
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
DBGPRINT(("Request is rejected \n"));
|
|
rc = FALSE;
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationSendWindowMessage
|
|
*
|
|
* Perform the the equivalent to SendMessage to a specific winstation as
|
|
* identified by the session ID. This is an exported function, at least used
|
|
* by the PNP manager to send a device change message (or any other window's message)
|
|
*
|
|
* LIMITATIONS:
|
|
* some messages, such as WM_COPYDATA send an address pointer to some user data as lParam.
|
|
* In this API, the only such case that is currently supported is for WM_DEVICECHANGE
|
|
* No error code will be returned if you try to use such an unsupported message, simply the
|
|
* lParam will be ignored.
|
|
*
|
|
* ENTRY:
|
|
* hServer
|
|
* this is a handle which identifies a Hydra server. For the local server, hServer
|
|
* should be set to SERVERNAME_CURRENT
|
|
* sessionID
|
|
* this idefntifies the hydra session to which message is being sent
|
|
*
|
|
* timeOut [ IN SECONDS ]
|
|
* set this to the amount of time you are willing to wait to get a response
|
|
* from the specified winstation. Even though Window's SendMessage API
|
|
* is blocking, the call from this side MUST choose how long it is willing to
|
|
* wait for a response.
|
|
*
|
|
* hWnd
|
|
* This is the HWND of the target window in the specified session that
|
|
* a message will be sent to.
|
|
* Msg
|
|
* the window's message to send
|
|
* wParam
|
|
* first message param
|
|
* lParam
|
|
* second message parameter
|
|
* pResponse
|
|
* this is the response to the message sent, it depends on the type of message sent, see MSDN
|
|
*
|
|
*
|
|
* EXIT:
|
|
* TRUE if all went well , check presponse for the actual response to the send message
|
|
* FALSE if something went wrong, the value of pResponse is not altered.
|
|
*
|
|
* WARNINGs:
|
|
* since the RPC call never blocks, you need to specify a reasonable timeOut if you want to wait for
|
|
* a response. Please remember that since this message is being sent to all winstations, the timeOut value
|
|
* will be on per-winstation.
|
|
*
|
|
*
|
|
* Comments:
|
|
* For more info, please see MSDN for SendMessage()
|
|
*
|
|
****************************************************************************/
|
|
LONG WinStationSendWindowMessage(
|
|
HANDLE hServer,
|
|
ULONG sessionID,
|
|
ULONG timeOut,
|
|
ULONG hWnd, // handle of destination window
|
|
ULONG Msg, // message to send
|
|
WPARAM wParam, // first message parameter
|
|
LPARAM lParam, // second message parameter
|
|
LONG *pResponse
|
|
)
|
|
{
|
|
|
|
DWORD Result = ERROR_SUCCESS;
|
|
LONG rc = TRUE ;
|
|
|
|
// these are used for PNP messages
|
|
PBYTE rpcBuffer=NULL;
|
|
ULONG bufferSize=0;
|
|
PWCHAR lpStr;
|
|
ULONG maxSize;
|
|
|
|
|
|
BOOLEAN fBufferHasValidData=FALSE;
|
|
|
|
BOOL bIsTerminalServer = !!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer));
|
|
if (!bIsTerminalServer)
|
|
{
|
|
return TRUE; // all is well, but we are not on a Hydra server
|
|
}
|
|
|
|
// we may want to make this general for the future, but for now...
|
|
// since we only alloc/copy the lparam in case of an WM_DEVICECHANGE msg, then, only
|
|
// let message with either lparam=0 to go thru, or any WM_DEVICECHANGE msg.
|
|
if (lParam)
|
|
{
|
|
switch ( Msg)
|
|
{
|
|
case WM_DEVICECHANGE:
|
|
case WM_SETTINGCHANGE:
|
|
case WM_APPCOMMAND:
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
// these are ok
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(("Request is rejected \n"));
|
|
return FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
// Since the PNP message uses the lparam to pass the address of a user memory location, we
|
|
// need to handle this by creating our own copy of that data, and then pass it to
|
|
// termServ
|
|
|
|
switch( Msg )
|
|
{
|
|
// if this is a PNP message
|
|
case WM_DEVICECHANGE:
|
|
|
|
if ( lParam ) // see if the PNP message has a pointer to some user data
|
|
{
|
|
bufferSize = ( (DEV_BROADCAST_HDR *)(lParam))->dbch_size;
|
|
rpcBuffer = LocalAlloc( LPTR, bufferSize );
|
|
if ( rpcBuffer )
|
|
{
|
|
// copy from user-space into our local rpc buffer
|
|
CopyMemory(rpcBuffer, (PBYTE) lParam, bufferSize );
|
|
fBufferHasValidData = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
break;
|
|
|
|
// if this is a settings change message the system-CPL sends out
|
|
// when an Admin changes the system env vars...
|
|
case WM_SETTINGCHANGE:
|
|
if ( lParam ) // see if message has a string data
|
|
{
|
|
// put some artificial limit on how large a buffer we are willing to use
|
|
// in order to protect against malicious use of this api
|
|
maxSize = 4096;
|
|
|
|
bufferSize = lstrlenW( (PWCHAR) lParam ) * sizeof( WCHAR );
|
|
if ( bufferSize < maxSize )
|
|
{
|
|
rpcBuffer = LocalAlloc( LPTR, bufferSize );
|
|
if ( rpcBuffer )
|
|
{
|
|
// copy from user-space into our local rpc buffer
|
|
CopyMemory(rpcBuffer, (PBYTE) lParam, bufferSize );
|
|
fBufferHasValidData = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we have too many
|
|
// vars in the user's profile.
|
|
KdPrint(("lParam length too big = %d \n", bufferSize));
|
|
break;
|
|
SetLastError( ERROR_MESSAGE_EXCEEDS_MAX_SIZE );
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
// if the rpcBuffer is still empty, we must fill it up with some bogus data, otherwise, we will get
|
|
// an RPC error of RPC_X_NULL_REF_POINTER (error code of 1780). It looks like Rpc does not check the
|
|
// bufferSize value, and it just throws an exception if the buffer is NULL.
|
|
if ( !rpcBuffer )
|
|
{
|
|
rpcBuffer = LocalAlloc( LPTR, sizeof(UINT) );
|
|
if ( !rpcBuffer )
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return ( FALSE );
|
|
}
|
|
|
|
bufferSize = sizeof(UINT);
|
|
fBufferHasValidData = FALSE; // note that this is set to FALSE, which means, the recepient will
|
|
// not use the buffer. We do free the alloc below in either case.
|
|
}
|
|
|
|
|
|
RpcTryExcept {
|
|
|
|
// rc is set to TRUE for a successful call, else, FALSE
|
|
rc = RpcWinStationSendWindowMessage(
|
|
hServer,
|
|
sessionID ,
|
|
timeOut,
|
|
hWnd,
|
|
Msg,
|
|
wParam,
|
|
lParam ,
|
|
rpcBuffer ,
|
|
bufferSize,
|
|
fBufferHasValidData,
|
|
pResponse );
|
|
|
|
//DBGPRINT(("done with call RpcWinStationSendWindowMessage() for sessionID= %d\n", sessionID ));
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d in RpcWinStationSendWindowMessage() for sessionID = %d \n",Result, sessionID ));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
LocalFree( rpcBuffer );
|
|
|
|
SetLastError( Result );
|
|
|
|
return( rc );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* _WinStationUpdateUserConfig()
|
|
* Used by notify when shell is about to start
|
|
* This will cause an update to the userconfig of the session by loading the user profile
|
|
* and reading policy data from their HKCU
|
|
*
|
|
* Params:
|
|
* [in] UserToken,
|
|
* [in] pDomain,
|
|
* [in] pUserName
|
|
*
|
|
* Return:
|
|
* TRUE if no errors, FALSE in case of error, use GetLastError() for more info
|
|
*
|
|
****************************************************************************/
|
|
BOOLEAN WINAPI
|
|
_WinStationUpdateUserConfig(
|
|
HANDLE UserToken
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc = TRUE;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
DWORD result;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return FALSE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationUpdateUserConfig(
|
|
hServer,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId(),
|
|
(DWORD)(INT_PTR) UserToken,
|
|
&result
|
|
);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*
|
|
* WinStationQueryLogonCredentialsW
|
|
*
|
|
* Used by Winlogon to get auto-logon credentials from termsrv. This replaces
|
|
* the dual calls to WinStationQueryInformation and
|
|
* ServerQueryInetConnectorInformation.
|
|
*/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationQueryLogonCredentialsW(
|
|
PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pCredentials
|
|
)
|
|
{
|
|
BOOLEAN fRet;
|
|
HANDLE hServer;
|
|
NTSTATUS Status;
|
|
PCHAR pWire;
|
|
ULONG cbWire;
|
|
|
|
if (pCredentials == NULL)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pCredentials->dwType != WLX_CREDENTIAL_TYPE_V2_0)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING(hServer);
|
|
|
|
pWire = NULL;
|
|
cbWire = 0;
|
|
|
|
__try
|
|
{
|
|
fRet = RpcWinStationQueryLogonCredentials(
|
|
hServer,
|
|
NtCurrentPeb()->SessionId,
|
|
&pWire,
|
|
&cbWire
|
|
);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
fRet = FALSE;
|
|
}
|
|
|
|
if (fRet)
|
|
{
|
|
fRet = CopyCredFromWire((PWLXCLIENTCREDWIREW)pWire, pCredentials);
|
|
}
|
|
|
|
if (pWire != NULL)
|
|
{
|
|
MIDL_user_free(pWire);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
BOOL WINAPI WinStationUnRegisterNotificationEvent (
|
|
ULONG_PTR NotificationId
|
|
)
|
|
{
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
BOOL bResult = FALSE;
|
|
|
|
HANDLE_CURRENT_BINDING(hServer);
|
|
|
|
RpcTryExcept {
|
|
|
|
bResult = RpcWinStationUnRegisterNotificationEvent(
|
|
hServer,
|
|
&Status,
|
|
NotificationId,
|
|
NtCurrentPeb()->SessionId
|
|
);
|
|
|
|
if (!bResult) {
|
|
|
|
//
|
|
// Convert NTSTATUS to winerror, and set last error here.
|
|
//
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
SetLastError(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
return (bResult);
|
|
}
|
|
|
|
BOOL WINAPI WinStationRegisterNotificationEvent (
|
|
HANDLE hEventHandle,
|
|
ULONG_PTR *pNotificationId,
|
|
DWORD dwFlags,
|
|
DWORD dwMask
|
|
)
|
|
{
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
BOOL bResult = FALSE;
|
|
|
|
if (!pNotificationId)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
HANDLE_CURRENT_BINDING(hServer);
|
|
|
|
RpcTryExcept {
|
|
|
|
ULONG_PTR Notificationid;
|
|
|
|
bResult = RpcWinStationRegisterNotificationEvent(
|
|
hServer,
|
|
&Status,
|
|
pNotificationId,
|
|
(ULONG_PTR)hEventHandle,
|
|
dwFlags,
|
|
dwMask,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId()
|
|
);
|
|
|
|
if (!bResult) {
|
|
|
|
//
|
|
// Convert NTSTATUS to winerror, and set last error here.
|
|
//
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
SetLastError(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
return (bResult);
|
|
|
|
}
|
|
|
|
|
|
BOOL WINAPI WinStationRegisterConsoleNotification (
|
|
HANDLE hServer,
|
|
HWND hWnd,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
return WinStationRegisterConsoleNotificationEx(hServer, hWnd, dwFlags, WTS_ALL_NOTIFICATION_MASK);
|
|
}
|
|
|
|
BOOL WINAPI WinStationRegisterConsoleNotificationEx (
|
|
HANDLE hServer,
|
|
HWND hWnd,
|
|
DWORD dwFlags,
|
|
DWORD dwMask
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
BOOL bResult = FALSE;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
bResult = RpcWinStationRegisterConsoleNotification (
|
|
hServer,
|
|
&Status,
|
|
NtCurrentPeb()->SessionId,
|
|
HandleToUlong(hWnd),
|
|
dwFlags,
|
|
dwMask
|
|
);
|
|
if (!bResult) {
|
|
|
|
//
|
|
// Convert NTSTATUS to winerror, and set last error here.
|
|
//
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
SetLastError(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
return (bResult);
|
|
}
|
|
|
|
BOOL WINAPI WinStationUnRegisterConsoleNotification (
|
|
HANDLE hServer,
|
|
HWND hWnd
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
BOOL bResult = FALSE;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
bResult = RpcWinStationUnRegisterConsoleNotification (
|
|
hServer,
|
|
&Status,
|
|
NtCurrentPeb()->SessionId,
|
|
HandleToUlong(hWnd)
|
|
);
|
|
if (!bResult) {
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
}
|
|
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
SetLastError(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
return (bResult);
|
|
}
|
|
|
|
|
|
BOOLEAN CloseContextHandle(HANDLE *pHandle, DWORD *pdwResult)
|
|
{
|
|
BOOLEAN bSuccess;
|
|
ASSERT(pHandle);
|
|
ASSERT(pdwResult);
|
|
|
|
RpcTryExcept {
|
|
|
|
bSuccess = RpcWinStationCloseServerEx( pHandle, pdwResult );
|
|
if( !bSuccess ) *pdwResult = RtlNtStatusToDosError( *pdwResult );
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
*pdwResult = RpcExceptionCode();
|
|
bSuccess = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (!bSuccess && (*pdwResult == RPC_S_PROCNUM_OUT_OF_RANGE)) {
|
|
//
|
|
// most probabaly we are calling an older server which does not have
|
|
// RpcWinStationCloseServerEx, so lets give a try to RpcWinStationCloseServer
|
|
//
|
|
RpcTryExcept {
|
|
|
|
bSuccess = RpcWinStationCloseServer( *pHandle, pdwResult );
|
|
if( !bSuccess ) *pdwResult = RtlNtStatusToDosError( *pdwResult );
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
*pdwResult = RpcExceptionCode();
|
|
bSuccess = FALSE;
|
|
DBGPRINT(("RPC Exception %d\n", *pdwResult));
|
|
}
|
|
RpcEndExcept
|
|
|
|
//
|
|
// RpcWinStationCloseServer does not take care of destroying the context handle.
|
|
// we we have to do it here at client end.
|
|
//
|
|
RpcTryExcept {
|
|
|
|
RpcSsDestroyClientContext(pHandle);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
ASSERT(FALSE);
|
|
}
|
|
RpcEndExcept
|
|
|
|
}
|
|
|
|
return (bSuccess);
|
|
}
|
|
|
|
BOOLEAN WINAPI
|
|
RemoteAssistancePrepareSystemRestore(
|
|
HANDLE hServer
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcRemoteAssistancePrepareSystemRestore(
|
|
hServer,
|
|
&Result
|
|
);
|
|
|
|
// TermSrv RpcRemoteAssistancePrepareSystemRestore() return
|
|
// win32 ERROR code or actual HRESULT code.
|
|
SetLastError(Result);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return rc;
|
|
}
|
|
|
|
BOOLEAN WinStationIsHelpAssistantSession(
|
|
SERVER_HANDLE hServer,
|
|
ULONG LogonId
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationIsHelpAssistantSession(
|
|
hServer,
|
|
&Result,
|
|
(LogonId == LOGONID_CURRENT) ? NtCurrentPeb()->SessionId : LogonId
|
|
);
|
|
|
|
// Since a program has called us, we need to set the last error code such
|
|
// that extended error information is available
|
|
|
|
//
|
|
// Ticket might be invalid so we set last error but we still
|
|
// return TRUE
|
|
//
|
|
SetLastError(RtlNtStatusToDosError(Result));
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*
|
|
* WinStationGetMachinePolicy
|
|
* Pass it a pointer to the callers ALREADY allocated policy struct, and this func
|
|
* will fill it up from the current machine policy known to TermSrv
|
|
*
|
|
* Params:
|
|
* hServer
|
|
* this is a handle which identifies a Hydra server. For the local server, hServer
|
|
* should be set to SERVERNAME_CURRENT
|
|
*
|
|
* pPolicy
|
|
* pointer to POLICY_TS_MACHINE already allocated by the caller.
|
|
*
|
|
*/
|
|
BOOLEAN WinStationGetMachinePolicy (
|
|
HANDLE hServer,
|
|
POLICY_TS_MACHINE *pPolicy
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
BOOLEAN bResult = FALSE;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
bResult = RpcWinStationGetMachinePolicy (
|
|
hServer,
|
|
(PBYTE)pPolicy,
|
|
sizeof( POLICY_TS_MACHINE )
|
|
);
|
|
|
|
if (!bResult) {
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
}
|
|
|
|
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
|
|
SetLastError(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
return (bResult);
|
|
|
|
}
|
|
|
|
/*****************************************************************************************************************
|
|
*
|
|
* _WinStationUpdateClientCachedCreadentials
|
|
*
|
|
* Comment
|
|
* Msgina calls this routine to notify TermSrv about the exact credentials specified by the User during logon
|
|
* Gina also notifies us if a SmartCard was used for logging into this particular TS session
|
|
* TermSrv uses this information to send back notification information to the client
|
|
* This call was introduced because the notification used before did not support UPN Names
|
|
*
|
|
* ENTRY:
|
|
* [in] pDomain
|
|
* [in] pUserName
|
|
* [in] fSmartCard
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS - no error
|
|
*
|
|
******************************************************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationUpdateClientCachedCredentials(
|
|
PWCHAR pDomain,
|
|
PWCHAR pUserName,
|
|
BOOLEAN fSmartCard
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD DomainLength;
|
|
DWORD UserNameLength;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
HANDLE ReadyEventHandle;
|
|
DWORD TermSrvWaitTime = 0;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Wait for the TermSrvReadyEvent to be set by TERMSRV.EXE. This
|
|
// event indicates that TermSrv is initialized to the point that
|
|
// the data used by _WinStationUpdateClientCachedCredentials() is available.
|
|
//
|
|
ReadyEventHandle = OpenEvent(SYNCHRONIZE, FALSE, TEXT("Global\\TermSrvReadyEvent"));
|
|
if (ReadyEventHandle != NULL) {
|
|
if (WaitForSingleObject(ReadyEventHandle, TermSrvWaitTime) != 0) {
|
|
DBGPRINT(("WinLogon: Wait for ReadyEventHandle failed\n"));
|
|
return TRUE;
|
|
}
|
|
CloseHandle(ReadyEventHandle);
|
|
} else {
|
|
DBGPRINT(("WinLogon: Create failed for ReadyEventHandle\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
if( pDomain ) {
|
|
DomainLength = lstrlenW(pDomain) + 1;
|
|
} else {
|
|
DomainLength = 0;
|
|
}
|
|
|
|
if( pUserName ) {
|
|
UserNameLength = lstrlenW(pUserName) + 1;
|
|
} else {
|
|
UserNameLength = 0;
|
|
}
|
|
|
|
rc = RpcWinStationUpdateClientCachedCredentials(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId(),
|
|
pDomain,
|
|
DomainLength,
|
|
pUserName,
|
|
UserNameLength,
|
|
fSmartCard
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = RtlNtStatusToDosError( Result );
|
|
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************************************************
|
|
*
|
|
* _WinStationFUSCanRemoteUserDisconnect
|
|
*
|
|
* Comment
|
|
* FUS specific call when a remote user wants to connect and hence disconnect the present User
|
|
* Winlogon calls this routine so that we can ask the present user if it is ok to disconnect him
|
|
* The Target LogonId, Username and Domain of the remote user are passed on from Winlogon (useful to display the MessageBox)
|
|
*
|
|
* ENTRY:
|
|
* [in] LogonId - Session Id of the new session
|
|
* [in] pDomain - Domain name of the remote user trying to connect
|
|
* [in] pUserName - Username of the remote user trying to connect
|
|
*
|
|
* EXIT:
|
|
* TRUE when local user allows the remote user to connect. FALSE otherwise.
|
|
*
|
|
******************************************************************************************************************/
|
|
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationFUSCanRemoteUserDisconnect(
|
|
ULONG LogonId,
|
|
PWCHAR pDomain,
|
|
PWCHAR pUserName
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
DWORD DomainLength;
|
|
DWORD UserNameLength;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
HANDLE ReadyEventHandle;
|
|
DWORD TermSrvWaitTime = 0;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
if( pDomain ) {
|
|
DomainLength = lstrlenW(pDomain) + 1;
|
|
} else {
|
|
DomainLength = 0;
|
|
}
|
|
|
|
if( pUserName ) {
|
|
UserNameLength = lstrlenW(pUserName) + 1;
|
|
} else {
|
|
UserNameLength = 0;
|
|
}
|
|
|
|
rc = RpcWinStationFUSCanRemoteUserDisconnect(
|
|
hServer,
|
|
&Result,
|
|
LogonId,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId(),
|
|
pDomain,
|
|
DomainLength,
|
|
pUserName,
|
|
UserNameLength
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = RtlNtStatusToDosError( Result );
|
|
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* WinStationCheckLoopBack
|
|
*
|
|
* Check if there is a loopback when a client tries to connect
|
|
*
|
|
* ENTRY:
|
|
* IN hServer : open RPC server handle
|
|
* IN ClientSessionId : ID of the Session from which the Client was started
|
|
* IN TargetLogonId : Session ID to which the client is trying to connect to
|
|
* IN pTargetServerName : name of target server
|
|
*
|
|
* EXIT:
|
|
* TRUE if there is a Loopback. FALSE otherwise.
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationCheckLoopBack(
|
|
HANDLE hServer,
|
|
ULONG ClientSessionId,
|
|
ULONG TargetLogonId,
|
|
LPWSTR pTargetServerName
|
|
)
|
|
{
|
|
DWORD NameSize;
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
if (pTargetServerName) {
|
|
NameSize = lstrlenW(pTargetServerName) + 1;
|
|
} else {
|
|
NameSize = 0;
|
|
}
|
|
|
|
rc = RpcWinStationCheckLoopBack(
|
|
hServer,
|
|
&Result,
|
|
ClientSessionId,
|
|
TargetLogonId,
|
|
pTargetServerName,
|
|
NameSize
|
|
);
|
|
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
//
|
|
// generic routine that can support all kind of protocol but this will
|
|
// require including tdi.h
|
|
//
|
|
BOOLEAN
|
|
WinStationConnectCallback(
|
|
HANDLE hServer,
|
|
DWORD Timeout,
|
|
ULONG AddressType,
|
|
PBYTE pAddress,
|
|
ULONG AddressSize
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcConnectCallback(
|
|
hServer,
|
|
&Result,
|
|
Timeout,
|
|
AddressType,
|
|
pAddress,
|
|
AddressSize
|
|
);
|
|
|
|
if( !rc ) SetLastError( RtlNtStatusToDosError(Result) );
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************************************************
|
|
*
|
|
* _WinStationNotifyDisconnectPipe
|
|
*
|
|
* Comment
|
|
* This routine is called by the temperory winlogon created during console reconnect, when it wants to inform
|
|
* the session 0 winlogon to disconnect the autologon Named Pipe. This can happen in some error handling paths
|
|
* during console reconnect.
|
|
*
|
|
* ENTRY: None
|
|
*
|
|
* EXIT:
|
|
* TRUE when notification succeeded. FALSE otherwise.
|
|
*
|
|
******************************************************************************************************************/
|
|
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationNotifyDisconnectPipe(
|
|
VOID
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationNotifyDisconnectPipe(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId()
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = RtlNtStatusToDosError( Result );
|
|
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
/*****************************************************************************************************************
|
|
*
|
|
* _WinStationSessionInitialized
|
|
*
|
|
* Comment
|
|
* This routine is called by the winlogon of a newly created session after it is done creating the
|
|
* windowstation and desktops for the new session
|
|
*
|
|
* ENTRY: None
|
|
*
|
|
* EXIT:
|
|
* TRUE when everything goes fine. FALSE otherwise.
|
|
*
|
|
******************************************************************************************************************/
|
|
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationSessionInitialized(
|
|
VOID
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return TRUE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationSessionInitialized(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
GetCurrentProcessId()
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = RtlNtStatusToDosError( Result );
|
|
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinStationAutoReconnect
|
|
*
|
|
* Atomically:
|
|
* 1) Queries a winstation to see if it should be autoreconnected
|
|
* and which session ID to autoreconnect to
|
|
* 2) Performs security checks to ensure session is authorized to ARC
|
|
* 3) Auto reconnect is done
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* flags (input)
|
|
* Extra settings, currently unused
|
|
*
|
|
* EXIT:
|
|
* The return value is an NTSTATUS code which could have the infromational
|
|
* class set to specify the call succeeded but autoreconnect did not happen
|
|
*
|
|
******************************************************************************/
|
|
ULONG WINAPI
|
|
WinStationAutoReconnect(
|
|
ULONG flags
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING( hServer );
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationAutoReconnect(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
flags
|
|
);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
SetLastError( Result );
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return( Result );
|
|
}
|
|
|
|
/*****************************************************************************************************************
|
|
*
|
|
* WinStationCheckAccess
|
|
*
|
|
* Comment
|
|
* Check if the User has the desired access to a WinStation
|
|
*
|
|
* ENTRY:
|
|
* [in] UserToken - token of the user against whom Access Check is made
|
|
* [in] TargetLogonId - Target Session for which access needs to be determined
|
|
* [in] AccessMask - The desired access (eg WINSTATION_LOGON )
|
|
*
|
|
* EXIT:
|
|
* TRUE when the User has required Access ; FALSE when not.
|
|
*
|
|
******************************************************************************************************************/
|
|
|
|
|
|
BOOLEAN WINAPI
|
|
WinStationCheckAccess(
|
|
HANDLE UserToken,
|
|
ULONG TargetLogonId,
|
|
ULONG AccessMask
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
DWORD Result;
|
|
HANDLE hServer = SERVERNAME_CURRENT;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
return FALSE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationCheckAccess(
|
|
hServer,
|
|
&Result,
|
|
NtCurrentPeb()->SessionId,
|
|
(DWORD)(INT_PTR)UserToken,
|
|
TargetLogonId,
|
|
AccessMask
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = RtlNtStatusToDosError( Result );
|
|
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _WinStationOpenSessionDirectory
|
|
*
|
|
* Call to Session Directory server to see if if it's accessible
|
|
*
|
|
* ENTRY:
|
|
* hServer: SERVERNAME_CURRENT
|
|
* pszServerName: Session Directory server name
|
|
* EXIT:
|
|
* ERROR_SUCCESS if Session Directory server is accessible
|
|
* otherwise NT error code is returned
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
_WinStationOpenSessionDirectory(
|
|
HANDLE hServer,
|
|
LPWSTR pszServerName
|
|
)
|
|
{
|
|
DWORD Result;
|
|
BOOLEAN rc;
|
|
|
|
HANDLE_CURRENT_BINDING_NO_SERVER( hServer );
|
|
|
|
if( hServer == RPC_HANDLE_NO_SERVER ) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
|
|
rc = RpcWinStationOpenSessionDirectory(
|
|
hServer,
|
|
&Result,
|
|
pszServerName
|
|
);
|
|
|
|
if( !rc ) {
|
|
Result = RtlNtStatusToDosError( Result );
|
|
}
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
|
|
Result = RpcExceptionCode();
|
|
DBGPRINT(("RPC Exception %d\n",Result));
|
|
rc = FALSE;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if( !rc ) SetLastError(Result);
|
|
return( rc );
|
|
}
|