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.
 
 
 
 
 
 

1621 lines
45 KiB

//+-------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft
//
// File: securd.cpp
//
// History: 30-March-2000 a-skuzin Created
//
//--------------------------------------------------------------------------
#include "stdafx.h"
#include <winsta.h>
#include <regapi.h>
#include "secupgrd.h"
#include "state.h"
// from winnt.h
#define MAXDWORD 0xffffffff
//Global variables
BYTE g_DefaultSD[] = { 0x01,0x00,0x14,0x80,0x88,0x00,0x00,0x00,0x94,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
0x02,0x00,0x74,0x00,0x05,0x00,0x00,0x00,0x00,0x00,
0x18,0x00,0xBF,0x03,0x0F,0x00,0x01,0x02,0x00,0x00,
0x00,0x00,0x00,0x05,0x20,0x00,0x00,0x00,0x20,0x02,
0x00,0x00,0x00,0x00,0x14,0x00,0xBF,0x03,0x0F,0x00,
0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x12,0x00,
0x00,0x00,0x00,0x00,0x18,0x00,0x21,0x01,0x00,0x00,
0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x00,
0x00,0x00,0x2B,0x02,0x00,0x00,0x00,0x00,0x14,0x00,
0x81,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,
0x00,0x05,0x13,0x00,0x00,0x00,0x00,0x00,0x14,0x00,
0x81,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,
0x00,0x05,0x14,0x00,0x00,0x00,0x01,0x01,0x00,0x00,
0x00,0x00,0x00,0x05,0x12,0x00,0x00,0x00,0x01,0x01,
0x00,0x00,0x00,0x00,0x00,0x05,0x12,0x00,0x00,0x00 };
BYTE g_ConsoleSD[] = { 0x01,0x00,0x14,0x80,0x70,0x00,0x00,0x00,0x7C,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
0x02,0x00,0x5C,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
0x18,0x00,0xBF,0x03,0x0F,0x00,0x01,0x02,0x00,0x00,
0x00,0x00,0x00,0x05,0x20,0x00,0x00,0x00,0x20,0x02,
0x00,0x00,0x00,0x00,0x14,0x00,0x81,0x00,0x00,0x00,
0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x13,0x00,
0x00,0x00,0x00,0x00,0x14,0x00,0x81,0x00,0x00,0x00,
0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x00,
0x00,0x00,0x00,0x00,0x14,0x00,0xBF,0x03,0x0F,0x00,
0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x12,0x00,
0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,
0x12,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,
0x00,0x05,0x12,0x00,0x00,0x00 };
DWORD AreThereAnyCustomSecurityDescriptors( BOOL &any )
{
HKEY hKey;
DWORD err;
err=RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REG_WINSTATION_KEY,
0,
KEY_READ,
&hKey
);
if( err!=ERROR_SUCCESS )
{
LOGMESSAGE1(_T("Could not open TS key %d"),err);
return err;
}
CDefaultSD DefaultSD;
CDefaultSD ConsoleSD;
//Load default SD from the registry, since we need to compare to this
err = DefaultSD.Init(hKey,DefaultRDPSD);
if( err!=ERROR_SUCCESS )
{
RegCloseKey(hKey);
return err;
}
//Load default console SD from the registry, since we need to compare to this
err = ConsoleSD.Init(hKey,DefaultConsoleSD);
if( err!=ERROR_SUCCESS )
{
RegCloseKey(hKey);
return err;
}
CNameAndSDList NameSDList;
DWORD dwTotalWinStations = 0;
DWORD dwDefaultWinStations = 0;
err=EnumWinStationSecurityDescriptors( hKey, &NameSDList);
if(err == ERROR_SUCCESS)
{
dwTotalWinStations = NameSDList.size();
if(dwTotalWinStations)
{
CNameAndSDList::iterator it;
for(it=NameSDList.begin();it!=NameSDList.end(); it++)
{
if((*it).IsDefaultOrEmpty(&DefaultSD,&ConsoleSD))
{
dwDefaultWinStations++;
}
}
//If all descriptors are default
if(dwDefaultWinStations == dwTotalWinStations)
{
any = FALSE;
}
else
{
any = TRUE;
}
}
}
RegCloseKey(hKey);
return err;
}
/*****************************************************************************
*
* SetupWorker
*
* ENTRY:
* IN const TSState &State
*
*
* NOTES:
*
* EXIT:
* Returns: 0 if success, error code if failure
*
****************************************************************************/
DWORD
SetupWorker(
IN const TSState &State )
{
DWORD Result;
const BOOL bStandAlone = State.IsStandAlone();
const BOOL bClean = State.IsTSFreshInstall();
const BOOL bAppServer = State.IsItAppServer();
const BOOL bServer = State.IsServer();
LOGMESSAGE4(_T("SetupWorker( %d, %d, %d, %d )"), bClean, bStandAlone, bServer, bAppServer );
if (!bStandAlone) // we are in GUI-setup mode
{
// clean install of OS or OS upgrade
Result = SetupWorkerNotStandAlone( bClean, bServer,bAppServer );
}
else
{
// we are being called from Add/Remove Programs, which means, we are
// switching modes
BOOL anyCustomSDs;
Result = AreThereAnyCustomSecurityDescriptors( anyCustomSDs ) ;
LOGMESSAGE1(_T("AreThereAnyCustomSecurityDescriptors = %d"), anyCustomSDs );
if ( Result == ERROR_SUCCESS )
{
if (!anyCustomSDs )
{
// make sure we don't have a left-over privilage on the EveryoneSID
Result = GrantRemotePrivilegeToEveryone( FALSE );
}
if (!bAppServer)
{
// we are switching to Remote-Admin mode, secure machine by
// removing the content of the RDU-Group
Result = RemoveAllFromRDUsersGroup();
}
}
else
{
LOGMESSAGE1(_T("AreThereAnyCustomSecurityDescriptors() returned : %d"),Result );
}
}
return Result;
}
/*****************************************************************************
*
* SetupWorkerNoStandAlone
* This will be called when machine is being upgraded or fresh OS is being installed.
* It is NOT called if switching modes (AS <->RA )
*
* ENTRY:
* none
*
*
* NOTES:
* IN BOOL bClean
* IN BOOL bServer
* IN BOOL bAppServer
*
* EXIT:
* Returns: 0 if success, error code if failure
*
****************************************************************************/
DWORD SetupWorkerNotStandAlone(
IN BOOL bClean,
IN BOOL bServer,
IN BOOL bAppServer)
{
HKEY hKey;
DWORD err;
err=RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REG_WINSTATION_KEY,
0,
KEY_READ|KEY_WRITE,
&hKey
);
if( err!=ERROR_SUCCESS )
{
LOGMESSAGE1(_T("Could not open TS key %d"),err);
return err;
}
if(!bClean)
{
err = GrantRemoteUsersAccessToWinstations(hKey,bServer,bAppServer);
LOGMESSAGE1(_T("GrantRemoteUsersAccessToWinstations() returned : %d"),err);
if(err != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return err;
}
}
err = SetNewDefaultSecurity(hKey);
LOGMESSAGE1(_T("SetNewDefaultSecurity() returned : %d"),err);
err = SetNewConsoleSecurity(hKey,bServer);
LOGMESSAGE1(_T("SetNewConsoleSecurity() returned : %d"),err);
RegCloseKey(hKey);
return err;
}
/*****************************************************************************
*
* GrantRemoteUsersAccessToWinstations
*
* if all winstations have default SD - copies all members from "Users" to
* "Remote Desktop Users", then deletes all winstation's security descriptors;
* otherwise grants "Everyone" with "SeRemoteInteractiveLogonRight" privilege
* and then adds "Remote Desktop Users" to each winstation's security descriptor
*
* ENTRY:
* IN HKEY hKey - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN BOOL bAppServer
*
* NOTES:
*
*
* EXIT:
* Returns: 0 if success, error code if failure
*
****************************************************************************/
DWORD
GrantRemoteUsersAccessToWinstations(
IN HKEY hKey,
IN BOOL bServer,
IN BOOL bAppServer)
{
DWORD err;
CDefaultSD DefaultSD;
CDefaultSD ConsoleSD;
//Load default SD from the registry
err = DefaultSD.Init(hKey,DefaultRDPSD);
if( err!=ERROR_SUCCESS )
{
//Default SD may not be present if TS was
//never enabled.
if(err == ERROR_FILE_NOT_FOUND)
{
err = ERROR_SUCCESS;
}
return err;
}
//Load default console SD from the registry
err = ConsoleSD.Init(hKey,DefaultConsoleSD);
if( err!=ERROR_SUCCESS )
{
return err;
}
BOOL bDefaultSDHasRemoteUsers;
err = DefaultSD.DoesDefaultSDHaveRemoteUsers(&bDefaultSDHasRemoteUsers);
if( err!=ERROR_SUCCESS )
{
return err;
}
else
{
//in this case assume that system already has been upgraded before.
if(bDefaultSDHasRemoteUsers)
{
return ERROR_SUCCESS;
}
}
CNameAndSDList NameSDList;
DWORD dwTotalWinStations = 0;
DWORD dwDefaultWinStations = 0;
err=EnumWinStationSecurityDescriptors( hKey, &NameSDList);
if(err == ERROR_SUCCESS)
{
dwTotalWinStations = NameSDList.size();
if(dwTotalWinStations)
{
CNameAndSDList::iterator it;
for(it=NameSDList.begin();it!=NameSDList.end(); it++)
{
if((*it).IsDefaultOrEmpty(&DefaultSD,&ConsoleSD))
{
dwDefaultWinStations++;
}
}
//If all descriptors are default
if(dwDefaultWinStations == dwTotalWinStations)
{
//remove all ald default SDs (because we will have
//different default SD
for(it=NameSDList.begin();it!=NameSDList.end(); it++)
{
if((*it).m_pSD)
{
//in case of error, continue with other winstations
//but return first error.
if(!err)
{
err = RemoveWinstationSecurity( hKey, (*it).m_pName );
}
else
{
RemoveWinstationSecurity( hKey, (*it).m_pName );
}
}
}
}
else
{
//Grant "SeRemoteInteractiveLogonRight" privilege to "Everyone"
err = GrantRemotePrivilegeToEveryone( TRUE );
//Add "Remote Desktop Users" group to WinStation's DS.
//Add also "LocalService" and "NetworkService".
//NOTE: (*it).m_pSD is being changed during each call
//to AddLocalAndNetworkServiceToWinstationSD or
//AddRemoteUsersToWinstationSD
for(it=NameSDList.begin();it!=NameSDList.end(); it++)
{
//On server - skip console
if(bServer && (*it).IsConsole())
{
//if SD is not NULL add "LocalService" and "NetworkService" to it
if((*it).m_pSD)
{
if(!err)
{
err = AddLocalAndNetworkServiceToWinstationSD( hKey, &(*it) );
}
else
{
AddLocalAndNetworkServiceToWinstationSD( hKey, &(*it) );
}
}
continue;
}
//if SD is not NULL add RDU to it
if((*it).m_pSD)
{
//in case of error, continue with other winstations
//but return first error.
if(!err)
{
err = AddRemoteUsersToWinstationSD( hKey, &(*it) );
}
else
{
AddRemoteUsersToWinstationSD( hKey, &(*it) );
}
//add "LocalService" and "NetworkService" to SD
if(!err)
{
err = AddLocalAndNetworkServiceToWinstationSD( hKey, &(*it) );
}
else
{
AddLocalAndNetworkServiceToWinstationSD( hKey, &(*it) );
}
}
}
}
}
}
return err;
}
/*****************************************************************************
*
* AddRemoteUserToWinstationSD
*
* Grants "user access" permissions to a winstation to "REMOTE DESKTOP USERS"
*
* ENTRY:
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN CNameAndSD *pNameSD - name and security descriptor of a winstation
*
*
* NOTES:
*
*
* EXIT:
* Returns: 0 if success, error code if failure
*
*
*
****************************************************************************/
DWORD
AddRemoteUsersToWinstationSD(
IN HKEY hKeyParent,
IN CNameAndSD *pNameSD)
{
//
DWORD err = ERROR_SUCCESS;
PACL pDacl = NULL;
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
PSID pRUSid=NULL;
if( !AllocateAndInitializeSid( &sia, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS,
0, 0, 0, 0, 0, 0,&pRUSid ) )
{
return GetLastError();
}
//get dacl
err = GetDacl(pNameSD->m_pSD, &pDacl );
if( err == ERROR_SUCCESS ) {
if(!pDacl)
{
//It shuold never be in our case
//so we return error here
FreeSid(pRUSid);
return ERROR_INVALID_PARAMETER;
}
//let's add it
err = AddUserToDacl( hKeyParent, pDacl, pRUSid, WINSTATION_USER_ACCESS, pNameSD );
}
FreeSid(pRUSid);
return err;
}
/*****************************************************************************
*
* AddLocalAndNetworkServiceToWinstationSD
*
* Grants WINSTATION_QUERY | WINSTATION_MSG permissions to
* a winstation to LocalService and NetworkService accounts
*
* ENTRY:
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN CNameAndSD *pNameSD - name and security descriptor of a winstation
*
*
* NOTES:
*
*
* EXIT:
* Returns: 0 if success, error code if failure
*
*
*
****************************************************************************/
DWORD
AddLocalAndNetworkServiceToWinstationSD(
IN HKEY hKeyParent,
IN CNameAndSD *pNameSD)
{
//
DWORD err = ERROR_SUCCESS;
PACL pDacl = NULL;
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
PSID pLSSid=NULL;
PSID pNSSid=NULL;
if( !AllocateAndInitializeSid( &sia, 1,
SECURITY_LOCAL_SERVICE_RID,
0, 0, 0, 0, 0, 0, 0,&pLSSid ) )
{
return GetLastError();
}
if( !AllocateAndInitializeSid( &sia, 1,
SECURITY_NETWORK_SERVICE_RID,
0, 0, 0, 0, 0, 0, 0,&pNSSid ) )
{
FreeSid(pLSSid);
return GetLastError();
}
//get dacl
err = GetDacl(pNameSD->m_pSD, &pDacl );
if( err == ERROR_SUCCESS ) {
if(!pDacl)
{
//It shuold never be in our case
//so we return error here
FreeSid(pLSSid);
FreeSid(pNSSid);
return ERROR_INVALID_PARAMETER;
}
//let's add it
err = AddUserToDacl( hKeyParent, pDacl, pLSSid,
WINSTATION_QUERY | WINSTATION_MSG, pNameSD );
if(err == ERROR_SUCCESS)
{
//SD has been changed. It makes pDacl invalid.
//So we need to get it again
err = GetDacl(pNameSD->m_pSD, &pDacl );
ASSERT(pDacl);
if(err == ERROR_SUCCESS)
{
err = AddUserToDacl( hKeyParent, pDacl, pNSSid,
WINSTATION_QUERY | WINSTATION_MSG, pNameSD );
}
}
}
FreeSid(pLSSid);
FreeSid(pNSSid);
return err;
}
/*****************************************************************************
*
* AddUserToDacl
*
* Grants
* WINSTATION_USER_ACCESS
* permissions to a winstation to user, defined by SID
*
* ENTRY:
*
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN PACL pOldACL: pointer to prewvious DACL of the key
* IN PSID pSid: pointer to SID of user to grant permissions to
* IN DWORD dwAccessMask: access flags for this SID
* IN CNameAndSD *pNameSD - name and security descriptor of a winstation
* NOTES:
*
* EXIT:
* Returns: error code if cannot grant permissions; ERROR_SUCCESS otherwise.
*
****************************************************************************/
DWORD
AddUserToDacl(
IN HKEY hKeyParent,
IN PACL pOldACL,
IN PSID pSid,
IN DWORD dwAccessMask,
IN CNameAndSD *pNameSD)
{
//See if this user is already in the DACL.
//In this case don't add the user
//search ACL for "REMOTE USERS" SID
ACL_SIZE_INFORMATION asiAclSize;
DWORD dwBufLength=sizeof(asiAclSize);
ACCESS_ALLOWED_ACE *paaAllowedAce;
DWORD dwAcl_i;
ASSERT(pOldACL);
if (GetAclInformation(pOldACL,
(LPVOID)&asiAclSize,
(DWORD)dwBufLength,
(ACL_INFORMATION_CLASS)AclSizeInformation))
{
for (dwAcl_i = 0; dwAcl_i < asiAclSize.AceCount; dwAcl_i++)
{
if(GetAce( pOldACL, dwAcl_i, (LPVOID *)&paaAllowedAce))
{
if(EqualSid((PSID)&(paaAllowedAce->SidStart),pSid))
{
//some permission already exist, we don't need to
//do anything (even if it is a different permission!)
return ERROR_SUCCESS;
}
}
}
}
DWORD err=ERROR_SUCCESS;
PACL pNewACL;
ACCESS_ALLOWED_ACE *pNewACE;
//calculate space needed for 1 additional ACE
WORD wSidSize=(WORD)GetLengthSid( pSid);
WORD wAceSize=(sizeof(ACCESS_ALLOWED_ACE)+wSidSize-sizeof( DWORD ));
pNewACL=(PACL)LocalAlloc(LPTR,pOldACL->AclSize+wAceSize);
if(!pNewACL)
{
return GetLastError();
}
//copy old ACL to new ACL
memcpy(pNewACL,pOldACL,pOldACL->AclSize);
//correct size
pNewACL->AclSize+=wAceSize;
//prepare new ACE
//----------------------------------------------------------
pNewACE=(ACCESS_ALLOWED_ACE*)LocalAlloc(LPTR,wAceSize);
if(!pNewACE)
{
LocalFree(pNewACL);
return GetLastError();
}
pNewACE->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pNewACE->Header.AceFlags = 0;
pNewACE->Header.AceSize = wAceSize;
pNewACE->Mask = dwAccessMask;
CopySid( wSidSize, (PSID) &(pNewACE->SidStart), pSid);
//append new ACE to the ACL
if(!AddAce(pNewACL,pNewACL->AclRevision,MAXDWORD,pNewACE,wAceSize))
{
err=GetLastError();
}
else
{
//create new security descriptor
SECURITY_DESCRIPTOR NewAbsSD;
if(InitializeSecurityDescriptor(&NewAbsSD, SECURITY_DESCRIPTOR_REVISION) &&
SetSecurityDescriptorDacl(&NewAbsSD,TRUE,pNewACL,FALSE) )
{
//---------------------------------------------------------
//Copy all other stuff from the old SD to the new SD
SECURITY_DESCRIPTOR_CONTROL sdc;
DWORD dwRevision;
if(GetSecurityDescriptorControl(pNameSD->m_pSD,&sdc,&dwRevision))
{
//Clear SE_SELF_RELATIVE flag
sdc &=~SE_SELF_RELATIVE;
SetSecurityDescriptorControl(&NewAbsSD,sdc,sdc);
}
PSID pSidTmp = NULL;
BOOL bDefaulted;
if(GetSecurityDescriptorOwner(pNameSD->m_pSD,&pSidTmp,&bDefaulted) && pSidTmp)
{
SetSecurityDescriptorOwner(&NewAbsSD,pSidTmp,bDefaulted);
}
pSidTmp = NULL;
if(GetSecurityDescriptorGroup(pNameSD->m_pSD,&pSidTmp,&bDefaulted) && pSidTmp)
{
SetSecurityDescriptorGroup(&NewAbsSD,pSidTmp,bDefaulted);
}
PACL pSacl = NULL;
BOOL bSaclPresent;
if(GetSecurityDescriptorSacl(pNameSD->m_pSD,&bSaclPresent,&pSacl,&bDefaulted))
{
SetSecurityDescriptorSacl(&NewAbsSD,bSaclPresent,pSacl,bDefaulted);
}
//---------------------------------------------------------
DWORD dwSDLen = GetSecurityDescriptorLength( &NewAbsSD );
PSECURITY_DESCRIPTOR pSD;
pSD = ( PSECURITY_DESCRIPTOR )LocalAlloc(LPTR,dwSDLen);
if(pSD)
{
if(MakeSelfRelativeSD( &NewAbsSD , pSD , &dwSDLen ))
{
err = SetWinStationSecurity(hKeyParent, pNameSD->m_pName, pSD );
if(err == ERROR_SUCCESS)
{
pNameSD->SetSD(pSD);
}
}
else
{
err=GetLastError();
}
}
else
{
err=GetLastError();
}
}
else
{
err=GetLastError();
}
}
LocalFree(pNewACE);
LocalFree(pNewACL);
return err;
}
/*****************************************************************************
*
* GetDacl
*
* Gets security descriptor DACL.
*
* ENTRY:
*
* IN PSECURITY_DESCRIPTOR *pSD: pointer to SD
* OUT PACL *ppDacl: pointer to pointer to DACL inside SD
*
* NOTES:
* Do not try to free DACL!
*
* EXIT:
* Returns: error code if cannot get DACL; ERROR_SUCCESS otherwise.
*
****************************************************************************/
DWORD
GetDacl(
IN PSECURITY_DESCRIPTOR pSD,
OUT PACL *ppDacl)
{
BOOL bDaclPresent;
BOOL bDaclDefaulted;
*ppDacl=NULL;
if(GetSecurityDescriptorDacl(pSD,&bDaclPresent,ppDacl,&bDaclDefaulted)) {
if(!bDaclPresent){
*ppDacl=NULL;
}
} else {
return GetLastError();
}
return ERROR_SUCCESS;
}
/*****************************************************************************
*
* GetSacl
*
* Gets security descriptor SACL.
*
* ENTRY:
*
* IN PSECURITY_DESCRIPTOR *pSD: pointer to SD
* OUT PACL *ppSacl: pointer to pointer to SACL inside SD
*
* NOTES:
* Do not try to free SACL!
*
* EXIT:
* Returns: error code if cannot get SACL; ERROR_SUCCESS otherwise.
*
****************************************************************************/
DWORD
GetSacl(
IN PSECURITY_DESCRIPTOR pSD,
OUT PACL *ppSacl)
{
BOOL bSaclPresent;
BOOL bSaclDefaulted;
*ppSacl=NULL;
if(GetSecurityDescriptorSacl(pSD,&bSaclPresent,ppSacl,&bSaclDefaulted)) {
if(!bSaclPresent){
*ppSacl=NULL;
}
} else {
return GetLastError();
}
return ERROR_SUCCESS;
}
/*****************************************************************************
*
* EnumWinStationSecurityDescriptors
*
* Enumerates winstations and gets their security descriptors
*
* ENTRY:
*
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* OUT CNameAndSDList - name and security descriptor of a winstation
* NOTES:
* Call LocalFree function to free SD, do not try to free DACL!
*
* EXIT:
* Returns: error code or ERROR_SUCCESS
*
****************************************************************************/
DWORD
EnumWinStationSecurityDescriptors(
IN HKEY hKeyParent,
OUT CNameAndSDList *pNameSDList)
{
DWORD err;
DWORD dwIndex;
TCHAR wszTmpName[MAX_PATH+1];
DWORD cbTmpName=MAX_PATH;
FILETIME ftLastWriteTime;
for(dwIndex=0;;dwIndex++)
{
cbTmpName=MAX_PATH;
err=RegEnumKeyEx(
hKeyParent, // handle of key to enumerate
dwIndex, // index of subkey to enumerate
wszTmpName, // address of buffer for subkey name
&cbTmpName, // address for size of subkey buffer
NULL, // reserved
NULL, // address of buffer for class string
NULL, // address for size of class buffer
&ftLastWriteTime // address for time key last written to
);
if((err!=ERROR_SUCCESS)&&
(err!=ERROR_MORE_DATA)&&
(err!=ERROR_NO_MORE_ITEMS))
{
return err;
}
if(err==ERROR_NO_MORE_ITEMS)
break;
else
{
try
{
CNameAndSD Entry(wszTmpName);
err = GetWinStationSecurity(hKeyParent, Entry.m_pName,
_T("Security"), &(Entry.m_pSD));
if( err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND )
{
pNameSDList->push_back(Entry);
}
}
catch(DWORD Except)
{
return Except;
}
}
}
return ERROR_SUCCESS;
}
/*****************************************************************************
*
* GetWinStationSecurity
*
* Returns WinStation's security descriptor.
*
* ENTRY:
*
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN PWINSTATIONNAMEW pWSName - name of a winstation
* if pWSName is NULL - function returns default SD
* OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor - pointer to pointer to SD
*
* NOTES:
* Call LocalFree function to free SD!
*
* EXIT:
* Returns: error code or ERROR_SUCCESS
*
****************************************************************************/
DWORD
GetWinStationSecurity(
IN HKEY hKeyParent,
IN PWINSTATIONNAME pWSName,
IN LPCTSTR szValueName,
OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
{
DWORD SDLength = 0;
DWORD ValueType =0;
HKEY hKey = NULL;
DWORD err;
*ppSecurityDescriptor = NULL;
if(pWSName)
{
err = RegOpenKeyEx(hKeyParent, pWSName, 0,KEY_READ, &hKey );
}
else
{
//If pWSName - get defauilt SD
hKey = hKeyParent;
err = ERROR_SUCCESS;
}
if(err == ERROR_SUCCESS)
{
err = RegQueryValueEx( hKey, szValueName, NULL, &ValueType,NULL, &SDLength );
if(err == ERROR_SUCCESS )
{
//Return error if not correct data type
if (ValueType == REG_BINARY)
{
//Allocate a buffer to read the Security info and read it
// ACLUI uses LocalFree
*ppSecurityDescriptor = ( PSECURITY_DESCRIPTOR )LocalAlloc( LMEM_FIXED , SDLength );
if ( *ppSecurityDescriptor )
{
err = RegQueryValueEx( hKey, szValueName, NULL, &ValueType,
(BYTE *) *ppSecurityDescriptor, &SDLength );
if(err == ERROR_SUCCESS )
{
//Check for a valid SD before returning.
if(! IsValidSecurityDescriptor( *ppSecurityDescriptor ) )
{
LocalFree(*ppSecurityDescriptor);
*ppSecurityDescriptor = NULL;
err = ERROR_INVALID_DATA;
}
}
else
{
LocalFree(*ppSecurityDescriptor);
*ppSecurityDescriptor = NULL;
}
}
else
{
err = ERROR_NOT_ENOUGH_MEMORY;
}
}
else
{
err = ERROR_INVALID_DATA;
}
}
if(hKey != hKeyParent)
{
RegCloseKey(hKey);
}
}
return err;
} // GetWinStationSecurity
/*****************************************************************************
*
* SetWinStationSecurity
*
* Writes winstation security descriptor to the registry
*
* ENTRY:
*
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN PWINSTATIONNAMEW pWSName - name of a winstation
* IN PSECURITY_DESCRIPTOR pSecurityDescriptor - pointer to SD
*
* NOTES:
* Call LocalFree function to free SD, do not try to free DACL!
*
* EXIT:
* Returns: 0: if success
* Error code: otherwise
*
****************************************************************************/
DWORD
SetWinStationSecurity(
IN HKEY hKeyParent,
IN PWINSTATIONNAME pWSName,
IN PSECURITY_DESCRIPTOR pSecurityDescriptor )
{
HKEY hKey = NULL;
DWORD err;
err = RegOpenKeyEx(hKeyParent, pWSName, 0,KEY_WRITE, &hKey );
if(err == ERROR_SUCCESS)
{
err = RegSetValueEx(hKey, _T("Security"),0,REG_BINARY,(LPBYTE)pSecurityDescriptor,
GetSecurityDescriptorLength(pSecurityDescriptor));
RegCloseKey(hKey);
}
return err;
} // SetWinStationSecurity
/*****************************************************************************
*
* RemoveWinStationSecurity
*
* Removes winstation's security descriptor from the registry
*
* ENTRY:
*
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN PWINSTATIONNAMEW pWSName - name of a winstation
*
* NOTES:
*
*
* EXIT:
* Returns: 0: if success
* Error code: otherwise
*
****************************************************************************/
DWORD
RemoveWinstationSecurity(
IN HKEY hKeyParent,
IN PWINSTATIONNAME pWSName)
{
HKEY hKey = NULL;
DWORD err;
err = RegOpenKeyEx(hKeyParent, pWSName, 0,KEY_WRITE, &hKey );
if(err == ERROR_SUCCESS)
{
err = RegDeleteValue(hKey, _T("Security"));
RegCloseKey(hKey);
}
return err;
}
/*****************************************************************************
*
* SetNewDefaultSecurity
*
* Sets new default security descriptor
*
* ENTRY:
*
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
*
* NOTES:
*
*
* EXIT:
* Returns: 0: if success
* Error code: otherwise
*
****************************************************************************/
DWORD
SetNewDefaultSecurity(
IN HKEY hKey)
{
//
DWORD err;
err = RegSetValueEx(hKey, _T("DefaultSecurity"), 0, REG_BINARY,
(LPBYTE)g_DefaultSD, sizeof(g_DefaultSD));
return err;
}
/*****************************************************************************
*
* SetNewConsoleSecurity
*
* Sets new console security descriptor
*
* ENTRY:
*
* IN HKEY hKeyParent - handle to HKLM\SYSTEM\CurrentControlSet\
* Control\Terminal Server\WinStations
* IN BOOL bServer
* NOTES:
*
*
* EXIT:
* Returns: 0: if success
* Error code: otherwise
*
****************************************************************************/
DWORD
SetNewConsoleSecurity(
IN HKEY hKeyParent,
IN BOOL bServer)
{
//
DWORD err;
//Set default console security
if(bServer)
{
err = RegSetValueEx(hKeyParent, _T("ConsoleSecurity"), 0, REG_BINARY,
(LPBYTE)g_ConsoleSD, sizeof(g_ConsoleSD));
}
else
{
// on Professional it's the same as "DefaultSecurity"
err = RegSetValueEx(hKeyParent, _T("ConsoleSecurity"), 0, REG_BINARY,
(LPBYTE)g_DefaultSD, sizeof(g_DefaultSD));
}
return err;
}
/*****************************************************************************
*
* CDefaultSD::DoesDefaultSDHaveRemoteUsers
*
* Checks if defauilt SD has "Remote Desktop Users" SID.
*
* ENTRY:
* OUT LPBOOL pbHas - TRUE if defauilt SD has "Remote Desktop Users" SID.
*
* NOTES:
*
* EXIT:
* Returns: 0: if success
* Error code: otherwise
*
****************************************************************************/
DWORD
CDefaultSD::DoesDefaultSDHaveRemoteUsers(
OUT LPBOOL pbHas)
{
*pbHas = FALSE;
//
DWORD err = ERROR_SUCCESS;
PACL pDacl = NULL;
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
PSID pRUSid=NULL;
if( !AllocateAndInitializeSid( &sia, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS,
0, 0, 0, 0, 0, 0,&pRUSid ) )
{
return GetLastError();
}
//get dacl
err = GetDacl(m_pSD, &pDacl );
if( err == ERROR_SUCCESS ) {
//search ACL for "REMOTE USERS" SID
ACL_SIZE_INFORMATION asiAclSize;
DWORD dwBufLength=sizeof(asiAclSize);
ACCESS_ALLOWED_ACE *paaAllowedAce;
DWORD dwAcl_i;
if(!pDacl)
{
//It shuold never be in our case
//so we return error here
FreeSid(pRUSid);
return ERROR_INVALID_PARAMETER;
}
else
//DACL present
{
if (GetAclInformation(pDacl,
(LPVOID)&asiAclSize,
(DWORD)dwBufLength,
(ACL_INFORMATION_CLASS)AclSizeInformation))
{
for (dwAcl_i = 0; dwAcl_i < asiAclSize.AceCount; dwAcl_i++)
{
if(GetAce( pDacl, dwAcl_i, (LPVOID *)&paaAllowedAce))
{
if(EqualSid((PSID)&(paaAllowedAce->SidStart),pRUSid))
{
//permission already exist, we don't need to
//do anything
*pbHas = TRUE;
}
}
}
}
}
}
FreeSid(pRUSid);
return err;
}
//*************************************************************
//
// LookupSid()
//
// Purpose: Given SID allocates and returns string containing
// name of the user in format DOMAINNAME\USERNAME
//
// Parameters: IN PSID pSid
// OUT LPWSTR ppName
// OUT SID_NAME_USE *peUse
//
// Return: TRUE if success, FALSE otherwise
//
// Comments:
//
// History: Date Author Comment
// 10/23/00 skuzin Created
//
//*************************************************************
BOOL
LookupSid(
IN PSID pSid,
OUT LPWSTR *ppName,
OUT SID_NAME_USE *peUse)
{
LPWSTR szName = NULL;
DWORD cName = 0;
LPWSTR szDomainName = NULL;
DWORD cDomainName = 0;
*ppName = NULL;
if(!LookupAccountSidW(NULL,pSid,
szName,&cName,
szDomainName,&cDomainName,
peUse) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
//cName and cDomainName include terminating 0
*ppName = (LPWSTR)LocalAlloc(LPTR,(cName+cDomainName)*sizeof(WCHAR));
if(*ppName)
{
szDomainName = *ppName;
szName = &(*ppName)[cDomainName];
if(LookupAccountSidW(NULL,pSid,
szName,&cName,
szDomainName,&cDomainName,
peUse))
{
//user name now in format DOMAINNAME\0USERNAME
//let's replace '\0' with '\\'
//now cName and cDomainName do not include terminating 0
//very confusing
if(cDomainName)
{
(*ppName)[cDomainName] = L'\\';
}
return TRUE;
}
else
{
LocalFree(*ppName);
*ppName = NULL;
}
}
}
return FALSE;
}
//*************************************************************
//
// IsLocal()
//
// Purpose:
//
// Parameters: wszDomainandname - domain\user
// determines whether the user is local or not
// if local - cuts out domain name
//
// Return: NONE
//
// Comments:
//
// History: Date Author Comment
// 03/13/01 skuzin Created
//
//*************************************************************
BOOL
IsLocal(
IN LPWSTR wszLocalCompName,
IN OUT LPWSTR wszDomainandname)
{
LPWSTR wszTmp = wcschr(wszDomainandname,L'\\');
if(!wszTmp)
{
return TRUE;
}
if(!_wcsnicmp(wszDomainandname, wszLocalCompName,wcslen(wszLocalCompName) ))
{
//get rid of useless domain name
wcscpy(wszDomainandname,wszTmp+1);
return TRUE;
}
return FALSE;
}
//*************************************************************
//
// GetAbsoluteSD()
//
// Purpose: Converts self-relative SD to absolute SD
// returns pointers to SACL DACL Owner and Group
// of the absolute SD.
//
// Parameters:
// IN PSECURITY_DESCRIPTOR pSelfRelativeSD
// OUT PSECURITY_DESCRIPTOR *ppAbsoluteSD
// OUT PACL *ppDacl
// OUT PACL *ppSacl
// OUT PSID *ppOwner
// OUT PSID *ppPrimaryGroup
//
// Return: error code if fails, ERROR_SUCCESS otherwise
//
// Comments: caller needs to free
// every returned pointer using LocalFree function.
//
// History: Date Author Comment
// 03/13/01 skuzin Created
//
//*************************************************************
DWORD
GetAbsoluteSD(
IN PSECURITY_DESCRIPTOR pSelfRelativeSD,
OUT PSECURITY_DESCRIPTOR *ppAbsoluteSD,
OUT PACL *ppDacl,
OUT PACL *ppSacl,
OUT PSID *ppOwner,
OUT PSID *ppPrimaryGroup)
{
DWORD dwAbsoluteSDSize = 0; // absolute SD size
DWORD dwDaclSize = 0; // size of DACL
DWORD dwSaclSize = 0; // size of SACL
DWORD dwOwnerSize = 0; // size of owner SID
DWORD dwPrimaryGroupSize = 0; // size of group SID
*ppAbsoluteSD = NULL;
*ppDacl = NULL;
*ppSacl = NULL;
*ppOwner = NULL;
*ppPrimaryGroup = NULL;
MakeAbsoluteSD(
pSelfRelativeSD, // self-relative SD
NULL, // absolute SD
&dwAbsoluteSDSize, // absolute SD size
NULL, // DACL
&dwDaclSize, // size of DACL
NULL, // SACL
&dwSaclSize, // size of SACL
NULL, // owner SID
&dwOwnerSize, // size of owner SID
NULL, // primary-group SID
&dwPrimaryGroupSize // size of group SID
);
try
{
if(dwAbsoluteSDSize)
{
*ppAbsoluteSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,dwAbsoluteSDSize);
if(!(*ppAbsoluteSD))
{
throw GetLastError();
}
}
if(dwDaclSize)
{
*ppDacl = (PACL)LocalAlloc(LPTR,dwDaclSize);
if(!(*ppDacl))
{
throw GetLastError();
}
}
if(dwSaclSize)
{
*ppSacl = (PACL)LocalAlloc(LPTR,dwSaclSize);
if(!(*ppSacl))
{
throw GetLastError();
}
}
if(dwOwnerSize)
{
*ppOwner = (PSID)LocalAlloc(LPTR,dwOwnerSize);
if(!(*ppOwner))
{
throw GetLastError();
}
}
if(dwPrimaryGroupSize)
{
*ppPrimaryGroup = (PSID)LocalAlloc(LPTR,dwPrimaryGroupSize);
if(!(*ppPrimaryGroup))
{
throw GetLastError();
}
}
if(!MakeAbsoluteSD(
pSelfRelativeSD, // self-relative SD
*ppAbsoluteSD, // absolute SD
&dwAbsoluteSDSize, // absolute SD size
*ppDacl, // DACL
&dwDaclSize, // size of DACL
*ppSacl, // SACL
&dwSaclSize, // size of SACL
*ppOwner, // owner SID
&dwOwnerSize, // size of owner SID
*ppPrimaryGroup, // primary-group SID
&dwPrimaryGroupSize // size of group SID
))
{
throw GetLastError();
}
}
catch(DWORD ret)
{
if(*ppAbsoluteSD)
{
LocalFree(*ppAbsoluteSD);
*ppAbsoluteSD = NULL;
}
if(*ppDacl)
{
LocalFree(*ppDacl);
*ppDacl = NULL;
}
if(*ppSacl)
{
LocalFree(*ppSacl);
*ppSacl = NULL;
}
if(*ppOwner)
{
LocalFree(*ppOwner);
*ppOwner = NULL;
}
if(*ppPrimaryGroup)
{
LocalFree(*ppPrimaryGroup);
*ppPrimaryGroup = NULL;
}
return ret;
}
return ERROR_SUCCESS;
}
//*************************************************************
//
// GetAbsoluteSD()
//
// Purpose: Converts absolute SD to self-relative SD
// returns pointer to self-relative SD.
//
// Parameters:
// IN PSECURITY_DESCRIPTOR pAbsoluteSD,
// OUT PSECURITY_DESCRIPTOR *ppSelfRelativeSD
//
// Return: error code if fails, ERROR_SUCCESS otherwise
//
// Comments: caller needs to free
// returned pointer using LocalFree function.
//
// History: Date Author Comment
// 03/13/01 skuzin Created
//
//*************************************************************
DWORD
GetSelfRelativeSD(
IN PSECURITY_DESCRIPTOR pAbsoluteSD,
OUT PSECURITY_DESCRIPTOR *ppSelfRelativeSD)
{
DWORD dwBufferLength = 0;
*ppSelfRelativeSD = NULL;
MakeSelfRelativeSD(pAbsoluteSD, NULL, &dwBufferLength);
if(dwBufferLength)
{
*ppSelfRelativeSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,dwBufferLength);
if(*ppSelfRelativeSD)
{
if(!MakeSelfRelativeSD(pAbsoluteSD, *ppSelfRelativeSD, &dwBufferLength))
{
DWORD dwResult = GetLastError();
LocalFree(*ppSelfRelativeSD);
return dwResult;
}
}
}
else
{
return GetLastError();
}
return ERROR_SUCCESS;
}