WindowsXP-SP1/termsrv/regapi/regwin.c

1681 lines
52 KiB
C

/*************************************************************************
*
* regwin.c
*
* Register APIs for window stations
*
* Copyright (c) 1998 Microsoft Corporation
*
*
*************************************************************************/
/*
* Includes
*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <ntddkbd.h>
#include <ntddmou.h>
#include <winstaw.h>
#include <regapi.h>
//
extern HKEY g_hTSPolicyKey;//handle to TS_POLICY_SUB_TREE key
extern HKEY g_hTSControlKey;//handle to REG_CONTROL_TSERVER key
/*
* External Procedures defined here
*/
LONG WINAPI RegWinStationAccessCheck( HANDLE, REGSAM );
LONG WINAPI RegWinStationEnumerateW( HANDLE, PULONG, PULONG, PWINSTATIONNAMEW, PULONG );
LONG WINAPI RegWinStationEnumerateA( HANDLE, PULONG, PULONG, PWINSTATIONNAMEA, PULONG );
LONG WINAPI RegWinStationCreateW( HANDLE, PWINSTATIONNAMEW, BOOLEAN,
PWINSTATIONCONFIG2W, ULONG );
LONG WINAPI RegWinStationCreateA( HANDLE, PWINSTATIONNAMEA, BOOLEAN,
PWINSTATIONCONFIG2A, ULONG );
LONG WINAPI RegWinStationQueryW( HANDLE, PWINSTATIONNAMEW, PWINSTATIONCONFIG2W,
ULONG, PULONG );
LONG WINAPI RegWinStationQueryA( HANDLE, PWINSTATIONNAMEA, PWINSTATIONCONFIG2A,
ULONG, PULONG );
LONG WINAPI RegWinStationDeleteW( HANDLE, PWINSTATIONNAMEW );
LONG WINAPI RegWinStationDeleteA( HANDLE, PWINSTATIONNAMEA );
LONG WINAPI RegWinStationSetSecurityW( HANDLE, PWINSTATIONNAMEW, PSECURITY_DESCRIPTOR,
ULONG );
LONG WINAPI RegWinStationSetSecurityA( HANDLE, PWINSTATIONNAMEA, PSECURITY_DESCRIPTOR,
ULONG );
LONG WINAPI RegWinStationQuerySecurityW( HANDLE, PWINSTATIONNAMEW, PSECURITY_DESCRIPTOR,
ULONG, PULONG );
LONG WINAPI RegWinStationQuerySecurityA( HANDLE, PWINSTATIONNAMEA, PSECURITY_DESCRIPTOR,
ULONG, PULONG );
LONG WINAPI RegWinStationQueryDefaultSecurity( HANDLE, PSECURITY_DESCRIPTOR,
ULONG, PULONG );
LONG WINAPI RegWinStationSetNumValueW( HANDLE, PWINSTATIONNAMEW, LPWSTR, ULONG );
LONG WINAPI RegWinStationQueryNumValueW( HANDLE, PWINSTATIONNAMEW, LPWSTR, PULONG );
LONG WINAPI
RegConsoleShadowQueryA( HANDLE hServer,
PWINSTATIONNAMEA pWinStationName,
PWDPREFIXA pWdPrefixName,
PWINSTATIONCONFIG2A pWinStationConfig,
ULONG WinStationConfigLength,
PULONG pReturnLength );
LONG WINAPI
RegConsoleShadowQueryW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
PWDPREFIXW pWdPrefixName,
PWINSTATIONCONFIG2W pWinStationConfig,
ULONG WinStationConfigLength,
PULONG pReturnLength );
/*
* Private Procedures defined here
*/
LONG _RegOpenWinStation( PWINSTATIONNAMEW, REGSAM, HKEY * );
LONG _RegGetWinStationSecurity( HKEY, LPWSTR, PSECURITY_DESCRIPTOR, ULONG, PULONG );
/*
* other internal Procedures used (not defined here)
*/
VOID CreateWinStaCreate( HKEY, PWINSTATIONCREATE );
VOID CreateConfig( HKEY, PWINSTATIONCONFIG );
VOID CreateWd( HKEY, PWDCONFIG );
VOID CreateCd( HKEY, PCDCONFIG );
VOID CreatePdConfig( BOOLEAN, HKEY, PPDCONFIG, ULONG );
VOID QueryWinStaCreate( HKEY, PWINSTATIONCREATE );
VOID QueryConfig( HKEY, PWINSTATIONCONFIG );
VOID QueryWd( HKEY, PWDCONFIG );
VOID QueryCd( HKEY, PCDCONFIG );
VOID QueryPdConfig( HKEY, PPDCONFIG, PULONG );
VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
VOID PdConfigU2A( PPDCONFIGA, PPDCONFIGW );
VOID PdConfigA2U( PPDCONFIGW, PPDCONFIGA );
VOID WdConfigU2A( PWDCONFIGA, PWDCONFIGW );
VOID WdConfigA2U( PWDCONFIGW, PWDCONFIGA );
VOID CdConfigU2A( PCDCONFIGA, PCDCONFIGW );
VOID CdConfigA2U( PCDCONFIGW, PCDCONFIGA );
VOID WinStationCreateU2A( PWINSTATIONCREATEA, PWINSTATIONCREATEW );
VOID WinStationCreateA2U( PWINSTATIONCREATEW, PWINSTATIONCREATEA );
VOID WinStationConfigU2A( PWINSTATIONCONFIGA, PWINSTATIONCONFIGW );
VOID WinStationConfigA2U( PWINSTATIONCONFIGW, PWINSTATIONCONFIGA );
VOID SetWallPaperDisabled( HKEY, BOOLEAN );
/****************************************************************************
*
* DllEntryPoint
*
* Function is called when the DLL is loaded and unloaded.
*
* ENTRY:
* hinstDLL (input)
* Handle of DLL module
*
* fdwReason (input)
* Why function was called
*
* lpvReserved (input)
* Reserved; must be NULL
*
* EXIT:
* TRUE - Success
* FALSE - Error occurred
*
****************************************************************************/
BOOL WINAPI
DllEntryPoint( HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved )
{
switch ( fdwReason ) {
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
if( g_hTSPolicyKey )
{
RegCloseKey(g_hTSPolicyKey);
}
if( g_hTSControlKey )
{
RegCloseKey(g_hTSControlKey);
}
break;
default:
break;
}
return( TRUE );
}
/*******************************************************************************
*
* RegWinStationAccessCheck (ANSI or UNICODE)
*
* Determines if the current user has the requested access to the
* WinStation registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* samDesired (input)
* Specifies the security access mask to be used in determining access
* to the WinStation registry.
*
* EXIT:
* ERROR_SUCCESS if the user has the requested access
* other error value (most likely ERROR_ACCESS_DENIED) if the user does
* not have the requested access.
*
******************************************************************************/
LONG WINAPI
RegWinStationAccessCheck( HANDLE hServer, REGSAM samDesired )
{
LONG Status;
HKEY Handle;
/*
* Attempt to open the registry (LOCAL_MACHINE\....\Citrix\Pd)
* at the requested access level.
*/
if ( (Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0,
samDesired, &Handle )) == ERROR_SUCCESS )
RegCloseKey( Handle );
return( Status );
}
/*******************************************************************************
*
* RegWinStationEnumerateA (ANSI stub)
*
* Returns a list of configured WinStations in the registry.
*
* ENTRY:
* see RegWinStationEnumerateW
*
* EXIT:
* see RegWinStationEnumerateW, plus
*
* ERROR_NOT_ENOUGH_MEMORY - the LocalAlloc failed
*
******************************************************************************/
LONG WINAPI
RegWinStationEnumerateA( HANDLE hServer,
PULONG pIndex,
PULONG pEntries,
PWINSTATIONNAMEA pWinStationName,
PULONG pByteCount )
{
PWINSTATIONNAMEW pBuffer = NULL, pWinStationNameW;
LONG 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 ( pWinStationName && ByteCountW )
{
if ( !(pBuffer = LocalAlloc(0, ByteCountW)) )
return ( ERROR_NOT_ENOUGH_MEMORY );
}
/*
* Enumerate WinStations
*/
pWinStationNameW = pBuffer;
Status = RegWinStationEnumerateW( hServer, pIndex, pEntries, pWinStationNameW,
&ByteCountW );
/*
* 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. Note: sucessful return may have copied
* 0 items from registry (end of enumeration), denoted by *pEntries
* == 0.
*/
if ( ((Status == ERROR_SUCCESS) || (Status == ERROR_NO_MORE_ITEMS))
&& pWinStationNameW && pWinStationName ) {
for ( Count = *pEntries; Count; Count-- ) {
UnicodeToAnsi( pWinStationName, sizeof(WINSTATIONNAMEA),
pWinStationNameW );
(char*)pWinStationName += sizeof(WINSTATIONNAMEA);
(char*)pWinStationNameW += sizeof(WINSTATIONNAMEW);
}
}
/*
* If we defined a buffer, free it now, then return the status
* of the Reg...EnumerateW function call.
*/
if ( pBuffer )
LocalFree(pBuffer);
return ( Status );
}
/*******************************************************************************
*
* RegWinStationEnumerateW (UNICODE)
*
* Returns a list of configured window stations in the registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pIndex (input/output)
* Specifies the subkey index for the \Citrix\WinStations subkeys in the
* registry. Should be set to 0 for the initial call, and supplied
* again (as modified by this function) for multi-call enumeration.
* 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.
* pWinStationName (input)
* Points to the buffer to receive the enumeration results, which are
* returned as an array of WINSTATIONNAME structures. If this parameter
* is NULL, then no data will be copied, but just an enumeration count
* will be made.
* pByteCount (input/output)
* Points to a variable that specifies the size, in bytes, of the
* pWinStationName parameter. If the buffer is too small to receive even
* one entry, the function returns an error code (ERROR_OUTOFMEMORY)
* and this variable receives the required size of the buffer for a
* single subkey. When the function finishes sucessfully, the variable
* pointed to by the pByteCount parameter contains the number of bytes
* actually stored in pWinStationName.
*
* EXIT:
*
* "No Error" codes:
* ERROR_SUCCESS - The enumeration completed as requested and there
* are more WinStations subkeys (WINSTATIONNAMEs) to
* be read.
* ERROR_NO_MORE_ITEMS - The enumeration completed as requested and there
* are no more WinStations subkeys (WINSTATIONNAMEs)
* to be read.
*
* "Error" codes:
* ERROR_OUTOFMEMORY - The pWinStationName buffer is too small for even
* one entry.
* ERROR_CANTOPEN - The Citrix\WinStations key can't be opened.
*
******************************************************************************/
LONG WINAPI
RegWinStationEnumerateW( HANDLE hServer,
PULONG pIndex,
PULONG pEntries,
PWINSTATIONNAMEW pWinStationName,
PULONG pByteCount )
{
LONG Status;
HKEY Handle;
ULONG Count;
ULONG i;
/*
* Get the number of names to return
*/
Count = pWinStationName ?
min( *pByteCount / sizeof(WINSTATIONNAME), *pEntries ) :
(ULONG) -1;
*pEntries = *pByteCount = 0;
/*
* Make sure buffer is big enough for at least one name
*/
if ( Count == 0 ) {
*pByteCount = sizeof(WINSTATIONNAME);
return( ERROR_OUTOFMEMORY );
}
/*
* Open registry (LOCAL_MACHINE\....\Citrix\WinStations)
*/
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0,
KEY_ENUMERATE_SUB_KEYS, &Handle ) != ERROR_SUCCESS ) {
goto DefaultConsole;
}
/*
* Get list of window stations
*/
for ( i = 0; i < Count; i++ ) {
WINSTATIONNAME WinStationName;
if ( (Status = RegEnumKey(Handle, *pIndex, WinStationName,
sizeof(WINSTATIONNAME)/sizeof(TCHAR) )) != ERROR_SUCCESS )
break;
/*
* If caller supplied a buffer, then copy the WinStationName
* and increment the pointer and byte count. Always increment the
* entry count and index for the next iteration.
*/
if ( pWinStationName ) {
wcscpy( pWinStationName, WinStationName );
(char*)pWinStationName += sizeof(WINSTATIONNAME);
*pByteCount += sizeof(WINSTATIONNAME);
}
(*pEntries)++;
(*pIndex)++;
}
/*
* Close registry
*/
RegCloseKey( Handle );
if ( Status == ERROR_NO_MORE_ITEMS ) {
if ( (*pEntries == 0) && (*pIndex == 0) )
goto DefaultConsole;
}
return( Status );
/*
* We come here when there are no WinStations defined.
* We return a default "Console" name (if pWinStationName isn't NULL).
*/
DefaultConsole:
if ( pWinStationName )
wcscpy( pWinStationName, L"Console" );
*pEntries = 1;
*pByteCount = sizeof(WINSTATIONNAME);
return( ERROR_NO_MORE_ITEMS );
}
/*******************************************************************************
*
* RegWinStationCreateA (ANSI stub)
*
* Creates a new WinStaton in the registry or updates an existing entry.
* (See RegWinStationCreateW)
*
* ENTRY:
* see RegWinStationCreateW
*
* EXIT:
* see RegWinStationCreateW
*
******************************************************************************/
LONG WINAPI
RegWinStationCreateA( HANDLE hServer,
PWINSTATIONNAMEA pWinStationName,
BOOLEAN bCreate,
PWINSTATIONCONFIG2A pWinStationConfig,
ULONG WinStationConfigLength )
{
WINSTATIONNAMEW WinStationNameW;
WINSTATIONCONFIG2W WinStationConfig2W;
int i;
/*
* Validate target buffer size.
*/
if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2A) )
return( ERROR_INSUFFICIENT_BUFFER );
/*
* Convert ANSI WinStationName to UNICODE.
*/
AnsiToUnicode( WinStationNameW, sizeof(WINSTATIONNAMEW), pWinStationName );
/*
* Copy WINSTATIONCONFIG2A elements to WINSTATIONCONFIG2W elements.
*/
WinStationCreateA2U( &(WinStationConfig2W.Create),
&(pWinStationConfig->Create) );
for ( i=0; i<MAX_PDCONFIG; i++ ) {
PdConfigA2U( &(WinStationConfig2W.Pd[i]),
&(pWinStationConfig->Pd[i]) );
}
WdConfigA2U( &(WinStationConfig2W.Wd),
&(pWinStationConfig->Wd) );
CdConfigA2U( &(WinStationConfig2W.Cd),
&(pWinStationConfig->Cd) );
WinStationConfigA2U( &(WinStationConfig2W.Config),
&(pWinStationConfig->Config) );
/*
* Call RegWinStationCreateW & return it's status.
*/
return ( RegWinStationCreateW( hServer, WinStationNameW, bCreate,
&WinStationConfig2W,
sizeof(WinStationConfig2W)) );
}
/*******************************************************************************
*
* RegWinStationCreateW (UNICODE)
*
* Creates a new WinStaton in the registry or updates an existing entry.
* The state of the bCreate flag determines whether this function will
* expect to create a new WinStation entry (bCreate == TRUE) or expects to
* update an existing entry (bCreate == FALSE).
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a new or exisiting window station in the registry.
* bCreate (input)
* TRUE if this is a creation of a new WinStation
* FALSE if this is an update to an existing WinStation
* pWinStationConfig (input)
* Pointer to a WINSTATIONCONFIG2 structure containing configuration
* information for the specified window station name.
* WinStationConfigLength (input)
* Specifies the length in bytes of the pWinStationConfig buffer.
*
* EXIT:
* ERROR_SUCCESS - no error
*
* ERROR_INSUFFICIENT_BUFFER - pWinStationConfig buffer too small
* ERROR_FILE_NOT_FOUND - can't open ...\Citrix\WinStations key
* ERROR_CANNOT_MAKE - can't create WinStation key (registry problem)
* ERROR_ALREADY_EXISTS - create; but WinStation key already present
* ERROR_CANTOPEN - update; but WinStation key could not be opened
*
******************************************************************************/
LONG WINAPI
RegWinStationCreateW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
BOOLEAN bCreate,
PWINSTATIONCONFIG2W pWinStationConfig,
ULONG WinStationConfigLength )
{
HKEY Handle;
HKEY Handle1;
DWORD Disp;
/*
* Validate length of buffer
*/
if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) )
return( ERROR_INSUFFICIENT_BUFFER );
/*
* Open registry (LOCAL_MACHINE\....\Citrix\WinStations).
* If it doesn't exist, we attemp to create it.
*/
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0,
KEY_ALL_ACCESS, &Handle1 ) != ERROR_SUCCESS &&
RegCreateKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&Handle1, &Disp ) != ERROR_SUCCESS ) {
return( ERROR_FILE_NOT_FOUND );
}
if ( bCreate ) {
/*
* Create requested: create a registry key for the specified
* WinStation name.
*/
if ( RegCreateKeyEx( Handle1, pWinStationName, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &Handle, &Disp ) != ERROR_SUCCESS ) {
RegCloseKey( Handle1 );
return( ERROR_CANNOT_MAKE );
}
/*
* If an existing key was returned instead of a new one being
* created, return error (don't update).
*/
if ( Disp != REG_CREATED_NEW_KEY ) {
RegCloseKey( Handle1 );
RegCloseKey( Handle );
return( ERROR_ALREADY_EXISTS );
}
} else {
/*
* Update requested: open the registry key for the specified
* WinStation name.
*/
if ( RegOpenKeyEx( Handle1, pWinStationName, 0, KEY_ALL_ACCESS,
&Handle ) != ERROR_SUCCESS ) {
RegCloseKey( Handle1 );
return( ERROR_CANTOPEN );
}
}
RegCloseKey( Handle1 );
/*
* Save WINSTATIONCONFIG2 Structure
*/
CreateWinStaCreate( Handle, &pWinStationConfig->Create );
CreatePdConfig( bCreate, Handle, pWinStationConfig->Pd, MAX_PDCONFIG );
CreateWd( Handle, &pWinStationConfig->Wd );
CreateCd( Handle, &pWinStationConfig->Cd );
CreateConfig( Handle, &pWinStationConfig->Config );
/*
* Close registry handle
*/
RegCloseKey( Handle );
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegWinStationQueryA (ANSI stub)
*
* Query configuration information of a window station in the registry.
*
* ENTRY:
* see RegWinStationQueryW
*
* EXIT:
* see RegWinStationQueryW
*
******************************************************************************/
LONG WINAPI
RegWinStationQueryA( HANDLE hServer,
PWINSTATIONNAMEA pWinStationName,
PWINSTATIONCONFIG2A pWinStationConfig,
ULONG WinStationConfigLength,
PULONG pReturnLength )
{
WINSTATIONNAMEW WinStationNameW;
WINSTATIONCONFIG2W WinStationConfig2W;
LONG Status;
ULONG ReturnLengthW;
int i;
/*
* Validate length and zero-initialize the destination
* WINSTATIONCONFIG2A structure.
*/
if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2A) )
return( ERROR_INSUFFICIENT_BUFFER );
memset(pWinStationConfig, 0, WinStationConfigLength);
/*
* Convert ANSI WinStationName to UNICODE.
*/
AnsiToUnicode( WinStationNameW, sizeof(WINSTATIONNAMEW), pWinStationName );
/*
* Query WinStation.
*/
if ( (Status = RegWinStationQueryW( hServer,
WinStationNameW,
&WinStationConfig2W,
sizeof(WINSTATIONCONFIG2W),
&ReturnLengthW)) != ERROR_SUCCESS )
return ( Status );
/*
* Copy WINSTATIONCONFIG2W elements to WINSTATIONCONFIG2A elements.
*/
WinStationCreateU2A( &(pWinStationConfig->Create),
&(WinStationConfig2W.Create) );
for ( i=0; i<MAX_PDCONFIG; i++ ) {
PdConfigU2A( &(pWinStationConfig->Pd[i]),
&(WinStationConfig2W.Pd[i]) );
}
WdConfigU2A( &(pWinStationConfig->Wd),
&(WinStationConfig2W.Wd) );
CdConfigU2A( &(pWinStationConfig->Cd),
&(WinStationConfig2W.Cd) );
WinStationConfigU2A( &(pWinStationConfig->Config),
&(WinStationConfig2W.Config) );
*pReturnLength = sizeof(WINSTATIONCONFIG2A);
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
*
*
* RegWinStationQueryEx (UNICODE)
*
* USE THIS CALL if you are in TermSrv.DLL, since it will update the global policy object
*
* Same as RegWinStationQueryW with the excpetion that a pointer to a global policy object is passed in.
*
* Query configuration information of a window station in the registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pMachinePolicy (input)
* pointer to a gloabl machine policy struct
* pWinStationName (input)
* Name of an exisiting window station in the registry.
* pWinStationConfig (input)
* Pointer to a WINSTATIONCONFIG2 structure that will receive
* information about the specified window station name.
* WinStationConfigLength (input)
* Specifies the length in bytes of the pWinStationConfig buffer.
* pReturnLength (output)
* Receives the number of bytes placed in the pWinStationConfig buffer.
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationQueryEx( HANDLE hServer,
PPOLICY_TS_MACHINE pMachinePolicy,
PWINSTATIONNAMEW pWinStationName,
PWINSTATIONCONFIG2W pWinStationConfig,
ULONG WinStationConfigLength,
PULONG pReturnLength,
BOOLEAN bPerformMerger)
{
LONG Status;
HKEY Handle;
ULONG Count;
/*
* Validate length and zero-initialize the destination
* WINSTATIONCONFIG2W buffer.
*/
if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) )
return( ERROR_INSUFFICIENT_BUFFER );
memset(pWinStationConfig, 0, WinStationConfigLength);
/*
* Open registry
*/
Status = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle );
if ( Status )
Handle = 0;
/*
* Query WINSTATIONCONFIG2 Structure
*/
QueryWinStaCreate( Handle, &pWinStationConfig->Create );
Count = MAX_PDCONFIG;
QueryPdConfig( Handle, pWinStationConfig->Pd, &Count );
QueryWd( Handle, &pWinStationConfig->Wd );
QueryCd( Handle, &pWinStationConfig->Cd );
// This will populate the winstation's userconfig data with machine's version of that data.
QueryConfig( Handle, &pWinStationConfig->Config );
// Since we want to co-exist with the legacy path thru TSCC, we continue to call QueryConfig()
// as we have done above, however, we follow up with a call that get's data from the group policy
// tree, and then overrides the existing data (aquired above) by the specific data from group policy.
RegGetMachinePolicy( pMachinePolicy );
if (bPerformMerger)
RegMergeMachinePolicy( pMachinePolicy, &pWinStationConfig->Config.User , &pWinStationConfig->Create );
/*
* Close registry
*/
if ( Status == ERROR_SUCCESS )
RegCloseKey( Handle );
*pReturnLength = sizeof(WINSTATIONCONFIG2);
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegWinStationQueryW (UNICODE)
*
* Query configuration information of a window station in the registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of an exisiting window station in the registry.
* pWinStationConfig (input)
* Pointer to a WINSTATIONCONFIG2 structure that will receive
* information about the specified window station name.
* WinStationConfigLength (input)
* Specifies the length in bytes of the pWinStationConfig buffer.
* pReturnLength (output)
* Receives the number of bytes placed in the pWinStationConfig buffer.
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationQueryW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
PWINSTATIONCONFIG2W pWinStationConfig,
ULONG WinStationConfigLength,
PULONG pReturnLength )
{
LONG Status;
HKEY Handle;
ULONG Count;
POLICY_TS_MACHINE MachinePolicy;
/*
* Validate length and zero-initialize the destination
* WINSTATIONCONFIG2W buffer.
*/
if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) )
return( ERROR_INSUFFICIENT_BUFFER );
memset(pWinStationConfig, 0, WinStationConfigLength);
/*
* Open registry
*/
Status = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle );
if ( Status )
Handle = 0;
/*
* Query WINSTATIONCONFIG2 Structure
*/
QueryWinStaCreate( Handle, &pWinStationConfig->Create );
Count = MAX_PDCONFIG;
QueryPdConfig( Handle, pWinStationConfig->Pd, &Count );
QueryWd( Handle, &pWinStationConfig->Wd );
QueryCd( Handle, &pWinStationConfig->Cd );
// This will populate the winstation's userconfig data with machine's version of that data.
QueryConfig( Handle, &pWinStationConfig->Config );
// Since we want to co-exist with the legacy path thru TSCC, we continue to call QueryConfig()
// as we have done above, however, we follow up with a call that get's data from the group policy
// tree, and then overrides the existing data (aquired above) by the specific data from group policy.
RegGetMachinePolicy( & MachinePolicy );
RegMergeMachinePolicy( & MachinePolicy, &pWinStationConfig->Config.User , &pWinStationConfig->Create );
/*
* Close registry
*/
if ( Status == ERROR_SUCCESS )
RegCloseKey( Handle );
*pReturnLength = sizeof(WINSTATIONCONFIG2);
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegConsoleShadowQueryA (ANSI stub)
*
* Query configuration information for the console shadow in the registry.
*
* ENTRY:
* see RegConsoleShadowQueryW
*
* EXIT:
* see RegConsoleShadowQueryW
*
******************************************************************************/
LONG WINAPI
RegConsoleShadowQueryA( HANDLE hServer,
PWINSTATIONNAMEA pWinStationName,
PWDPREFIXA pWdPrefixName,
PWINSTATIONCONFIG2A pWinStationConfig,
ULONG WinStationConfigLength,
PULONG pReturnLength )
{
WINSTATIONNAMEW WinStationNameW;
WDPREFIXW WdPrefixNameW;
WINSTATIONCONFIG2W WinStationConfig2W;
LONG Status;
ULONG ReturnLengthW;
int i;
/*
* Validate length and zero-initialize the destination
* WINSTATIONCONFIG2A structure.
*/
if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2A) )
return( ERROR_INSUFFICIENT_BUFFER );
/*
* Convert ANSI WinStationName and prefix name to UNICODE.
*/
AnsiToUnicode( WinStationNameW, sizeof(WINSTATIONNAMEW), pWinStationName );
AnsiToUnicode( WdPrefixNameW, sizeof(WDPREFIXW), pWdPrefixName );
/*
* Query WinStation.
*/
if ( (Status = RegConsoleShadowQueryW( hServer,
WinStationNameW,
WdPrefixNameW,
&WinStationConfig2W,
sizeof(WINSTATIONCONFIG2W),
&ReturnLengthW)) != ERROR_SUCCESS )
return ( Status );
/*
* Copy WINSTATIONCONFIG2W elements to WINSTATIONCONFIG2A elements.
*/
for ( i=0; i<MAX_PDCONFIG; i++ ) {
PdConfigU2A( &(pWinStationConfig->Pd[i]),
&(WinStationConfig2W.Pd[i]) );
}
WdConfigU2A( &(pWinStationConfig->Wd),
&(WinStationConfig2W.Wd) );
CdConfigU2A( &(pWinStationConfig->Cd),
&(WinStationConfig2W.Cd) );
*pReturnLength = sizeof(WINSTATIONCONFIG2A);
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegConsoleShadowQueryW (UNICODE)
*
* Query configuration information for the console shadow in the registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of an exisiting window station in the registry.
* pWdPrefixName (input)
* Name of the Wd prefix used to point to the sub-winstation key.
* pWinStationConfig (input)
* Pointer to a WINSTATIONCONFIG2 structure that will receive
* information about the specified window station name.
* WinStationConfigLength (input)
* Specifies the length in bytes of the pWinStationConfig buffer.
* pReturnLength (output)
* Receives the number of bytes placed in the pWinStationConfig buffer.
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegConsoleShadowQueryW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
PWDPREFIXW pWdPrefixName,
PWINSTATIONCONFIG2W pWinStationConfig,
ULONG WinStationConfigLength,
PULONG pReturnLength )
{
LONG Status;
LONG lLength;
HKEY Handle;
ULONG Count;
WCHAR szRegName[ WINSTATIONNAME_LENGTH + WDPREFIX_LENGTH + 2 ];
/*
* Validate length and zero-initialize the destination
* WINSTATIONCONFIG2W buffer.
*/
if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) )
return( ERROR_INSUFFICIENT_BUFFER );
/*
* Open registry
*/
wcsncpy( szRegName, pWinStationName, sizeof(szRegName)/sizeof(WCHAR) - 1 );
szRegName[sizeof(szRegName)/sizeof(WCHAR) - 1] = 0; // terminate the string even if pWinStationName is longer than the buffer
lLength = wcslen( szRegName );
if ( sizeof(szRegName)/sizeof(WCHAR) > ( lLength + 1 + wcslen( pWdPrefixName ) ) ) {
wcsncat( szRegName, L"\\", sizeof(szRegName)/sizeof(WCHAR) - lLength - 1 );
wcsncat( szRegName, pWdPrefixName, sizeof(szRegName)/sizeof(WCHAR) - lLength - 2 );
} else {
return ERROR_INVALID_PARAMETER;
}
Status = _RegOpenWinStation( szRegName, KEY_READ, &Handle );
if ( Status )
Handle = 0;
/*
* Query WINSTATIONCONFIG2 Structure
*/
Count = MAX_PDCONFIG;
QueryPdConfig( Handle, pWinStationConfig->Pd, &Count );
QueryWd( Handle, &pWinStationConfig->Wd );
QueryCd( Handle, &pWinStationConfig->Cd );
/*
* Close registry
*/
if ( Status == ERROR_SUCCESS )
RegCloseKey( Handle );
*pReturnLength = sizeof(WINSTATIONCONFIG2);
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegWinStationDeleteA (ANSI stub)
*
* Deletes a window station from the registry.
*
* ENTRY:
* see RegWinStationDeleteW
*
* EXIT:
* see RegWinStationDeleteW
*
******************************************************************************/
LONG WINAPI
RegWinStationDeleteA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName )
{
WINSTATIONNAMEW WinStationNameW;
AnsiToUnicode( WinStationNameW, sizeof(WinStationNameW), pWinStationName );
return ( RegWinStationDeleteW ( hServer, WinStationNameW ) );
}
/*******************************************************************************
*
* RegWinStationDeleteW (UNICODE)
*
* Deletes a window station from the registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a window station to delete from the registry.
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationDeleteW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName )
{
LONG Status;
HKEY Handle1, Handle2;
/*
* Open registry (LOCAL_MACHINE\....\Citrix\WinStations).
*/
if ( (Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
WINSTATION_REG_NAME, 0,
KEY_ALL_ACCESS, &Handle1 )
!= ERROR_SUCCESS) ) {
return( Status );
}
/*
* Open the registry key for the specified WinStation name.
*/
if ( (Status = RegOpenKeyEx( Handle1, pWinStationName, 0,
KEY_ALL_ACCESS, &Handle2 )
!= ERROR_SUCCESS) ) {
RegCloseKey( Handle1 );
return( Status );
}
SetWallPaperDisabled( Handle2, FALSE );
/*
* Close the WinStation key handle just opened (so we can delete key),
* delete the key, and close the Citrix registry handle.
*/
RegCloseKey( Handle2 );
Status = RegDeleteKey( Handle1, pWinStationName );
RegCloseKey( Handle1 );
return( Status );
}
/*******************************************************************************
*
* RegWinStationSetSecurityA (ANSI stub)
*
* Sets security info for the specified WinStation.
*
* ENTRY:
* see RegWinStationSetSecurityW
*
* EXIT:
* see RegWinStationSetSecurityW
*
******************************************************************************/
LONG WINAPI
RegWinStationSetSecurityA( HANDLE hServer,
PWINSTATIONNAMEA pWinStationName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length )
{
WINSTATIONNAMEW WinStationNameW;
AnsiToUnicode( WinStationNameW, sizeof(WinStationNameW), pWinStationName );
return ( RegWinStationSetSecurityW( hServer, WinStationNameW,
SecurityDescriptor,
Length ) );
}
/*******************************************************************************
*
* RegWinStationSetSecurityW (UNICODE)
*
* Sets security info for the specified WinStation.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a window station to set security for.
* pSecurityDescriptor (input)
* Pointer to Security Descriptor to save
* Length (input)
* Length of SecurityDescriptor above
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationSetSecurityW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length )
{
HKEY Handle;
ULONG SrLength;
PSECURITY_DESCRIPTOR SrSecurityDescriptor;
LONG Error;
NTSTATUS Status;
/*
* Open registry
*/
if ( Error = _RegOpenWinStation( pWinStationName, KEY_ALL_ACCESS, &Handle ) )
return( Error );
/*
* Determine buffer length needed to convert SD to self-relative format.
*/
SrLength = 0;
Status = RtlMakeSelfRelativeSD( SecurityDescriptor, NULL, &SrLength );
if ( Status != STATUS_BUFFER_TOO_SMALL ) {
RegCloseKey( Handle );
return( RtlNtStatusToDosError( Status ) );
}
/*
* Allocate buffer for self-relative SD.
*/
SrSecurityDescriptor = LocalAlloc( 0, SrLength );
if ( SrSecurityDescriptor == NULL ) {
RegCloseKey( Handle );
return( ERROR_NOT_ENOUGH_MEMORY );
}
/*
* Now convert SD to self-relative format.
*/
Status = RtlMakeSelfRelativeSD( SecurityDescriptor,
SrSecurityDescriptor, &SrLength );
if ( !NT_SUCCESS( Status ) ) {
LocalFree( SrSecurityDescriptor );
RegCloseKey( Handle );
return( RtlNtStatusToDosError( Status ) );
}
/*
* Save the security data
*/
Error = RegSetValueEx( Handle, L"Security", 0, REG_BINARY,
(BYTE *)SrSecurityDescriptor, SrLength );
/*
* Free memory used for Self-relative Security Descriptor
*/
LocalFree( SrSecurityDescriptor );
/*
* Close registry
*/
RegCloseKey( Handle );
return( Error );
}
/*******************************************************************************
*
* RegWinStationQuerySecurityA (ANSI stub)
*
* Query security info for the specified WinStation.
*
* ENTRY:
* see RegWinStationQuerySecurityW
*
* EXIT:
* see RegWinStationQuerySecurityW
*
******************************************************************************/
LONG WINAPI
RegWinStationQuerySecurityA( HANDLE hServer,
PWINSTATIONNAMEA pWinStationName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length,
PULONG ReturnLength )
{
WINSTATIONNAMEW WinStationNameW;
AnsiToUnicode( WinStationNameW, sizeof(WinStationNameW), pWinStationName );
return ( RegWinStationQuerySecurityW( hServer, WinStationNameW,
SecurityDescriptor,
Length,
ReturnLength ) );
}
/*******************************************************************************
*
* RegWinStationQuerySecurityW (UNICODE)
*
* Query security info for the specified WinStation.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a window station to query security for.
* pSecurityDescriptor (output)
* Pointer to location to return SecurityDescriptor.
* Length (input)
* Length of SecurityDescriptor buffer.
* ReturnLength (output)
* Pointer to location to return length of SecurityDescriptor returned.
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationQuerySecurityW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length,
PULONG ReturnLength )
{
HKEY Handle;
LONG Error;
/*
* Open registry
*/
if ( Error = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ) )
return( Error );
/*
* Call RegGetWinStationSecurity() to do all the work
*/
Error = _RegGetWinStationSecurity( Handle, L"Security",
SecurityDescriptor, Length, ReturnLength );
RegCloseKey( Handle );
return( Error );
}
/*******************************************************************************
*
* RegWinStationQueryDefaultSecurity
*
* Query default WinStation security.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pSecurityDescriptor (output)
* Pointer to location to return SecurityDescriptor.
* Length (input)
* Length of SecurityDescriptor buffer.
* ReturnLength (output)
* Pointer to location to return length of SecurityDescriptor returned.
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationQueryDefaultSecurity( HANDLE hServer,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length,
PULONG ReturnLength )
{
HKEY Handle;
LONG Error;
/*
* Open registry
*/
if ( Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0,
KEY_READ, &Handle ) )
return( Error );
/*
* Call RegGetWinStationSecurity() to do all the work
*/
Error = _RegGetWinStationSecurity( Handle, L"DefaultSecurity",
SecurityDescriptor, Length, ReturnLength );
RegCloseKey( Handle );
return( Error );
}
/*******************************************************************************
*
* RegWinStationSetNumValueW (UNICODE)
*
* Set numeric value in WinStation registry configuration
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a window station to modify from the registry.
* pValueName (input)
* name of registry value to set
* ValueData (input)
* data (DWORD) for registry value to set
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationSetNumValueW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
LPWSTR pValueName,
ULONG ValueData )
{
HKEY Handle;
LONG Error;
/*
* Open registry
*/
if ( Error = _RegOpenWinStation( pWinStationName, KEY_ALL_ACCESS, &Handle ) )
return( Error );
/*
* Set the numeric value
*/
Error = RegSetValueEx( Handle, pValueName, 0, REG_DWORD,
(BYTE *)&ValueData, sizeof(DWORD) );
/*
* Close registry
*/
RegCloseKey( Handle );
return( Error );
}
/*******************************************************************************
*
* RegWinStationQueryNumValueW (UNICODE)
*
* Query numeric value from WinStation registry configuration
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a window station to modify from the registry.
* pValueName (input)
* name of registry value to set
* pValueData (output)
* address to return data (DWORD) value from registry
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationQueryNumValueW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
LPWSTR pValueName,
PULONG pValueData )
{
DWORD ValueSize = sizeof(DWORD);
DWORD ValueType;
HKEY Handle;
LONG Error;
/*
* Open registry
*/
if ( Error = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ) )
return( Error );
/*
* Query the numeric value
*/
Error = RegQueryValueEx( Handle, pValueName, NULL, &ValueType,
(LPBYTE) pValueData, &ValueSize );
/*
* Close registry
*/
RegCloseKey( Handle );
return( Error );
}
/*******************************************************************************
*
* RegWinStationQueryValueW (UNICODE)
*
* Query value from WinStation registry configuration
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a window station to modify from the registry.
* pValueName (input)
* name of registry value to set
* pValueData (output)
* address to return data (DWORD) value from registry
* ValueSize (input)
* size of value buffer
* pValueSize (input)
* actual value size
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG WINAPI
RegWinStationQueryValueW( HANDLE hServer,
PWINSTATIONNAMEW pWinStationName,
LPWSTR pValueName,
PVOID pValueData,
ULONG ValueSize,
PULONG pValueSize )
{
DWORD ValueType;
HKEY Handle;
LONG Error;
*pValueSize = ValueSize;
/*
* Open registry
*/
if ( Error = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ) )
return( Error );
/*
* Query the numeric value
*/
Error = RegQueryValueEx( Handle, pValueName, NULL, &ValueType,
(LPBYTE) pValueData, pValueSize );
/*
* Close registry
*/
RegCloseKey( Handle );
return( Error );
}
/*******************************************************************************
*
* -- private routine --
*
* _RegOpenWinStation
*
* open registry of specified winstation
*
* NOTE: handle must be closed with "RegCloseKey"
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWinStationName (input)
* Name of a window station to modify from the registry.
* samDesired (input)
* REGSAM access level for registry open.
* pHandle (output)
* address to return handle
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG
_RegOpenWinStation( PWINSTATIONNAMEW pWinStationName,
REGSAM samDesired,
HKEY * pHandle )
{
HKEY Handle1;
LONG Error;
/*
* Open registry (LOCAL_MACHINE\....\Citrix\WinStations).
*/
if ( (Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0,
samDesired, &Handle1 ) != ERROR_SUCCESS) ) {
return( Error );
}
/*
* Open the registry key for the specified WinStation name.
*/
Error = RegOpenKeyEx( Handle1, pWinStationName, 0, samDesired, pHandle);
RegCloseKey( Handle1 );
return( Error );
}
/*******************************************************************************
*
* -- private routine --
*
* _RegGetWinStationSecurity
*
* Query the security descriptor from the specified registry key.
*
* ENTRY:
* Handle (input)
* Open registry key handle.
* ValueName (input)
* Name of security value.
* pSecurityDescriptor (output)
* Pointer to location to return SecurityDescriptor.
* Length (input)
* Length of SecurityDescriptor buffer.
* ReturnLength (output)
* Pointer to location to return length of SecurityDescriptor returned.
*
* EXIT:
* ERROR_SUCCESS - no error
* otherwise: the error code
*
******************************************************************************/
LONG
_RegGetWinStationSecurity( HKEY Handle,
LPWSTR ValueName,
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length,
PULONG ReturnLength )
{
DWORD ValueType;
DWORD SrLength;
ULONG SdSize, DaclSize, SaclSize, OwnerSize, GroupSize;
PSECURITY_DESCRIPTOR SrSecurityDescriptor;
PACL pDacl, pSacl;
PSID pOwner, pGroup;
LONG Error;
NTSTATUS Status;
/*
* Query the length of the Security value
*/
SrLength = 0;
if ( Error = RegQueryValueEx( Handle, ValueName, NULL, &ValueType,
NULL, &SrLength ) ) {
return( Error );
}
/*
* Return error if not correct data type
*/
if ( ValueType != REG_BINARY ) {
return( ERROR_FILE_NOT_FOUND );
}
/*
* Allocate a buffer to read the Security info and read it
*/
SrSecurityDescriptor = LocalAlloc( 0, SrLength );
if ( SrSecurityDescriptor == NULL ) {
return( ERROR_NOT_ENOUGH_MEMORY );
}
if ( Error = RegQueryValueEx( Handle, ValueName, NULL, &ValueType,
SrSecurityDescriptor, &SrLength ) ) {
LocalFree( SrSecurityDescriptor );
return( Error );
}
/*
* Determine amount of space required to convert SD from
* self-relative format to absolute format.
*/
SdSize = DaclSize = SaclSize = OwnerSize = GroupSize = 0;
Status = RtlSelfRelativeToAbsoluteSD( SrSecurityDescriptor,
NULL, &SdSize,
NULL, &DaclSize,
NULL, &SaclSize,
NULL, &OwnerSize,
NULL, &GroupSize );
if ( Status != STATUS_BUFFER_TOO_SMALL ) {
LocalFree( SrSecurityDescriptor );
return( RtlNtStatusToDosError( Status ) );
}
*ReturnLength = SdSize + DaclSize + SaclSize + OwnerSize + GroupSize;
/*
* If required size is greater than callers buffer size, then return
*/
if ( *ReturnLength > Length ) {
LocalFree( SrSecurityDescriptor );
return( ERROR_INSUFFICIENT_BUFFER );
}
pDacl = (PACL)((PCHAR)SecurityDescriptor + SdSize);
pSacl = (PACL)((PCHAR)pDacl + DaclSize);
pOwner = (PSID)((PCHAR)pSacl + SaclSize);
pGroup = (PSID)((PCHAR)pOwner + OwnerSize);
/*
* Now convert self-relative SD to absolute format.
*/
Status = RtlSelfRelativeToAbsoluteSD( SrSecurityDescriptor,
SecurityDescriptor, &SdSize,
pDacl, &DaclSize,
pSacl, &SaclSize,
pOwner, &OwnerSize,
pGroup, &GroupSize );
if ( !NT_SUCCESS( Status ) )
Error = RtlNtStatusToDosError( Status );
/*
* Free memory used for Self-relative Security Descriptor
*/
LocalFree( SrSecurityDescriptor );
return( Error );
}