//+------------------------------------------------------------------------- // // // Copyright (C) Microsoft // // File: securd.cpp // // History: 30-March-2000 a-skuzin Created // //-------------------------------------------------------------------------- #include "stdafx.h" #include #include #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; }