// Berkeley Open Infrastructure for Network Computing // http://boinc.berkeley.edu // Copyright (C) 2006 University of California // // This is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any later version. // // This software is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Lesser General Public License for more details. // // To view the GNU Lesser General Public License visit // http://www.gnu.org/copyleft/lesser.html // or write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #ifdef _BOINC_DLL #include "stdafx.h" #else #include "boinc_win.h" #endif #include "win_util.h" #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \ DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | \ DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \ DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED) #define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \ WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \ WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \ WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | \ STANDARD_RIGHTS_REQUIRED) #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | \ GENERIC_EXECUTE | GENERIC_ALL) /** * Find out if we are on a Windows 2000 compatible system **/ BOOL IsWindows2000Compatible() { OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) return FALSE; return (osvi.dwMajorVersion >= 5); } /** * Define these if they aren't defined. They are normally found in * winnt.h, but some compilers don't have them. **/ #ifndef VER_AND #define VER_AND 6 #endif #ifndef VER_SUITENAME #define VER_SUITENAME 0x0000040 #endif #ifndef VER_SUITE_SINGLEUSERTS #define VER_SUITE_SINGLEUSERTS 0x00000100 #endif /** * This function performs the basic check to see if * the platform on which it is running is Terminal * services enabled. Note, this code is compatible on * all Win32 platforms. For the Windows 2000 platform * we perform a "lazy" bind to the new product suite * APIs that were first introduced on that platform. **/ BOOL IsTerminalServicesEnabled() { BOOL bResult = FALSE; // assume Terminal Services is not enabled DWORD dwVersion; OSVERSIONINFOEXA osVersionInfo; DWORDLONG dwlConditionMask = 0; HMODULE hmodK32 = NULL; HMODULE hmodNtDll = NULL; typedef ULONGLONG (WINAPI *PFnVerSetConditionMask)(ULONGLONG,ULONG,UCHAR); typedef BOOL (WINAPI *PFnVerifyVersionInfoA)(POSVERSIONINFOEXA, DWORD, DWORDLONG); PFnVerSetConditionMask pfnVerSetConditionMask; PFnVerifyVersionInfoA pfnVerifyVersionInfoA; dwVersion = GetVersion(); // are we running NT ? if (!(dwVersion & 0x80000000)) { // Is it Windows 2000 (NT 5.0) or greater ? if (LOBYTE(LOWORD(dwVersion)) > 4) { // In Windows 2000 we need to use the Product Suite APIs // Don't static link because it won't load on non-Win2000 systems hmodNtDll = GetModuleHandle( "NTDLL.DLL" ); if (hmodNtDll != NULL) { pfnVerSetConditionMask = (PFnVerSetConditionMask )GetProcAddress( hmodNtDll, "VerSetConditionMask"); if (pfnVerSetConditionMask != NULL) { dwlConditionMask = (*pfnVerSetConditionMask)( dwlConditionMask, VER_SUITENAME, VER_AND ); hmodK32 = GetModuleHandle( "KERNEL32.DLL" ); if (hmodK32 != NULL) { pfnVerifyVersionInfoA = (PFnVerifyVersionInfoA)GetProcAddress( hmodK32, "VerifyVersionInfoA") ; if (pfnVerifyVersionInfoA != NULL) { ZeroMemory(&osVersionInfo, sizeof(osVersionInfo)); osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo); osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS; bResult = (*pfnVerifyVersionInfoA)( &osVersionInfo, VER_SUITENAME, dwlConditionMask); } } } } } else { // This is NT 4.0 or older bResult = ValidateProductSuite( "Terminal Server" ); } } return bResult; } /** * This function compares the passed in "suite name" string * to the product suite information stored in the registry. * This only works on the Terminal Server 4.0 platform. **/ BOOL ValidateProductSuite (LPSTR SuiteName) { BOOL rVal = FALSE; LONG Rslt; HKEY hKey = NULL; DWORD Type = 0; DWORD Size = 0; LPSTR ProductSuite = NULL; LPSTR p; Rslt = RegOpenKeyA( HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\ProductOptions", &hKey ); if (Rslt != ERROR_SUCCESS) goto exit; Rslt = RegQueryValueExA( hKey, "ProductSuite", NULL, &Type, NULL, &Size ); if (Rslt != ERROR_SUCCESS || !Size) goto exit; ProductSuite = (LPSTR) LocalAlloc( LPTR, Size ); if (!ProductSuite) goto exit; Rslt = RegQueryValueExA( hKey, "ProductSuite", NULL, &Type, (LPBYTE) ProductSuite, &Size ); if (Rslt != ERROR_SUCCESS || Type != REG_MULTI_SZ) goto exit; p = ProductSuite; while (*p) { if (lstrcmpA( p, SuiteName ) == 0) { rVal = TRUE; break; } p += (lstrlenA( p ) + 1); } exit: if (ProductSuite) LocalFree( ProductSuite ); if (hKey) RegCloseKey( hKey ); return rVal; } /** * This function terminates a process by process id instead of a handle. **/ BOOL TerminateProcessById( DWORD dwProcessID ) { HANDLE hProcess; BOOL bRetVal = FALSE; hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, dwProcessID ); if (hProcess) { bRetVal = TerminateProcess(hProcess, 1); } CloseHandle( hProcess ); return bRetVal; } /** * This function adjusts the specified WindowStation to include the specfied * user. * * See: http://msdn2.microsoft.com/en-us/library/aa379608(VS.85).aspx **/ BOOL AddAceToWindowStation(HWINSTA hwinsta, PSID psid) { ACCESS_ALLOWED_ACE *pace = NULL; ACL_SIZE_INFORMATION aclSizeInfo; BOOL bDaclExist; BOOL bDaclPresent; BOOL bSuccess = FALSE; DWORD dwNewAclSize; DWORD dwSidSize = 0; DWORD dwSdSizeNeeded; PACL pacl = NULL; PACL pNewAcl = NULL; PSECURITY_DESCRIPTOR psd = NULL; PSECURITY_DESCRIPTOR psdNew = NULL; PVOID pTempAce; SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; unsigned int i; __try { // Obtain the DACL for the window station. if (!GetUserObjectSecurity( hwinsta, &si, psd, dwSidSize, &dwSdSizeNeeded) ) if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { psd = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded); if (psd == NULL) __leave; psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded); if (psdNew == NULL) __leave; dwSidSize = dwSdSizeNeeded; if (!GetUserObjectSecurity( hwinsta, &si, psd, dwSidSize, &dwSdSizeNeeded) ) __leave; } else __leave; // Create a new DACL. if (!InitializeSecurityDescriptor( psdNew, SECURITY_DESCRIPTOR_REVISION) ) __leave; // Get the DACL from the security descriptor. if (!GetSecurityDescriptorDacl( psd, &bDaclPresent, &pacl, &bDaclExist) ) __leave; // Initialize the ACL. ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION)); aclSizeInfo.AclBytesInUse = sizeof(ACL); // Call only if the DACL is not NULL. if (pacl != NULL) { // get the file ACL size info if (!GetAclInformation( pacl, (LPVOID)&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation) ) __leave; } // Compute the size of the new ACL. dwNewAclSize = aclSizeInfo.AclBytesInUse + (2*sizeof(ACCESS_ALLOWED_ACE)) + (2*GetLengthSid(psid)) - (2*sizeof(DWORD)); // Allocate memory for the new ACL. pNewAcl = (PACL)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwNewAclSize); if (pNewAcl == NULL) __leave; // Initialize the new DACL. if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION)) __leave; // If DACL is present, copy it to a new DACL. if (bDaclPresent) { // Copy the ACEs to the new ACL. if (aclSizeInfo.AceCount) { for (i=0; i < aclSizeInfo.AceCount; i++) { // Get an ACE. if (!GetAce(pacl, i, &pTempAce)) __leave; // Add the ACE to the new ACL. if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER)pTempAce)->AceSize) ) __leave; } } } // Add the first ACE to the window station. pace = (ACCESS_ALLOWED_ACE *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD)); if (pace == NULL) __leave; pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; pace->Header.AceFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE; pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD); pace->Mask = GENERIC_ACCESS; if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid)) __leave; if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, (LPVOID)pace, pace->Header.AceSize) ) __leave; // Add the second ACE to the window station. pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE; pace->Mask = WINSTA_ALL; if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, (LPVOID)pace, pace->Header.AceSize) ) __leave; // Set a new DACL for the security descriptor. if (!SetSecurityDescriptorDacl( psdNew, TRUE, pNewAcl, FALSE) ) __leave; // Set the new security descriptor for the window station. if (!SetUserObjectSecurity(hwinsta, &si, psdNew)) __leave; // Indicate success. bSuccess = TRUE; } __finally { // Free the allocated buffers. if (pace != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pace); if (pNewAcl != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl); if (psd != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psd); if (psdNew != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew); } return bSuccess; } /** * This function adjusts the specified Desktop to include the specfied * user. * * See: http://msdn2.microsoft.com/en-us/library/aa379608(VS.85).aspx **/ BOOL AddAceToDesktop(HDESK hdesk, PSID psid) { ACL_SIZE_INFORMATION aclSizeInfo; BOOL bDaclExist; BOOL bDaclPresent; BOOL bSuccess = FALSE; DWORD dwNewAclSize; DWORD dwSidSize = 0; DWORD dwSdSizeNeeded; PACL pacl = NULL; PACL pNewAcl = NULL; PSECURITY_DESCRIPTOR psd = NULL; PSECURITY_DESCRIPTOR psdNew = NULL; PVOID pTempAce; SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; unsigned int i; __try { // Obtain the security descriptor for the desktop object. if (!GetUserObjectSecurity( hdesk, &si, psd, dwSidSize, &dwSdSizeNeeded)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { psd = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded ); if (psd == NULL) __leave; psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded); if (psdNew == NULL) __leave; dwSidSize = dwSdSizeNeeded; if (!GetUserObjectSecurity( hdesk, &si, psd, dwSidSize, &dwSdSizeNeeded) ) __leave; } else __leave; } // Create a new security descriptor. if (!InitializeSecurityDescriptor( psdNew, SECURITY_DESCRIPTOR_REVISION) ) __leave; // Obtain the DACL from the security descriptor. if (!GetSecurityDescriptorDacl( psd, &bDaclPresent, &pacl, &bDaclExist) ) __leave; // Initialize. ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION)); aclSizeInfo.AclBytesInUse = sizeof(ACL); // Call only if NULL DACL. if (pacl != NULL) { // Determine the size of the ACL information. if (!GetAclInformation( pacl, (LPVOID)&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation) ) __leave; } // Compute the size of the new ACL. dwNewAclSize = aclSizeInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD); // Allocate buffer for the new ACL. pNewAcl = (PACL)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwNewAclSize); if (pNewAcl == NULL) __leave; // Initialize the new ACL. if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION)) __leave; // If DACL is present, copy it to a new DACL. if (bDaclPresent) { // Copy the ACEs to the new ACL. if (aclSizeInfo.AceCount) { for (i=0; i < aclSizeInfo.AceCount; i++) { // Get an ACE. if (!GetAce(pacl, i, &pTempAce)) __leave; // Add the ACE to the new ACL. if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER)pTempAce)->AceSize) ) __leave; } } } // Add ACE to the DACL. if (!AddAccessAllowedAce( pNewAcl, ACL_REVISION, DESKTOP_ALL, psid) ) __leave; // Set new DACL to the new security descriptor. if (!SetSecurityDescriptorDacl( psdNew, TRUE, pNewAcl, FALSE) ) __leave; // Set the new security descriptor for the desktop object. if (!SetUserObjectSecurity(hdesk, &si, psdNew)) __leave; // Indicate success. bSuccess = TRUE; } __finally { // Free buffers. if (pNewAcl != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl); if (psd != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psd); if (psdNew != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew); } return bSuccess; }