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.

1185 lines
29 KiB

  1. // Copyright (c) 2000-2002 Microsoft Corporation, All Rights Reserved
  2. //
  3. // CMDH.cpp - Helper class for working with
  4. // logical disks mapped by logon
  5. // session.
  6. //
  7. // Created: 4/23/2000 Kevin Hughes (khughes)
  8. //
  9. // USEAGE NOTE: This class presents a view of
  10. // information pertaining to mapped drives in
  11. // the context of the process id specified in
  12. // the class constructor.
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <ntobapi.h>
  17. #define _WINNT_ // have what is needed from above
  18. #pragma warning (disable: 4786)
  19. #pragma warning (disable: 4284)
  20. #include <precomp.h>
  21. #include <objbase.h>
  22. #include <comdef.h>
  23. #include <stdio.h> //sprintf
  24. #include <stdlib.h>
  25. #include <assert.h>
  26. #include <strstrea.h>
  27. #include <vector>
  28. #include <DskQuota.h>
  29. #include <smartptr.h>
  30. #include "DllWrapperBase.h"
  31. #include "AdvApi32Api.h"
  32. #include "NtDllApi.h"
  33. #include "Kernel32Api.h"
  34. #include <ntioapi.h>
  35. #include "cmdh.h"
  36. #include <session.h>
  37. #include <dllutils.h>
  38. #include <..\..\framework\provexpt\include\provexpt.h>
  39. #include "Sid.h"
  40. #include "AccessEntry.h" // CAccessEntry class
  41. #include "AccessEntryList.h"
  42. #include "DACL.h" // CDACL class
  43. #include "SACL.h"
  44. #include "securitydescriptor.h"
  45. #include "CToken.h"
  46. #include "SecureKernelObj.h"
  47. #include <cominit.h>
  48. #include <autoptr.h>
  49. #include <scopeguard.h>
  50. ///////////////////////////////////////////////////////////////////////////////
  51. // CMDH Public interface functions
  52. ///////////////////////////////////////////////////////////////////////////////
  53. HRESULT CMDH::GetMDData(
  54. DWORD dwReqProps,
  55. VARIANT* pvarData)
  56. {
  57. HRESULT hr = S_OK;
  58. if(!pvarData) return E_POINTER;
  59. if(SUCCEEDED(hr))
  60. {
  61. hr = GetMappedDisksAndData(
  62. dwReqProps,
  63. pvarData);
  64. }
  65. return hr;
  66. }
  67. HRESULT CMDH::GetOneMDData(
  68. BSTR bstrDrive,
  69. DWORD dwReqProps,
  70. VARIANT* pvarData)
  71. {
  72. HRESULT hr = S_OK;
  73. if(!pvarData) return E_POINTER;
  74. if(SUCCEEDED(hr))
  75. {
  76. hr = GetSingleMappedDiskAndData(
  77. bstrDrive,
  78. dwReqProps,
  79. pvarData);
  80. }
  81. return hr;
  82. }
  83. ///////////////////////////////////////////////////////////////////////////////
  84. // CMDH Private internal functions
  85. ///////////////////////////////////////////////////////////////////////////////
  86. // This function does pretty much all of the
  87. // work this object was constructed to do -
  88. // it obtains, for the process space that this
  89. // server is running in, the set of mapped
  90. // drives, and for each of these, the following
  91. // information as well:
  92. //
  93. HRESULT CMDH::GetMappedDisksAndData(
  94. DWORD dwReqProps,
  95. VARIANT* pvarData)
  96. {
  97. HRESULT hr = WBEM_S_NO_ERROR;
  98. ::VariantInit(pvarData);
  99. V_VT(pvarData) = VT_EMPTY;
  100. // Get the mapped drives into a vector...
  101. std::vector<_bstr_t> vecMappedDrives;
  102. {
  103. // Impersonate member process...
  104. SmartRevertTokenHANDLE hCurImpTok;
  105. hCurImpTok = Impersonate();
  106. if(hCurImpTok != INVALID_HANDLE_VALUE)
  107. {
  108. GetMappedDriveList(
  109. vecMappedDrives);
  110. }
  111. }
  112. // Now allocate the two dimensional
  113. // safearray that will hold the properties
  114. // for each mapped drive...
  115. SAFEARRAY* saDriveProps = NULL;
  116. SAFEARRAYBOUND rgsabound[2];
  117. rgsabound[0].cElements = PROP_COUNT;
  118. rgsabound[0].lLbound = 0;
  119. rgsabound[1].cElements = vecMappedDrives.size();
  120. rgsabound[1].lLbound = 0;
  121. saDriveProps = ::SafeArrayCreate(
  122. VT_BSTR,
  123. 2,
  124. rgsabound);
  125. if(saDriveProps)
  126. {
  127. // For each mapped drive, obtain its
  128. // properties and store in the safearray...
  129. for(long m = 0;
  130. m < vecMappedDrives.size() && SUCCEEDED(hr);
  131. m++)
  132. {
  133. hr = GetMappedDriveInfo(
  134. vecMappedDrives[m],
  135. m,
  136. saDriveProps,
  137. dwReqProps);
  138. }
  139. // And finally package the safearray
  140. // into the outgoing variant.
  141. if(SUCCEEDED(hr))
  142. {
  143. ::VariantInit(pvarData);
  144. V_VT(pvarData) = VT_BSTR | VT_ARRAY;
  145. V_ARRAY(pvarData) = saDriveProps;
  146. }
  147. }
  148. else
  149. {
  150. hr = WBEM_E_OUT_OF_MEMORY;
  151. }
  152. return hr;
  153. }
  154. // Similar to GetMappedDisksAndData, but only
  155. // retrieves info for a single disk.
  156. //
  157. HRESULT CMDH::GetSingleMappedDiskAndData(
  158. BSTR bstrDrive,
  159. DWORD dwReqProps,
  160. VARIANT* pvarData)
  161. {
  162. HRESULT hr = WBEM_S_NO_ERROR;
  163. ::VariantInit(pvarData);
  164. V_VT(pvarData) = VT_EMPTY;
  165. // Impersonate member process...
  166. SmartRevertTokenHANDLE hCurImpTok;
  167. hCurImpTok = Impersonate();
  168. if(hCurImpTok != INVALID_HANDLE_VALUE)
  169. {
  170. // Get the mapped drives into a vector...
  171. std::vector<_bstr_t> vecMappedDrives;
  172. GetMappedDriveList(
  173. vecMappedDrives);
  174. // Now allocate the two dimensional
  175. // safearray that will hold the properties
  176. // for each mapped drive...
  177. // Note: in this routine, it is really
  178. // only a one dimensional array, but,
  179. // for code reuse, we'll treat it as a
  180. // two dimensional array with only one
  181. // element in one of the dimensions.
  182. SAFEARRAY* saDriveProps = NULL;
  183. SAFEARRAYBOUND rgsabound[2];
  184. rgsabound[0].cElements = PROP_COUNT;
  185. rgsabound[0].lLbound = 0;
  186. rgsabound[1].cElements = 1; // for code reuse
  187. rgsabound[1].lLbound = 0;
  188. saDriveProps = ::SafeArrayCreate(
  189. VT_BSTR,
  190. 2,
  191. rgsabound);
  192. if(saDriveProps)
  193. {
  194. // See if the drive specified is a member
  195. // of the vector.
  196. _bstr_t bstrtTmp = bstrDrive;
  197. bstrtTmp += L"\\";
  198. bool fFoundIt = false;
  199. for(long n = 0;
  200. n < vecMappedDrives.size() && !fFoundIt;
  201. n++)
  202. {
  203. if(_wcsicmp(bstrtTmp, vecMappedDrives[n]) == 0)
  204. {
  205. fFoundIt = true;
  206. n--;
  207. }
  208. }
  209. // For the mapped drive, obtain its
  210. // properties and store in the safearray...
  211. if(fFoundIt)
  212. {
  213. hr = GetMappedDriveInfo(
  214. vecMappedDrives[n],
  215. 0, // for code reuse
  216. saDriveProps,
  217. dwReqProps);
  218. // And finally package the safearray
  219. // into the outgoing variant.
  220. ::VariantInit(pvarData);
  221. V_VT(pvarData) = VT_BSTR | VT_ARRAY;
  222. V_ARRAY(pvarData) = saDriveProps;
  223. }
  224. }
  225. else
  226. {
  227. hr = WBEM_E_OUT_OF_MEMORY;
  228. }
  229. }
  230. return hr;
  231. }
  232. // Builds a list of mapped drives as
  233. // seen with respect to the process
  234. // identified by m_dwImpPID. Hence, this
  235. // routine will return a valid picture
  236. // of the drives seen by m_dwImpPID, regardless
  237. // of our current thread impersonation.
  238. //
  239. #ifdef NTONLY // uses ntdll.dll functions
  240. void CMDH::GetMappedDriveList(
  241. std::vector<_bstr_t>& vecMappedDrives)
  242. {
  243. // Need to call NtQueryInformationProcess,
  244. // asking for ProcessDeviceMap info, specifying
  245. // a handle to the process identified by
  246. // m_dwImpPID.
  247. // Need to get a process handle to the
  248. // process specified by PID.
  249. NTSTATUS Status;
  250. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
  251. Status = ::NtQueryInformationProcess(
  252. ::GetCurrentProcess() /*hProcess*/,
  253. ProcessDeviceMap,
  254. &ProcessDeviceMapInfo.Query,
  255. sizeof(ProcessDeviceMapInfo.Query),
  256. NULL);
  257. if(NT_SUCCESS(Status))
  258. {
  259. WCHAR wstrDrive[4];
  260. for(short s = 0;
  261. s < 32;
  262. s++)
  263. {
  264. if(ProcessDeviceMapInfo.Query.DriveMap & (1<<s))
  265. {
  266. wstrDrive[0] = s + L'A';
  267. wstrDrive[1] = L':';
  268. wstrDrive[2] = L'\\';
  269. wstrDrive[3] = L'\0';
  270. if(ProcessDeviceMapInfo.Query.DriveType[s] ==
  271. DOSDEVICE_DRIVE_REMOTE)
  272. {
  273. vecMappedDrives.push_back(wstrDrive);
  274. }
  275. else if(ProcessDeviceMapInfo.Query.DriveType[s] ==
  276. DOSDEVICE_DRIVE_CALCULATE)
  277. {
  278. // We have more work to do.
  279. // Create an nt file path...
  280. WCHAR NtDrivePath[_MAX_PATH] = { '\0' };
  281. wcscpy(NtDrivePath, L"\\??\\");
  282. wcscat(NtDrivePath, wstrDrive);
  283. // Create the unicode string...
  284. UNICODE_STRING ustrNtFileName;
  285. ::RtlInitUnicodeString(
  286. &ustrNtFileName,
  287. NtDrivePath);
  288. // Get the object attributes...
  289. OBJECT_ATTRIBUTES oaAttributes;
  290. InitializeObjectAttributes(&oaAttributes,
  291. &ustrNtFileName,
  292. OBJ_CASE_INSENSITIVE,
  293. NULL,
  294. NULL);
  295. // Open the file
  296. DWORD dwStatus = ERROR_SUCCESS;
  297. IO_STATUS_BLOCK IoStatusBlock;
  298. HANDLE hFile = NULL;
  299. dwStatus = ::NtOpenFile(
  300. &hFile,
  301. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  302. &oaAttributes,
  303. &IoStatusBlock,
  304. FILE_SHARE_READ | FILE_SHARE_WRITE,
  305. 0);
  306. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  307. if(NT_SUCCESS(dwStatus))
  308. {
  309. try
  310. {
  311. // Get information on the file...
  312. dwStatus = ::NtQueryVolumeInformationFile(
  313. hFile,
  314. &IoStatusBlock,
  315. &DeviceInfo,
  316. sizeof(DeviceInfo),
  317. FileFsDeviceInformation);
  318. ::NtClose(hFile);
  319. hFile = NULL;
  320. }
  321. catch(...)
  322. {
  323. ::NtClose(hFile);
  324. hFile = NULL;
  325. throw;
  326. }
  327. }
  328. if(NT_SUCCESS(dwStatus))
  329. {
  330. if((DeviceInfo.Characteristics & FILE_REMOTE_DEVICE) ||
  331. (DeviceInfo.DeviceType == FILE_DEVICE_NETWORK ||
  332. DeviceInfo.DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM))
  333. {
  334. // it is a remote drive...
  335. vecMappedDrives.push_back(wstrDrive);
  336. }
  337. }
  338. }
  339. }
  340. }
  341. }
  342. }
  343. #endif
  344. // All of the routines used in this function -
  345. // GetProviderName, GetVolumeInformation,
  346. // and GetDriveFreeSpace, return information
  347. // for the drive who's mapping string appears
  348. // in wstrDriveName with respect to that
  349. // mapping string's meaning in the context of
  350. // the current thread's impersonation. Hence
  351. // we impersonate before calling them.
  352. //
  353. HRESULT CMDH::GetMappedDriveInfo(
  354. LPCWSTR wstrDriveName,
  355. long lDrivePropArrayDriveIndex,
  356. SAFEARRAY* saDriveProps,
  357. DWORD dwReqProps)
  358. {
  359. HRESULT hr = S_OK;
  360. // Right away we can set the device id prop...
  361. hr = SetProperty(
  362. lDrivePropArrayDriveIndex,
  363. PROP_DEVICEID,
  364. wstrDriveName,
  365. saDriveProps);
  366. // If we couldn't even set the device id, it is
  367. // a problem. Otherwise, continue.
  368. if(SUCCEEDED(hr))
  369. {
  370. // Set the other properties if they
  371. // were requested...
  372. // Get Expensive properties now if appropriate.
  373. if(dwReqProps &
  374. (SPIN_DISK |
  375. GET_PROVIDER_NAME))
  376. {
  377. // Impersonate member process...
  378. SmartRevertTokenHANDLE hCurImpTok;
  379. hCurImpTok = Impersonate();
  380. if(dwReqProps & GET_PROVIDER_NAME)
  381. {
  382. GetProviderName(
  383. wstrDriveName,
  384. lDrivePropArrayDriveIndex,
  385. saDriveProps);
  386. }
  387. if(dwReqProps & GET_VOL_INFO)
  388. {
  389. // Obtain volume information
  390. GetDriveVolumeInformation(
  391. wstrDriveName,
  392. lDrivePropArrayDriveIndex,
  393. saDriveProps);
  394. }
  395. if ( dwReqProps &
  396. (PROP_SIZE |
  397. PROP_FREE_SPACE) )
  398. {
  399. GetDriveFreeSpace(
  400. wstrDriveName,
  401. lDrivePropArrayDriveIndex,
  402. saDriveProps);
  403. }
  404. }
  405. }
  406. return hr;
  407. }
  408. // Presents a view based on the current
  409. // impersonation of the current thread.
  410. //
  411. HRESULT CMDH::GetProviderName(
  412. LPCWSTR wstrDriveName,
  413. long lDrivePropArrayDriveIndex,
  414. SAFEARRAY* saDriveProps)
  415. {
  416. HRESULT hr = S_OK;
  417. WCHAR wstrTempDrive[_MAX_PATH] ;
  418. wsprintf(
  419. wstrTempDrive,
  420. L"%c%c",
  421. wstrDriveName[0],
  422. wstrDriveName[1]);
  423. WCHAR wstrProvName[_MAX_PATH];
  424. DWORD dwProvName = sizeof(wstrProvName ) ;
  425. WCHAR* wstrNewProvName = NULL;
  426. // Use of delay loaded function requires exception handler.
  427. SetStructuredExceptionHandler seh;
  428. try
  429. {
  430. DWORD dwRetCode = ::WNetGetConnection(
  431. wstrTempDrive,
  432. wstrProvName,
  433. &dwProvName);
  434. if(dwRetCode == NO_ERROR ||
  435. dwRetCode == ERROR_CONNECTION_UNAVAIL)
  436. {
  437. hr = SetProperty(
  438. lDrivePropArrayDriveIndex,
  439. PROP_PROVIDER_NAME,
  440. wstrProvName,
  441. saDriveProps);
  442. }
  443. else
  444. {
  445. dwRetCode = GetLastError();
  446. if((dwRetCode == ERROR_MORE_DATA) &&
  447. (dwProvName > _MAX_PATH))
  448. {
  449. wstrNewProvName = new WCHAR[dwProvName];
  450. if(wstrNewProvName != NULL)
  451. {
  452. dwRetCode = ::WNetGetConnection(
  453. wstrTempDrive,
  454. wstrNewProvName,
  455. &dwProvName);
  456. if(dwRetCode == NO_ERROR ||
  457. dwRetCode == ERROR_CONNECTION_UNAVAIL)
  458. {
  459. hr = SetProperty(
  460. lDrivePropArrayDriveIndex,
  461. PROP_PROVIDER_NAME,
  462. wstrNewProvName,
  463. saDriveProps);
  464. }
  465. else
  466. {
  467. hr = HRESULT_FROM_WIN32(dwRetCode);
  468. }
  469. delete wstrNewProvName;
  470. }
  471. else
  472. {
  473. hr = E_OUTOFMEMORY;
  474. }
  475. }
  476. else
  477. {
  478. hr = HRESULT_FROM_WIN32(dwRetCode);
  479. }
  480. }
  481. }
  482. catch(Structured_Exception se)
  483. {
  484. DelayLoadDllExceptionFilter(se.GetExtendedInfo());
  485. if(wstrNewProvName)
  486. {
  487. delete wstrNewProvName;
  488. wstrNewProvName = NULL;
  489. }
  490. hr = WBEM_E_FAILED;
  491. }
  492. catch(...)
  493. {
  494. if(wstrNewProvName)
  495. {
  496. delete wstrNewProvName;
  497. wstrNewProvName = NULL;
  498. }
  499. // The filter will do the work. Just re-throw here.
  500. throw;
  501. }
  502. return hr;
  503. }
  504. // Presents a view based on the current
  505. // impersonation of the current thread.
  506. //
  507. HRESULT CMDH::GetDriveVolumeInformation(
  508. LPCWSTR wstrDriveName,
  509. long lDrivePropArrayDriveIndex,
  510. SAFEARRAY* saDriveProps)
  511. {
  512. HRESULT hr = S_OK;
  513. DWORD dwResult = ERROR_SUCCESS;
  514. WCHAR wstrVolumeName[_MAX_PATH];
  515. WCHAR wstrFileSystem[_MAX_PATH];
  516. WCHAR wstrTmp[_MAX_PATH];
  517. DWORD dwSerialNumber;
  518. DWORD dwMaxComponentLength;
  519. DWORD dwFSFlags;
  520. BOOL fReturn = ::GetVolumeInformation(
  521. wstrDriveName,
  522. wstrVolumeName,
  523. sizeof(wstrVolumeName)/sizeof(WCHAR),
  524. &dwSerialNumber,
  525. &dwMaxComponentLength,
  526. &dwFSFlags,
  527. wstrFileSystem,
  528. sizeof(wstrFileSystem)/sizeof(WCHAR)
  529. );
  530. if(fReturn)
  531. {
  532. // Win32 API will return volume information for all drive types.
  533. SetProperty(
  534. lDrivePropArrayDriveIndex,
  535. PROP_VOLUME_NAME,
  536. wstrVolumeName,
  537. saDriveProps);
  538. SetProperty(
  539. lDrivePropArrayDriveIndex,
  540. PROP_FILE_SYSTEM,
  541. wstrFileSystem,
  542. saDriveProps);
  543. if (dwSerialNumber != 0)
  544. {
  545. WCHAR wstrSerialNumber[_MAX_PATH];
  546. wsprintf(wstrSerialNumber,
  547. L"%.8X",
  548. dwSerialNumber);
  549. SetProperty(
  550. lDrivePropArrayDriveIndex,
  551. PROP_VOLUME_SERIAL_NUMBER,
  552. wstrSerialNumber,
  553. saDriveProps);
  554. }
  555. SetProperty(
  556. lDrivePropArrayDriveIndex,
  557. PROP_COMPRESSED,
  558. STR_FROM_bool(dwFSFlags & FS_VOL_IS_COMPRESSED),
  559. saDriveProps);
  560. SetProperty(
  561. lDrivePropArrayDriveIndex,
  562. PROP_SUPPORTS_FILE_BASED_COMPRESSION,
  563. STR_FROM_bool(dwFSFlags & FS_FILE_COMPRESSION),
  564. saDriveProps);
  565. _ultow(dwMaxComponentLength,
  566. wstrTmp,
  567. 10);
  568. SetProperty(
  569. lDrivePropArrayDriveIndex,
  570. PROP_MAXIMUM_COMPONENT_LENGTH,
  571. wstrTmp,
  572. saDriveProps);
  573. SetProperty(
  574. lDrivePropArrayDriveIndex,
  575. PROP_SUPPORTS_DISK_QUOTAS,
  576. STR_FROM_bool(dwFSFlags & FILE_VOLUME_QUOTAS),
  577. saDriveProps);
  578. // To get the state of the volume,
  579. // we need to get the Interface pointer...
  580. IDiskQuotaControlPtr pIQuotaControl;
  581. ::SetLastError(ERROR_SUCCESS);
  582. if(SUCCEEDED(CoCreateInstance(
  583. CLSID_DiskQuotaControl,
  584. NULL,
  585. CLSCTX_INPROC_SERVER,
  586. IID_IDiskQuotaControl,
  587. (void **)&pIQuotaControl)))
  588. {
  589. WCHAR wstrVolumePathName[MAX_PATH + 1];
  590. ::SetLastError(ERROR_SUCCESS);
  591. BOOL fRetVal = FALSE;
  592. CKernel32Api* pKernel32 = NULL;
  593. pKernel32 = (CKernel32Api*)CResourceManager::sm_TheResourceManager.GetResource(
  594. g_guidKernel32Api, NULL);
  595. try
  596. {
  597. if(pKernel32)
  598. {
  599. pKernel32->GetVolumePathName(
  600. wstrDriveName,
  601. wstrVolumePathName,
  602. MAX_PATH,
  603. &fRetVal);
  604. CResourceManager::sm_TheResourceManager.ReleaseResource(
  605. g_guidKernel32Api, pKernel32);
  606. pKernel32 = NULL;
  607. }
  608. }
  609. catch(...)
  610. {
  611. if(pKernel32)
  612. {
  613. CResourceManager::sm_TheResourceManager.ReleaseResource(
  614. g_guidKernel32Api, pKernel32);
  615. }
  616. throw;
  617. }
  618. if(fRetVal)
  619. {
  620. ::SetLastError(ERROR_SUCCESS);
  621. if(SUCCEEDED(pIQuotaControl->Initialize(
  622. wstrVolumePathName,
  623. TRUE)))
  624. {
  625. DWORD dwQuotaState;
  626. ::SetLastError(ERROR_SUCCESS);
  627. hr = pIQuotaControl->GetQuotaState(&dwQuotaState);
  628. if(SUCCEEDED(hr))
  629. {
  630. SetProperty(
  631. lDrivePropArrayDriveIndex,
  632. PROP_QUOTAS_INCOMPLETE,
  633. STR_FROM_bool(DISKQUOTA_FILE_INCOMPLETE(dwQuotaState)),
  634. saDriveProps);
  635. SetProperty(
  636. lDrivePropArrayDriveIndex,
  637. PROP_QUOTAS_REBUILDING,
  638. STR_FROM_bool(DISKQUOTA_FILE_REBUILDING(dwQuotaState)),
  639. saDriveProps);
  640. SetProperty(
  641. lDrivePropArrayDriveIndex,
  642. PROP_QUOTAS_DISABLED,
  643. STR_FROM_bool(DISKQUOTA_STATE_DISABLED & dwQuotaState),
  644. saDriveProps);
  645. }
  646. else
  647. {
  648. dwResult = GetLastError();
  649. }
  650. }
  651. else
  652. {
  653. dwResult = GetLastError();
  654. }
  655. }
  656. }
  657. else
  658. {
  659. dwResult = GetLastError();
  660. }
  661. }
  662. else
  663. {
  664. dwResult = GetLastError();
  665. }
  666. // for chkdsk VolumeDirty Property
  667. BOOLEAN fVolumeDirty = FALSE;
  668. BOOL fSuccess = FALSE;
  669. _bstr_t bstrtDosDrive(wstrDriveName);
  670. UNICODE_STRING string = { 0 };
  671. _bstr_t nt_drive_name;
  672. try
  673. {
  674. if ( RtlDosPathNameToNtPathName_U (
  675. (LPCWSTR)bstrtDosDrive,
  676. &string,
  677. NULL,
  678. NULL
  679. )
  680. )
  681. {
  682. string.Buffer[string.Length/sizeof(WCHAR) - 1] = 0;
  683. nt_drive_name = string.Buffer;
  684. if(string.Buffer)
  685. {
  686. RtlFreeUnicodeString(&string);
  687. string.Buffer = NULL;
  688. }
  689. }
  690. else
  691. {
  692. dwResult = RtlNtStatusToDosError ( (NTSTATUS)NtCurrentTeb()->LastStatusValue );
  693. }
  694. }
  695. catch(...)
  696. {
  697. if(string.Buffer)
  698. {
  699. RtlFreeUnicodeString(&string);
  700. string.Buffer = NULL;
  701. }
  702. throw;
  703. }
  704. if ( dwResult == ERROR_SUCCESS )
  705. {
  706. ::SetLastError(ERROR_SUCCESS);
  707. fSuccess = IsVolumeDirty(
  708. nt_drive_name,
  709. &fVolumeDirty );
  710. if(fSuccess)
  711. {
  712. SetProperty(
  713. lDrivePropArrayDriveIndex,
  714. PROP_PERFORM_AUTOCHECK,
  715. STR_FROM_bool(!fVolumeDirty),
  716. saDriveProps);
  717. }
  718. else
  719. {
  720. dwResult = GetLastError();
  721. }
  722. }
  723. if(dwResult != ERROR_SUCCESS)
  724. {
  725. hr = HRESULT_FROM_WIN32(dwResult);
  726. }
  727. return hr;
  728. }
  729. // Presents a view based on the current
  730. // impersonation of the current thread.
  731. //
  732. BOOLEAN CMDH::IsVolumeDirty(
  733. _bstr_t &bstrtNtDriveName,
  734. BOOLEAN *Result)
  735. {
  736. UNICODE_STRING u;
  737. OBJECT_ATTRIBUTES obj;
  738. NTSTATUS status = 0;
  739. IO_STATUS_BLOCK iosb;
  740. HANDLE h = 0;
  741. ULONG r = 0;
  742. BOOLEAN bRetVal = FALSE;
  743. WCHAR wstrNtDriveName[_MAX_PATH];
  744. wcscpy(wstrNtDriveName, bstrtNtDriveName);
  745. u.Length = (USHORT) wcslen(wstrNtDriveName) * sizeof(WCHAR);
  746. u.MaximumLength = u.Length;
  747. u.Buffer = wstrNtDriveName;
  748. InitializeObjectAttributes(&obj, &u, OBJ_CASE_INSENSITIVE, 0, 0);
  749. status = NtOpenFile(
  750. &h,
  751. SYNCHRONIZE | FILE_READ_DATA,
  752. &obj,
  753. &iosb,
  754. FILE_SHARE_READ|FILE_SHARE_WRITE,
  755. FILE_SYNCHRONOUS_IO_ALERT);
  756. if(NT_SUCCESS(status))
  757. {
  758. try
  759. {
  760. status = NtFsControlFile(
  761. h, NULL, NULL, NULL,
  762. &iosb,
  763. FSCTL_IS_VOLUME_DIRTY,
  764. NULL, 0,
  765. &r, sizeof(r));
  766. if(NT_SUCCESS(status))
  767. {
  768. #if(_WIN32_WINNT >= 0x0500)
  769. *Result = (BOOLEAN)(r & VOLUME_IS_DIRTY);
  770. #else
  771. *Result = (BOOLEAN)r;
  772. #endif
  773. bRetVal = TRUE;
  774. }
  775. }
  776. catch(...)
  777. {
  778. NtClose(h);
  779. h = 0;
  780. throw;
  781. }
  782. NtClose(h);
  783. h = 0;
  784. }
  785. return bRetVal;
  786. }
  787. // Presents a view based on the current
  788. // impersonation of the current thread.
  789. //
  790. HRESULT CMDH::GetDriveFreeSpace(
  791. LPCWSTR wstrDriveName,
  792. long lDrivePropArrayDriveIndex,
  793. SAFEARRAY* saDriveProps)
  794. {
  795. HRESULT hr = S_OK;
  796. ULARGE_INTEGER uliTotalBytes;
  797. ULARGE_INTEGER uliUserFreeBytes;
  798. ULARGE_INTEGER uliTotalFreeBytes;
  799. ::SetLastError(ERROR_SUCCESS);
  800. if(::GetDiskFreeSpaceEx(
  801. wstrDriveName,
  802. &uliUserFreeBytes,
  803. &uliTotalBytes,
  804. &uliTotalFreeBytes))
  805. {
  806. WCHAR wstrTmp[128] = { L'\0' };
  807. SetProperty(
  808. lDrivePropArrayDriveIndex,
  809. PROP_SIZE,
  810. _ui64tow(
  811. uliTotalBytes.QuadPart,
  812. wstrTmp,
  813. 10),
  814. saDriveProps);
  815. SetProperty(
  816. lDrivePropArrayDriveIndex,
  817. PROP_FREE_SPACE,
  818. _ui64tow(
  819. uliTotalFreeBytes.QuadPart,
  820. wstrTmp,
  821. 10),
  822. saDriveProps);
  823. }
  824. else
  825. {
  826. hr = HRESULT_FROM_WIN32(::GetLastError());
  827. }
  828. return hr;
  829. }
  830. // Sets a property for a given drive
  831. // in the drive safearray.
  832. //
  833. HRESULT CMDH::SetProperty(
  834. long lDrivePropArrayDriveIndex,
  835. long lDrivePropArrayPropIndex,
  836. LPCWSTR wstrPropValue,
  837. SAFEARRAY* saDriveProps)
  838. {
  839. HRESULT hr = S_OK;
  840. bstr_t bstrTmp( wstrPropValue); // this will work because PutElement makes a copy
  841. long ix[2];
  842. ix[0] = lDrivePropArrayPropIndex;
  843. ix[1] = lDrivePropArrayDriveIndex;
  844. hr = ::SafeArrayPutElement(saDriveProps, ix, (void *)((BSTR)bstrTmp));
  845. return hr;
  846. }
  847. // Sets our current thread's impersonation
  848. // to the token belonging to the process
  849. // identified by our member, m_dwImpPID.
  850. //
  851. HANDLE CMDH::Impersonate()
  852. {
  853. HANDLE hCurToken = INVALID_HANDLE_VALUE;
  854. // Find the explorer process...
  855. if(m_dwImpPID != -1L)
  856. {
  857. //
  858. // get SID of current process
  859. //
  860. CSid csidCurrentProcess;
  861. {
  862. //
  863. // get process credentials
  864. // and try to get client's back when leaving scope
  865. //
  866. WbemCoRevertToSelf () ;
  867. ScopeGuard SmartWbemCoImpersonateClientFnc = MakeGuard ( WbemCoImpersonateClient ) ;
  868. CProcessToken cpt ( NULL, true, TOKEN_QUERY ) ;
  869. PBYTE buff = NULL ;
  870. DWORD dwBuff = 0L ;
  871. if ( FALSE == ::GetTokenInformation (
  872. cpt.GetTokenHandle () ,
  873. TokenUser ,
  874. NULL ,
  875. 0 ,
  876. &dwBuff
  877. )
  878. )
  879. {
  880. if ( ERROR_INSUFFICIENT_BUFFER == ::GetLastError () )
  881. {
  882. buff = new BYTE [ dwBuff ] ;
  883. wmilib::auto_buffer < BYTE > SmartBuff ( buff ) ;
  884. if ( TRUE == ::GetTokenInformation (
  885. cpt.GetTokenHandle () ,
  886. TokenUser ,
  887. buff ,
  888. dwBuff ,
  889. &dwBuff
  890. )
  891. )
  892. {
  893. csidCurrentProcess = CSid ( ( ( PTOKEN_USER ) buff )->User.Sid ) ;
  894. }
  895. }
  896. }
  897. SmartWbemCoImpersonateClientFnc.Dismiss () ;
  898. HRESULT t_hResult = S_OK ;
  899. if ( FAILED ( t_hResult = WbemCoImpersonateClient () ) )
  900. {
  901. throw CFramework_Exception( L"CoImpersonateClient failed", t_hResult ) ;
  902. }
  903. }
  904. if ( csidCurrentProcess.IsValid () )
  905. {
  906. //
  907. // smart CloseHandle
  908. //
  909. ScopeGuard SmartCloseHandleFnc = MakeGuard ( CloseHandle, hCurToken ) ;
  910. bool fOK = false;
  911. if(::OpenThreadToken(
  912. ::GetCurrentThread(),
  913. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  914. TRUE,
  915. &hCurToken))
  916. {
  917. SmartCloseHandle hProcess;
  918. hProcess = ::OpenProcess(
  919. PROCESS_QUERY_INFORMATION,
  920. FALSE,
  921. m_dwImpPID);
  922. if(hProcess != INVALID_HANDLE_VALUE)
  923. {
  924. // now open its token...
  925. SmartCloseHandle hProcToken;
  926. if(::OpenProcessToken(
  927. hProcess,
  928. TOKEN_READ | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  929. &hProcToken))
  930. {
  931. CProcessToken cpt ( hProcToken );
  932. if ( cpt.IsValidToken () )
  933. {
  934. TOKEN_TYPE type;
  935. if ( cpt.GetTokenType ( type ) )
  936. {
  937. if ( TokenPrimary == type )
  938. {
  939. CToken ct;
  940. if ( ct.Duplicate ( cpt, FALSE ) )
  941. {
  942. // Set the thread token...
  943. if(::SetThreadToken(NULL, ct.GetTokenHandle ()))
  944. {
  945. fOK = true;
  946. }
  947. }
  948. }
  949. else
  950. {
  951. #if DBG == 1
  952. // for testing purpose I will let process break
  953. ::DebugBreak();
  954. #endif
  955. // Set the thread token...
  956. if(::SetThreadToken(NULL, cpt.GetTokenHandle ()))
  957. {
  958. fOK = true;
  959. }
  960. }
  961. }
  962. }
  963. }
  964. }
  965. }
  966. SmartCloseHandleFnc.Dismiss () ;
  967. if(!fOK)
  968. {
  969. if(hCurToken != INVALID_HANDLE_VALUE)
  970. {
  971. ::CloseHandle(hCurToken);
  972. hCurToken = INVALID_HANDLE_VALUE;
  973. }
  974. }
  975. else
  976. {
  977. BOOL bSucceeded = FALSE ;
  978. //
  979. // need to adjust SD associated with thread
  980. // to contain current process' SID
  981. //
  982. CThreadToken ctt;
  983. if ( ctt.IsValidToken () )
  984. {
  985. // Obtain access to its security descriptor...
  986. CSecureKernelObj sko(ctt.GetTokenHandle(), FALSE);
  987. // Modify the security descriptor...
  988. if( sko.AddDACLEntry (
  989. csidCurrentProcess,
  990. ENUM_ACCESS_ALLOWED_ACE_TYPE,
  991. TOKEN_ALL_ACCESS,
  992. 0,
  993. NULL,
  994. NULL
  995. ))
  996. {
  997. if ( ERROR_SUCCESS == sko.ApplySecurity( DACL_SECURITY_INFORMATION ) )
  998. {
  999. bSucceeded = TRUE ;
  1000. }
  1001. }
  1002. }
  1003. if ( FALSE == bSucceeded )
  1004. {
  1005. //
  1006. // we need to revert back as SD was
  1007. // not successfully adjusted
  1008. //
  1009. if ( ! ::SetThreadToken ( NULL, hCurToken ) )
  1010. {
  1011. ::CloseHandle ( hCurToken ) ;
  1012. throw CFramework_Exception(L"SetThreadToken failed", GetLastError());
  1013. }
  1014. ::CloseHandle ( hCurToken ) ;
  1015. hCurToken = INVALID_HANDLE_VALUE ;
  1016. }
  1017. }
  1018. }
  1019. }
  1020. return hCurToken;
  1021. }