windows-nt/Source/XPSP1/NT/termsrv/remdsk/server/sessmgr/policy.cpp

803 lines
18 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
policy.cpp
Abstract:
RDS Policy related function
Author:
HueiWang 5/2/2000
--*/
#include "stdafx.h"
#include "policy.h"
#ifndef __WIN9XBUILD__
extern "C" BOOLEAN RegDenyTSConnectionsPolicy();
typedef struct __RDSLevelShadowMap {
SHADOWCLASS shadowClass;
REMOTE_DESKTOP_SHARING_CLASS rdsLevel;
} RDSLevelShadowMap;
static const RDSLevelShadowMap ShadowMap[] = {
{ Shadow_Disable, NO_DESKTOP_SHARING }, // No RDS sharing
{ Shadow_EnableInputNotify, CONTROLDESKTOP_PERMISSION_REQUIRE }, // Interact with user permission
{ Shadow_EnableInputNoNotify, CONTROLDESKTOP_PERMISSION_NOT_REQUIRE }, // Interact without user permission
{ Shadow_EnableNoInputNotify, VIEWDESKTOP_PERMISSION_REQUIRE}, // View with user permission
{ Shadow_EnableNoInputNoNotify, VIEWDESKTOP_PERMISSION_NOT_REQUIRE } // View without user permission
};
DWORD
GetPolicyAllowGetHelpSetting(
HKEY hKey,
LPCTSTR pszKeyName,
LPCTSTR pszValueName,
IN DWORD* value
)
/*++
Routine Description:
Routine to query policy registry value.
Parameters:
hKey : Currently open registry key.
pszKeyName : Pointer to a null-terminated string containing
the name of the subkey to open.
pszValueName : Pointer to a null-terminated string containing
the name of the value to query
value : Pointer to DWORD to receive GetHelp policy setting.
Returns:
ERROR_SUCCESS or error code from RegOpenKeyEx().
--*/
{
DWORD dwStatus;
HKEY hPolicyKey = NULL;
DWORD dwType;
DWORD cbData;
//
// Open registry key for system policy
//
dwStatus = RegOpenKeyEx(
hKey,
pszKeyName,
0,
KEY_READ,
&hPolicyKey
);
if( ERROR_SUCCESS == dwStatus )
{
// query value
cbData = 0;
dwType = 0;
dwStatus = RegQueryValueEx(
hPolicyKey,
pszValueName,
NULL,
&dwType,
NULL,
&cbData
);
if( ERROR_SUCCESS == dwStatus )
{
if( REG_DWORD == dwType )
{
cbData = sizeof(DWORD);
// our registry value is REG_DWORD, if different type,
// assume not exist.
dwStatus = RegQueryValueEx(
hPolicyKey,
pszValueName,
NULL,
&dwType,
(LPBYTE)value,
&cbData
);
ASSERT( ERROR_SUCCESS == dwStatus );
}
else
{
// bad registry key type, assume
// key does not exist.
dwStatus = ERROR_FILE_NOT_FOUND;
}
}
RegCloseKey( hPolicyKey );
}
return dwStatus;
}
SHADOWCLASS
MapRDSLevelToTSShadowSetting(
IN REMOTE_DESKTOP_SHARING_CLASS RDSLevel
)
/*++
Routine Description:
Convert TS Shadow settings to our RDS sharing level.
Parameter:
TSShadowClass : TS Shadow setting.
Returns:
REMOTE_DESKTOP_SHARING_CLASS
--*/
{
SHADOWCLASS shadowClass;
for( int i=0; i < sizeof(ShadowMap)/sizeof(ShadowMap[0]); i++)
{
if( ShadowMap[i].rdsLevel == RDSLevel )
{
break;
}
}
if( i < sizeof(ShadowMap)/sizeof(ShadowMap[0]) )
{
shadowClass = ShadowMap[i].shadowClass;
}
else
{
MYASSERT(FALSE);
shadowClass = Shadow_Disable;
}
return shadowClass;
}
REMOTE_DESKTOP_SHARING_CLASS
MapTSShadowSettingToRDSLevel(
SHADOWCLASS TSShadowClass
)
/*++
Routine Description:
Convert TS Shadow settings to our RDS sharing level.
Parameter:
TSShadowClass : TS Shadow setting.
Returns:
REMOTE_DESKTOP_SHARING_CLASS
--*/
{
REMOTE_DESKTOP_SHARING_CLASS level;
for( int i=0; i < sizeof(ShadowMap)/sizeof(ShadowMap[0]); i++)
{
if( ShadowMap[i].shadowClass == TSShadowClass )
{
break;
}
}
if( i < sizeof(ShadowMap)/sizeof(ShadowMap[0]) )
{
level = ShadowMap[i].rdsLevel;
}
else
{
MYASSERT(FALSE);
level = NO_DESKTOP_SHARING;
}
return level;
}
DWORD
MapSessionIdToWinStationName(
IN ULONG ulSessionID,
OUT PWINSTATIONNAME pWinstationName
)
/*++
Routine Description:
Find out TS winstation name for the session specified.
Parameters:
ulSessionID : TS Session ID to query.
pWinstationName : Pointer to WINSTATIONNAME to receive
name of WinStation for Session ID specified.
Returns:
ERROR_SUCCESS or Error code.
-*/
{
BOOL bSuccess;
DWORD dwStatus;
LPTSTR pBuffer = NULL;
DWORD bytesReturned;
bSuccess = WTSQuerySessionInformation(
WTS_CURRENT_SERVER,
ulSessionID,
WTSWinStationName,
&pBuffer,
&bytesReturned
);
if( TRUE == bSuccess )
{
LPTSTR pszChr;
//
// WINSTATIONNAME returned from WTSQuerySessionInformation
// has '#...' appended to it, we can't use it to query
// WINSTATION configuration as RegApi look for exact WINSTATION
// name in registry and so it will return default value.
//
pszChr = _tcschr( pBuffer, _TEXT('#') );
if( NULL != pszChr )
{
*pszChr = _TEXT('\0');
}
ZeroMemory( pWinstationName, sizeof( WINSTATIONNAME ) );
CopyMemory( pWinstationName, pBuffer, bytesReturned );
dwStatus = ERROR_SUCCESS;
}
else
{
dwStatus = GetLastError();
}
if( NULL != pBuffer )
{
WTSFreeMemory( pBuffer );
}
return dwStatus;
}
DWORD
GetWinStationConfig(
IN ULONG ulSessionId,
OUT WINSTATIONCONFIG2* pConfig
)
/*++
Routine Description:
Retrieve WINSTATIONCONFIG2 for session specified.
Parameters:
ulSessionId : TS Session to query.
pConfig : Pointer to WINSTATIONCONIF2 to receive result.
Returns:
ERROR_SUCCESS or error code.
--*/
{
WINSTATIONNAME WinStationName;
DWORD dwStatus;
ULONG length = 0;
dwStatus = MapSessionIdToWinStationName(
ulSessionId,
WinStationName
);
if( ERROR_SUCCESS == dwStatus )
{
dwStatus = RegWinStationQuery(
NULL,
WinStationName,
pConfig,
sizeof(WINSTATIONCONFIG2),
&length
);
}
return dwStatus;
}
#endif
BOOL
IsUserAllowToGetHelp(
IN ULONG ulSessionId,
IN LPCTSTR pszUserSid
)
/*++
Routine Description:
Determine if caller can 'GetHelp'
Parameters:
ulSessionId : User's TS logon ID.
pszUserSid : User's SID in textual form.
Returns:
TRUE/FALSE
Note:
Must have impersonate user first.
--*/
{
BOOL bAllow;
DWORD dwStatus;
DWORD dwAllow;
LPTSTR pszUserHive = NULL;
MYASSERT( NULL != pszUserSid );
//
// Must be able to GetHelp from machine
//
bAllow = TSIsMachinePolicyAllowHelp();
if( TRUE == bAllow )
{
pszUserHive = (LPTSTR)LocalAlloc(
LPTR,
sizeof(TCHAR) * (lstrlen(pszUserSid) + lstrlen(RDS_GROUPPOLICY_SUBTREE) + 2 )
);
lstrcpy( pszUserHive, pszUserSid );
lstrcat( pszUserHive, _TEXT("\\") );
lstrcat( pszUserHive, RDS_GROUPPOLICY_SUBTREE );
//
// Query user level AllowGetHelp setting.
dwStatus = GetPolicyAllowGetHelpSetting(
HKEY_USERS,
pszUserHive,
RDS_ALLOWGETHELP_VALUENAME,
&dwAllow
);
if( ERROR_SUCCESS == dwStatus )
{
bAllow = (POLICY_ENABLE == dwAllow);
}
else
{
// no configuration for this user, assume GetHelp
// is enabled.
bAllow = TRUE;
}
}
if( NULL != pszUserHive )
{
LocalFree( pszUserHive );
}
return bAllow;
}
DWORD
GetSystemRDSLevel(
IN ULONG ulSessionId,
OUT REMOTE_DESKTOP_SHARING_CLASS* pSharingLevel
)
/*++
Routine Description:
Retrieve policy setting for remote desktop sharing level.
Parameters:
ulSessionId : TS session ID, unuse if TS group policy is set.
pSharingLever : Pointer to REMOTE_DESKTOP_SHARING_CLASS to receive
machine RDS level.
Returns:
REMOTE_DESKTOP_SHARING_CLASS
--*/
{
DWORD dwStatus;
#ifndef __WIN9XBUILD__
WINSTATIONCONFIG2 WSConfig;
ULONG length = 0;
//
// TS Group Policy does not have machine level shadow
// setting, only TSCC has this setting, and TSCC setting
// is based on WINSTATION not entire machine.
//
// We can't query TS since TS already merger all policy
// setting into USERCONFIG which might not be correct
//
dwStatus = GetWinStationConfig(
ulSessionId,
&WSConfig
);
if( ERROR_SUCCESS == dwStatus )
{
if( TRUE == WSConfig.Config.User.fInheritShadow )
{
// Shadow config is inherite from user properies
// so we query user level setting.
dwStatus = GetUserRDSLevel( ulSessionId, pSharingLevel );
}
else
{
*pSharingLevel = MapTSShadowSettingToRDSLevel( WSConfig.Config.User.Shadow );
}
}
#else
// TODO - revisit this for Win9x Build
MYASSERT(FALSE);
*pSharingLevel = CONTROLDESKTOP_PERMISSION_REQUIRE;
dwStatus = ERROR_SUCCESS;
#endif
return dwStatus;
}
DWORD
GetUserRDSLevel(
IN ULONG ulSessionId,
OUT REMOTE_DESKTOP_SHARING_CLASS* pLevel
)
/*++
same as GetSystemRDSLevel() except it retrieve currently logon user's
RDS level.
--*/
{
DWORD dwStatus;
#ifndef __WIN9XBUILD__
BOOL bSuccess;
WINSTATIONCONFIG WSConfig;
DWORD dwByteReturned;
memset( &WSConfig, 0, sizeof(WSConfig) );
// Here we call WInStationQueryInformation() since WTSAPI require
// few calls to get the same result
bSuccess = WinStationQueryInformation(
WTS_CURRENT_SERVER,
ulSessionId,
WinStationConfiguration,
&WSConfig,
sizeof( WSConfig ),
&dwByteReturned
);
if( TRUE == bSuccess )
{
dwStatus = ERROR_SUCCESS;
*pLevel = MapTSShadowSettingToRDSLevel( WSConfig.User.Shadow );
}
else
{
dwStatus = GetLastError();
}
#else
// TODO - revisit this for Win9x Build
MYASSERT(FALSE);
*pLevel = CONTROLDESKTOP_PERMISSION_REQUIRE;
dwStatus = ERROR_SUCCESS;
#endif
return dwStatus;
}
DWORD
ConfigSystemGetHelp(
BOOL bEnable
)
/*++
Routine Description:
Enable/disable 'GetHelp' on local machine.
Parameters:
bEnable : TRUE to enable, FALSE otherwise.
Returns:
ERROR_SUCCESS or error code.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
BOOL bMember;
HKEY hKey = NULL;
DWORD dwValue;
BOOL bAllowHelp;
#ifndef __WIN9XBUILD__
dwStatus = IsUserAdmin( &bMember );
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
if( FALSE == bMember )
{
dwStatus = ERROR_ACCESS_DENIED;
goto CLEANUPANDEXIT;
}
#endif
// We only check if Group Policy has this setting and no
// checking on TSCC deny connection setting since
// TSCC set WINSTATION deny connection not entire machine
// and we can't be sure which connection that connection
// is denied, so it is still possible that GetHelp is enabled
// but WINSTATION's deny connection is still set to TRUE
// in this case, no help is available even this funtion
// return SUCCEEDED.
// verify no group policy on this
dwStatus = GetPolicyAllowGetHelpSetting(
HKEY_LOCAL_MACHINE,
RDS_GROUPPOLICY_SUBTREE,
RDS_ALLOWGETHELP_VALUENAME,
&dwValue
);
if( ERROR_SUCCESS == dwStatus )
{
dwStatus = ERROR_ACCESS_DENIED;
}
else
{
//
// Write to registry
//
dwStatus = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
RDS_MACHINEPOLICY_SUBTREE,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
);
if( ERROR_SUCCESS == dwStatus )
{
dwValue = (bEnable) ? POLICY_ENABLE : POLICY_DISABLE;
dwStatus = RegSetValueEx(
hKey,
RDS_ALLOWGETHELP_VALUENAME,
0,
REG_DWORD,
(LPBYTE) &dwValue,
sizeof(DWORD)
);
}
MYASSERT( ERROR_SUCCESS == dwStatus );
}
#ifndef __WIN9XBUILD__
CLEANUPANDEXIT:
#endif
if( NULL != hKey )
{
RegCloseKey(hKey);
}
return dwStatus;
}
DWORD
ConfigSystemRDSLevel(
IN REMOTE_DESKTOP_SHARING_CLASS level
)
/*++
Routine Description:
This routine set machine wide RDS level.
Parameters:
level : new RDS level.
Returns:
ERROR_SUCCESS or error code.
--*/
{
//
// TODO - revisit this, on Win2K and Whilster,
// group policy override this setting via User Properties
// or if group policy is not set, TSCC can override this.
// and since a user account always has some default value
// for this, so we have no way to determine whether this is
// a default or else, so we simple return ERROR for Win2K
// and Whilster platform.
//
//
// TODO : For legacy platform, Win9x/NT40/TS40, we need to figure
// out how/where poledit put this setting, for now,
// just return error.
//
DWORD dwStatus = ERROR_INVALID_FUNCTION;
return dwStatus;
}
DWORD
ConfigUserSessionRDSLevel(
IN ULONG ulSessionId,
IN REMOTE_DESKTOP_SHARING_CLASS level
)
/*++
--*/
{
#ifndef __WIN9XBUILD__
WINSTATIONCONFIG winstationConfig;
SHADOWCLASS shadowClass = MapRDSLevelToTSShadowSetting( level );
BOOL bSuccess;
DWORD dwLength;
DWORD dwStatus;
memset( &winstationConfig, 0, sizeof(winstationConfig) );
bSuccess = WinStationQueryInformation(
WTS_CURRENT_SERVER,
ulSessionId,
WinStationConfiguration,
&winstationConfig,
sizeof(winstationConfig),
&dwLength
);
if( TRUE == bSuccess )
{
winstationConfig.User.Shadow = shadowClass;
bSuccess = WinStationSetInformation(
WTS_CURRENT_SERVER,
ulSessionId,
WinStationConfiguration,
&winstationConfig,
sizeof(winstationConfig)
);
}
if( TRUE == bSuccess )
{
dwStatus = ERROR_SUCCESS;
}
else
{
dwStatus = GetLastError();
}
return dwStatus;
#else
return ERROR_SUCCESS;
#endif
}
#if 0
HRESULT
PolicyGetAllowUnSolicitedHelp(
BOOL* bAllow
)
/*++
--*/
{
HRESULT hRes;
CComPtr<IRARegSetting> IRegSetting;
hRes = IRegSetting.CoCreateInstance( CLSID_RARegSetting );
if( SUCCEEDED(hRes) )
{
hRes = IRegSetting->get_AllowUnSolicited(bAllow);
}
MYASSERT( SUCCEEDED(hRes) );
return hRes;
}
#endif
HRESULT
PolicyGetMaxTicketExpiry(
LONG* value
)
/*++
--*/
{
HRESULT hRes;
CComPtr<IRARegSetting> IRegSetting;
hRes = IRegSetting.CoCreateInstance( CLSID_RARegSetting );
if( SUCCEEDED(hRes) )
{
hRes = IRegSetting->get_MaxTicketExpiry(value);
}
MYASSERT( SUCCEEDED(hRes) );
return hRes;
}