|
|
/*************************************************************************
* * 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 ); }
|