517 lines
12 KiB
C++
517 lines
12 KiB
C++
//=======================================================================
|
|
//
|
|
// 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 <windows.h>
|
|
#include <oleauto.h>
|
|
#include <wuiutest.h>
|
|
#include <tchar.h>
|
|
#include <osdet.h>
|
|
#include <logging.h>
|
|
#include <iucommon.h>
|
|
#include <stdio.h> // for _i64tot
|
|
|
|
// #define __IUENGINE_USES_ATL_
|
|
#if defined(__IUENGINE_USES_ATL_)
|
|
#include <atlbase.h>
|
|
#define USES_IU_CONVERSION USES_CONVERSION
|
|
#else
|
|
#include <MemUtil.h>
|
|
#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 "<drive letter>:\" by checking for ':' in second position
|
|
//
|
|
if (_T(':') != pszRootPathName[1])
|
|
{
|
|
LOG_Error(_T("Root paths must be of form \"<drive letter>:\\\""));
|
|
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;
|
|
}
|