//======================================================================= // // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved. // // File: osdetutl.cpp // // Description: // // Additional OS detection utility routines for: // * Returning free drive space // * Returning "Administrator" flag // //======================================================================= #include #include #include #include #include #include #include #include // for _i64tot // #define __IUENGINE_USES_ATL_ #if defined(__IUENGINE_USES_ATL_) #include #define USES_IU_CONVERSION USES_CONVERSION #else #include #endif typedef BOOL (WINAPI * PFN_GetDiskFreeSpaceEx) (LPTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); const TCHAR REGPATH_AU[] = _T("Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU"); const TCHAR REGKEY_AU_OPTIONS[] = _T("NoAutoUpdate"); const TCHAR REGPATH_EXPLORER[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"); const TCHAR REGKEY_WINUPD_DISABLED[] = _T("NoWindowsUpdate"); const TCHAR REGPATH_POLICY_USERACCESS_DISABLED[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\WindowsUpdate"); const TCHAR REGKEY_WU_USERACCESS_DISABLED[] = _T("DisableWindowsUpdateAccess"); HRESULT GetLocalFixedDriveInfo(DWORD* pdwNumDrives, PPIU_DRIVEINFO ppDriveInfo) { USES_IU_CONVERSION; LOG_Block("GetLocalFixedDriveInfo"); DWORD dwNumCharacters = 0; LPTSTR pszDriveStrBuffer = NULL; HRESULT hr = E_FAIL; LPTSTR pszRootPathName; if (NULL == pdwNumDrives || ppDriveInfo == NULL) { LOG_Error(_T("E_INVALIDARG")); return E_INVALIDARG; } *ppDriveInfo = NULL; *pdwNumDrives = 0; // // kernel32.dll is loaded into all processes, so we don't need to LoadLibrary, but need to look for W or A versions // PFN_GetDiskFreeSpaceEx pfnGetDiskFreeSpaceEx; #if defined(UNICODE) || defined (_UNICODE) pfnGetDiskFreeSpaceEx = (PFN_GetDiskFreeSpaceEx) GetProcAddress( GetModuleHandle(L"kernel32.dll"), "GetDiskFreeSpaceExW"); #else pfnGetDiskFreeSpaceEx = (PFN_GetDiskFreeSpaceEx) GetProcAddress( GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA"); #endif if (NULL == pfnGetDiskFreeSpaceEx) { // // This could fail on Win95 Gold, but we don't support that anyway // Win32MsgSetHrGotoCleanup(GetLastError()); } // // Handle corner case of race issue when new drives are hot-plugged between the first // and second calls to GetLogicalDriveStrings and the buffer requirements increase // for (;;) { if (0 == (dwNumCharacters = GetLogicalDriveStrings(0, NULL))) { Win32MsgSetHrGotoCleanup(GetLastError()); } // // Add space for terminating NULL // dwNumCharacters += 1; CleanUpFailedAllocSetHrMsg(pszDriveStrBuffer = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwNumCharacters * sizeof(TCHAR))); DWORD dwRet = GetLogicalDriveStrings(dwNumCharacters, pszDriveStrBuffer); if (0 == dwRet) { // // Unknown error - we gotta bail // Win32MsgSetHrGotoCleanup(GetLastError()); } else if (dwRet > dwNumCharacters) { // // Someone plugged in a new drive, get the new buffer space requirements and try again // SafeHeapFree(pszDriveStrBuffer); continue; } // // GetLogicalDriveStrings succeeded, break and continue // break; } // // Count the number of fixed drives while building the return array of IU_DRIVEINFO // for (pszRootPathName = pszDriveStrBuffer; NULL != *pszRootPathName; pszRootPathName += lstrlen(pszRootPathName) + 1) { // // Only return sizes for fixed drives // if (DRIVE_FIXED == GetDriveType(pszRootPathName)) { // // Make sure pszRootPathName is of the form ":\" by checking for ':' in second position // if (_T(':') != pszRootPathName[1]) { LOG_Error(_T("Root paths must be of form \":\\\"")); SetHrAndGotoCleanUp(E_FAIL); } ULARGE_INTEGER i64FreeBytesAvailable; ULARGE_INTEGER i64TotalBytes; ULARGE_INTEGER i64TotalFreeBytes; BOOL fResult; // // Get the free space // fResult = pfnGetDiskFreeSpaceEx(pszRootPathName, &i64FreeBytesAvailable, &i64TotalBytes, &i64TotalFreeBytes); // Process GetDiskFreeSpaceEx results. if (!fResult) { LOG_Driver(_T("GetDiskFreeSpaceEx(%s, ...) returned an error. We will not report space for this drive"), \ pszRootPathName); LOG_ErrorMsg(GetLastError()); } else { // // We return KiloBytes // i64FreeBytesAvailable.QuadPart /= 1024; if (NULL == *ppDriveInfo) { // // Allocate one IU_DRIVEINFO struct // CleanUpFailedAllocSetHrMsg(*ppDriveInfo = (PIU_DRIVEINFO) HeapAlloc(GetProcessHeap(), 0, sizeof(IU_DRIVEINFO))); } else { // // Realloc buffer so we can append // PIU_DRIVEINFO pDriveInfoTemp; if (NULL == (pDriveInfoTemp = (PIU_DRIVEINFO) HeapReAlloc(GetProcessHeap(), 0, *ppDriveInfo, ((*pdwNumDrives)+1) * sizeof(IU_DRIVEINFO)))) { LOG_Error(_T("E_OUTOFMEMORY")); SetHrAndGotoCleanUp(E_OUTOFMEMORY); // Note: *ppDriveInfo still points to previously allocated memory } *ppDriveInfo = pDriveInfoTemp; // in case it was moved } // // First copy the drive letter // lstrcpyn(((&(*ppDriveInfo)[*pdwNumDrives]))->szDriveStr, pszRootPathName, 4); // // Next copy the bytes, but truncate to MAXLONG // ((&(*ppDriveInfo)[*pdwNumDrives]))->iKBytes = (i64FreeBytesAvailable.QuadPart > 0x000000007FFFFFFF) ? MAXLONG : (INT) i64FreeBytesAvailable.QuadPart; // // increment drive count // (*pdwNumDrives)++; } } } hr = S_OK; CleanUp: SafeHeapFree(pszDriveStrBuffer); if (FAILED(hr)) { SafeHeapFree(*ppDriveInfo); *pdwNumDrives = 0; } return hr; } // // Code adapted from MSDN SearchTokenGroupsForSID since CheckTokenMembership is Win2K only // BOOL IsAdministrator(void) { LOG_Block("IsAdministrator"); return (GetLogonGroupInfo() & IU_SECURITY_MASK_ADMINS); } DWORD GetLogonGroupInfo(void) { DWORD dwRet = 0x0; LOG_Block("GetLogonGroupInfo"); DWORD dwSize = 0; DWORD i = 0; HANDLE hToken = INVALID_HANDLE_VALUE; PTOKEN_GROUPS pGroupInfo = NULL; PSID pAdminSID = NULL, pPowerUsrSID = NULL; SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY; HRESULT hr; // so we can use CleanUpXxxxx macros OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osvi)) { if (VER_PLATFORM_WIN32_NT != osvi.dwPlatformId) { LOG_Driver(_T("Platform isn't VER_PLATFORM_WIN32_NT - returning TRUE by default")); dwRet = IU_SECURITY_MASK_ADMINS | IU_SECURITY_MAST_POWERUSERS; LOG_Out(_T("Non NT system, return TRUE for all groups")); goto CleanUp; } } else { LOG_Error(_T("GetVersionEx:")); Win32MsgSetHrGotoCleanup(GetLastError()); } // // Open a handle to the access token for the calling process. // if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken )) { LOG_Error(_T("OpenProcessToken:")); Win32MsgSetHrGotoCleanup(GetLastError()); } // Call GetTokenInformation to get the buffer size. if (!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize)) { DWORD dwResult = GetLastError(); if( dwResult != ERROR_INSUFFICIENT_BUFFER ) { LOG_Error(_T("GetTokenInformation:")); Win32MsgSetHrGotoCleanup(dwResult); } } // Allocate the buffer. if (NULL == (pGroupInfo = (PTOKEN_GROUPS) HeapAlloc(GetProcessHeap(), 0, dwSize))) { LOG_Error(_T("HeapAlloc")); goto CleanUp; } // Call GetTokenInformation again to get the group information. if (! GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSize, &dwSize ) ) { LOG_Error(_T("GetTokenInformation:")); Win32MsgSetHrGotoCleanup(GetLastError()); } // Create a SID for the BUILTIN\Administrators group. if (! AllocateAndInitializeSid( &SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID) ) { LOG_Error(_T("AllocateAndInitializeSid:")); Win32MsgSetHrGotoCleanup(GetLastError()); } if (! AllocateAndInitializeSid( &SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &pPowerUsrSID) ) { LOG_Error(_T("AllocateAndInitializeSid:")); Win32MsgSetHrGotoCleanup(GetLastError()); } // Loop through the group SIDs looking for the administrator SID. for(i = 0; i < pGroupInfo->GroupCount; i++) { if (EqualSid(pAdminSID, pGroupInfo->Groups[i].Sid) && (pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED)) { dwRet |= IU_SECURITY_MASK_ADMINS; } if (EqualSid(pPowerUsrSID, pGroupInfo->Groups[i].Sid) && (pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED)) { dwRet |= IU_SECURITY_MAST_POWERUSERS; } } CleanUp: if (pAdminSID) { FreeSid(pAdminSID); } if (pPowerUsrSID) { FreeSid(pPowerUsrSID); } SafeHeapFree(pGroupInfo); if (INVALID_HANDLE_VALUE != hToken) { CloseHandle(hToken); } LOG_Out(_T("Return 0x%08x"), dwRet); return dwRet; } // ---------------------------------------------------------------------------------- // // Returns: // 1 If the NoWindowsUpdate value exists and is != 0 under // HKEY_CURRENT_USER for NT or HKEY_LOCAL_MACHINE for Win9x. // 0 If the NoWindowsUpdate value exists and is zero. // -1 If the NoWindowsUpdate value doesn't exist. // // ---------------------------------------------------------------------------------- int IsWindowsUpdateDisabled(void) { LOG_Block("IsWindowsUpdateDisabled"); int nRet = -1; HKEY hKey; DWORD dwDisabled; DWORD dwSize = sizeof(dwDisabled); DWORD dwType; HKEY hkeyRoot; OSVERSIONINFO versionInformation; versionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&versionInformation); if (versionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT) { hkeyRoot = HKEY_CURRENT_USER; } else { hkeyRoot = HKEY_LOCAL_MACHINE; } if ( RegOpenKeyEx( hkeyRoot, REGPATH_EXPLORER, NULL, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS ) { if ( RegQueryValueEx(hKey, REGKEY_WINUPD_DISABLED, NULL, &dwType, (LPBYTE)&dwDisabled, &dwSize) == ERROR_SUCCESS ) { if ( (dwType == REG_DWORD) && (dwDisabled == 0) ) { nRet = 0; } else { nRet = 1; } } RegCloseKey(hKey); } LOG_Out(_T("Return: %d"), nRet); return nRet; } // ---------------------------------------------------------------------------------- // // Returns: // 1 If the DisableWindowsUpdateAccess value exists and is != 0 under // HKEY_CURRENT_USER for NT or HKEY_LOCAL_MACHINE for Win9x. // 0 If the DisableWindowsUpdateAccess value exists and is zero. // -1 If the DisableWindowsUpdateAccess value doesn't exist. // // ---------------------------------------------------------------------------------- int IsWindowsUpdateUserAccessDisabled(void) { LOG_Block("IsWindowsUpdateUserAccessDisabled"); int nRet = -1; HKEY hKey; DWORD dwDisabled; DWORD dwSize = sizeof(dwDisabled); DWORD dwType; HKEY hkeyRoot; OSVERSIONINFO versionInformation; versionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&versionInformation); if (versionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT) { hkeyRoot = HKEY_CURRENT_USER; } else { hkeyRoot = HKEY_LOCAL_MACHINE; } if ( RegOpenKeyEx( hkeyRoot, REGPATH_POLICY_USERACCESS_DISABLED, NULL, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS ) { if ( RegQueryValueEx(hKey, REGKEY_WU_USERACCESS_DISABLED, NULL, &dwType, (LPBYTE)&dwDisabled, &dwSize) == ERROR_SUCCESS ) { if ( (dwType == REG_DWORD) && (dwDisabled == 0) ) { nRet = 0; } else { nRet = 1; } } RegCloseKey(hKey); } LOG_Out(_T("Return: %d"), nRet); if (1 == nRet) { LogMessage("Access to Windows Update has been disabled by administrative policy"); } return nRet; } // // Returns 1 for enabled, 0 for disabled, and -1 for unknown/default (registry doesn't exist) // int IsAutoUpdateEnabled(void) { LOG_Block("IsAutoUpdateEnabled"); HKEY hSubKey; DWORD dwType; ULONG nLen; DWORD dwAUOptions; int nRet = -1; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_AU, 0, KEY_READ, &hSubKey)) { nLen = sizeof(dwAUOptions); if (ERROR_SUCCESS == RegQueryValueEx(hSubKey, REGKEY_AU_OPTIONS, NULL, &dwType, (LPBYTE)&dwAUOptions, &nLen)) { // // 1 is disabled, 2 & 3 are enabled // nRet = (1 == dwAUOptions ? 0 : 1); } RegCloseKey(hSubKey); } else { LOG_Error(_T("RegOpenKeyEx failed - returning -1")); } return nRet; }