windows-nt/Source/XPSP1/NT/enduser/windows.com/lib/detect/osdetutl.cpp

517 lines
12 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//=======================================================================
//
// 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;
}