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.
1045 lines
34 KiB
1045 lines
34 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2002-2004 Microsoft Corporation
|
|
//
|
|
// Module Name: Quota.cpp
|
|
//
|
|
// Description:
|
|
// Implementation of VDS WMI Provider quota classes
|
|
//
|
|
// Author: Jim Benton (jbenton) 25-Mar-2002
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Pch.h"
|
|
#include "Quota.h"
|
|
#include "volutil.h"
|
|
|
|
#define INITGUIDS
|
|
#include "dskquota.h"
|
|
|
|
HRESULT FindQuotaUserFromEnum(
|
|
WCHAR* pwszUser,
|
|
IDiskQuotaControl* pIDQC,
|
|
IDiskQuotaUser** ppQuotaUser);
|
|
|
|
HRESULT FindQuotaUserWithRecord(
|
|
IN _bstr_t bstrDomain,
|
|
IN _bstr_t bstrUser,
|
|
IN IDiskQuotaControl* pIDQC,
|
|
OUT IDiskQuotaUser** ppIQuotaUser);
|
|
|
|
HRESULT FindQuotaUser(
|
|
IN _bstr_t bstrDomain,
|
|
IN _bstr_t bstrUser,
|
|
IN IDiskQuotaControl* pIDQC,
|
|
OUT IDiskQuotaUser** ppIQuotaUser);
|
|
|
|
BOOL TranslateDomainName(
|
|
IN WCHAR* pwszDomain,
|
|
OUT CVssAutoPWSZ& rawszDomain);
|
|
|
|
BOOL GetLocalDomainName(
|
|
IN DWORD dwWellKnownAuthority,
|
|
OUT CVssAutoPWSZ& rawszDomain);
|
|
|
|
|
|
//****************************************************************************
|
|
//
|
|
// CVolumeQuota
|
|
//
|
|
//****************************************************************************
|
|
|
|
CVolumeQuota::CVolumeQuota(
|
|
IN LPCWSTR pwszName,
|
|
IN CWbemServices* pNamespace
|
|
)
|
|
: CProvBase(pwszName, pNamespace)
|
|
{
|
|
|
|
} //*** CVolumeQuota::CVolumeQuota()
|
|
|
|
CProvBase *
|
|
CVolumeQuota::S_CreateThis(
|
|
IN LPCWSTR pwszName,
|
|
IN CWbemServices* pNamespace
|
|
)
|
|
{
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
CVolumeQuota * pObj= NULL;
|
|
|
|
pObj = new CVolumeQuota(pwszName, pNamespace);
|
|
|
|
if (pObj)
|
|
{
|
|
hr = pObj->Initialize();
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
delete pObj;
|
|
pObj = NULL;
|
|
}
|
|
return pObj;
|
|
|
|
} //*** CVolumeQuota::S_CreateThis()
|
|
|
|
|
|
HRESULT
|
|
CVolumeQuota::Initialize()
|
|
{
|
|
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeQuota::Initialize");
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
HRESULT
|
|
CVolumeQuota::EnumInstance(
|
|
IN long lFlags,
|
|
IN IWbemContext* pCtx,
|
|
IN IWbemObjectSink * pHandler
|
|
)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeQuota::EnumInstance");
|
|
CVssAutoPWSZ awszVolume;
|
|
|
|
try
|
|
{
|
|
awszVolume.Allocate(MAX_PATH);
|
|
|
|
CVssVolumeIterator volumeIterator;
|
|
|
|
while (true)
|
|
{
|
|
DWORD dwDontCare = 0;
|
|
DWORD dwFileSystemFlags = 0;
|
|
|
|
// Get the volume name
|
|
if (!volumeIterator.SelectNewVolume(ft, awszVolume, MAX_PATH))
|
|
break;
|
|
|
|
if (VolumeSupportsQuotas(awszVolume))
|
|
{
|
|
CComPtr<IWbemClassObject> spInstance;
|
|
WCHAR wszDisplayName[MAX_PATH+1] ;
|
|
|
|
// The key property on the QuotaSetting object is the display name
|
|
VssGetVolumeDisplayName(
|
|
awszVolume,
|
|
wszDisplayName,
|
|
MAX_PATH);
|
|
|
|
ft.hr = m_pClass->SpawnInstance(0, &spInstance);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
|
|
|
|
LoadInstance(awszVolume, wszDisplayName, spInstance.p);
|
|
|
|
ft.hr = pHandler->Indicate(1, &spInstance.p);
|
|
}
|
|
}
|
|
}
|
|
catch (HRESULT hrEx)
|
|
{
|
|
ft.hr = hrEx;
|
|
}
|
|
|
|
return ft.hr;
|
|
|
|
} //*** CVolumeQuota::EnumInstance()
|
|
|
|
void
|
|
CVolumeQuota:: LoadInstance(
|
|
IN WCHAR* pwszVolume,
|
|
IN WCHAR* pwszQuotaSetting,
|
|
IN OUT IWbemClassObject* pObject)
|
|
{
|
|
CWbemClassObject wcoInstance(pObject);
|
|
CObjPath pathQuotaSetting;
|
|
CObjPath pathVolume;
|
|
|
|
// Set the QuotaSetting Ref property
|
|
pathQuotaSetting.Init(PVDR_CLASS_QUOTASETTING);
|
|
pathQuotaSetting.AddProperty(PVDR_PROP_VOLUMEPATH, pwszQuotaSetting);
|
|
wcoInstance.SetProperty((wchar_t*)pathQuotaSetting.GetObjectPathString(), PVD_WBEM_PROP_SETTING);
|
|
|
|
// Set the Volume Ref property
|
|
pathVolume.Init(PVDR_CLASS_VOLUME);
|
|
pathVolume.AddProperty(PVDR_PROP_DEVICEID, pwszVolume);
|
|
wcoInstance.SetProperty((wchar_t*)pathVolume.GetObjectPathString(), PVD_WBEM_PROP_ELEMENT);
|
|
}
|
|
|
|
//****************************************************************************
|
|
//
|
|
// CVolumeUserQuota
|
|
//
|
|
//****************************************************************************
|
|
|
|
CVolumeUserQuota::CVolumeUserQuota(
|
|
IN LPCWSTR pwszName,
|
|
IN CWbemServices* pNamespace
|
|
)
|
|
: CProvBase(pwszName, pNamespace)
|
|
{
|
|
|
|
} //*** CVolumeUserQuota::CVolumeUserQuota()
|
|
|
|
CProvBase *
|
|
CVolumeUserQuota::S_CreateThis(
|
|
IN LPCWSTR pwszName,
|
|
IN CWbemServices* pNamespace
|
|
)
|
|
{
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
CVolumeUserQuota * pObj= NULL;
|
|
|
|
pObj = new CVolumeUserQuota(pwszName, pNamespace);
|
|
|
|
if (pObj)
|
|
{
|
|
hr = pObj->Initialize();
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
delete pObj;
|
|
pObj = NULL;
|
|
}
|
|
return pObj;
|
|
|
|
} //*** CVolumeUserQuota::S_CreateThis()
|
|
|
|
|
|
HRESULT
|
|
CVolumeUserQuota::Initialize()
|
|
{
|
|
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::Initialize");
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
HRESULT
|
|
CVolumeUserQuota::EnumInstance(
|
|
IN long lFlags,
|
|
IN IWbemContext* pCtx,
|
|
IN IWbemObjectSink * pHandler
|
|
)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::EnumInstance");
|
|
CVssAutoPWSZ awszVolume;
|
|
|
|
try
|
|
{
|
|
awszVolume.Allocate(MAX_PATH);
|
|
|
|
CVssVolumeIterator volumeIterator;
|
|
|
|
while (true)
|
|
{
|
|
DWORD dwDontCare = 0;
|
|
DWORD dwFileSystemFlags = 0;
|
|
|
|
// Get the volume name
|
|
if (!volumeIterator.SelectNewVolume(ft, awszVolume, MAX_PATH))
|
|
break;
|
|
|
|
if (VolumeSupportsQuotas(awszVolume))
|
|
{
|
|
CComPtr<IDiskQuotaControl> spIDQC;
|
|
IDiskQuotaControl* pIDQC = NULL;
|
|
CComPtr<IEnumDiskQuotaUsers> spIEnum;
|
|
|
|
ft.hr = CoCreateInstance(
|
|
CLSID_DiskQuotaControl,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDiskQuotaControl,
|
|
(void **)&pIDQC);
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl");
|
|
}
|
|
|
|
spIDQC.Attach(pIDQC);
|
|
|
|
ft.hr = spIDQC->Initialize(awszVolume, FALSE /* read only */);
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaControl::Initialize failed for volume %lS", awszVolume);
|
|
continue;
|
|
}
|
|
|
|
// Need to update the cache, else we can get old names
|
|
ft.hr = spIDQC->InvalidateSidNameCache();
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaControl::InvalidateSidNameCache failed for volume %lS", awszVolume);
|
|
continue;
|
|
}
|
|
|
|
ft.hr = spIDQC->CreateEnumUsers(
|
|
NULL, //All the users will be enumerated
|
|
0, // Ignored for enumerating all users
|
|
DISKQUOTA_USERNAME_RESOLVE_SYNC,
|
|
&spIEnum );
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaControl::CreateEnumUsers failed for volume %lS", awszVolume);
|
|
continue;
|
|
}
|
|
|
|
if (spIEnum != NULL)
|
|
{
|
|
while (true)
|
|
{
|
|
CComPtr<IWbemClassObject> spInstance;
|
|
CComPtr<IDiskQuotaUser> spIQuotaUser;
|
|
DWORD cUsers = 0;
|
|
|
|
ft.hr = spIEnum->Next(1, &spIQuotaUser, &cUsers);
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.Trace(VSSDBG_VSSADMIN, L"IEnumDiskQuotaUsers::Next failed for volume %lS", awszVolume);
|
|
continue;
|
|
}
|
|
|
|
if (ft.hr == S_FALSE)
|
|
break;
|
|
|
|
ft.hr = m_pClass->SpawnInstance(0, &spInstance);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
|
|
|
|
LoadInstance(awszVolume, spIQuotaUser, spInstance.p);
|
|
|
|
ft.hr = pHandler->Indicate(1, &spInstance.p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (HRESULT hrEx)
|
|
{
|
|
ft.hr = hrEx;
|
|
}
|
|
|
|
return ft.hr;
|
|
|
|
} //*** CVolumeUserQuota::EnumInstance()
|
|
|
|
HRESULT
|
|
CVolumeUserQuota::GetObject(
|
|
IN CObjPath& rObjPath,
|
|
IN long lFlags,
|
|
IN IWbemContext* pCtx,
|
|
IN IWbemObjectSink* pHandler
|
|
)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::GetObject");
|
|
|
|
try
|
|
{
|
|
_bstr_t bstrVolumeRef, bstrVolumeName;
|
|
_bstr_t bstrAccountRef, bstrDomainName, bstrUserName;
|
|
CObjPath objPathVolume;
|
|
CObjPath objPathAccount;
|
|
CComPtr<IWbemClassObject> spInstance;
|
|
CComPtr<IDiskQuotaUser> spIQuotaUser;
|
|
CComPtr<IDiskQuotaControl> spIDQC;
|
|
IDiskQuotaControl* pIDQC = NULL;
|
|
_bstr_t bstrFQUser;
|
|
|
|
// Get the Volume reference
|
|
bstrVolumeRef = rObjPath.GetStringValueForProperty(PVDR_PROP_VOLUME);
|
|
|
|
// Get the Account reference
|
|
bstrAccountRef = rObjPath.GetStringValueForProperty(PVDR_PROP_ACCOUNT);
|
|
|
|
// Extract the Volume and Account Names
|
|
objPathVolume.Init(bstrVolumeRef);
|
|
objPathAccount.Init(bstrAccountRef);
|
|
|
|
bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
|
|
if ((wchar_t*)bstrVolumeName == NULL || ((wchar_t*)bstrVolumeName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property DeviceID not found");
|
|
}
|
|
|
|
bstrUserName = objPathAccount.GetStringValueForProperty(PVDR_PROP_NAME);
|
|
if ((wchar_t*)bstrUserName == NULL || ((wchar_t*)bstrUserName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Name not found");
|
|
}
|
|
|
|
bstrDomainName = objPathAccount.GetStringValueForProperty(PVDR_PROP_DOMAIN);
|
|
if ((wchar_t*)bstrDomainName == NULL || ((wchar_t*)bstrDomainName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Domain not found");
|
|
}
|
|
|
|
ft.hr = CoCreateInstance(
|
|
CLSID_DiskQuotaControl,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDiskQuotaControl,
|
|
(void **)&pIDQC);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl, %#x", ft.hr);
|
|
|
|
spIDQC.Attach(pIDQC);
|
|
|
|
ft.hr = spIDQC->Initialize(bstrVolumeName, TRUE /* read/write */);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IDiskQuotaControl::Initialize failed for volume %lS, %#x", bstrVolumeName, ft.hr);
|
|
|
|
ft.hr = FindQuotaUser(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.hr = WBEM_E_NOT_FOUND;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolumeQuotaUser::GetObject: could not find user %lS\\%lS", bstrDomainName, bstrUserName);
|
|
}
|
|
|
|
ft.hr = m_pClass->SpawnInstance(0, &spInstance);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
|
|
|
|
LoadInstance(bstrVolumeName, spIQuotaUser, spInstance.p);
|
|
|
|
ft.hr = pHandler->Indicate(1, &spInstance.p);
|
|
}
|
|
catch (HRESULT hrEx)
|
|
{
|
|
ft.hr = hrEx;
|
|
}
|
|
|
|
return ft.hr;
|
|
|
|
} //*** CVolume::GetObject()
|
|
|
|
|
|
void
|
|
CVolumeUserQuota:: LoadInstance(
|
|
IN WCHAR* pwszVolume,
|
|
IN IDiskQuotaUser* pIQuotaUser,
|
|
IN OUT IWbemClassObject* pObject)
|
|
{
|
|
CWbemClassObject wcoInstance(pObject);
|
|
CObjPath pathAccount;
|
|
CObjPath pathVolume;
|
|
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::LoadInstance");
|
|
|
|
do
|
|
{
|
|
WCHAR wszDomain[g_cchAccountNameMax], *pwszDomain = NULL;
|
|
WCHAR wszFQUser[g_cchAccountNameMax], *pwszUser = NULL;
|
|
CVssAutoPWSZ awszDomain;
|
|
DISKQUOTA_USER_INFORMATION UserQuotaInfo;
|
|
DWORD dwStatus = 0;
|
|
|
|
ft.hr = pIQuotaUser->GetName(wszDomain, g_cchAccountNameMax,
|
|
wszFQUser, g_cchAccountNameMax, NULL, 0);
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaUser::GetName failed for volume %lS", pwszVolume);
|
|
break;
|
|
}
|
|
|
|
// Win32_Account separates domain\user into two keys, Domain and Name
|
|
|
|
// Prepare the Domain and Name keys
|
|
pwszUser = wcschr(wszFQUser, L'\\'); // user name is domain\\name format
|
|
if (pwszUser != NULL)
|
|
{
|
|
pwszDomain = wszFQUser;
|
|
*pwszUser = L'\0';
|
|
pwszUser++;
|
|
}
|
|
else
|
|
{
|
|
pwszDomain = wcschr(wszFQUser, L'@'); // user name is [email protected] format
|
|
if (pwszDomain != NULL)
|
|
{
|
|
pwszUser = wszFQUser;
|
|
*pwszDomain = L'\0';
|
|
pwszDomain++;
|
|
|
|
WCHAR* pwc = wcschr(pwszDomain, L'.');
|
|
if (pwc != NULL)
|
|
*pwc = L'\0';
|
|
}
|
|
else
|
|
{
|
|
pwszDomain = wszDomain;
|
|
pwszUser = wszFQUser;
|
|
}
|
|
}
|
|
|
|
// The GetName API returns BUILTIN and NT AUTHORITY
|
|
// as the domain name for built-in local accounts.
|
|
// BUILTIN and NT AUTHORITY accounts are represented
|
|
// by Win32_Account and its children with the domain
|
|
// name being the name of the machine, instead of
|
|
// either of these strings. We'll convert the domain name here.
|
|
|
|
TranslateDomainName(pwszDomain, awszDomain);
|
|
|
|
ft.hr = pIQuotaUser->GetQuotaInformation(&UserQuotaInfo, sizeof(UserQuotaInfo));
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaUser::GetQuotaInformation failed for volume %lS", pwszVolume);
|
|
break;
|
|
}
|
|
|
|
// Set the Account Ref property
|
|
pathAccount.Init(PVDR_CLASS_ACCOUNT);
|
|
pathAccount.AddProperty(PVDR_PROP_DOMAIN, awszDomain);
|
|
pathAccount.AddProperty(PVDR_PROP_NAME, pwszUser);
|
|
wcoInstance.SetProperty((wchar_t*)pathAccount.GetObjectPathString(), PVDR_PROP_ACCOUNT);
|
|
|
|
// Set the Volume Ref property
|
|
pathVolume.Init(PVDR_CLASS_VOLUME);
|
|
pathVolume.AddProperty(PVDR_PROP_DEVICEID, pwszVolume);
|
|
wcoInstance.SetProperty((wchar_t*)pathVolume.GetObjectPathString(), PVDR_PROP_VOLUME);
|
|
|
|
wcoInstance.SetPropertyI64((ULONGLONG)UserQuotaInfo.QuotaUsed, PVDR_PROP_DISKSPACEUSED);
|
|
wcoInstance.SetPropertyI64((ULONGLONG)UserQuotaInfo.QuotaThreshold, PVDR_PROP_WARNINGLIMIT);
|
|
wcoInstance.SetPropertyI64((ULONGLONG)UserQuotaInfo.QuotaLimit, PVDR_PROP_LIMIT);
|
|
|
|
|
|
if (UserQuotaInfo.QuotaLimit == -1)
|
|
dwStatus = 0; // OK, no limit set
|
|
else
|
|
{
|
|
if (UserQuotaInfo.QuotaUsed >= UserQuotaInfo.QuotaLimit)
|
|
dwStatus = 2; // Limit exceeded
|
|
else if (UserQuotaInfo.QuotaUsed >= UserQuotaInfo.QuotaThreshold)
|
|
dwStatus = 1; // Warning limit exceeded
|
|
else
|
|
dwStatus = 0; // OK, under the warning limit
|
|
}
|
|
|
|
wcoInstance.SetProperty(dwStatus, PVDR_PROP_STATUS);
|
|
}
|
|
while(false);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CVolumeUserQuota::PutInstance(
|
|
IN CWbemClassObject& rInstToPut,
|
|
IN long lFlag,
|
|
IN IWbemContext* pCtx,
|
|
IN IWbemObjectSink* pHandler
|
|
)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::PutInstance");
|
|
|
|
try
|
|
{
|
|
_bstr_t bstrVolumeRef, bstrVolumeName;
|
|
_bstr_t bstrAccountRef, bstrDomainName, bstrUserName;
|
|
CObjPath objPathVolume;
|
|
CObjPath objPathAccount;
|
|
_bstr_t bstrFQUser;
|
|
CComPtr<IDiskQuotaUser> spIQuotaUser;
|
|
CComPtr<IDiskQuotaControl> spIDQC;
|
|
IDiskQuotaControl* pIDQC = NULL;
|
|
BOOL fCreate = FALSE;
|
|
BOOL fUpdate = FALSE;
|
|
LONGLONG llLimit = -1, llThreshold = -1;
|
|
|
|
// Retrieve key properties of the object to be saved.
|
|
rInstToPut.GetProperty(bstrVolumeRef, PVDR_PROP_VOLUME);
|
|
rInstToPut.GetProperty(bstrAccountRef, PVDR_PROP_ACCOUNT);
|
|
|
|
// Extract the Volume, Domain and User names
|
|
objPathVolume.Init(bstrVolumeRef);
|
|
objPathAccount.Init(bstrAccountRef);
|
|
|
|
bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
|
|
if ((wchar_t*)bstrVolumeName == NULL || ((wchar_t*)bstrVolumeName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property DeviceID not found");
|
|
}
|
|
|
|
bstrDomainName = objPathAccount.GetStringValueForProperty(PVDR_PROP_DOMAIN);
|
|
if ((wchar_t*)bstrDomainName == NULL || ((wchar_t*)bstrDomainName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Domain not found");
|
|
}
|
|
|
|
bstrUserName = objPathAccount.GetStringValueForProperty(PVDR_PROP_NAME);
|
|
if ((wchar_t*)bstrUserName == NULL || ((wchar_t*)bstrUserName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Name not found");
|
|
}
|
|
|
|
// Retrieve writeable properties
|
|
// If the properties are NULL it is expected that llLimit and llThreshold will retain their default values (-1)
|
|
rInstToPut.GetPropertyI64(&llLimit, PVDR_PROP_LIMIT);
|
|
rInstToPut.GetPropertyI64(&llThreshold, PVDR_PROP_WARNINGLIMIT);
|
|
|
|
ft.hr = CoCreateInstance(
|
|
CLSID_DiskQuotaControl,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDiskQuotaControl,
|
|
(void **)&pIDQC);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl, %#x", ft.hr);
|
|
|
|
spIDQC.Attach(pIDQC);
|
|
|
|
ft.hr = spIDQC->Initialize(bstrVolumeName, TRUE /* read/write */);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IDiskQuotaControl::Initialize failed for volume %lS, %#x", bstrVolumeName, ft.hr);
|
|
|
|
ft.hr = FindQuotaUserWithRecord(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unexpected failure searching for quota account");
|
|
|
|
DWORD dwPossibleOperations = (WBEM_FLAG_CREATE_OR_UPDATE | WBEM_FLAG_UPDATE_ONLY | WBEM_FLAG_CREATE_ONLY);
|
|
switch (lFlag & dwPossibleOperations)
|
|
{
|
|
case WBEM_FLAG_CREATE_OR_UPDATE:
|
|
{
|
|
if (ft.hr == S_FALSE) // account not found
|
|
fCreate = TRUE;
|
|
else
|
|
fUpdate = TRUE;
|
|
}
|
|
break;
|
|
case WBEM_FLAG_UPDATE_ONLY:
|
|
{
|
|
if (ft.hr == S_FALSE)
|
|
{
|
|
ft.hr = WBEM_E_NOT_FOUND;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"QuotaUser %lS\\%lS not found", bstrDomainName, bstrUserName);
|
|
}
|
|
fUpdate = TRUE;
|
|
}
|
|
break;
|
|
case WBEM_FLAG_CREATE_ONLY:
|
|
{
|
|
if (ft.hr == S_FALSE) // account not found
|
|
{
|
|
fCreate = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ft.hr = WBEM_E_ALREADY_EXISTS;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota %lS/%lS already exists", bstrVolumeName, bstrFQUser);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
ft.hr = WBEM_E_PROVIDER_NOT_CAPABLE;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolumeUserQuota::PutInstance flag not supported %d", lFlag);
|
|
}
|
|
}
|
|
|
|
ft.hr = S_OK;
|
|
|
|
if (fCreate)
|
|
{
|
|
ft.hr = Create(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
|
|
if (ft.hr == S_FALSE) // User already exists
|
|
ft.hr = E_UNEXPECTED; // If so we should have found it above
|
|
else if (ft.HrFailed())
|
|
ft.hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (ft.HrSucceeded() || fUpdate)
|
|
{
|
|
ft.hr = spIQuotaUser->SetQuotaLimit (llLimit, TRUE);
|
|
if (ft.HrSucceeded())
|
|
ft.hr = spIQuotaUser->SetQuotaThreshold (llThreshold, TRUE);
|
|
}
|
|
}
|
|
catch (HRESULT hrEx)
|
|
{
|
|
ft.hr = hrEx;
|
|
}
|
|
|
|
return ft.hr;
|
|
|
|
} //*** CVolumeUserQuota::PutInstance()
|
|
|
|
// The CIMV2 provider maps BUILTIN and NT AUTHORITY domains to <local machine name>
|
|
// so we must try each of these if AddUserName fails
|
|
HRESULT
|
|
CVolumeUserQuota::Create(
|
|
IN _bstr_t bstrDomainName,
|
|
IN _bstr_t bstrUserName,
|
|
IN IDiskQuotaControl* pIDQC,
|
|
OUT IDiskQuotaUser** ppIQuotaUser)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::Create");
|
|
_bstr_t bstrFQUser;
|
|
|
|
bstrFQUser = bstrDomainName + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = pIDQC->AddUserName(
|
|
bstrFQUser ,
|
|
DISKQUOTA_USERNAME_RESOLVE_SYNC,
|
|
ppIQuotaUser);
|
|
if (ft.hr == HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER))
|
|
{
|
|
CVssAutoPWSZ awszDomain;
|
|
|
|
// Get the localized NT Authority name
|
|
if(!GetLocalDomainName(
|
|
SECURITY_NETWORK_SERVICE_RID,
|
|
awszDomain))
|
|
{
|
|
ft.hr = E_UNEXPECTED;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'NT Authority' name");
|
|
}
|
|
|
|
bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = pIDQC->AddUserName(
|
|
bstrFQUser ,
|
|
DISKQUOTA_USERNAME_RESOLVE_SYNC,
|
|
ppIQuotaUser);
|
|
if (ft.hr == HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER))
|
|
{
|
|
awszDomain.Clear();
|
|
// Get the localized BuiltIn name and try again
|
|
if(!GetLocalDomainName(
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
awszDomain))
|
|
{
|
|
ft.hr = E_UNEXPECTED;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'BuiltIn' name");
|
|
}
|
|
bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = pIDQC->AddUserName(
|
|
bstrFQUser ,
|
|
DISKQUOTA_USERNAME_RESOLVE_SYNC,
|
|
ppIQuotaUser);
|
|
}
|
|
}
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
HRESULT
|
|
CVolumeUserQuota::DeleteInstance(
|
|
IN CObjPath& rObjPath,
|
|
IN long lFlag,
|
|
IN IWbemContext* pCtx,
|
|
IN IWbemObjectSink* pHandler
|
|
)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::DeleteInstance");
|
|
|
|
try
|
|
{
|
|
_bstr_t bstrVolumeRef, bstrVolumeName;
|
|
_bstr_t bstrAccountRef, bstrDomainName, bstrUserName;
|
|
CObjPath objPathVolume;
|
|
CObjPath objPathAccount;
|
|
CComPtr<IDiskQuotaUser> spIQuotaUser;
|
|
CComPtr<IDiskQuotaControl> spIDQC;
|
|
IDiskQuotaControl* pIDQC = NULL;
|
|
_bstr_t bstrFQUser;
|
|
|
|
// Get the Volume reference
|
|
bstrVolumeRef = rObjPath.GetStringValueForProperty(PVDR_PROP_VOLUME);
|
|
|
|
// Get the Account reference
|
|
bstrAccountRef = rObjPath.GetStringValueForProperty(PVDR_PROP_ACCOUNT);
|
|
|
|
// Extract the Volume and Account Names
|
|
objPathVolume.Init(bstrVolumeRef);
|
|
objPathAccount.Init(bstrAccountRef);
|
|
|
|
bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
|
|
if ((wchar_t*)bstrVolumeName == NULL || ((wchar_t*)bstrVolumeName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property DeviceID not found");
|
|
}
|
|
|
|
bstrUserName = objPathAccount.GetStringValueForProperty(PVDR_PROP_NAME);
|
|
if ((wchar_t*)bstrUserName == NULL || ((wchar_t*)bstrUserName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Name not found");
|
|
}
|
|
|
|
bstrDomainName = objPathAccount.GetStringValueForProperty(PVDR_PROP_DOMAIN);
|
|
if ((wchar_t*)bstrDomainName == NULL || ((wchar_t*)bstrDomainName)[0] == L'\0')
|
|
{
|
|
ft.hr = E_INVALIDARG;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Domain not found");
|
|
}
|
|
|
|
ft.hr = CoCreateInstance(
|
|
CLSID_DiskQuotaControl,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDiskQuotaControl,
|
|
(void **)&pIDQC);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl, %#x", ft.hr);
|
|
|
|
spIDQC.Attach(pIDQC);
|
|
|
|
ft.hr = spIDQC->Initialize(bstrVolumeName, TRUE /* read/write */);
|
|
if (ft.HrFailed())
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IDiskQuotaControl::Initialize failed for volume %lS, %#x", bstrVolumeName, ft.hr);
|
|
|
|
ft.hr = FindQuotaUser(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
|
|
if (ft.HrFailed())
|
|
{
|
|
ft.hr = WBEM_E_NOT_FOUND;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolumeQuotaUser::DeleteInstance: could not find user %lS\\%lS", bstrDomainName, bstrUserName);
|
|
}
|
|
|
|
ft.hr = spIDQC->DeleteUser(spIQuotaUser);
|
|
}
|
|
catch (HRESULT hrEx)
|
|
{
|
|
ft.hr = hrEx;
|
|
}
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TranslateDomainName(
|
|
IN WCHAR* pwszDomain,
|
|
OUT CVssAutoPWSZ& rawszDomain
|
|
)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
CVssAutoPWSZ awszNtAuthorityDomain;
|
|
CVssAutoPWSZ awszBuiltInDomain;
|
|
CVssAutoPWSZ awszComputerName;
|
|
DWORD cchBuf = 0;
|
|
|
|
do
|
|
{
|
|
// Get the computer name
|
|
awszComputerName.Allocate(MAX_COMPUTERNAME_LENGTH);
|
|
cchBuf = MAX_COMPUTERNAME_LENGTH + 1;
|
|
fReturn = GetComputerName(awszComputerName, &cchBuf);
|
|
if (!fReturn) break;
|
|
|
|
// Get the localized NT Authority name
|
|
fReturn = GetLocalDomainName(
|
|
SECURITY_NETWORK_SERVICE_RID, // NetworkService is a member of Nt Authority domain
|
|
awszNtAuthorityDomain);
|
|
if (!fReturn) break;
|
|
|
|
// Get the localized BUILTIN name
|
|
fReturn = GetLocalDomainName(
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
awszBuiltInDomain);
|
|
if (!fReturn) break;
|
|
|
|
// Replace either of these domain names with the NetBIOS computer name
|
|
if (lstrcmpi(pwszDomain, awszNtAuthorityDomain) == 0 ||
|
|
lstrcmpi(pwszDomain, awszBuiltInDomain) == 0)
|
|
rawszDomain.TransferFrom(awszComputerName);
|
|
else
|
|
rawszDomain.CopyFrom(pwszDomain);
|
|
}
|
|
while(false);
|
|
|
|
return fReturn;
|
|
|
|
}
|
|
|
|
BOOL
|
|
GetLocalDomainName(
|
|
IN DWORD dwWellKnownAuthority,
|
|
OUT CVssAutoPWSZ& rawszDomain
|
|
)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
PSID pSID = NULL;
|
|
SID_NAME_USE snUse = SidTypeUnknown;
|
|
SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;
|
|
CVssAutoPWSZ awszAccount;
|
|
DWORD cchDomainName = 0;
|
|
DWORD cchAccount = 0;
|
|
|
|
do
|
|
{
|
|
// Allocate the SID for the given well known Authority
|
|
fReturn = AllocateAndInitializeSid(
|
|
&sidAuth,
|
|
1,
|
|
dwWellKnownAuthority,0,0,0,0,0,0,0,
|
|
&pSID);
|
|
if (!fReturn) break;
|
|
|
|
// How long is the domain name?
|
|
fReturn = LookupAccountSid(
|
|
NULL, // computer name defaults to local
|
|
pSID,
|
|
NULL, // account name
|
|
&cchAccount, // account name len
|
|
NULL, // domain name
|
|
&cchDomainName,
|
|
&snUse);
|
|
if (!fReturn && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
|
|
|
|
// Allocate the space
|
|
rawszDomain.Allocate(cchDomainName); // allocates the term null too
|
|
awszAccount.Allocate(cchAccount); // allocates the term null too
|
|
|
|
// Get the domain name now
|
|
fReturn = LookupAccountSid(
|
|
NULL, // computer name defaults to local
|
|
pSID,
|
|
awszAccount, // account name
|
|
&cchAccount, // account name len
|
|
rawszDomain, // domain name
|
|
&cchDomainName,
|
|
&snUse);
|
|
}
|
|
while(false);
|
|
|
|
if (pSID)
|
|
FreeSid(pSID);
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
HRESULT FindQuotaUserFromEnum(
|
|
WCHAR* pwszUser,
|
|
IDiskQuotaControl* pIDQC,
|
|
IDiskQuotaUser** ppQuotaUser)
|
|
{
|
|
WCHAR logonName[MAX_PATH+1];
|
|
CComPtr<IEnumDiskQuotaUsers> spUserEnum;
|
|
|
|
_ASSERTE(ppQuotaUser != NULL);
|
|
*ppQuotaUser = NULL;
|
|
|
|
HRESULT hr = pIDQC->CreateEnumUsers(0,0,DISKQUOTA_USERNAME_RESOLVE_SYNC, &spUserEnum);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
while((hr = spUserEnum->Next(1, ppQuotaUser, 0)) == NOERROR)
|
|
{
|
|
if (SUCCEEDED((*ppQuotaUser)->GetName( 0, 0, logonName, MAX_PATH, 0, 0))
|
|
&& _wcsicmp(logonName, pwszUser) == 0) return S_OK;
|
|
(*ppQuotaUser)->Release();
|
|
*ppQuotaUser = NULL;
|
|
};
|
|
|
|
return hr;
|
|
};
|
|
|
|
HRESULT FindQuotaUserWithRecord(
|
|
IN _bstr_t bstrDomainName,
|
|
IN _bstr_t bstrUserName,
|
|
IN IDiskQuotaControl* pIDQC,
|
|
OUT IDiskQuotaUser** ppIQuotaUser)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"FindQuotaUserWithRecord");
|
|
_bstr_t bstrFQUser;
|
|
|
|
bstrFQUser = bstrDomainName + _bstr_t(L"\\") + bstrUserName;
|
|
// Look for the account name as-is
|
|
ft.hr = FindQuotaUserFromEnum(bstrFQUser, pIDQC, ppIQuotaUser);
|
|
if (ft.hr == S_FALSE)
|
|
{
|
|
CVssAutoPWSZ awszDomain;
|
|
|
|
// Get the localized NT Authority name and try again
|
|
if(!GetLocalDomainName(
|
|
SECURITY_NETWORK_SERVICE_RID,
|
|
awszDomain))
|
|
{
|
|
ft.hr = E_UNEXPECTED;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'NT Authority' name");
|
|
}
|
|
|
|
bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = FindQuotaUserFromEnum(bstrFQUser, pIDQC, ppIQuotaUser);
|
|
if (ft.hr == S_FALSE)
|
|
{
|
|
awszDomain.Clear();
|
|
// Get the localized BuiltIn name and try again
|
|
if(!GetLocalDomainName(
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
awszDomain))
|
|
{
|
|
ft.hr = E_UNEXPECTED;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'BuiltIn' name");
|
|
}
|
|
bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = FindQuotaUserFromEnum(bstrFQUser, pIDQC, ppIQuotaUser);
|
|
}
|
|
}
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
HRESULT FindQuotaUser(
|
|
IN _bstr_t bstrDomainName,
|
|
IN _bstr_t bstrUserName,
|
|
IN IDiskQuotaControl* pIDQC,
|
|
OUT IDiskQuotaUser** ppIQuotaUser)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"FindQuotaUser");
|
|
_bstr_t bstrFQUser;
|
|
|
|
bstrFQUser = bstrDomainName + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = pIDQC->FindUserName(bstrFQUser, ppIQuotaUser);
|
|
if (ft.HrFailed())
|
|
{
|
|
CVssAutoPWSZ awszDomain;
|
|
|
|
// Get the localized NT Authority name
|
|
if(!GetLocalDomainName(
|
|
SECURITY_NETWORK_SERVICE_RID,
|
|
awszDomain))
|
|
{
|
|
ft.hr = E_UNEXPECTED;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'NT Authority' name");
|
|
}
|
|
|
|
bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = pIDQC->FindUserName(bstrFQUser, ppIQuotaUser);
|
|
if (ft.HrFailed())
|
|
{
|
|
awszDomain.Clear();
|
|
if(!GetLocalDomainName(
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
awszDomain))
|
|
{
|
|
ft.hr = E_UNEXPECTED;
|
|
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'BuiltIn' name");
|
|
}
|
|
bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
|
|
ft.hr = pIDQC->FindUserName(bstrFQUser, ppIQuotaUser);
|
|
}
|
|
}
|
|
|
|
return ft.hr;
|
|
}
|
|
|