Leaked source code of windows server 2003
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

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2002-2004 Microsoft Corporation
  4. //
  5. // Module Name: Quota.cpp
  6. //
  7. // Description:
  8. // Implementation of VDS WMI Provider quota classes
  9. //
  10. // Author: Jim Benton (jbenton) 25-Mar-2002
  11. //
  12. //////////////////////////////////////////////////////////////////////////////
  13. #include "Pch.h"
  14. #include "Quota.h"
  15. #include "volutil.h"
  16. #define INITGUIDS
  17. #include "dskquota.h"
  18. HRESULT FindQuotaUserFromEnum(
  19. WCHAR* pwszUser,
  20. IDiskQuotaControl* pIDQC,
  21. IDiskQuotaUser** ppQuotaUser);
  22. HRESULT FindQuotaUserWithRecord(
  23. IN _bstr_t bstrDomain,
  24. IN _bstr_t bstrUser,
  25. IN IDiskQuotaControl* pIDQC,
  26. OUT IDiskQuotaUser** ppIQuotaUser);
  27. HRESULT FindQuotaUser(
  28. IN _bstr_t bstrDomain,
  29. IN _bstr_t bstrUser,
  30. IN IDiskQuotaControl* pIDQC,
  31. OUT IDiskQuotaUser** ppIQuotaUser);
  32. BOOL TranslateDomainName(
  33. IN WCHAR* pwszDomain,
  34. OUT CVssAutoPWSZ& rawszDomain);
  35. BOOL GetLocalDomainName(
  36. IN DWORD dwWellKnownAuthority,
  37. OUT CVssAutoPWSZ& rawszDomain);
  38. //****************************************************************************
  39. //
  40. // CVolumeQuota
  41. //
  42. //****************************************************************************
  43. CVolumeQuota::CVolumeQuota(
  44. IN LPCWSTR pwszName,
  45. IN CWbemServices* pNamespace
  46. )
  47. : CProvBase(pwszName, pNamespace)
  48. {
  49. } //*** CVolumeQuota::CVolumeQuota()
  50. CProvBase *
  51. CVolumeQuota::S_CreateThis(
  52. IN LPCWSTR pwszName,
  53. IN CWbemServices* pNamespace
  54. )
  55. {
  56. HRESULT hr = WBEM_E_FAILED;
  57. CVolumeQuota * pObj= NULL;
  58. pObj = new CVolumeQuota(pwszName, pNamespace);
  59. if (pObj)
  60. {
  61. hr = pObj->Initialize();
  62. }
  63. else
  64. {
  65. hr = E_OUTOFMEMORY;
  66. }
  67. if (FAILED(hr))
  68. {
  69. delete pObj;
  70. pObj = NULL;
  71. }
  72. return pObj;
  73. } //*** CVolumeQuota::S_CreateThis()
  74. HRESULT
  75. CVolumeQuota::Initialize()
  76. {
  77. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeQuota::Initialize");
  78. return ft.hr;
  79. }
  80. HRESULT
  81. CVolumeQuota::EnumInstance(
  82. IN long lFlags,
  83. IN IWbemContext* pCtx,
  84. IN IWbemObjectSink * pHandler
  85. )
  86. {
  87. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeQuota::EnumInstance");
  88. CVssAutoPWSZ awszVolume;
  89. try
  90. {
  91. awszVolume.Allocate(MAX_PATH);
  92. CVssVolumeIterator volumeIterator;
  93. while (true)
  94. {
  95. DWORD dwDontCare = 0;
  96. DWORD dwFileSystemFlags = 0;
  97. // Get the volume name
  98. if (!volumeIterator.SelectNewVolume(ft, awszVolume, MAX_PATH))
  99. break;
  100. if (VolumeSupportsQuotas(awszVolume))
  101. {
  102. CComPtr<IWbemClassObject> spInstance;
  103. WCHAR wszDisplayName[MAX_PATH+1] ;
  104. // The key property on the QuotaSetting object is the display name
  105. VssGetVolumeDisplayName(
  106. awszVolume,
  107. wszDisplayName,
  108. MAX_PATH);
  109. ft.hr = m_pClass->SpawnInstance(0, &spInstance);
  110. if (ft.HrFailed())
  111. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
  112. LoadInstance(awszVolume, wszDisplayName, spInstance.p);
  113. ft.hr = pHandler->Indicate(1, &spInstance.p);
  114. }
  115. }
  116. }
  117. catch (HRESULT hrEx)
  118. {
  119. ft.hr = hrEx;
  120. }
  121. return ft.hr;
  122. } //*** CVolumeQuota::EnumInstance()
  123. void
  124. CVolumeQuota:: LoadInstance(
  125. IN WCHAR* pwszVolume,
  126. IN WCHAR* pwszQuotaSetting,
  127. IN OUT IWbemClassObject* pObject)
  128. {
  129. CWbemClassObject wcoInstance(pObject);
  130. CObjPath pathQuotaSetting;
  131. CObjPath pathVolume;
  132. // Set the QuotaSetting Ref property
  133. pathQuotaSetting.Init(PVDR_CLASS_QUOTASETTING);
  134. pathQuotaSetting.AddProperty(PVDR_PROP_VOLUMEPATH, pwszQuotaSetting);
  135. wcoInstance.SetProperty((wchar_t*)pathQuotaSetting.GetObjectPathString(), PVD_WBEM_PROP_SETTING);
  136. // Set the Volume Ref property
  137. pathVolume.Init(PVDR_CLASS_VOLUME);
  138. pathVolume.AddProperty(PVDR_PROP_DEVICEID, pwszVolume);
  139. wcoInstance.SetProperty((wchar_t*)pathVolume.GetObjectPathString(), PVD_WBEM_PROP_ELEMENT);
  140. }
  141. //****************************************************************************
  142. //
  143. // CVolumeUserQuota
  144. //
  145. //****************************************************************************
  146. CVolumeUserQuota::CVolumeUserQuota(
  147. IN LPCWSTR pwszName,
  148. IN CWbemServices* pNamespace
  149. )
  150. : CProvBase(pwszName, pNamespace)
  151. {
  152. } //*** CVolumeUserQuota::CVolumeUserQuota()
  153. CProvBase *
  154. CVolumeUserQuota::S_CreateThis(
  155. IN LPCWSTR pwszName,
  156. IN CWbemServices* pNamespace
  157. )
  158. {
  159. HRESULT hr = WBEM_E_FAILED;
  160. CVolumeUserQuota * pObj= NULL;
  161. pObj = new CVolumeUserQuota(pwszName, pNamespace);
  162. if (pObj)
  163. {
  164. hr = pObj->Initialize();
  165. }
  166. else
  167. {
  168. hr = E_OUTOFMEMORY;
  169. }
  170. if (FAILED(hr))
  171. {
  172. delete pObj;
  173. pObj = NULL;
  174. }
  175. return pObj;
  176. } //*** CVolumeUserQuota::S_CreateThis()
  177. HRESULT
  178. CVolumeUserQuota::Initialize()
  179. {
  180. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::Initialize");
  181. return ft.hr;
  182. }
  183. HRESULT
  184. CVolumeUserQuota::EnumInstance(
  185. IN long lFlags,
  186. IN IWbemContext* pCtx,
  187. IN IWbemObjectSink * pHandler
  188. )
  189. {
  190. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::EnumInstance");
  191. CVssAutoPWSZ awszVolume;
  192. try
  193. {
  194. awszVolume.Allocate(MAX_PATH);
  195. CVssVolumeIterator volumeIterator;
  196. while (true)
  197. {
  198. DWORD dwDontCare = 0;
  199. DWORD dwFileSystemFlags = 0;
  200. // Get the volume name
  201. if (!volumeIterator.SelectNewVolume(ft, awszVolume, MAX_PATH))
  202. break;
  203. if (VolumeSupportsQuotas(awszVolume))
  204. {
  205. CComPtr<IDiskQuotaControl> spIDQC;
  206. IDiskQuotaControl* pIDQC = NULL;
  207. CComPtr<IEnumDiskQuotaUsers> spIEnum;
  208. ft.hr = CoCreateInstance(
  209. CLSID_DiskQuotaControl,
  210. NULL,
  211. CLSCTX_INPROC_SERVER,
  212. IID_IDiskQuotaControl,
  213. (void **)&pIDQC);
  214. if (ft.HrFailed())
  215. {
  216. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl");
  217. }
  218. spIDQC.Attach(pIDQC);
  219. ft.hr = spIDQC->Initialize(awszVolume, FALSE /* read only */);
  220. if (ft.HrFailed())
  221. {
  222. ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaControl::Initialize failed for volume %lS", awszVolume);
  223. continue;
  224. }
  225. // Need to update the cache, else we can get old names
  226. ft.hr = spIDQC->InvalidateSidNameCache();
  227. if (ft.HrFailed())
  228. {
  229. ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaControl::InvalidateSidNameCache failed for volume %lS", awszVolume);
  230. continue;
  231. }
  232. ft.hr = spIDQC->CreateEnumUsers(
  233. NULL, //All the users will be enumerated
  234. 0, // Ignored for enumerating all users
  235. DISKQUOTA_USERNAME_RESOLVE_SYNC,
  236. &spIEnum );
  237. if (ft.HrFailed())
  238. {
  239. ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaControl::CreateEnumUsers failed for volume %lS", awszVolume);
  240. continue;
  241. }
  242. if (spIEnum != NULL)
  243. {
  244. while (true)
  245. {
  246. CComPtr<IWbemClassObject> spInstance;
  247. CComPtr<IDiskQuotaUser> spIQuotaUser;
  248. DWORD cUsers = 0;
  249. ft.hr = spIEnum->Next(1, &spIQuotaUser, &cUsers);
  250. if (ft.HrFailed())
  251. {
  252. ft.Trace(VSSDBG_VSSADMIN, L"IEnumDiskQuotaUsers::Next failed for volume %lS", awszVolume);
  253. continue;
  254. }
  255. if (ft.hr == S_FALSE)
  256. break;
  257. ft.hr = m_pClass->SpawnInstance(0, &spInstance);
  258. if (ft.HrFailed())
  259. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
  260. LoadInstance(awszVolume, spIQuotaUser, spInstance.p);
  261. ft.hr = pHandler->Indicate(1, &spInstance.p);
  262. }
  263. }
  264. }
  265. }
  266. }
  267. catch (HRESULT hrEx)
  268. {
  269. ft.hr = hrEx;
  270. }
  271. return ft.hr;
  272. } //*** CVolumeUserQuota::EnumInstance()
  273. HRESULT
  274. CVolumeUserQuota::GetObject(
  275. IN CObjPath& rObjPath,
  276. IN long lFlags,
  277. IN IWbemContext* pCtx,
  278. IN IWbemObjectSink* pHandler
  279. )
  280. {
  281. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::GetObject");
  282. try
  283. {
  284. _bstr_t bstrVolumeRef, bstrVolumeName;
  285. _bstr_t bstrAccountRef, bstrDomainName, bstrUserName;
  286. CObjPath objPathVolume;
  287. CObjPath objPathAccount;
  288. CComPtr<IWbemClassObject> spInstance;
  289. CComPtr<IDiskQuotaUser> spIQuotaUser;
  290. CComPtr<IDiskQuotaControl> spIDQC;
  291. IDiskQuotaControl* pIDQC = NULL;
  292. _bstr_t bstrFQUser;
  293. // Get the Volume reference
  294. bstrVolumeRef = rObjPath.GetStringValueForProperty(PVDR_PROP_VOLUME);
  295. // Get the Account reference
  296. bstrAccountRef = rObjPath.GetStringValueForProperty(PVDR_PROP_ACCOUNT);
  297. // Extract the Volume and Account Names
  298. objPathVolume.Init(bstrVolumeRef);
  299. objPathAccount.Init(bstrAccountRef);
  300. bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
  301. if ((wchar_t*)bstrVolumeName == NULL || ((wchar_t*)bstrVolumeName)[0] == L'\0')
  302. {
  303. ft.hr = E_INVALIDARG;
  304. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property DeviceID not found");
  305. }
  306. bstrUserName = objPathAccount.GetStringValueForProperty(PVDR_PROP_NAME);
  307. if ((wchar_t*)bstrUserName == NULL || ((wchar_t*)bstrUserName)[0] == L'\0')
  308. {
  309. ft.hr = E_INVALIDARG;
  310. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Name not found");
  311. }
  312. bstrDomainName = objPathAccount.GetStringValueForProperty(PVDR_PROP_DOMAIN);
  313. if ((wchar_t*)bstrDomainName == NULL || ((wchar_t*)bstrDomainName)[0] == L'\0')
  314. {
  315. ft.hr = E_INVALIDARG;
  316. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Domain not found");
  317. }
  318. ft.hr = CoCreateInstance(
  319. CLSID_DiskQuotaControl,
  320. NULL,
  321. CLSCTX_INPROC_SERVER,
  322. IID_IDiskQuotaControl,
  323. (void **)&pIDQC);
  324. if (ft.HrFailed())
  325. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl, %#x", ft.hr);
  326. spIDQC.Attach(pIDQC);
  327. ft.hr = spIDQC->Initialize(bstrVolumeName, TRUE /* read/write */);
  328. if (ft.HrFailed())
  329. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IDiskQuotaControl::Initialize failed for volume %lS, %#x", bstrVolumeName, ft.hr);
  330. ft.hr = FindQuotaUser(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
  331. if (ft.HrFailed())
  332. {
  333. ft.hr = WBEM_E_NOT_FOUND;
  334. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolumeQuotaUser::GetObject: could not find user %lS\\%lS", bstrDomainName, bstrUserName);
  335. }
  336. ft.hr = m_pClass->SpawnInstance(0, &spInstance);
  337. if (ft.HrFailed())
  338. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
  339. LoadInstance(bstrVolumeName, spIQuotaUser, spInstance.p);
  340. ft.hr = pHandler->Indicate(1, &spInstance.p);
  341. }
  342. catch (HRESULT hrEx)
  343. {
  344. ft.hr = hrEx;
  345. }
  346. return ft.hr;
  347. } //*** CVolume::GetObject()
  348. void
  349. CVolumeUserQuota:: LoadInstance(
  350. IN WCHAR* pwszVolume,
  351. IN IDiskQuotaUser* pIQuotaUser,
  352. IN OUT IWbemClassObject* pObject)
  353. {
  354. CWbemClassObject wcoInstance(pObject);
  355. CObjPath pathAccount;
  356. CObjPath pathVolume;
  357. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::LoadInstance");
  358. do
  359. {
  360. WCHAR wszDomain[g_cchAccountNameMax], *pwszDomain = NULL;
  361. WCHAR wszFQUser[g_cchAccountNameMax], *pwszUser = NULL;
  362. CVssAutoPWSZ awszDomain;
  363. DISKQUOTA_USER_INFORMATION UserQuotaInfo;
  364. DWORD dwStatus = 0;
  365. ft.hr = pIQuotaUser->GetName(wszDomain, g_cchAccountNameMax,
  366. wszFQUser, g_cchAccountNameMax, NULL, 0);
  367. if (ft.HrFailed())
  368. {
  369. ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaUser::GetName failed for volume %lS", pwszVolume);
  370. break;
  371. }
  372. // Win32_Account separates domain\user into two keys, Domain and Name
  373. // Prepare the Domain and Name keys
  374. pwszUser = wcschr(wszFQUser, L'\\'); // user name is domain\\name format
  375. if (pwszUser != NULL)
  376. {
  377. pwszDomain = wszFQUser;
  378. *pwszUser = L'\0';
  379. pwszUser++;
  380. }
  381. else
  382. {
  383. pwszDomain = wcschr(wszFQUser, L'@'); // user name is [email protected] format
  384. if (pwszDomain != NULL)
  385. {
  386. pwszUser = wszFQUser;
  387. *pwszDomain = L'\0';
  388. pwszDomain++;
  389. WCHAR* pwc = wcschr(pwszDomain, L'.');
  390. if (pwc != NULL)
  391. *pwc = L'\0';
  392. }
  393. else
  394. {
  395. pwszDomain = wszDomain;
  396. pwszUser = wszFQUser;
  397. }
  398. }
  399. // The GetName API returns BUILTIN and NT AUTHORITY
  400. // as the domain name for built-in local accounts.
  401. // BUILTIN and NT AUTHORITY accounts are represented
  402. // by Win32_Account and its children with the domain
  403. // name being the name of the machine, instead of
  404. // either of these strings. We'll convert the domain name here.
  405. TranslateDomainName(pwszDomain, awszDomain);
  406. ft.hr = pIQuotaUser->GetQuotaInformation(&UserQuotaInfo, sizeof(UserQuotaInfo));
  407. if (ft.HrFailed())
  408. {
  409. ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaUser::GetQuotaInformation failed for volume %lS", pwszVolume);
  410. break;
  411. }
  412. // Set the Account Ref property
  413. pathAccount.Init(PVDR_CLASS_ACCOUNT);
  414. pathAccount.AddProperty(PVDR_PROP_DOMAIN, awszDomain);
  415. pathAccount.AddProperty(PVDR_PROP_NAME, pwszUser);
  416. wcoInstance.SetProperty((wchar_t*)pathAccount.GetObjectPathString(), PVDR_PROP_ACCOUNT);
  417. // Set the Volume Ref property
  418. pathVolume.Init(PVDR_CLASS_VOLUME);
  419. pathVolume.AddProperty(PVDR_PROP_DEVICEID, pwszVolume);
  420. wcoInstance.SetProperty((wchar_t*)pathVolume.GetObjectPathString(), PVDR_PROP_VOLUME);
  421. wcoInstance.SetPropertyI64((ULONGLONG)UserQuotaInfo.QuotaUsed, PVDR_PROP_DISKSPACEUSED);
  422. wcoInstance.SetPropertyI64((ULONGLONG)UserQuotaInfo.QuotaThreshold, PVDR_PROP_WARNINGLIMIT);
  423. wcoInstance.SetPropertyI64((ULONGLONG)UserQuotaInfo.QuotaLimit, PVDR_PROP_LIMIT);
  424. if (UserQuotaInfo.QuotaLimit == -1)
  425. dwStatus = 0; // OK, no limit set
  426. else
  427. {
  428. if (UserQuotaInfo.QuotaUsed >= UserQuotaInfo.QuotaLimit)
  429. dwStatus = 2; // Limit exceeded
  430. else if (UserQuotaInfo.QuotaUsed >= UserQuotaInfo.QuotaThreshold)
  431. dwStatus = 1; // Warning limit exceeded
  432. else
  433. dwStatus = 0; // OK, under the warning limit
  434. }
  435. wcoInstance.SetProperty(dwStatus, PVDR_PROP_STATUS);
  436. }
  437. while(false);
  438. }
  439. HRESULT
  440. CVolumeUserQuota::PutInstance(
  441. IN CWbemClassObject& rInstToPut,
  442. IN long lFlag,
  443. IN IWbemContext* pCtx,
  444. IN IWbemObjectSink* pHandler
  445. )
  446. {
  447. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::PutInstance");
  448. try
  449. {
  450. _bstr_t bstrVolumeRef, bstrVolumeName;
  451. _bstr_t bstrAccountRef, bstrDomainName, bstrUserName;
  452. CObjPath objPathVolume;
  453. CObjPath objPathAccount;
  454. _bstr_t bstrFQUser;
  455. CComPtr<IDiskQuotaUser> spIQuotaUser;
  456. CComPtr<IDiskQuotaControl> spIDQC;
  457. IDiskQuotaControl* pIDQC = NULL;
  458. BOOL fCreate = FALSE;
  459. BOOL fUpdate = FALSE;
  460. LONGLONG llLimit = -1, llThreshold = -1;
  461. // Retrieve key properties of the object to be saved.
  462. rInstToPut.GetProperty(bstrVolumeRef, PVDR_PROP_VOLUME);
  463. rInstToPut.GetProperty(bstrAccountRef, PVDR_PROP_ACCOUNT);
  464. // Extract the Volume, Domain and User names
  465. objPathVolume.Init(bstrVolumeRef);
  466. objPathAccount.Init(bstrAccountRef);
  467. bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
  468. if ((wchar_t*)bstrVolumeName == NULL || ((wchar_t*)bstrVolumeName)[0] == L'\0')
  469. {
  470. ft.hr = E_INVALIDARG;
  471. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property DeviceID not found");
  472. }
  473. bstrDomainName = objPathAccount.GetStringValueForProperty(PVDR_PROP_DOMAIN);
  474. if ((wchar_t*)bstrDomainName == NULL || ((wchar_t*)bstrDomainName)[0] == L'\0')
  475. {
  476. ft.hr = E_INVALIDARG;
  477. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Domain not found");
  478. }
  479. bstrUserName = objPathAccount.GetStringValueForProperty(PVDR_PROP_NAME);
  480. if ((wchar_t*)bstrUserName == NULL || ((wchar_t*)bstrUserName)[0] == L'\0')
  481. {
  482. ft.hr = E_INVALIDARG;
  483. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Name not found");
  484. }
  485. // Retrieve writeable properties
  486. // If the properties are NULL it is expected that llLimit and llThreshold will retain their default values (-1)
  487. rInstToPut.GetPropertyI64(&llLimit, PVDR_PROP_LIMIT);
  488. rInstToPut.GetPropertyI64(&llThreshold, PVDR_PROP_WARNINGLIMIT);
  489. ft.hr = CoCreateInstance(
  490. CLSID_DiskQuotaControl,
  491. NULL,
  492. CLSCTX_INPROC_SERVER,
  493. IID_IDiskQuotaControl,
  494. (void **)&pIDQC);
  495. if (ft.HrFailed())
  496. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl, %#x", ft.hr);
  497. spIDQC.Attach(pIDQC);
  498. ft.hr = spIDQC->Initialize(bstrVolumeName, TRUE /* read/write */);
  499. if (ft.HrFailed())
  500. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IDiskQuotaControl::Initialize failed for volume %lS, %#x", bstrVolumeName, ft.hr);
  501. ft.hr = FindQuotaUserWithRecord(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
  502. if (ft.HrFailed())
  503. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unexpected failure searching for quota account");
  504. DWORD dwPossibleOperations = (WBEM_FLAG_CREATE_OR_UPDATE | WBEM_FLAG_UPDATE_ONLY | WBEM_FLAG_CREATE_ONLY);
  505. switch (lFlag & dwPossibleOperations)
  506. {
  507. case WBEM_FLAG_CREATE_OR_UPDATE:
  508. {
  509. if (ft.hr == S_FALSE) // account not found
  510. fCreate = TRUE;
  511. else
  512. fUpdate = TRUE;
  513. }
  514. break;
  515. case WBEM_FLAG_UPDATE_ONLY:
  516. {
  517. if (ft.hr == S_FALSE)
  518. {
  519. ft.hr = WBEM_E_NOT_FOUND;
  520. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"QuotaUser %lS\\%lS not found", bstrDomainName, bstrUserName);
  521. }
  522. fUpdate = TRUE;
  523. }
  524. break;
  525. case WBEM_FLAG_CREATE_ONLY:
  526. {
  527. if (ft.hr == S_FALSE) // account not found
  528. {
  529. fCreate = TRUE;
  530. }
  531. else
  532. {
  533. ft.hr = WBEM_E_ALREADY_EXISTS;
  534. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota %lS/%lS already exists", bstrVolumeName, bstrFQUser);
  535. }
  536. }
  537. break;
  538. default:
  539. {
  540. ft.hr = WBEM_E_PROVIDER_NOT_CAPABLE;
  541. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolumeUserQuota::PutInstance flag not supported %d", lFlag);
  542. }
  543. }
  544. ft.hr = S_OK;
  545. if (fCreate)
  546. {
  547. ft.hr = Create(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
  548. if (ft.hr == S_FALSE) // User already exists
  549. ft.hr = E_UNEXPECTED; // If so we should have found it above
  550. else if (ft.HrFailed())
  551. ft.hr = WBEM_E_INVALID_PARAMETER;
  552. }
  553. if (ft.HrSucceeded() || fUpdate)
  554. {
  555. ft.hr = spIQuotaUser->SetQuotaLimit (llLimit, TRUE);
  556. if (ft.HrSucceeded())
  557. ft.hr = spIQuotaUser->SetQuotaThreshold (llThreshold, TRUE);
  558. }
  559. }
  560. catch (HRESULT hrEx)
  561. {
  562. ft.hr = hrEx;
  563. }
  564. return ft.hr;
  565. } //*** CVolumeUserQuota::PutInstance()
  566. // The CIMV2 provider maps BUILTIN and NT AUTHORITY domains to <local machine name>
  567. // so we must try each of these if AddUserName fails
  568. HRESULT
  569. CVolumeUserQuota::Create(
  570. IN _bstr_t bstrDomainName,
  571. IN _bstr_t bstrUserName,
  572. IN IDiskQuotaControl* pIDQC,
  573. OUT IDiskQuotaUser** ppIQuotaUser)
  574. {
  575. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::Create");
  576. _bstr_t bstrFQUser;
  577. bstrFQUser = bstrDomainName + _bstr_t(L"\\") + bstrUserName;
  578. ft.hr = pIDQC->AddUserName(
  579. bstrFQUser ,
  580. DISKQUOTA_USERNAME_RESOLVE_SYNC,
  581. ppIQuotaUser);
  582. if (ft.hr == HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER))
  583. {
  584. CVssAutoPWSZ awszDomain;
  585. // Get the localized NT Authority name
  586. if(!GetLocalDomainName(
  587. SECURITY_NETWORK_SERVICE_RID,
  588. awszDomain))
  589. {
  590. ft.hr = E_UNEXPECTED;
  591. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'NT Authority' name");
  592. }
  593. bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
  594. ft.hr = pIDQC->AddUserName(
  595. bstrFQUser ,
  596. DISKQUOTA_USERNAME_RESOLVE_SYNC,
  597. ppIQuotaUser);
  598. if (ft.hr == HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER))
  599. {
  600. awszDomain.Clear();
  601. // Get the localized BuiltIn name and try again
  602. if(!GetLocalDomainName(
  603. SECURITY_BUILTIN_DOMAIN_RID,
  604. awszDomain))
  605. {
  606. ft.hr = E_UNEXPECTED;
  607. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'BuiltIn' name");
  608. }
  609. bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
  610. ft.hr = pIDQC->AddUserName(
  611. bstrFQUser ,
  612. DISKQUOTA_USERNAME_RESOLVE_SYNC,
  613. ppIQuotaUser);
  614. }
  615. }
  616. return ft.hr;
  617. }
  618. HRESULT
  619. CVolumeUserQuota::DeleteInstance(
  620. IN CObjPath& rObjPath,
  621. IN long lFlag,
  622. IN IWbemContext* pCtx,
  623. IN IWbemObjectSink* pHandler
  624. )
  625. {
  626. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolumeUserQuota::DeleteInstance");
  627. try
  628. {
  629. _bstr_t bstrVolumeRef, bstrVolumeName;
  630. _bstr_t bstrAccountRef, bstrDomainName, bstrUserName;
  631. CObjPath objPathVolume;
  632. CObjPath objPathAccount;
  633. CComPtr<IDiskQuotaUser> spIQuotaUser;
  634. CComPtr<IDiskQuotaControl> spIDQC;
  635. IDiskQuotaControl* pIDQC = NULL;
  636. _bstr_t bstrFQUser;
  637. // Get the Volume reference
  638. bstrVolumeRef = rObjPath.GetStringValueForProperty(PVDR_PROP_VOLUME);
  639. // Get the Account reference
  640. bstrAccountRef = rObjPath.GetStringValueForProperty(PVDR_PROP_ACCOUNT);
  641. // Extract the Volume and Account Names
  642. objPathVolume.Init(bstrVolumeRef);
  643. objPathAccount.Init(bstrAccountRef);
  644. bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
  645. if ((wchar_t*)bstrVolumeName == NULL || ((wchar_t*)bstrVolumeName)[0] == L'\0')
  646. {
  647. ft.hr = E_INVALIDARG;
  648. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property DeviceID not found");
  649. }
  650. bstrUserName = objPathAccount.GetStringValueForProperty(PVDR_PROP_NAME);
  651. if ((wchar_t*)bstrUserName == NULL || ((wchar_t*)bstrUserName)[0] == L'\0')
  652. {
  653. ft.hr = E_INVALIDARG;
  654. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Name not found");
  655. }
  656. bstrDomainName = objPathAccount.GetStringValueForProperty(PVDR_PROP_DOMAIN);
  657. if ((wchar_t*)bstrDomainName == NULL || ((wchar_t*)bstrDomainName)[0] == L'\0')
  658. {
  659. ft.hr = E_INVALIDARG;
  660. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"VolumeUserQuota key property Domain not found");
  661. }
  662. ft.hr = CoCreateInstance(
  663. CLSID_DiskQuotaControl,
  664. NULL,
  665. CLSCTX_INPROC_SERVER,
  666. IID_IDiskQuotaControl,
  667. (void **)&pIDQC);
  668. if (ft.HrFailed())
  669. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl, %#x", ft.hr);
  670. spIDQC.Attach(pIDQC);
  671. ft.hr = spIDQC->Initialize(bstrVolumeName, TRUE /* read/write */);
  672. if (ft.HrFailed())
  673. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IDiskQuotaControl::Initialize failed for volume %lS, %#x", bstrVolumeName, ft.hr);
  674. ft.hr = FindQuotaUser(bstrDomainName, bstrUserName, spIDQC, &spIQuotaUser);
  675. if (ft.HrFailed())
  676. {
  677. ft.hr = WBEM_E_NOT_FOUND;
  678. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolumeQuotaUser::DeleteInstance: could not find user %lS\\%lS", bstrDomainName, bstrUserName);
  679. }
  680. ft.hr = spIDQC->DeleteUser(spIQuotaUser);
  681. }
  682. catch (HRESULT hrEx)
  683. {
  684. ft.hr = hrEx;
  685. }
  686. return ft.hr;
  687. }
  688. BOOL
  689. TranslateDomainName(
  690. IN WCHAR* pwszDomain,
  691. OUT CVssAutoPWSZ& rawszDomain
  692. )
  693. {
  694. BOOL fReturn = FALSE;
  695. CVssAutoPWSZ awszNtAuthorityDomain;
  696. CVssAutoPWSZ awszBuiltInDomain;
  697. CVssAutoPWSZ awszComputerName;
  698. DWORD cchBuf = 0;
  699. do
  700. {
  701. // Get the computer name
  702. awszComputerName.Allocate(MAX_COMPUTERNAME_LENGTH);
  703. cchBuf = MAX_COMPUTERNAME_LENGTH + 1;
  704. fReturn = GetComputerName(awszComputerName, &cchBuf);
  705. if (!fReturn) break;
  706. // Get the localized NT Authority name
  707. fReturn = GetLocalDomainName(
  708. SECURITY_NETWORK_SERVICE_RID, // NetworkService is a member of Nt Authority domain
  709. awszNtAuthorityDomain);
  710. if (!fReturn) break;
  711. // Get the localized BUILTIN name
  712. fReturn = GetLocalDomainName(
  713. SECURITY_BUILTIN_DOMAIN_RID,
  714. awszBuiltInDomain);
  715. if (!fReturn) break;
  716. // Replace either of these domain names with the NetBIOS computer name
  717. if (lstrcmpi(pwszDomain, awszNtAuthorityDomain) == 0 ||
  718. lstrcmpi(pwszDomain, awszBuiltInDomain) == 0)
  719. rawszDomain.TransferFrom(awszComputerName);
  720. else
  721. rawszDomain.CopyFrom(pwszDomain);
  722. }
  723. while(false);
  724. return fReturn;
  725. }
  726. BOOL
  727. GetLocalDomainName(
  728. IN DWORD dwWellKnownAuthority,
  729. OUT CVssAutoPWSZ& rawszDomain
  730. )
  731. {
  732. BOOL fReturn = FALSE;
  733. PSID pSID = NULL;
  734. SID_NAME_USE snUse = SidTypeUnknown;
  735. SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;
  736. CVssAutoPWSZ awszAccount;
  737. DWORD cchDomainName = 0;
  738. DWORD cchAccount = 0;
  739. do
  740. {
  741. // Allocate the SID for the given well known Authority
  742. fReturn = AllocateAndInitializeSid(
  743. &sidAuth,
  744. 1,
  745. dwWellKnownAuthority,0,0,0,0,0,0,0,
  746. &pSID);
  747. if (!fReturn) break;
  748. // How long is the domain name?
  749. fReturn = LookupAccountSid(
  750. NULL, // computer name defaults to local
  751. pSID,
  752. NULL, // account name
  753. &cchAccount, // account name len
  754. NULL, // domain name
  755. &cchDomainName,
  756. &snUse);
  757. if (!fReturn && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
  758. // Allocate the space
  759. rawszDomain.Allocate(cchDomainName); // allocates the term null too
  760. awszAccount.Allocate(cchAccount); // allocates the term null too
  761. // Get the domain name now
  762. fReturn = LookupAccountSid(
  763. NULL, // computer name defaults to local
  764. pSID,
  765. awszAccount, // account name
  766. &cchAccount, // account name len
  767. rawszDomain, // domain name
  768. &cchDomainName,
  769. &snUse);
  770. }
  771. while(false);
  772. if (pSID)
  773. FreeSid(pSID);
  774. return fReturn;
  775. }
  776. HRESULT FindQuotaUserFromEnum(
  777. WCHAR* pwszUser,
  778. IDiskQuotaControl* pIDQC,
  779. IDiskQuotaUser** ppQuotaUser)
  780. {
  781. WCHAR logonName[MAX_PATH+1];
  782. CComPtr<IEnumDiskQuotaUsers> spUserEnum;
  783. _ASSERTE(ppQuotaUser != NULL);
  784. *ppQuotaUser = NULL;
  785. HRESULT hr = pIDQC->CreateEnumUsers(0,0,DISKQUOTA_USERNAME_RESOLVE_SYNC, &spUserEnum);
  786. if (FAILED(hr))
  787. return hr;
  788. while((hr = spUserEnum->Next(1, ppQuotaUser, 0)) == NOERROR)
  789. {
  790. if (SUCCEEDED((*ppQuotaUser)->GetName( 0, 0, logonName, MAX_PATH, 0, 0))
  791. && _wcsicmp(logonName, pwszUser) == 0) return S_OK;
  792. (*ppQuotaUser)->Release();
  793. *ppQuotaUser = NULL;
  794. };
  795. return hr;
  796. };
  797. HRESULT FindQuotaUserWithRecord(
  798. IN _bstr_t bstrDomainName,
  799. IN _bstr_t bstrUserName,
  800. IN IDiskQuotaControl* pIDQC,
  801. OUT IDiskQuotaUser** ppIQuotaUser)
  802. {
  803. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"FindQuotaUserWithRecord");
  804. _bstr_t bstrFQUser;
  805. bstrFQUser = bstrDomainName + _bstr_t(L"\\") + bstrUserName;
  806. // Look for the account name as-is
  807. ft.hr = FindQuotaUserFromEnum(bstrFQUser, pIDQC, ppIQuotaUser);
  808. if (ft.hr == S_FALSE)
  809. {
  810. CVssAutoPWSZ awszDomain;
  811. // Get the localized NT Authority name and try again
  812. if(!GetLocalDomainName(
  813. SECURITY_NETWORK_SERVICE_RID,
  814. awszDomain))
  815. {
  816. ft.hr = E_UNEXPECTED;
  817. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'NT Authority' name");
  818. }
  819. bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
  820. ft.hr = FindQuotaUserFromEnum(bstrFQUser, pIDQC, ppIQuotaUser);
  821. if (ft.hr == S_FALSE)
  822. {
  823. awszDomain.Clear();
  824. // Get the localized BuiltIn name and try again
  825. if(!GetLocalDomainName(
  826. SECURITY_BUILTIN_DOMAIN_RID,
  827. awszDomain))
  828. {
  829. ft.hr = E_UNEXPECTED;
  830. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'BuiltIn' name");
  831. }
  832. bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
  833. ft.hr = FindQuotaUserFromEnum(bstrFQUser, pIDQC, ppIQuotaUser);
  834. }
  835. }
  836. return ft.hr;
  837. }
  838. HRESULT FindQuotaUser(
  839. IN _bstr_t bstrDomainName,
  840. IN _bstr_t bstrUserName,
  841. IN IDiskQuotaControl* pIDQC,
  842. OUT IDiskQuotaUser** ppIQuotaUser)
  843. {
  844. CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"FindQuotaUser");
  845. _bstr_t bstrFQUser;
  846. bstrFQUser = bstrDomainName + _bstr_t(L"\\") + bstrUserName;
  847. ft.hr = pIDQC->FindUserName(bstrFQUser, ppIQuotaUser);
  848. if (ft.HrFailed())
  849. {
  850. CVssAutoPWSZ awszDomain;
  851. // Get the localized NT Authority name
  852. if(!GetLocalDomainName(
  853. SECURITY_NETWORK_SERVICE_RID,
  854. awszDomain))
  855. {
  856. ft.hr = E_UNEXPECTED;
  857. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'NT Authority' name");
  858. }
  859. bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
  860. ft.hr = pIDQC->FindUserName(bstrFQUser, ppIQuotaUser);
  861. if (ft.HrFailed())
  862. {
  863. awszDomain.Clear();
  864. if(!GetLocalDomainName(
  865. SECURITY_BUILTIN_DOMAIN_RID,
  866. awszDomain))
  867. {
  868. ft.hr = E_UNEXPECTED;
  869. ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to get localized 'BuiltIn' name");
  870. }
  871. bstrFQUser = _bstr_t(awszDomain) + _bstr_t(L"\\") + bstrUserName;
  872. ft.hr = pIDQC->FindUserName(bstrFQUser, ppIQuotaUser);
  873. }
  874. }
  875. return ft.hr;
  876. }