You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1186 lines
29 KiB
1186 lines
29 KiB
// Copyright (c) 2000-2002 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// CMDH.cpp - Helper class for working with
|
|
// logical disks mapped by logon
|
|
// session.
|
|
//
|
|
// Created: 4/23/2000 Kevin Hughes (khughes)
|
|
//
|
|
|
|
// USEAGE NOTE: This class presents a view of
|
|
// information pertaining to mapped drives in
|
|
// the context of the process id specified in
|
|
// the class constructor.
|
|
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntobapi.h>
|
|
|
|
#define _WINNT_ // have what is needed from above
|
|
|
|
#pragma warning (disable: 4786)
|
|
#pragma warning (disable: 4284)
|
|
|
|
#include <precomp.h>
|
|
#include <objbase.h>
|
|
#include <comdef.h>
|
|
#include <stdio.h> //sprintf
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <strstrea.h>
|
|
#include <vector>
|
|
#include <DskQuota.h>
|
|
#include <smartptr.h>
|
|
|
|
#include "DllWrapperBase.h"
|
|
#include "AdvApi32Api.h"
|
|
#include "NtDllApi.h"
|
|
#include "Kernel32Api.h"
|
|
|
|
#include <ntioapi.h>
|
|
#include "cmdh.h"
|
|
|
|
#include <session.h>
|
|
#include <dllutils.h>
|
|
#include <..\..\framework\provexpt\include\provexpt.h>
|
|
|
|
#include "Sid.h"
|
|
#include "AccessEntry.h" // CAccessEntry class
|
|
#include "AccessEntryList.h"
|
|
#include "DACL.h" // CDACL class
|
|
#include "SACL.h"
|
|
#include "securitydescriptor.h"
|
|
#include "CToken.h"
|
|
#include "SecureKernelObj.h"
|
|
|
|
#include <cominit.h>
|
|
|
|
#include <autoptr.h>
|
|
#include <scopeguard.h>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CMDH Public interface functions
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
HRESULT CMDH::GetMDData(
|
|
DWORD dwReqProps,
|
|
VARIANT* pvarData)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!pvarData) return E_POINTER;
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = GetMappedDisksAndData(
|
|
dwReqProps,
|
|
pvarData);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CMDH::GetOneMDData(
|
|
BSTR bstrDrive,
|
|
DWORD dwReqProps,
|
|
VARIANT* pvarData)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!pvarData) return E_POINTER;
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = GetSingleMappedDiskAndData(
|
|
bstrDrive,
|
|
dwReqProps,
|
|
pvarData);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CMDH Private internal functions
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// This function does pretty much all of the
|
|
// work this object was constructed to do -
|
|
// it obtains, for the process space that this
|
|
// server is running in, the set of mapped
|
|
// drives, and for each of these, the following
|
|
// information as well:
|
|
//
|
|
HRESULT CMDH::GetMappedDisksAndData(
|
|
DWORD dwReqProps,
|
|
VARIANT* pvarData)
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
::VariantInit(pvarData);
|
|
V_VT(pvarData) = VT_EMPTY;
|
|
|
|
// Get the mapped drives into a vector...
|
|
std::vector<_bstr_t> vecMappedDrives;
|
|
{
|
|
// Impersonate member process...
|
|
SmartRevertTokenHANDLE hCurImpTok;
|
|
hCurImpTok = Impersonate();
|
|
|
|
if(hCurImpTok != INVALID_HANDLE_VALUE)
|
|
{
|
|
GetMappedDriveList(
|
|
vecMappedDrives);
|
|
}
|
|
}
|
|
|
|
// Now allocate the two dimensional
|
|
// safearray that will hold the properties
|
|
// for each mapped drive...
|
|
SAFEARRAY* saDriveProps = NULL;
|
|
SAFEARRAYBOUND rgsabound[2];
|
|
|
|
rgsabound[0].cElements = PROP_COUNT;
|
|
rgsabound[0].lLbound = 0;
|
|
|
|
rgsabound[1].cElements = vecMappedDrives.size();
|
|
rgsabound[1].lLbound = 0;
|
|
|
|
saDriveProps = ::SafeArrayCreate(
|
|
VT_BSTR,
|
|
2,
|
|
rgsabound);
|
|
|
|
if(saDriveProps)
|
|
{
|
|
// For each mapped drive, obtain its
|
|
// properties and store in the safearray...
|
|
for(long m = 0;
|
|
m < vecMappedDrives.size() && SUCCEEDED(hr);
|
|
m++)
|
|
{
|
|
hr = GetMappedDriveInfo(
|
|
vecMappedDrives[m],
|
|
m,
|
|
saDriveProps,
|
|
dwReqProps);
|
|
}
|
|
|
|
// And finally package the safearray
|
|
// into the outgoing variant.
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
::VariantInit(pvarData);
|
|
V_VT(pvarData) = VT_BSTR | VT_ARRAY;
|
|
V_ARRAY(pvarData) = saDriveProps;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Similar to GetMappedDisksAndData, but only
|
|
// retrieves info for a single disk.
|
|
//
|
|
HRESULT CMDH::GetSingleMappedDiskAndData(
|
|
BSTR bstrDrive,
|
|
DWORD dwReqProps,
|
|
VARIANT* pvarData)
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
::VariantInit(pvarData);
|
|
V_VT(pvarData) = VT_EMPTY;
|
|
|
|
// Impersonate member process...
|
|
SmartRevertTokenHANDLE hCurImpTok;
|
|
hCurImpTok = Impersonate();
|
|
|
|
if(hCurImpTok != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Get the mapped drives into a vector...
|
|
std::vector<_bstr_t> vecMappedDrives;
|
|
GetMappedDriveList(
|
|
vecMappedDrives);
|
|
|
|
// Now allocate the two dimensional
|
|
// safearray that will hold the properties
|
|
// for each mapped drive...
|
|
// Note: in this routine, it is really
|
|
// only a one dimensional array, but,
|
|
// for code reuse, we'll treat it as a
|
|
// two dimensional array with only one
|
|
// element in one of the dimensions.
|
|
SAFEARRAY* saDriveProps = NULL;
|
|
SAFEARRAYBOUND rgsabound[2];
|
|
|
|
rgsabound[0].cElements = PROP_COUNT;
|
|
rgsabound[0].lLbound = 0;
|
|
|
|
rgsabound[1].cElements = 1; // for code reuse
|
|
rgsabound[1].lLbound = 0;
|
|
|
|
saDriveProps = ::SafeArrayCreate(
|
|
VT_BSTR,
|
|
2,
|
|
rgsabound);
|
|
|
|
if(saDriveProps)
|
|
{
|
|
// See if the drive specified is a member
|
|
// of the vector.
|
|
_bstr_t bstrtTmp = bstrDrive;
|
|
bstrtTmp += L"\\";
|
|
bool fFoundIt = false;
|
|
|
|
for(long n = 0;
|
|
n < vecMappedDrives.size() && !fFoundIt;
|
|
n++)
|
|
{
|
|
if(_wcsicmp(bstrtTmp, vecMappedDrives[n]) == 0)
|
|
{
|
|
fFoundIt = true;
|
|
n--;
|
|
}
|
|
}
|
|
// For the mapped drive, obtain its
|
|
// properties and store in the safearray...
|
|
if(fFoundIt)
|
|
{
|
|
hr = GetMappedDriveInfo(
|
|
vecMappedDrives[n],
|
|
0, // for code reuse
|
|
saDriveProps,
|
|
dwReqProps);
|
|
|
|
// And finally package the safearray
|
|
// into the outgoing variant.
|
|
::VariantInit(pvarData);
|
|
V_VT(pvarData) = VT_BSTR | VT_ARRAY;
|
|
V_ARRAY(pvarData) = saDriveProps;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Builds a list of mapped drives as
|
|
// seen with respect to the process
|
|
// identified by m_dwImpPID. Hence, this
|
|
// routine will return a valid picture
|
|
// of the drives seen by m_dwImpPID, regardless
|
|
// of our current thread impersonation.
|
|
//
|
|
#ifdef NTONLY // uses ntdll.dll functions
|
|
void CMDH::GetMappedDriveList(
|
|
std::vector<_bstr_t>& vecMappedDrives)
|
|
{
|
|
// Need to call NtQueryInformationProcess,
|
|
// asking for ProcessDeviceMap info, specifying
|
|
// a handle to the process identified by
|
|
// m_dwImpPID.
|
|
|
|
// Need to get a process handle to the
|
|
// process specified by PID.
|
|
NTSTATUS Status;
|
|
|
|
PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
|
|
|
|
Status = ::NtQueryInformationProcess(
|
|
::GetCurrentProcess() /*hProcess*/,
|
|
ProcessDeviceMap,
|
|
&ProcessDeviceMapInfo.Query,
|
|
sizeof(ProcessDeviceMapInfo.Query),
|
|
|
|
NULL);
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
WCHAR wstrDrive[4];
|
|
for(short s = 0;
|
|
s < 32;
|
|
s++)
|
|
{
|
|
if(ProcessDeviceMapInfo.Query.DriveMap & (1<<s))
|
|
{
|
|
wstrDrive[0] = s + L'A';
|
|
wstrDrive[1] = L':';
|
|
wstrDrive[2] = L'\\';
|
|
wstrDrive[3] = L'\0';
|
|
|
|
if(ProcessDeviceMapInfo.Query.DriveType[s] ==
|
|
DOSDEVICE_DRIVE_REMOTE)
|
|
{
|
|
vecMappedDrives.push_back(wstrDrive);
|
|
}
|
|
else if(ProcessDeviceMapInfo.Query.DriveType[s] ==
|
|
DOSDEVICE_DRIVE_CALCULATE)
|
|
{
|
|
// We have more work to do.
|
|
// Create an nt file path...
|
|
WCHAR NtDrivePath[_MAX_PATH] = { '\0' };
|
|
wcscpy(NtDrivePath, L"\\??\\");
|
|
wcscat(NtDrivePath, wstrDrive);
|
|
|
|
// Create the unicode string...
|
|
UNICODE_STRING ustrNtFileName;
|
|
|
|
::RtlInitUnicodeString(
|
|
&ustrNtFileName,
|
|
NtDrivePath);
|
|
|
|
// Get the object attributes...
|
|
OBJECT_ATTRIBUTES oaAttributes;
|
|
|
|
InitializeObjectAttributes(&oaAttributes,
|
|
&ustrNtFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
// Open the file
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
HANDLE hFile = NULL;
|
|
|
|
dwStatus = ::NtOpenFile(
|
|
&hFile,
|
|
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
&oaAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
0);
|
|
|
|
FILE_FS_DEVICE_INFORMATION DeviceInfo;
|
|
|
|
if(NT_SUCCESS(dwStatus))
|
|
{
|
|
try
|
|
{
|
|
// Get information on the file...
|
|
dwStatus = ::NtQueryVolumeInformationFile(
|
|
hFile,
|
|
&IoStatusBlock,
|
|
&DeviceInfo,
|
|
sizeof(DeviceInfo),
|
|
FileFsDeviceInformation);
|
|
|
|
::NtClose(hFile);
|
|
hFile = NULL;
|
|
}
|
|
catch(...)
|
|
{
|
|
::NtClose(hFile);
|
|
hFile = NULL;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
if(NT_SUCCESS(dwStatus))
|
|
{
|
|
if((DeviceInfo.Characteristics & FILE_REMOTE_DEVICE) ||
|
|
(DeviceInfo.DeviceType == FILE_DEVICE_NETWORK ||
|
|
DeviceInfo.DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM))
|
|
{
|
|
// it is a remote drive...
|
|
vecMappedDrives.push_back(wstrDrive);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// All of the routines used in this function -
|
|
// GetProviderName, GetVolumeInformation,
|
|
// and GetDriveFreeSpace, return information
|
|
// for the drive who's mapping string appears
|
|
// in wstrDriveName with respect to that
|
|
// mapping string's meaning in the context of
|
|
// the current thread's impersonation. Hence
|
|
// we impersonate before calling them.
|
|
//
|
|
HRESULT CMDH::GetMappedDriveInfo(
|
|
LPCWSTR wstrDriveName,
|
|
long lDrivePropArrayDriveIndex,
|
|
SAFEARRAY* saDriveProps,
|
|
DWORD dwReqProps)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Right away we can set the device id prop...
|
|
hr = SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_DEVICEID,
|
|
wstrDriveName,
|
|
saDriveProps);
|
|
|
|
// If we couldn't even set the device id, it is
|
|
// a problem. Otherwise, continue.
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Set the other properties if they
|
|
// were requested...
|
|
// Get Expensive properties now if appropriate.
|
|
if(dwReqProps &
|
|
(SPIN_DISK |
|
|
GET_PROVIDER_NAME))
|
|
{
|
|
|
|
// Impersonate member process...
|
|
SmartRevertTokenHANDLE hCurImpTok;
|
|
hCurImpTok = Impersonate();
|
|
|
|
if(dwReqProps & GET_PROVIDER_NAME)
|
|
{
|
|
GetProviderName(
|
|
wstrDriveName,
|
|
lDrivePropArrayDriveIndex,
|
|
saDriveProps);
|
|
}
|
|
|
|
if(dwReqProps & GET_VOL_INFO)
|
|
{
|
|
// Obtain volume information
|
|
GetDriveVolumeInformation(
|
|
wstrDriveName,
|
|
lDrivePropArrayDriveIndex,
|
|
saDriveProps);
|
|
}
|
|
|
|
|
|
if ( dwReqProps &
|
|
(PROP_SIZE |
|
|
PROP_FREE_SPACE) )
|
|
{
|
|
GetDriveFreeSpace(
|
|
wstrDriveName,
|
|
lDrivePropArrayDriveIndex,
|
|
saDriveProps);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Presents a view based on the current
|
|
// impersonation of the current thread.
|
|
//
|
|
HRESULT CMDH::GetProviderName(
|
|
LPCWSTR wstrDriveName,
|
|
long lDrivePropArrayDriveIndex,
|
|
SAFEARRAY* saDriveProps)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WCHAR wstrTempDrive[_MAX_PATH] ;
|
|
wsprintf(
|
|
wstrTempDrive,
|
|
L"%c%c",
|
|
wstrDriveName[0],
|
|
wstrDriveName[1]);
|
|
|
|
WCHAR wstrProvName[_MAX_PATH];
|
|
DWORD dwProvName = sizeof(wstrProvName ) ;
|
|
WCHAR* wstrNewProvName = NULL;
|
|
|
|
// Use of delay loaded function requires exception handler.
|
|
SetStructuredExceptionHandler seh;
|
|
try
|
|
{
|
|
DWORD dwRetCode = ::WNetGetConnection(
|
|
wstrTempDrive,
|
|
wstrProvName,
|
|
&dwProvName);
|
|
|
|
if(dwRetCode == NO_ERROR ||
|
|
dwRetCode == ERROR_CONNECTION_UNAVAIL)
|
|
{
|
|
hr = SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_PROVIDER_NAME,
|
|
wstrProvName,
|
|
saDriveProps);
|
|
}
|
|
else
|
|
{
|
|
dwRetCode = GetLastError();
|
|
|
|
if((dwRetCode == ERROR_MORE_DATA) &&
|
|
(dwProvName > _MAX_PATH))
|
|
{
|
|
wstrNewProvName = new WCHAR[dwProvName];
|
|
if(wstrNewProvName != NULL)
|
|
{
|
|
dwRetCode = ::WNetGetConnection(
|
|
wstrTempDrive,
|
|
wstrNewProvName,
|
|
&dwProvName);
|
|
|
|
if(dwRetCode == NO_ERROR ||
|
|
dwRetCode == ERROR_CONNECTION_UNAVAIL)
|
|
{
|
|
hr = SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_PROVIDER_NAME,
|
|
wstrNewProvName,
|
|
saDriveProps);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwRetCode);
|
|
}
|
|
|
|
delete wstrNewProvName;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwRetCode);
|
|
}
|
|
}
|
|
}
|
|
catch(Structured_Exception se)
|
|
{
|
|
DelayLoadDllExceptionFilter(se.GetExtendedInfo());
|
|
if(wstrNewProvName)
|
|
{
|
|
delete wstrNewProvName;
|
|
wstrNewProvName = NULL;
|
|
}
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
catch(...)
|
|
{
|
|
if(wstrNewProvName)
|
|
{
|
|
delete wstrNewProvName;
|
|
wstrNewProvName = NULL;
|
|
}
|
|
// The filter will do the work. Just re-throw here.
|
|
throw;
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// Presents a view based on the current
|
|
// impersonation of the current thread.
|
|
//
|
|
HRESULT CMDH::GetDriveVolumeInformation(
|
|
LPCWSTR wstrDriveName,
|
|
long lDrivePropArrayDriveIndex,
|
|
SAFEARRAY* saDriveProps)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
|
|
WCHAR wstrVolumeName[_MAX_PATH];
|
|
WCHAR wstrFileSystem[_MAX_PATH];
|
|
WCHAR wstrTmp[_MAX_PATH];
|
|
DWORD dwSerialNumber;
|
|
DWORD dwMaxComponentLength;
|
|
DWORD dwFSFlags;
|
|
|
|
BOOL fReturn = ::GetVolumeInformation(
|
|
wstrDriveName,
|
|
wstrVolumeName,
|
|
sizeof(wstrVolumeName)/sizeof(WCHAR),
|
|
&dwSerialNumber,
|
|
&dwMaxComponentLength,
|
|
&dwFSFlags,
|
|
wstrFileSystem,
|
|
sizeof(wstrFileSystem)/sizeof(WCHAR)
|
|
);
|
|
|
|
if(fReturn)
|
|
{
|
|
// Win32 API will return volume information for all drive types.
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_VOLUME_NAME,
|
|
wstrVolumeName,
|
|
saDriveProps);
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_FILE_SYSTEM,
|
|
wstrFileSystem,
|
|
saDriveProps);
|
|
|
|
if (dwSerialNumber != 0)
|
|
{
|
|
WCHAR wstrSerialNumber[_MAX_PATH];
|
|
wsprintf(wstrSerialNumber,
|
|
L"%.8X",
|
|
dwSerialNumber);
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_VOLUME_SERIAL_NUMBER,
|
|
wstrSerialNumber,
|
|
saDriveProps);
|
|
}
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_COMPRESSED,
|
|
STR_FROM_bool(dwFSFlags & FS_VOL_IS_COMPRESSED),
|
|
saDriveProps);
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_SUPPORTS_FILE_BASED_COMPRESSION,
|
|
STR_FROM_bool(dwFSFlags & FS_FILE_COMPRESSION),
|
|
saDriveProps);
|
|
|
|
_ultow(dwMaxComponentLength,
|
|
wstrTmp,
|
|
10);
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_MAXIMUM_COMPONENT_LENGTH,
|
|
wstrTmp,
|
|
saDriveProps);
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_SUPPORTS_DISK_QUOTAS,
|
|
STR_FROM_bool(dwFSFlags & FILE_VOLUME_QUOTAS),
|
|
saDriveProps);
|
|
|
|
|
|
|
|
// To get the state of the volume,
|
|
// we need to get the Interface pointer...
|
|
IDiskQuotaControlPtr pIQuotaControl;
|
|
::SetLastError(ERROR_SUCCESS);
|
|
|
|
if(SUCCEEDED(CoCreateInstance(
|
|
CLSID_DiskQuotaControl,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDiskQuotaControl,
|
|
(void **)&pIQuotaControl)))
|
|
{
|
|
WCHAR wstrVolumePathName[MAX_PATH + 1];
|
|
::SetLastError(ERROR_SUCCESS);
|
|
|
|
BOOL fRetVal = FALSE;
|
|
|
|
CKernel32Api* pKernel32 = NULL;
|
|
pKernel32 = (CKernel32Api*)CResourceManager::sm_TheResourceManager.GetResource(
|
|
g_guidKernel32Api, NULL);
|
|
|
|
try
|
|
{
|
|
if(pKernel32)
|
|
{
|
|
pKernel32->GetVolumePathName(
|
|
wstrDriveName,
|
|
wstrVolumePathName,
|
|
MAX_PATH,
|
|
&fRetVal);
|
|
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource(
|
|
g_guidKernel32Api, pKernel32);
|
|
|
|
pKernel32 = NULL;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(pKernel32)
|
|
{
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource(
|
|
g_guidKernel32Api, pKernel32);
|
|
}
|
|
throw;
|
|
}
|
|
|
|
if(fRetVal)
|
|
{
|
|
::SetLastError(ERROR_SUCCESS);
|
|
if(SUCCEEDED(pIQuotaControl->Initialize(
|
|
wstrVolumePathName,
|
|
TRUE)))
|
|
{
|
|
DWORD dwQuotaState;
|
|
::SetLastError(ERROR_SUCCESS);
|
|
|
|
hr = pIQuotaControl->GetQuotaState(&dwQuotaState);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_QUOTAS_INCOMPLETE,
|
|
STR_FROM_bool(DISKQUOTA_FILE_INCOMPLETE(dwQuotaState)),
|
|
saDriveProps);
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_QUOTAS_REBUILDING,
|
|
STR_FROM_bool(DISKQUOTA_FILE_REBUILDING(dwQuotaState)),
|
|
saDriveProps);
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_QUOTAS_DISABLED,
|
|
STR_FROM_bool(DISKQUOTA_STATE_DISABLED & dwQuotaState),
|
|
saDriveProps);
|
|
}
|
|
else
|
|
{
|
|
dwResult = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwResult = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwResult = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwResult = GetLastError();
|
|
}
|
|
|
|
// for chkdsk VolumeDirty Property
|
|
BOOLEAN fVolumeDirty = FALSE;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
_bstr_t bstrtDosDrive(wstrDriveName);
|
|
UNICODE_STRING string = { 0 };
|
|
_bstr_t nt_drive_name;
|
|
|
|
try
|
|
{
|
|
if ( RtlDosPathNameToNtPathName_U (
|
|
(LPCWSTR)bstrtDosDrive,
|
|
&string,
|
|
NULL,
|
|
NULL
|
|
)
|
|
)
|
|
{
|
|
string.Buffer[string.Length/sizeof(WCHAR) - 1] = 0;
|
|
nt_drive_name = string.Buffer;
|
|
|
|
if(string.Buffer)
|
|
{
|
|
RtlFreeUnicodeString(&string);
|
|
string.Buffer = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwResult = RtlNtStatusToDosError ( (NTSTATUS)NtCurrentTeb()->LastStatusValue );
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(string.Buffer)
|
|
{
|
|
RtlFreeUnicodeString(&string);
|
|
string.Buffer = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
|
|
if ( dwResult == ERROR_SUCCESS )
|
|
{
|
|
::SetLastError(ERROR_SUCCESS);
|
|
fSuccess = IsVolumeDirty(
|
|
nt_drive_name,
|
|
&fVolumeDirty );
|
|
|
|
if(fSuccess)
|
|
{
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_PERFORM_AUTOCHECK,
|
|
STR_FROM_bool(!fVolumeDirty),
|
|
saDriveProps);
|
|
}
|
|
else
|
|
{
|
|
dwResult = GetLastError();
|
|
}
|
|
}
|
|
|
|
if(dwResult != ERROR_SUCCESS)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwResult);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// Presents a view based on the current
|
|
// impersonation of the current thread.
|
|
//
|
|
BOOLEAN CMDH::IsVolumeDirty(
|
|
_bstr_t &bstrtNtDriveName,
|
|
BOOLEAN *Result)
|
|
{
|
|
UNICODE_STRING u;
|
|
OBJECT_ATTRIBUTES obj;
|
|
NTSTATUS status = 0;
|
|
IO_STATUS_BLOCK iosb;
|
|
HANDLE h = 0;
|
|
ULONG r = 0;
|
|
BOOLEAN bRetVal = FALSE;
|
|
WCHAR wstrNtDriveName[_MAX_PATH];
|
|
|
|
wcscpy(wstrNtDriveName, bstrtNtDriveName);
|
|
u.Length = (USHORT) wcslen(wstrNtDriveName) * sizeof(WCHAR);
|
|
u.MaximumLength = u.Length;
|
|
u.Buffer = wstrNtDriveName;
|
|
|
|
InitializeObjectAttributes(&obj, &u, OBJ_CASE_INSENSITIVE, 0, 0);
|
|
|
|
status = NtOpenFile(
|
|
&h,
|
|
SYNCHRONIZE | FILE_READ_DATA,
|
|
&obj,
|
|
&iosb,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
try
|
|
{
|
|
status = NtFsControlFile(
|
|
h, NULL, NULL, NULL,
|
|
&iosb,
|
|
FSCTL_IS_VOLUME_DIRTY,
|
|
NULL, 0,
|
|
&r, sizeof(r));
|
|
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
|
|
#if(_WIN32_WINNT >= 0x0500)
|
|
*Result = (BOOLEAN)(r & VOLUME_IS_DIRTY);
|
|
#else
|
|
*Result = (BOOLEAN)r;
|
|
#endif
|
|
bRetVal = TRUE;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
NtClose(h);
|
|
h = 0;
|
|
throw;
|
|
}
|
|
|
|
NtClose(h);
|
|
h = 0;
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
|
|
|
|
// Presents a view based on the current
|
|
// impersonation of the current thread.
|
|
//
|
|
HRESULT CMDH::GetDriveFreeSpace(
|
|
LPCWSTR wstrDriveName,
|
|
long lDrivePropArrayDriveIndex,
|
|
SAFEARRAY* saDriveProps)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ULARGE_INTEGER uliTotalBytes;
|
|
ULARGE_INTEGER uliUserFreeBytes;
|
|
ULARGE_INTEGER uliTotalFreeBytes;
|
|
|
|
::SetLastError(ERROR_SUCCESS);
|
|
if(::GetDiskFreeSpaceEx(
|
|
wstrDriveName,
|
|
&uliUserFreeBytes,
|
|
&uliTotalBytes,
|
|
&uliTotalFreeBytes))
|
|
{
|
|
WCHAR wstrTmp[128] = { L'\0' };
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_SIZE,
|
|
_ui64tow(
|
|
uliTotalBytes.QuadPart,
|
|
wstrTmp,
|
|
10),
|
|
saDriveProps);
|
|
|
|
SetProperty(
|
|
lDrivePropArrayDriveIndex,
|
|
PROP_FREE_SPACE,
|
|
_ui64tow(
|
|
uliTotalFreeBytes.QuadPart,
|
|
wstrTmp,
|
|
10),
|
|
saDriveProps);
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// Sets a property for a given drive
|
|
// in the drive safearray.
|
|
//
|
|
HRESULT CMDH::SetProperty(
|
|
long lDrivePropArrayDriveIndex,
|
|
long lDrivePropArrayPropIndex,
|
|
LPCWSTR wstrPropValue,
|
|
SAFEARRAY* saDriveProps)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
bstr_t bstrTmp( wstrPropValue); // this will work because PutElement makes a copy
|
|
long ix[2];
|
|
ix[0] = lDrivePropArrayPropIndex;
|
|
ix[1] = lDrivePropArrayDriveIndex;
|
|
|
|
hr = ::SafeArrayPutElement(saDriveProps, ix, (void *)((BSTR)bstrTmp));
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Sets our current thread's impersonation
|
|
// to the token belonging to the process
|
|
// identified by our member, m_dwImpPID.
|
|
//
|
|
HANDLE CMDH::Impersonate()
|
|
{
|
|
HANDLE hCurToken = INVALID_HANDLE_VALUE;
|
|
|
|
// Find the explorer process...
|
|
if(m_dwImpPID != -1L)
|
|
{
|
|
//
|
|
// get SID of current process
|
|
//
|
|
CSid csidCurrentProcess;
|
|
{
|
|
//
|
|
// get process credentials
|
|
// and try to get client's back when leaving scope
|
|
//
|
|
|
|
WbemCoRevertToSelf () ;
|
|
ScopeGuard SmartWbemCoImpersonateClientFnc = MakeGuard ( WbemCoImpersonateClient ) ;
|
|
|
|
CProcessToken cpt ( NULL, true, TOKEN_QUERY ) ;
|
|
|
|
PBYTE buff = NULL ;
|
|
DWORD dwBuff = 0L ;
|
|
|
|
if ( FALSE == ::GetTokenInformation (
|
|
cpt.GetTokenHandle () ,
|
|
TokenUser ,
|
|
NULL ,
|
|
0 ,
|
|
&dwBuff
|
|
)
|
|
)
|
|
{
|
|
if ( ERROR_INSUFFICIENT_BUFFER == ::GetLastError () )
|
|
{
|
|
buff = new BYTE [ dwBuff ] ;
|
|
wmilib::auto_buffer < BYTE > SmartBuff ( buff ) ;
|
|
|
|
if ( TRUE == ::GetTokenInformation (
|
|
cpt.GetTokenHandle () ,
|
|
TokenUser ,
|
|
buff ,
|
|
dwBuff ,
|
|
&dwBuff
|
|
)
|
|
)
|
|
{
|
|
csidCurrentProcess = CSid ( ( ( PTOKEN_USER ) buff )->User.Sid ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
SmartWbemCoImpersonateClientFnc.Dismiss () ;
|
|
|
|
HRESULT t_hResult = S_OK ;
|
|
if ( FAILED ( t_hResult = WbemCoImpersonateClient () ) )
|
|
{
|
|
throw CFramework_Exception( L"CoImpersonateClient failed", t_hResult ) ;
|
|
}
|
|
}
|
|
|
|
if ( csidCurrentProcess.IsValid () )
|
|
{
|
|
//
|
|
// smart CloseHandle
|
|
//
|
|
ScopeGuard SmartCloseHandleFnc = MakeGuard ( CloseHandle, hCurToken ) ;
|
|
|
|
bool fOK = false;
|
|
|
|
if(::OpenThreadToken(
|
|
::GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&hCurToken))
|
|
{
|
|
SmartCloseHandle hProcess;
|
|
hProcess = ::OpenProcess(
|
|
PROCESS_QUERY_INFORMATION,
|
|
FALSE,
|
|
m_dwImpPID);
|
|
|
|
if(hProcess != INVALID_HANDLE_VALUE)
|
|
{
|
|
// now open its token...
|
|
SmartCloseHandle hProcToken;
|
|
if(::OpenProcessToken(
|
|
hProcess,
|
|
TOKEN_READ | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
|
|
&hProcToken))
|
|
{
|
|
CProcessToken cpt ( hProcToken );
|
|
if ( cpt.IsValidToken () )
|
|
{
|
|
TOKEN_TYPE type;
|
|
if ( cpt.GetTokenType ( type ) )
|
|
{
|
|
if ( TokenPrimary == type )
|
|
{
|
|
CToken ct;
|
|
if ( ct.Duplicate ( cpt, FALSE ) )
|
|
{
|
|
// Set the thread token...
|
|
if(::SetThreadToken(NULL, ct.GetTokenHandle ()))
|
|
{
|
|
fOK = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
|
|
// Set the thread token...
|
|
if(::SetThreadToken(NULL, cpt.GetTokenHandle ()))
|
|
{
|
|
fOK = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SmartCloseHandleFnc.Dismiss () ;
|
|
if(!fOK)
|
|
{
|
|
if(hCurToken != INVALID_HANDLE_VALUE)
|
|
{
|
|
::CloseHandle(hCurToken);
|
|
hCurToken = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL bSucceeded = FALSE ;
|
|
|
|
//
|
|
// need to adjust SD associated with thread
|
|
// to contain current process' SID
|
|
//
|
|
|
|
CThreadToken ctt;
|
|
if ( ctt.IsValidToken () )
|
|
{
|
|
// Obtain access to its security descriptor...
|
|
CSecureKernelObj sko(ctt.GetTokenHandle(), FALSE);
|
|
// Modify the security descriptor...
|
|
if( sko.AddDACLEntry (
|
|
csidCurrentProcess,
|
|
ENUM_ACCESS_ALLOWED_ACE_TYPE,
|
|
TOKEN_ALL_ACCESS,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
))
|
|
{
|
|
if ( ERROR_SUCCESS == sko.ApplySecurity( DACL_SECURITY_INFORMATION ) )
|
|
{
|
|
bSucceeded = TRUE ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( FALSE == bSucceeded )
|
|
{
|
|
//
|
|
// we need to revert back as SD was
|
|
// not successfully adjusted
|
|
//
|
|
|
|
if ( ! ::SetThreadToken ( NULL, hCurToken ) )
|
|
{
|
|
::CloseHandle ( hCurToken ) ;
|
|
throw CFramework_Exception(L"SetThreadToken failed", GetLastError());
|
|
}
|
|
|
|
::CloseHandle ( hCurToken ) ;
|
|
hCurToken = INVALID_HANDLE_VALUE ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hCurToken;
|
|
}
|