Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1391 lines
45 KiB

/*
* Includes
*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntsam.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <lm.h>
#include <winsta.h>
#include <rpc.h>
#include <rpcdce.h>
#include <ntdsapi.h>
// For more info, check out \\index1\src\nt\private\security\tools\delegate\ldap.c
#include "usrprop.h"
#include "regapi.h"
extern "C" {
BOOLEAN RegGetUserPolicy( LPWSTR userSID , PPOLICY_TS_USER pPolicy , PUSERCONFIGW pData );
void RegGetMachinePolicy( PPOLICY_TS_MACHINE pPolicy );
void RegMergeMachinePolicy( PPOLICY_TS_MACHINE pPolicy, USERCONFIGW *pMachineConfigData ,
WINSTATIONCREATE * pCreate );
BOOLEAN RegDenyTSConnectionsPolicy();
DWORD WaitForTSConnectionsPolicyChanges( BOOLEAN bWaitForAccept, HANDLE hExtraEvent);
BOOLEAN RegGetMachinePolicyEx(
BOOLEAN forcePolicyRead,
FILETIME *pTime ,
PPOLICY_TS_MACHINE pPolicy );
BOOLEAN RegIsMachineInHelpMode();
BOOLEAN RegIsTimeZoneRedirectionEnabled();
}
extern "C"
{
//
HKEY g_hTSPolicyKey = NULL;//handle to TS_POLICY_SUB_TREE key
HKEY g_hTSControlKey = NULL;//handle to REG_CONTROL_TSERVER key
}
/******************************************************************
* *
* Check to see if the policy is set to stop accepting connections *
* *
******************************************************************/
BOOLEAN RegDenyTSConnectionsPolicy()
{
LONG errorCode = ERROR_SUCCESS;
DWORD ValueType;
DWORD ValueSize = sizeof(DWORD);
DWORD valueData ;
//
// first check the policy tree,
//
if( !g_hTSPolicyKey )
{
errorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TS_POLICY_SUB_TREE, 0,
KEY_READ, &g_hTSPolicyKey );
//If error code is ERROR_FILE_NOT_FOUND, this is not an error.
if( !g_hTSPolicyKey && errorCode != ERROR_FILE_NOT_FOUND )
{
//we could not open policy key for some reason other
//than key not found.
//return TRUE to be on the safe side
return TRUE;
}
}
if ( g_hTSPolicyKey )
{
errorCode = RegQueryValueEx( g_hTSPolicyKey, POLICY_DENY_TS_CONNECTIONS , NULL, &ValueType,
(LPBYTE) &valueData, &ValueSize );
switch( errorCode )
{
case ERROR_SUCCESS :
return ( valueData ? TRUE : FALSE ) ; // we have data from the policyKey handle to return
break;
case ERROR_KEY_DELETED:
// Group policy must have deleted this key, close it
// Then, below we check for the local machine key
RegCloseKey( g_hTSPolicyKey );
g_hTSPolicyKey = NULL;
break;
case ERROR_FILE_NOT_FOUND:
// there is no policy from GP, so see (below) what the local machine
// value has.
break;
default:
// if we are having any other kind of a problem, claim TRUE and
// stop connections to be on the safe side (a security angle).
return TRUE;
break;
}
}
// if we got this far, then no policy was set. Check the local machine now.
if( !g_hTSControlKey )
{
errorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
KEY_READ, &g_hTSControlKey );
}
if ( g_hTSControlKey )
{
errorCode = RegQueryValueEx( g_hTSControlKey, POLICY_DENY_TS_CONNECTIONS , NULL, &ValueType,
(LPBYTE) &valueData, &ValueSize );
if (errorCode == ERROR_SUCCESS )
{
return ( valueData ? TRUE : FALSE ) ; // we have data from the policyKey handle to return
}
}
// if no localKey, gee... the registry is missing data... return TRUE to be on the safe side
return TRUE;
}
/******************************************************************
* *
* Wait until POLICY_DENY_TS_CONNECTIONS is changed *
* *
* Parameters: *
* bWaitForAccept *
* if TRUE, test if connections are accepted and wait for *
* them to be accepted if they are not currently accepted. *
* if FALSE, test if connections are not accepted and wait *
* for them to be denied if they are currently accepted. *
* *
* hExtraEvent *
* optional handle to an event to wait for. *
* *
* Returns: *
* WAIT_OBJECT_0 *
* if a change in TS connections policy occurred *
* *
* WAIT_OBJECT_0 + 1 *
* if the extra event is present and signaled *
* *
******************************************************************/
//
// Note that opening the global g_hTSControlKey without protection
// can cause the key to be opened twice.
//
// This macro is TRUE if the TS connections are denied
#define TSConnectionsDenied (RegDenyTSConnectionsPolicy() && \
!(RegIsMachinePolicyAllowHelp() && RegIsMachineInHelpMode()))
DWORD WaitForTSConnectionsPolicyChanges(
BOOLEAN bWaitForAccept,
HANDLE hExtraEvent
)
{
DWORD errorCode = ERROR_SUCCESS;
HKEY hControlKey = NULL;
HKEY hPoliciesKey = NULL;
HKEY hFipsPolicy = NULL;
HANDLE hEvents[4] = { NULL, NULL, NULL, NULL };
//
// Wait for a policy change if
// we want TS connections and they are denied OR
// we don't want TS connections and they are accepted
//
if((bWaitForAccept && TSConnectionsDenied) ||
(!bWaitForAccept && !TSConnectionsDenied))
{
errorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
KEY_READ, &hControlKey );
if( !hControlKey )
{
goto error_exit;
}
//We cannot wait for g_hTSPolicyKey because it can be deleted and created
//Instead we wait for HKLM\Policies key
errorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Policies"), 0,
KEY_READ, &hPoliciesKey );
if( !hPoliciesKey )
{
goto error_exit;
}
errorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TS_FIPS_POLICY, 0,
KEY_READ, &hFipsPolicy );
hEvents[0] = CreateEvent(NULL,FALSE,FALSE,NULL);
if( !hEvents[0])
{
errorCode = GetLastError();
goto error_exit;
}
hEvents[1] = CreateEvent(NULL,FALSE,FALSE,NULL);
if( !hEvents[1])
{
errorCode = GetLastError();
goto error_exit;
}
hEvents[2] = CreateEvent(NULL,FALSE,FALSE,NULL);
if( !hEvents[2])
{
errorCode = GetLastError();
goto error_exit;
}
hEvents[3] = hExtraEvent;
DWORD whichObject;
errorCode = RegNotifyChangeKeyValue(hControlKey,
FALSE,REG_NOTIFY_CHANGE_LAST_SET,
hEvents[0], TRUE );
if( errorCode != ERROR_SUCCESS )
{
goto error_exit;
}
errorCode = RegNotifyChangeKeyValue(hPoliciesKey,
TRUE,REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME,
hEvents[1], TRUE );
if( errorCode != ERROR_SUCCESS )
{
goto error_exit;
}
errorCode = RegNotifyChangeKeyValue(hFipsPolicy,
TRUE,REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME,
hEvents[2], TRUE );
if( errorCode != ERROR_SUCCESS )
{
goto error_exit;
}
if ( hExtraEvent == NULL )
{
whichObject = WaitForMultipleObjects(3,hEvents,FALSE,INFINITE);
}
else
{
whichObject = WaitForMultipleObjects(4,hEvents,FALSE,INFINITE);
}
errorCode = GetLastError();
CloseHandle( hEvents[0] );
CloseHandle( hEvents[1] );
CloseHandle( hEvents[2] );
RegCloseKey(hPoliciesKey);
RegCloseKey(hControlKey);
RegCloseKey(hFipsPolicy);
if(whichObject == WAIT_FAILED)
{
SetLastError( errorCode );
return WAIT_FAILED;
}
else
{
if ( whichObject >= WAIT_OBJECT_0 + 2 )
{
return WAIT_OBJECT_0 + 1;
}
else
{
return WAIT_OBJECT_0;
}
}
}
return WAIT_OBJECT_0;
error_exit:
if(hEvents[0])
{
CloseHandle( hEvents[0] );
}
if(hEvents[1])
{
CloseHandle( hEvents[1] );
}
if(hEvents[2])
{
CloseHandle( hEvents[2] );
}
if(hPoliciesKey)
{
RegCloseKey(hPoliciesKey);
}
if(hControlKey)
{
RegCloseKey(hControlKey);
}
if(hFipsPolicy)
{
RegCloseKey(hFipsPolicy);
}
SetLastError( errorCode );
return WAIT_FAILED;
}
/********************************************************************************
*
* GPGetNumValue()
*
* Params
* [in] policyKey : hkey to the policy reg tree where values are stored
* [in] ValueName : name of the value (which is the policy) we are looking for
* [out] pValueData: the data for the policy
*
* Return:
* if the policy defined by the passed in valuename is present, then
* return TRUE. Else, return FALSE
*
********************************************************************************/
BOOLEAN GPGetNumValue(
HKEY policyKey,
LPWSTR ValueName,
DWORD *pValueData )
{
LONG Status = ERROR_SUCCESS;
DWORD ValueType;
DWORD ValueSize = sizeof(DWORD);
// init data value to zero, just to get Prefix off our backs. This is a wasted OP
// since unless policy is set, value is not used.
*pValueData = 0;
//
// See if any values are present from the policyKey .
//
if ( policyKey )
{
Status = RegQueryValueEx( policyKey, ValueName, NULL, &ValueType,
(LPBYTE) pValueData, &ValueSize );
if (Status == ERROR_SUCCESS )
{
return TRUE; // we have data from the policyKey handle to return
}
}
// else, no key means policy is not set
return FALSE;
}
/********************************************************************************
*
* GPGetStringValue()
*
* same as GPGetNumValue() but for policies that have a string value
*
*
********************************************************************************/
BOOLEAN
GPGetStringValue( HKEY policyKey,
LPWSTR ValueName,
LPWSTR pValueData,
DWORD MaxValueSize )
{
LONG Status;
DWORD ValueType;
DWORD ValueSize = MaxValueSize << 1;
if (policyKey )
{
Status = RegQueryValueEx( policyKey, ValueName, NULL, &ValueType,
(LPBYTE) pValueData, &ValueSize );
if ( Status != ERROR_SUCCESS || ValueSize == sizeof(UNICODE_NULL) )
{
return FALSE; // no data found.
}
else
{
if ( ValueType != REG_SZ )
{
return FALSE; // bad data, pretend we have no data.
}
}
// we did get data
return( TRUE );
}
return FALSE;
}
/********************************************************************************
*
* GPGetStringValue()
*
* Variant of the above function that returns false if error happens, but not
* when value does not exist.
* If the value does not exist it sets bValueExists to FALSE.
*
*
********************************************************************************/
extern "C"
BOOLEAN
GPGetStringValue( HKEY policyKey,
LPWSTR ValueName,
LPWSTR pValueData,
DWORD MaxValueSize,
BOOLEAN *pbValueExists)
{
LONG Status;
DWORD ValueType;
DWORD ValueSize = MaxValueSize << 1;
if(!pValueData || !MaxValueSize)
{
return FALSE;
}
*pbValueExists = FALSE;
pValueData[0] = 0;
if (policyKey )
{
Status = RegQueryValueEx( policyKey, ValueName, NULL, &ValueType,
(LPBYTE) pValueData, &ValueSize );
if ( Status == ERROR_FILE_NOT_FOUND || ValueSize == sizeof(UNICODE_NULL) )
{
return TRUE; // no data found.
}
else
{
if ( Status != ERROR_SUCCESS || ValueType != REG_SZ )
{
return FALSE; // bad data, DO NOT pretend we have no data.
}
}
// we did get data
*pbValueExists = TRUE;
return( TRUE );
}
else
{
//Policy key may not exist. Now we pretend we have no data!
return TRUE;
}
}
/*******************************************************************************
*
* GPQueryUserConfig
*
* query USERCONFIG structure
*
* Params:
* policyKey : hkey to the HKCU policy tree
* pPolicy : points to the user policy struct which has flags for any policy
* value that is present in the policy tree
* pUser : pointer to a userconfigw struct used as a sracth pad to hold the
* policy values (if present).
* Return:
* void
*
******************************************************************************/
VOID
GPQueryUserConfig( HKEY policyKey, PPOLICY_TS_USER pPolicy , PUSERCONFIGW pUser )
{
UCHAR seed;
UNICODE_STRING UnicodePassword;
WCHAR encPassword[ PASSWORD_LENGTH + 2 ];
DWORD dwTmpValue;
// ----------------
pPolicy->fPolicyInitialProgram = GPGetStringValue( policyKey, WIN_INITIALPROGRAM,
pUser->InitialProgram,
INITIALPROGRAM_LENGTH + 1 );
GPGetStringValue( policyKey, WIN_WORKDIRECTORY,
pUser->WorkDirectory,
DIRECTORY_LENGTH + 1 );
// ----------------
pPolicy->fPolicyResetBroken =
GPGetNumValue( policyKey,WIN_RESETBROKEN , & dwTmpValue );
pUser->fResetBroken = (BOOLEAN) dwTmpValue;
// ----------------
pPolicy->fPolicyReconnectSame =
GPGetNumValue( policyKey,WIN_RECONNECTSAME , &dwTmpValue );
pUser->fReconnectSame = (BOOLEAN) dwTmpValue;
// ----------------
pPolicy->fPolicyShadow =
GPGetNumValue( policyKey, WIN_SHADOW, &dwTmpValue );
pUser->Shadow = (SHADOWCLASS) dwTmpValue;
// ----------------
pPolicy->fPolicyMaxSessionTime =
GPGetNumValue( policyKey, WIN_MAXCONNECTIONTIME , &dwTmpValue );
pUser->MaxConnectionTime = dwTmpValue;
// ----------------
pPolicy->fPolicyMaxDisconnectionTime =
GPGetNumValue( policyKey,WIN_MAXDISCONNECTIONTIME ,&dwTmpValue );
pUser->MaxDisconnectionTime = dwTmpValue;
// ----------------
pPolicy->fPolicyMaxIdleTime =
GPGetNumValue( policyKey,WIN_MAXIDLETIME , &dwTmpValue );
pUser->MaxIdleTime = dwTmpValue;
// ----------------
pPolicy->fPolicyCallback =
GPGetNumValue( policyKey, WIN_CALLBACK, &dwTmpValue );
pUser->Callback = (CALLBACKCLASS ) dwTmpValue;
// ----------------
pPolicy->fPolicyCallbackNumber =
GPGetStringValue( policyKey, WIN_CALLBACKNUMBER,
pUser->CallbackNumber,
CALLBACK_LENGTH + 1 );
// ----------------
pPolicy->fPolicyAutoClientDrives =
GPGetNumValue( policyKey,WIN_AUTOCLIENTDRIVES , &dwTmpValue );
pUser->fAutoClientDrives = (BOOLEAN) dwTmpValue;
// ----------------
pPolicy->fPolicyAutoClientLpts =
GPGetNumValue( policyKey,WIN_AUTOCLIENTLPTS , &dwTmpValue );
pUser->fAutoClientLpts = (BOOLEAN) dwTmpValue;
// ----------------
pPolicy->fPolicyForceClientLptDef =
GPGetNumValue( policyKey,WIN_FORCECLIENTLPTDEF , &dwTmpValue );
pUser->fForceClientLptDef = (BOOLEAN) dwTmpValue;
}
/*******************************************************************************
* RegGetUserPolicy()
*
* Params:
* [in] userSID : user sid in a text format
* [out] pPolicy : user policy struct
* [out] pUser : policy values
*
* Return:
* BOOLEAN : TRUE if user policy was found
* FALSE if there was a problem getting user policy
*******************************************************************************/
BOOLEAN RegGetUserPolicy(
LPWSTR userSID ,
PPOLICY_TS_USER pPolicy,
PUSERCONFIGW pUser )
{
DWORD status= ERROR_SUCCESS;
HKEY policyKey;
WCHAR userHive [MAX_PATH];
if (userSID) // this would never happen, but Master Prefix complains and we must server him!
{
wcscpy(userHive, userSID);
wcscat(userHive, L"\\");
wcscat(userHive, TS_POLICY_SUB_TREE );
status = RegOpenKeyEx( HKEY_USERS, userHive , 0,
KEY_READ, &policyKey );
if (status == ERROR_SUCCESS )
{
GPQueryUserConfig( policyKey, pPolicy, pUser );
RegCloseKey( policyKey );
return TRUE;
}
}
return FALSE;
}
/*******************************************************************************
* GPQueryMachineConfig()
*
* Params:
* [in] policyKey : key to the policy tree under hklm
* [out] pPolicy : pointer to a machine policy data that is filled up by this function
*
* Return:
* void
*
*
* !!! WARNING !!!
*
* All TS related values MUST be in the flat TS-POLICY-TREE, no sub keys.
* This is due to the fact that time-stamp checks by the caller of RegGetMachinePolicyEx() will
* check the time stamp on the TS-POLICY key, which is NOT updated when a value in a sub-key is
* altered.
*
*
*******************************************************************************/
void GPQueryMachineConfig( HKEY policyKey, PPOLICY_TS_MACHINE pPolicy )
{
DWORD dwTmpValue;
// ---------------- SessionDirectoryActive
pPolicy->fPolicySessionDirectoryActive =
GPGetNumValue( policyKey,WIN_SESSIONDIRECTORYACTIVE, &dwTmpValue );
pPolicy->SessionDirectoryActive = (BOOLEAN) dwTmpValue;
// ---------------- SessionDirectoryLocation
pPolicy->fPolicySessionDirectoryLocation = GPGetStringValue( policyKey, WIN_SESSIONDIRECTORYLOCATION ,
pPolicy->SessionDirectoryLocation,
DIRECTORY_LENGTH + 1 );
// ---------------- SessionDirectoryClusterName
pPolicy->fPolicySessionDirectoryClusterName = GPGetStringValue( policyKey, WIN_SESSIONDIRECTORYCLUSTERNAME ,
pPolicy->SessionDirectoryClusterName,
DIRECTORY_LENGTH + 1 );
// ---------------- SessionDirectoryAdditionalParams
pPolicy->fPolicySessionDirectoryAdditionalParams = GPGetStringValue( policyKey, WIN_SESSIONDIRECTORYADDITIONALPARAMS ,
pPolicy->SessionDirectoryAdditionalParams,
DIRECTORY_LENGTH + 1 );
// ---------------- EnableTimeZoneRedirection
pPolicy->fPolicyEnableTimeZoneRedirection =
GPGetNumValue( policyKey,POLICY_TS_ENABLE_TIME_ZONE_REDIRECTION , &dwTmpValue );
pPolicy->fEnableTimeZoneRedirection = (BOOLEAN) dwTmpValue;
// ---------------- EncryptRPCTraffic
pPolicy->fPolicyEncryptRPCTraffic =
GPGetNumValue( policyKey, POLICY_TS_ENCRYPT_RPC_TRAFFIC , &dwTmpValue );
if(pPolicy->fPolicyEncryptRPCTraffic)
{
pPolicy->fEncryptRPCTraffic = (BOOLEAN) dwTmpValue;
}
else
{
pPolicy->fEncryptRPCTraffic = FALSE;
}
// ---------------- Clipboard
pPolicy->fPolicyDisableClip =
GPGetNumValue( policyKey,WIN_DISABLECLIP, &dwTmpValue );
pPolicy->fDisableClip = (BOOLEAN) dwTmpValue;
// ---------------- Audio
pPolicy->fPolicyDisableCam =
GPGetNumValue( policyKey,WIN_DISABLECAM , &dwTmpValue );
pPolicy->fDisableCam = (BOOLEAN) dwTmpValue;
// ---------------- Comport
pPolicy->fPolicyDisableCcm =
GPGetNumValue( policyKey,WIN_DISABLECCM , &dwTmpValue );
pPolicy->fDisableCcm = (BOOLEAN) dwTmpValue;
// ---------------- LPT
pPolicy->fPolicyDisableLPT =
GPGetNumValue( policyKey,WIN_DISABLELPT , &dwTmpValue );
pPolicy->fDisableLPT = (BOOLEAN) dwTmpValue;
// ---------------- PRN
pPolicy->fPolicyDisableCpm =
GPGetNumValue( policyKey,WIN_DISABLECPM , &dwTmpValue );
pPolicy->fDisableCpm = (BOOLEAN) dwTmpValue;
// ---------------- Password
pPolicy->fPolicyPromptForPassword =
GPGetNumValue( policyKey, WIN_PROMPTFORPASSWORD , &dwTmpValue );
pPolicy->fPromptForPassword = (BOOLEAN) dwTmpValue;
// ---------------- Max Instance Count
pPolicy->fPolicyMaxInstanceCount =
GPGetNumValue( policyKey,WIN_MAXINSTANCECOUNT , &dwTmpValue );
pPolicy->MaxInstanceCount = dwTmpValue;
// ---------------- Min Encryption Level
pPolicy->fPolicyMinEncryptionLevel =
GPGetNumValue( policyKey, WIN_MINENCRYPTIONLEVEL , &dwTmpValue );
pPolicy->MinEncryptionLevel = (BYTE) dwTmpValue;
// ---------------- AutoReconect
pPolicy->fPolicyDisableAutoReconnect =
GPGetNumValue( policyKey, WIN_DISABLEAUTORECONNECT , &dwTmpValue );
pPolicy->fDisableAutoReconnect = (BOOLEAN) dwTmpValue;
// New machine wide profile, home dir and home drive
/*
pPolicy->fPolicyWFProfilePath = GPGetStringValue( policyKey, WIN_WFPROFILEPATH,
pPolicy ->WFProfilePath,
DIRECTORY_LENGTH + 1 );
*/
pPolicy->fErrorInvalidProfile = FALSE;
BOOLEAN bValueExists;
pPolicy->fErrorInvalidProfile = !GPGetStringValue( policyKey, WIN_WFPROFILEPATH,
pPolicy ->WFProfilePath, DIRECTORY_LENGTH + 1, &bValueExists );
pPolicy->fPolicyWFProfilePath = bValueExists;
if (!pPolicy->fPolicyWFProfilePath)
{
pPolicy->WFProfilePath[0]=L'\0';
}
pPolicy->fPolicyWFHomeDir = GPGetStringValue( policyKey, WIN_WFHOMEDIR ,
pPolicy->WFHomeDir,
DIRECTORY_LENGTH + 1 );
if (!pPolicy->fPolicyWFHomeDir)
{
pPolicy->WFHomeDir[0]=L'\0';
}
pPolicy->fPolicyWFHomeDirDrive =GPGetStringValue( policyKey, WIN_WFHOMEDIRDRIVE,
pPolicy->WFHomeDirDrive,
4 );
if(!pPolicy->WFHomeDir[0])
{
pPolicy->WFHomeDirDrive[0] = L'\0';
}
// if home dir is of the form "driveletter:\path" (such as c:\foo), null out the dir-drive to
// eliminate any confusion.
if ( pPolicy->WFHomeDir[1] == L':' )
{
pPolicy->WFHomeDirDrive[0] = L'\0';
}
// --------------- deny connection policy, this is directly read by RegDenyTSConnectionsPolicy() too
pPolicy->fPolicyDenyTSConnections =
GPGetNumValue( policyKey, POLICY_DENY_TS_CONNECTIONS , &dwTmpValue );
pPolicy->fDenyTSConnections = (BOOLEAN) dwTmpValue;
// track the rest of all possivle GP policies
// even thou not all are used by term-srv's USERCONFIGW . A good example is the
// delete tmp folders that Winlogon/wlnotify uses.
// --------------- Per session tmp folders, WARNING : GINA reads policy tree directly for the sake of lower overhead during login
pPolicy->fPolicyTempFoldersPerSession =
GPGetNumValue( policyKey, REG_TERMSRV_PERSESSIONTEMPDIR , &dwTmpValue );
pPolicy-> fTempFoldersPerSession = (BOOLEAN) dwTmpValue;
// -------------- delete per session folders on exit, WARNING : GINA reads policy tree directly for the sake of lower overhead during login
pPolicy->fPolicyDeleteTempFoldersOnExit =
GPGetNumValue( policyKey, REG_CITRIX_DELETETEMPDIRSONEXIT , &dwTmpValue );
pPolicy->fDeleteTempFoldersOnExit = (BOOLEAN) dwTmpValue;
pPolicy->fPolicyPreventLicenseUpgrade =
GPGetNumValue( policyKey, REG_POLICY_PREVENT_LICENSE_UPGRADE , &dwTmpValue );
pPolicy->fPreventLicenseUpgrade = (BOOLEAN) dwTmpValue;
pPolicy->fPolicySecureLicensing =
GPGetNumValue( policyKey, REG_POLICY_SECURE_LICENSING , &dwTmpValue );
pPolicy->fSecureLicensing = (BOOLEAN) dwTmpValue;
// -------------- Color Depth
pPolicy->fPolicyColorDepth =
GPGetNumValue( policyKey, POLICY_TS_COLOR_DEPTH , &dwTmpValue );
// disabled policy will set value to zero, which we will force it
// to be the min color depth of 8 bits.
if ( dwTmpValue < TS_8BPP_SUPPORT )
{
pPolicy->ColorDepth = TS_8BPP_SUPPORT ;
}
else if ( dwTmpValue == TS_CLIENT_COMPAT_BPP_SUPPORT )
{
pPolicy->ColorDepth = TS_24BPP_SUPPORT; // our current max, may change in teh future.
}
else
{
pPolicy->ColorDepth = dwTmpValue;
}
// ---------------- TSCC's permissions TAB
pPolicy->fPolicyWritableTSCCPermissionsTAB =
GPGetNumValue( policyKey, POLICY_TS_TSCC_PERM_TAB_WRITABLE , &dwTmpValue );
pPolicy->fWritableTSCCPermissionsTAB= (BOOLEAN) dwTmpValue;
// ----------------
// Ritu has folded the user policy into machine policy for the drive re-direction.
pPolicy->fPolicyDisableCdm =
GPGetNumValue( policyKey, WIN_DISABLECDM , &dwTmpValue );
pPolicy->fDisableCdm = (BOOLEAN) dwTmpValue;
// ----------------
// fold user config policy into machine config policy
pPolicy->fPolicyForceClientLptDef =
GPGetNumValue( policyKey,WIN_FORCECLIENTLPTDEF , &dwTmpValue );
pPolicy->fForceClientLptDef = (BOOLEAN) dwTmpValue;
// for user config policy into machine config policy
// ----------------
pPolicy->fPolicyShadow =
GPGetNumValue( policyKey, WIN_SHADOW, &dwTmpValue );
pPolicy->Shadow = (SHADOWCLASS) dwTmpValue;
//
// ---- Sessions Policy
//
// ----------------
pPolicy->fPolicyResetBroken =
GPGetNumValue( policyKey,WIN_RESETBROKEN , & dwTmpValue );
pPolicy->fResetBroken = (BOOLEAN) dwTmpValue;
// ----------------
pPolicy->fPolicyReconnectSame =
GPGetNumValue( policyKey,WIN_RECONNECTSAME , &dwTmpValue );
pPolicy->fReconnectSame = (BOOLEAN) dwTmpValue;
// ----------------
pPolicy->fPolicyMaxSessionTime =
GPGetNumValue( policyKey, WIN_MAXCONNECTIONTIME , &dwTmpValue );
pPolicy->MaxConnectionTime = dwTmpValue;
// ----------------
pPolicy->fPolicyMaxDisconnectionTime =
GPGetNumValue( policyKey,WIN_MAXDISCONNECTIONTIME ,&dwTmpValue );
pPolicy->MaxDisconnectionTime = dwTmpValue;
// ----------------
pPolicy->fPolicyMaxIdleTime =
GPGetNumValue( policyKey,WIN_MAXIDLETIME , &dwTmpValue );
pPolicy->MaxIdleTime = dwTmpValue;
// ---------------- Start program policy
pPolicy->fPolicyInitialProgram = GPGetStringValue( policyKey, WIN_INITIALPROGRAM,
pPolicy->InitialProgram,
INITIALPROGRAM_LENGTH + 1 );
GPGetStringValue( policyKey, WIN_WORKDIRECTORY,
pPolicy->WorkDirectory,
DIRECTORY_LENGTH + 1 );
// ---------------- single session per user
pPolicy->fPolicySingleSessionPerUser=
GPGetNumValue( policyKey,POLICY_TS_SINGLE_SESSION_PER_USER, &dwTmpValue );
pPolicy->fSingleSessionPerUser = dwTmpValue;
pPolicy->fPolicySessionDirectoryExposeServerIP =
GPGetNumValue( policyKey, REG_TS_SESSDIR_EXPOSE_SERVER_ADDR , &dwTmpValue );
pPolicy->SessionDirectoryExposeServerIP = dwTmpValue;
// policy for disabling wallpaper in remote desktop
pPolicy->fPolicyDisableWallpaper =
GPGetNumValue( policyKey, POLICY_TS_NO_REMOTE_DESKTOP_WALLPAPER, &dwTmpValue );
pPolicy->fDisableWallpaper = dwTmpValue;
// policy to enable disable keep alive
pPolicy->fPolicyKeepAlive =
GPGetNumValue( policyKey, KEEP_ALIVE_ENABLE_KEY , &dwTmpValue );
pPolicy->fKeepAliveEnable = dwTmpValue;
GPGetNumValue( policyKey, KEEP_ALIVE_INTERVAL_KEY , &dwTmpValue );
pPolicy->KeepAliveInterval = dwTmpValue;
// Policy for disabling forcible logoff
pPolicy->fPolicyDisableForcibleLogoff =
GPGetNumValue( policyKey, POLICY_TS_DISABLE_FORCIBLE_LOGOFF, &dwTmpValue );
pPolicy->fDisableForcibleLogoff = dwTmpValue;
// ---------------- FIPS Encryption Enabled/Disabled
// FIPS policy key is stored separately from the others so we must explicity
// read it in from its location in registry
HKEY hkey;
LONG lRet;
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TS_FIPS_POLICY,
0,
KEY_READ,
&hkey);
if (lRet == ERROR_SUCCESS)
{
// if policy is not set GPGetNumValue returns dwTmpValue = 0
GPGetNumValue(hkey, FIPS_ALGORITH_POLICY, &dwTmpValue);
pPolicy->fPolicyFipsEnabled = dwTmpValue;
RegCloseKey(hkey);
}
else
pPolicy->fPolicyFipsEnabled = 0;
}
/*******************************************************************************
* RegGetMachinePolicy()
*
* Params:
* [out] pPolicy : the machine policy used by ts session's userconfig
*
* Return:
* void
*
*******************************************************************************/
void RegGetMachinePolicy(
PPOLICY_TS_MACHINE pPolicy )
{
NTSTATUS status= STATUS_SUCCESS;
HKEY policyKey;
status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TS_POLICY_SUB_TREE, 0,
KEY_READ, &policyKey );
if ( status != ERROR_SUCCESS)
{
policyKey = NULL; // prefix complains.
}
// ok to call this with policyKey=NULL since func will init pPolicy using default values for the case of NULL key.
GPQueryMachineConfig( policyKey, pPolicy );
if ( policyKey )
{
RegCloseKey( policyKey );
}
}
/*******************************************************************************
* RegGetMachinePolicyiEx()
*
* This func is identical to RegGetMachinePolicy() , and provides the time stampt for
* the last write time of the policy key, and if the time of the key is the same as the
* time for the last read, then it will not bother with any reads and return false
*
* Params:
* [in ] forcePolicyRead : 1st time around, you want to init all vars so force a read.
* [in/out] pTime : caller passes in the last write time for the machine policy key.
* if key is missing, then time is set to zero.
* On return, this param is updated to reflect the most recent
* update time, which could be zero if the policy key was deleted
*
* [out] pPolicy : the machine policy struct updated
*
* Return:
* TRUE : means there was a real change present
* FALSE : means no values had changed.
*******************************************************************************/
BOOLEAN RegGetMachinePolicyEx(
BOOLEAN forcePolicyRead,
FILETIME *pTime ,
PPOLICY_TS_MACHINE pPolicy )
{
HKEY policyKey;
HKEY FipsPolicyKey;
FILETIME newTime;
FILETIME FipsNewTime;
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN rc = FALSE;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TS_POLICY_SUB_TREE,
0,
KEY_READ,
&policyKey );
if (status != ERROR_SUCCESS)
{
policyKey = NULL; // prefix complains.
}
// if we have a policy key, get the time for that key
if (policyKey)
{
RegQueryInfoKey( policyKey, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &newTime );
}
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TS_FIPS_POLICY,
0,
KEY_READ,
&FipsPolicyKey);
if (status != ERROR_SUCCESS)
{
FipsPolicyKey = NULL; // prefix complains.
}
// if we have a Fips policy key, get the time for that key
if (FipsPolicyKey)
{
RegQueryInfoKey(FipsPolicyKey, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &FipsNewTime);
}
// If we got times back for both policies pick the newest
if (policyKey && FipsPolicyKey)
{
if ( (FipsNewTime.dwHighDateTime > newTime.dwHighDateTime) ||
( (FipsNewTime.dwHighDateTime == newTime.dwHighDateTime) &&
(FipsNewTime.dwLowDateTime > newTime.dwLowDateTime) ) )
{
// FipsNewTime is newer, set it as the time to use
newTime = FipsNewTime;
}
}
// If we don't have a time for either policy keys then init time to the current system time
else
{
SYSTEMTIME currentTimeOnSystemInSystemTimeUnits;
GetSystemTime(&currentTimeOnSystemInSystemTimeUnits);
SystemTimeToFileTime(&currentTimeOnSystemInSystemTimeUnits, &newTime);
}
if ( forcePolicyRead ||
( (pTime->dwHighDateTime < newTime.dwHighDateTime ) ||
( ( pTime->dwHighDateTime == newTime.dwHighDateTime ) && pTime->dwLowDateTime < newTime.dwLowDateTime ) ) )
{
// this call will init struct memebers even if the policy key in null, so it
// is required to make this call on startup, with or without an actual reg key being present
GPQueryMachineConfig( policyKey, pPolicy );
rc = TRUE;
}
pTime->dwHighDateTime = newTime.dwHighDateTime;
pTime->dwLowDateTime = newTime.dwLowDateTime;
if ( policyKey )
{
RegCloseKey( policyKey );
}
if ( FipsPolicyKey )
{
RegCloseKey( FipsPolicyKey );
}
return rc;
}
/*******************************************************************************
* RegMergeMachinePolicy()
*
* Params:
* [in] pPolicy : policy data to use to override userconfig
* [in/out] pWSConfig : userconfig data that is modified based on the policy data
*
* Return:
* void
*
********************************************************************************/
void RegMergeMachinePolicy(
PPOLICY_TS_MACHINE pPolicy, // the policy override data
USERCONFIGW * pWSConfig, // the machine config data represented thru a USERCONFIGW data struct (mostly)
PWINSTATIONCREATE pCreate // some of winstation data is stored here
)
{
// ---------------------------------------------- Clipboard
if ( pPolicy->fPolicyDisableClip )
{
pWSConfig->fDisableClip = pPolicy->fDisableClip;
}
// ---------------------------------------------- Audio
if ( pPolicy->fPolicyDisableCam )
{
pWSConfig->fDisableCam = pPolicy->fDisableCam;
}
// ---------------------------------------------- Comport
if ( pPolicy->fPolicyDisableCcm )
{
pWSConfig->fDisableCcm = pPolicy->fDisableCcm;
}
// ---------------------------------------------- LPT
if ( pPolicy->fPolicyDisableLPT )
{
pWSConfig->fDisableLPT = pPolicy->fDisableLPT;
}
// ---------------------------------------------- PRN
if ( pPolicy->fPolicyDisableCpm )
{
pWSConfig->fDisableCpm = pPolicy->fDisableCpm;
}
// ---------------------------------------------- Password
if ( pPolicy->fPolicyPromptForPassword )
{
pWSConfig->fPromptForPassword = pPolicy->fPromptForPassword;
}
// ---------------------------------------------- Max Instance
if ( pPolicy->fPolicyMaxInstanceCount )
{
pCreate->MaxInstanceCount = pPolicy->MaxInstanceCount;
}
// ---------------------------------------------- Min Encryption Level
if ( pPolicy->fPolicyMinEncryptionLevel )
{
pWSConfig->MinEncryptionLevel = pPolicy->MinEncryptionLevel;
}
// ---------------------------------------------- FIPS Enabled/Disabled
if ( pPolicy->fPolicyFipsEnabled )
{
pWSConfig->MinEncryptionLevel = (BYTE)REG_FIPS_ENCRYPTION_LEVEL;
}
// ---------------------------------------------- Auto Reconnect disable
if ( pPolicy->fPolicyDisableAutoReconnect )
{
pWSConfig->fDisableAutoReconnect = pPolicy->fDisableAutoReconnect;
}
//----------------------------------------------- "Invalid Profile" flag
if(pPolicy->fErrorInvalidProfile)
{
pWSConfig->fErrorInvalidProfile = pPolicy->fErrorInvalidProfile;
}
// ---------------------------------------------- Profile Path
if (pPolicy->fPolicyWFProfilePath )
{
wcscpy( pWSConfig->WFProfilePath, pPolicy->WFProfilePath );
}
// ---------------------------------------------- Home Directory
if ( pPolicy->fPolicyWFHomeDir )
{
wcscpy( pWSConfig->WFHomeDir, pPolicy->WFHomeDir );
}
// ---------------------------------------------- Home Directory Drive
if ( pPolicy->fPolicyWFHomeDirDrive )
{
wcscpy( pWSConfig->WFHomeDirDrive, pPolicy->WFHomeDirDrive );
}
// ---------------------------------------------- Color Depth
if ( pPolicy->fPolicyColorDepth)
{
pWSConfig->ColorDepth = pPolicy->ColorDepth ;
pWSConfig->fInheritColorDepth = FALSE;
}
//
if ( pPolicy->fPolicyDisableCdm)
{
pWSConfig->fDisableCdm = pPolicy->fDisableCdm;
}
//
if ( pPolicy->fPolicyForceClientLptDef )
{
pWSConfig->fForceClientLptDef = pPolicy->fForceClientLptDef;
}
// Shadow
if ( pPolicy->fPolicyShadow)
{
pWSConfig->Shadow = pPolicy->Shadow;
pWSConfig->fInheritShadow = FALSE;
}
if (pPolicy->fPolicyResetBroken )
{
pWSConfig->fResetBroken = pPolicy->fResetBroken;
pWSConfig->fInheritResetBroken = FALSE;
}
if (pPolicy->fPolicyReconnectSame )
{
pWSConfig->fReconnectSame = pPolicy->fReconnectSame;
pWSConfig->fInheritReconnectSame = FALSE;
}
if (pPolicy->fPolicyMaxSessionTime )
{
pWSConfig->MaxConnectionTime = pPolicy->MaxConnectionTime;
pWSConfig->fInheritMaxSessionTime = FALSE;
}
if (pPolicy->fPolicyMaxDisconnectionTime)
{
pWSConfig->MaxDisconnectionTime = pPolicy->MaxDisconnectionTime;
pWSConfig->fInheritMaxDisconnectionTime = FALSE;
}
if (pPolicy->fPolicyMaxIdleTime)
{
pWSConfig->MaxIdleTime = pPolicy->MaxIdleTime;
pWSConfig->fInheritMaxIdleTime = FALSE;
}
if (pPolicy->fPolicyInitialProgram)
{
wcscpy( pWSConfig->InitialProgram, pPolicy->InitialProgram );
wcscpy( pWSConfig->WorkDirectory, pPolicy->WorkDirectory );
pWSConfig->fInheritInitialProgram = FALSE;
}
if ( pPolicy->fPolicyDisableWallpaper )
{
pWSConfig->fWallPaperDisabled = pPolicy->fDisableWallpaper ;
}
// ----------------------------------------------
// There is no UI for setting these... So it's probably never used
//
// if ( pPolicy->fPolicytSecurity )
// {
// pWSConfig->fDisableEncryption = pPolicy->fDisableEncryption;
// pWSConfig->MinEncryptionLevel = pPolicy->MinEncryptionLevel;
// }
// else
// {
// if ( pWSConfig->fInheritSecurity )
// {
// pWSConfig->fDisableEncryption = pPolicy->fDisableEncryption;
// pWSConfig->MinEncryptionLevel = pPolicy->MinEncryptionLevel;
// }
// }
}
__inline BOOL IsAppServer()
{
OSVERSIONINFOEX osVersionInfo;
DWORDLONG dwlConditionMask = 0;
BOOL fIsWTS = FALSE;
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
fIsWTS = GetVersionEx((OSVERSIONINFO *)&osVersionInfo) &&
(osVersionInfo.wSuiteMask & VER_SUITE_TERMINAL) &&
!(osVersionInfo.wSuiteMask & VER_SUITE_SINGLEUSERTS);
return fIsWTS;
}
/*******************************************************************************
* RegIsTimeZoneRedirectionEnabled()
*
* Purpose:
* Checks the registry settings for Time Zone redirection.
* Params:
* NONE
*
* Return:
* TRUE if time zone redirection is enabled.
* Note:
* This function reads the registry only once. So for new settings to take
* effect one needs to reboot machine. This is done on purpose, to avoid
* confusions when one creates a session having TZ redirection disabled, then
* disconnects, enables TZ redirection and reconnects again.
********************************************************************************/
BOOLEAN
RegIsTimeZoneRedirectionEnabled()
{
LONG errorCode = ERROR_SUCCESS;
DWORD ValueType;
DWORD ValueSize = sizeof(DWORD);
DWORD valueData ;
HKEY hKey = NULL;
if(!IsAppServer())
{
return FALSE;
}
//
// first check the policy tree,
//
errorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TS_POLICY_SUB_TREE, 0, KEY_READ, &hKey );
//If error code is ERROR_FILE_NOT_FOUND, this is not an error.
if( !hKey && errorCode != ERROR_FILE_NOT_FOUND )
{
return FALSE;
}
if ( hKey )
{
errorCode = RegQueryValueEx( hKey, POLICY_TS_ENABLE_TIME_ZONE_REDIRECTION,
NULL, &ValueType, (LPBYTE) &valueData, &ValueSize );
RegCloseKey(hKey);
hKey = NULL;
switch( errorCode )
{
case ERROR_SUCCESS :
return (valueData != 0); // we have data from the policyKey handle to return
case ERROR_FILE_NOT_FOUND:
// there is no policy from GP, so see (below) what the local machine
// value has.
break;
default:
// if we are having any other kind of a problem, claim FALSE
//to be on the safe side.
return FALSE;
}
}
// if we got this far, then no policy was set. Check the local machine now.
errorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0, KEY_READ, &hKey );
if ( hKey )
{
errorCode = RegQueryValueEx( hKey, POLICY_TS_ENABLE_TIME_ZONE_REDIRECTION,
NULL, &ValueType, (LPBYTE) &valueData, &ValueSize );
RegCloseKey(hKey);
hKey = NULL;
if (errorCode == ERROR_SUCCESS )
{
return (valueData != 0); // we have data from the ControlKey handle to return
}
}
return FALSE;
}