Source code of Windows XP (NT5)
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.

860 lines
26 KiB

  1. // Copyright (c) 1996-2002 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. //
  6. // File: sharenum.cxx
  7. //
  8. // Contents: The CShareEnumerator class implementation.
  9. //
  10. // Classes: CShareEnumerator
  11. //
  12. // History: 28-Jan-98 MikeHill Created
  13. //
  14. // Notes:
  15. //
  16. //--------------------------------------------------------------------------
  17. #include "pch.cxx"
  18. #pragma hdrstop
  19. #include "trklib.hxx"
  20. //+-------------------------------------------------------------------
  21. //
  22. // Function: CShareEnumerator::Initialize
  23. //
  24. // Synopsis: Initializes this enumeration by calling
  25. // NetShareEnum.
  26. //
  27. // Arguments: [IDL_handle] (in)
  28. // The RPC binding handle to the client on whom's
  29. // behalf we're acting.
  30. //
  31. // [ptszMachineName] (in)
  32. // The machine on which shares are to be enumerated.
  33. // If this value is NULL, the local machine is assumed.
  34. //
  35. //
  36. // Returns: None.
  37. //
  38. // Raises: On error.
  39. //
  40. //--------------------------------------------------------------------
  41. VOID
  42. CShareEnumerator::Initialize( RPC_BINDING_HANDLE IDL_handle, const TCHAR *ptszMachineName )
  43. {
  44. NET_API_STATUS netstatus;
  45. NETRESOURCE netresourceMachine;
  46. DWORD dwTotalEntries;
  47. TrkAssert( !_fInitialized );
  48. // Start with a clean state
  49. _ClearCache();
  50. _iCurrentEntry = static_cast<ULONG>(-1);
  51. _fInitialized = TRUE;
  52. _IDL_handle = IDL_handle;
  53. // Keep the machine name, retrieving it if necessary.
  54. _tcscpy( _tszMachineName, TEXT("\\\\") );
  55. if( NULL != ptszMachineName )
  56. _tcscpy( &_tszMachineName[2], ptszMachineName );
  57. else
  58. {
  59. DWORD cbMachineName = sizeof(_tszMachineName) - 2;
  60. if( !GetComputerName( &_tszMachineName[2], &cbMachineName ))
  61. TrkRaiseLastError();
  62. }
  63. // Start the enumeration. We'll simply get all the share information
  64. // at once, instead of using a resume handle and making repeated RPC
  65. // calls to the Server service.
  66. netstatus = NetShareEnum( (TCHAR*) ptszMachineName, // Server (we must de-const it)
  67. 502, // Info level
  68. (LPBYTE*) &_prgshare_info, // Return buffer
  69. MAX_PREFERRED_LENGTH, // Get everything
  70. &_cEntries, // Entries read
  71. &dwTotalEntries, // Total entries avail
  72. NULL ); // Resume handle
  73. if( STATUS_SUCCESS != netstatus )
  74. TrkRaiseWin32Error( HRESULT_FROM_WIN32(netstatus) );
  75. TrkAssert( _cEntries == dwTotalEntries );
  76. return;
  77. }
  78. //+-------------------------------------------------------------------
  79. //
  80. // Function: CShareEnumerator::UnInitialize
  81. //
  82. // Synopsis: Free any resources.
  83. //
  84. // Arguments: None.
  85. //
  86. // Returns: None.
  87. //
  88. // Raises: No
  89. //
  90. //--------------------------------------------------------------------
  91. VOID
  92. CShareEnumerator::UnInitialize()
  93. {
  94. if( _fInitialized )
  95. {
  96. if( NULL != _prgshare_info )
  97. NetApiBufferFree( _prgshare_info );
  98. InitLocals();
  99. }
  100. CTrkRpcConfig::UnInitialize();
  101. }
  102. //+-------------------------------------------------------------------
  103. //
  104. // Function: CShareEnumerator::_ClearCache
  105. //
  106. // Synopsis: Clear the data members of the CShareEnumerator
  107. // which are cached information about the current share.
  108. // (This is done in preparation to move on to the next
  109. // share in the enumeration.)
  110. //
  111. // Arguments: None.
  112. //
  113. // Returns: None.
  114. //
  115. // Raises: No
  116. //
  117. //--------------------------------------------------------------------
  118. VOID
  119. CShareEnumerator::_ClearCache()
  120. {
  121. // Clear the cached information about the
  122. // current share.
  123. _cchSharePath = (ULONG) -1;
  124. _ulMerit = 0;
  125. _enumHiddenState = HS_UNKNOWN;
  126. }
  127. //+-------------------------------------------------------------------
  128. //
  129. // Function: CShareEnumerator::Next
  130. //
  131. // Synopsis: Moves the enumerator on to the next share in the
  132. // the enumeration.
  133. //
  134. // Arguments: None.
  135. //
  136. // Returns: TRUE if there was another element in the enumeration,
  137. // FALSE if there are no more shares to enumerate.
  138. //
  139. // Raises: No.
  140. //
  141. //--------------------------------------------------------------------
  142. BOOL
  143. CShareEnumerator::Next()
  144. {
  145. TrkAssert( _fInitialized );
  146. if( _iCurrentEntry + 1 < _cEntries )
  147. {
  148. _ClearCache();
  149. _iCurrentEntry++;
  150. return( TRUE );
  151. }
  152. else
  153. return( FALSE );
  154. }
  155. //+-------------------------------------------------------------------
  156. //
  157. // Function: CShareEnumerator::CoversDrivePath
  158. //
  159. // Synopsis: Determines if the current share in the enumeration
  160. // "covers" a given drive path. E.g., a share to
  161. // "c:\docs" covers the drive path "c:\docs\mydoc.doc".
  162. //
  163. // Arguments: [ptszDrivePath]
  164. // The drive-based path to check for coverage.
  165. //
  166. // Returns: TRUE if the current share covers the given path,
  167. // FALSE otherwise.
  168. //
  169. // Raises: No
  170. //
  171. //--------------------------------------------------------------------
  172. BOOL
  173. CShareEnumerator::CoversDrivePath( const TCHAR *ptszDrivePath )
  174. {
  175. TrkAssert( _fInitialized );
  176. TrkAssert( TEXT(':') == ptszDrivePath[1] );
  177. // Does the current share path cover the file? It does if it compares
  178. // successfully with the local path, up to the entire length of the
  179. // share path.
  180. if( _IsValidShare()
  181. &&
  182. QueryCCHSharePath() <= _tcslen(ptszDrivePath)
  183. &&
  184. !_tcsnicmp( GetSharePath(), ptszDrivePath, QueryCCHSharePath() )
  185. )
  186. return TRUE;
  187. else
  188. return FALSE;
  189. }
  190. //+-------------------------------------------------------------------
  191. //
  192. // Function: CShareEnumerator::_IsHiddenShare
  193. //
  194. // Synopsis: Determines if the current share is "hidden"
  195. // (i.e., the share name ends in a '$').
  196. //
  197. // The first time this method is called, the share
  198. // named is checked for hidden-ness. The result is
  199. // cached for subsequent calls.
  200. //
  201. // Arguments: None.
  202. //
  203. // Returns: TRUE if the current share is hidden,
  204. // FALSE if it is visible.
  205. //
  206. // Raises: On error.
  207. //
  208. //--------------------------------------------------------------------
  209. BOOL
  210. CShareEnumerator::_IsHiddenShare()
  211. {
  212. TrkAssert( _fInitialized );
  213. TrkAssert( _IsValidShare() );
  214. TrkAssert( NULL != GetShareName() );
  215. TrkAssert( TEXT('\0') != GetShareName()[0] );
  216. if( _enumHiddenState == HS_UNKNOWN )
  217. {
  218. _enumHiddenState = TEXT('$') == GetShareName()[ _tcslen(GetShareName()) - 1 ]
  219. ? HS_HIDDEN
  220. : HS_VISIBLE;
  221. }
  222. return( HS_HIDDEN == _enumHiddenState );
  223. }
  224. //+-------------------------------------------------------------------
  225. //
  226. // Function: CShareEnumerator::_IsAdminShare
  227. //
  228. // Synopsis: Determines if the current share is Admin share.
  229. // Admin shares are automatically created by the Server
  230. // service during initialization. They're hard-coded
  231. // to be A$, B$, C$, etc., for each of the drives,
  232. // and ADMIN$ for the %windir% directory.
  233. //
  234. // Arguments: None.
  235. //
  236. // Returns: TRUE if the current share is an auto-generated admin share,
  237. // FALSE otherwise.
  238. //
  239. //--------------------------------------------------------------------
  240. BOOL
  241. CShareEnumerator::_IsAdminShare()
  242. {
  243. TCHAR tcDriveLetter;
  244. TrkAssert( _fInitialized );
  245. TrkAssert( _IsValidShare() );
  246. TrkAssert( NULL != GetShareName() );
  247. TrkAssert( TEXT('\0') != GetShareName()[0] );
  248. tcDriveLetter = TrkCharUpper( GetShareName()[0] );
  249. // Check for the admin share characteristics.
  250. if( 2 == _tcslen(GetShareName())
  251. &&
  252. TEXT('$') == GetShareName()[ 1 ]
  253. &&
  254. TEXT('A') <= tcDriveLetter
  255. &&
  256. TEXT('Z') >= tcDriveLetter
  257. )
  258. {
  259. return( TRUE ); // It's a drive share
  260. }
  261. else if( !_tcsicmp( TEXT("admin$"), GetShareName() ))
  262. return( TRUE ); // It's the %windir% share
  263. else
  264. return( FALSE );
  265. }
  266. //+----------------------------------------------------------------------------
  267. //
  268. // Method: _IsValidShare
  269. //
  270. // Synopsis: Returns True if the current share is valid. A share
  271. // valid it if it is in the form "<drive letter>:\\". E.g.
  272. // "IPC$" isn't a valid share.
  273. //
  274. // Arguments: None
  275. //
  276. // Returns: None
  277. //
  278. //+----------------------------------------------------------------------------
  279. inline BOOL
  280. CShareEnumerator::_IsValidShare()
  281. {
  282. TCHAR tcFirstChar;
  283. // There should be a path, and it should be at least 3 characters
  284. // (e.g. "D:\")
  285. if( NULL == GetSharePath() || 3 > QueryCCHSharePath() )
  286. return FALSE;
  287. tcFirstChar = TrkCharUpper( GetSharePath()[0] );
  288. // Make sure that the share path begins with "<Drive>:\\".
  289. if( TEXT('A') <= tcFirstChar && tcFirstChar <= TEXT('Z')
  290. &&
  291. TEXT(':') == GetSharePath()[1]
  292. &&
  293. TEXT('\\') == GetSharePath()[2]
  294. )
  295. {
  296. return( TRUE );
  297. }
  298. else
  299. return( FALSE );
  300. }
  301. //+-------------------------------------------------------------------
  302. //
  303. // Function: CShareEnumerator::GetMerit
  304. //
  305. // Synopsis: Returns the linear (ULONG) merit of the current path.
  306. // The greater this merit value, the more useful the share
  307. // is. This is calculated on the first call to this method,
  308. // and cached for use in subsequent calls.
  309. //
  310. // Arguments: None.
  311. //
  312. // Returns: None.
  313. //
  314. // Raises: On error.
  315. //
  316. //--------------------------------------------------------------------
  317. ULONG
  318. CShareEnumerator::GetMerit()
  319. {
  320. TrkAssert( _fInitialized );
  321. // The merit of a share is the bitwise-OR of the share's
  322. // enumAccessLevel, its hidden-ness, and the length of
  323. // the covered path.
  324. //
  325. // Shorter paths are more mertious than longer paths
  326. // (because they cover more of the volume), so we subtract
  327. // the path length from the max-value; thus giving shorter
  328. // paths more weight.
  329. if( 0 == _ulMerit && _IsValidShare() )
  330. {
  331. _ulMerit = ( _GetAccessLevel() )
  332. |
  333. ( SPC_MAX_COVERAGE - QueryCCHSharePath() )
  334. |
  335. ( _IsHiddenShare() ? HS_HIDDEN : HS_VISIBLE );
  336. }
  337. TrkLog(( TRKDBG_MEND, TEXT("Score %d for %s (%s)"),
  338. _ulMerit,
  339. _prgshare_info[ _iCurrentEntry ].shi502_netname,
  340. _prgshare_info[ _iCurrentEntry ].shi502_path ));
  341. return( _ulMerit );
  342. }
  343. static void SDAllocHelper( BYTE **ppb, ULONG cbCurrent, ULONG cbRequired )
  344. {
  345. if( cbRequired <= cbCurrent )
  346. return;
  347. *ppb = new BYTE[ cbRequired ];
  348. if( NULL == *ppb )
  349. {
  350. TrkLog((TRKDBG_ERROR, TEXT("Failed alloc in SDAllocHelper")));
  351. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  352. }
  353. return;
  354. }
  355. void
  356. CShareEnumerator::_AbsoluteSDHelper( const PSECURITY_DESCRIPTOR pSDRelative,
  357. PSECURITY_DESCRIPTOR *ppSDAbs, ULONG *pcbSDAbs,
  358. PACL *ppDaclAbs, ULONG *pcbDaclAbs,
  359. PACL *ppSaclAbs, ULONG *pcbSaclAbs,
  360. PSID *ppSidOwnerAbs, ULONG *pcbSidOwnerAbs,
  361. PSID *ppSidGroupAbs, ULONG *pcbSidGroupAbs )
  362. {
  363. ULONG cbSDAbs = *pcbSDAbs;
  364. ULONG cbDaclAbs = *pcbDaclAbs;
  365. ULONG cbSaclAbs = *pcbSaclAbs;
  366. ULONG cbSidOwnerAbs = *pcbSidOwnerAbs;
  367. ULONG cbSidGroupAbs = *pcbSidGroupAbs;
  368. for( int i = 0; i < 2; i++ )
  369. {
  370. if( !MakeAbsoluteSD( pSDRelative,
  371. *ppSDAbs, pcbSDAbs,
  372. *ppDaclAbs, pcbDaclAbs,
  373. *ppSaclAbs, pcbSaclAbs,
  374. *ppSidOwnerAbs, pcbSidOwnerAbs,
  375. *ppSidGroupAbs, pcbSidGroupAbs ))
  376. {
  377. if( i > 0 || ERROR_INSUFFICIENT_BUFFER != GetLastError() )
  378. {
  379. TrkLog((TRKDBG_ERROR, TEXT("Couldn't make absolute SD")));
  380. TrkRaiseLastError( );
  381. }
  382. TrkLog(( TRKDBG_MEND, TEXT("Realloc _AbsoluteSDHelper") ));
  383. SDAllocHelper( (BYTE**) ppSDAbs, cbSDAbs, *pcbSDAbs );
  384. SDAllocHelper( (BYTE**) ppDaclAbs, cbDaclAbs, *pcbDaclAbs );
  385. SDAllocHelper( (BYTE**) ppSaclAbs, cbSaclAbs, *pcbSaclAbs );
  386. SDAllocHelper( (BYTE**) ppSidOwnerAbs, cbSidOwnerAbs, *pcbSidOwnerAbs );
  387. SDAllocHelper( (BYTE**) ppSidGroupAbs, cbSidGroupAbs, *pcbSidGroupAbs );
  388. }
  389. }
  390. }
  391. //+-------------------------------------------------------------------
  392. //
  393. // Function: CShareEnumerator::_GetAccessLevel
  394. //
  395. // Synopsis: Determines the "access level" of the current share.
  396. // The definition of an access level is provided by
  397. // the enumAccessLevels enumeration in PShareMerit.
  398. //
  399. // Once calculated, this access level is not cached for
  400. // subsequent calls, because this method is only called
  401. // by GetMerit, which provides its own cacheing.
  402. //
  403. // *** Note: This is a temporary solution. This should
  404. // be replaced with a solution that simply checks security
  405. // on the share, without actually attempting to open the
  406. // file.
  407. //
  408. // Arguments: None.
  409. //
  410. // Returns: An access level in the form of an enumAccessLevels.
  411. //
  412. // Raises: On error.
  413. //
  414. //--------------------------------------------------------------------
  415. PShareMerit::enumAccessLevels
  416. CShareEnumerator::_GetAccessLevel()
  417. {
  418. enumAccessLevels AccessLevel = AL_NO_ACCESS;
  419. static const int StackBufferSizes = 256;
  420. TCHAR tszUNCPath[ MAX_PATH + 1 ];
  421. HANDLE hFile = INVALID_HANDLE_VALUE;
  422. int iAttempt;
  423. DWORD rgAccess[] = { GENERIC_READ | GENERIC_WRITE, // => AL_READWRITE_ACCESS
  424. GENERIC_READ, // => AL_READ_ACCESS
  425. GENERIC_WRITE }; // => AL_WRITE_ACCESS
  426. HANDLE hAccessToken;
  427. BOOL fAccessToken = FALSE;
  428. RPC_STATUS rpc_status;
  429. DWORD dwStatus;
  430. DWORD cbActual;
  431. BOOL fImpersonating = FALSE;
  432. BYTE rgbTokenUser[StackBufferSizes];
  433. ULONG cbTokenUser = sizeof(rgbTokenUser);
  434. TOKEN_USER *pTokenUser = (TOKEN_USER*) rgbTokenUser;
  435. BYTE rgbTokenGroups[ 4 * StackBufferSizes ];
  436. ULONG cbTokenGroups = sizeof(rgbTokenGroups);
  437. TOKEN_GROUPS *pTokenGroups = (TOKEN_GROUPS*) rgbTokenGroups;
  438. BYTE rgbSDAbs[ StackBufferSizes ];
  439. ULONG cbSDAbs = sizeof(rgbSDAbs);
  440. PSECURITY_DESCRIPTOR pSDAbs = (PSECURITY_DESCRIPTOR) rgbSDAbs;
  441. BYTE rgbDaclAbs[ StackBufferSizes ];
  442. ULONG cbDaclAbs = sizeof(rgbDaclAbs);
  443. PACL pDaclAbs = (PACL) rgbDaclAbs;
  444. BYTE rgbSaclAbs[ StackBufferSizes ];
  445. ULONG cbSaclAbs = sizeof(rgbSaclAbs);
  446. PACL pSaclAbs = (PACL) rgbSaclAbs;
  447. BYTE rgbSidOwnerAbs[ StackBufferSizes ];
  448. ULONG cbSidOwnerAbs = sizeof(rgbSidOwnerAbs);
  449. PSID pSidOwnerAbs = (PSID) rgbSidOwnerAbs;
  450. BYTE rgbSidGroupAbs[ StackBufferSizes ];
  451. ULONG cbSidGroupAbs = sizeof(rgbSidGroupAbs);
  452. PSID pSidGroupAbs = (PSID) rgbSidGroupAbs;
  453. GENERIC_MAPPING Generic_Mapping = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
  454. PRIVILEGE_SET rgPrivilegeSet[ 10 ];
  455. ULONG cbPrivilegeSet = sizeof(rgPrivilegeSet);
  456. PRIVILEGE_SET *pPrivilegeSet = rgPrivilegeSet;
  457. DWORD dwGrantedAccess;
  458. BOOL fAccessStatus;
  459. CSID csidAdministrators;
  460. CSecDescriptor csdAdministrators;
  461. PSECURITY_DESCRIPTOR psdCheck = NULL;
  462. // If there is no security descriptor and this isn't an admin share,
  463. // it means that Everyone has 'full control'.
  464. if( NULL == _prgshare_info[ _iCurrentEntry ].shi502_security_descriptor && !_IsAdminShare() )
  465. return( AL_FULL_ACCESS );
  466. // Otherwise, we'll look at the share's DACL ...
  467. __try
  468. {
  469. // Impersonate the client
  470. TrkAssert( NULL != _IDL_handle );
  471. if( RpcSecurityEnabled() )
  472. {
  473. rpc_status = RpcImpersonateClient( _IDL_handle );
  474. if( S_OK != rpc_status )
  475. {
  476. TrkLog((TRKDBG_ERROR, TEXT("Couldn't impersonate client")));
  477. TrkRaiseWin32Error( rpc_status );
  478. }
  479. fImpersonating = TRUE;
  480. }
  481. else
  482. {
  483. if( !ImpersonateSelf( SecurityImpersonation ) )
  484. {
  485. TrkLog((TRKDBG_ERROR, TEXT("Couldn't impersonate self")));
  486. TrkRaiseLastError( );
  487. }
  488. fImpersonating = TRUE;
  489. }
  490. // Get the client's access token
  491. if( !OpenThreadToken( GetCurrentThread(),
  492. TOKEN_READ, //TOKEN_ALL_ACCESS,
  493. TRUE, // Open as self
  494. &hAccessToken ))
  495. {
  496. TrkLog((TRKDBG_ERROR, TEXT("Failed OpenThreadToken")));
  497. TrkRaiseLastError( );
  498. }
  499. fAccessToken = TRUE;
  500. // Get the client's owner SID
  501. for( int i = 0; i < 2; i++ )
  502. {
  503. if( !GetTokenInformation( hAccessToken,
  504. TokenUser,
  505. (LPVOID) pTokenUser,
  506. cbTokenUser,
  507. &cbActual ))
  508. {
  509. if( i > 0 || ERROR_INSUFFICIENT_BUFFER != GetLastError() )
  510. {
  511. TrkLog((TRKDBG_ERROR, TEXT("Failed GetTokenInformation (TokenUser)")));
  512. TrkRaiseLastError( );
  513. }
  514. TrkLog(( TRKDBG_MEND, TEXT("Realloc pTokenUser") ));
  515. cbTokenUser = cbActual;
  516. pTokenUser = (TOKEN_USER*) new BYTE[ cbTokenUser ];
  517. if( NULL == pTokenUser )
  518. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  519. }
  520. }
  521. // Get the client's group SID
  522. for( i = 0; i < 2; i++ )
  523. {
  524. if( !GetTokenInformation( hAccessToken,
  525. TokenGroups,
  526. (LPVOID) pTokenGroups,
  527. cbTokenGroups,
  528. &cbActual ))
  529. {
  530. if( i > 0 || ERROR_INSUFFICIENT_BUFFER != GetLastError() )
  531. {
  532. TrkLog((TRKDBG_ERROR, TEXT("Failed GetTokenInformation (TokenGroups)")));
  533. TrkRaiseLastError( );
  534. }
  535. TrkLog(( TRKDBG_MEND, TEXT("Realloc pTokenGroups") ));
  536. cbTokenGroups = cbActual;
  537. pTokenGroups = (TOKEN_GROUPS*) new BYTE[ cbTokenGroups ];
  538. if( NULL == pTokenGroups )
  539. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  540. }
  541. }
  542. // Get a pointer to the security descriptor we want to check against.
  543. if( _IsAdminShare() )
  544. {
  545. // For admin shares, we don't get a security descriptor in _prgshare_info
  546. // from the NetShareEnum call. But, we know what the ACLs on admin shares
  547. // should be, so we'll craft up an SD.
  548. csidAdministrators.Initialize( CSID::CSID_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID,
  549. DOMAIN_ALIAS_RID_ADMINS );
  550. csdAdministrators.Initialize();
  551. csdAdministrators.AddAce( CSecDescriptor::ACL_IS_DACL, CSecDescriptor::AT_ACCESS_ALLOWED,
  552. FILE_ALL_ACCESS, csidAdministrators );
  553. psdCheck = csdAdministrators;
  554. }
  555. else
  556. {
  557. // Convert the share's Security Descriptor into absolute form.
  558. _AbsoluteSDHelper( _prgshare_info[ _iCurrentEntry ].shi502_security_descriptor,
  559. &pSDAbs, &cbSDAbs,
  560. &pDaclAbs, &cbDaclAbs,
  561. &pSaclAbs, &cbSaclAbs,
  562. &pSidOwnerAbs, &cbSidOwnerAbs,
  563. &pSidGroupAbs, &cbSidGroupAbs );
  564. psdCheck = pSDAbs;
  565. }
  566. // The appropriate security descriptor is now in 'psdCheck'
  567. // Put the client's owner SID in the Security Descriptor.
  568. if( !SetSecurityDescriptorOwner( psdCheck,
  569. pTokenUser->User.Sid,
  570. FALSE ))
  571. {
  572. TrkLog((TRKDBG_ERROR, TEXT("Couldn't add user to SD")));
  573. TrkRaiseLastError( );
  574. }
  575. // Put the client's group SID in the Security Descriptor.
  576. // (Perf) Why? I think it's because GetEffectiveRightsFromAcl wasn't working,
  577. // so we had to use AccessCheck. But to use that call I think we had to pass
  578. // in an SD with an owner/group, and the one returned from shi502_security_descriptor
  579. // didn't have them.
  580. if( !SetSecurityDescriptorGroup( psdCheck,
  581. pTokenGroups->Groups->Sid,
  582. FALSE ))
  583. {
  584. TrkLog((TRKDBG_ERROR, TEXT("Couldn't add group to SD")));
  585. TrkRaiseLastError( );
  586. }
  587. // We have to stop impersonating in order to make the AccessCheck call.
  588. fImpersonating = FALSE;
  589. if( RpcSecurityEnabled() )
  590. RpcRevertToSelf();
  591. else
  592. RevertToSelf();
  593. // Check the access that this user has to this share. If this returns
  594. // false, it means that NtAccessCheck returned an error. If this returns
  595. // true, but fAccessStatus is false, it means that NtAccessCheck succeeded,
  596. // but it returned an error in its RealStatus parameter. In either case,
  597. // we need to check GetLastError.
  598. for( i = 0; i < 2; i++ )
  599. {
  600. if( !AccessCheck( psdCheck,
  601. hAccessToken, MAXIMUM_ALLOWED, &Generic_Mapping,
  602. pPrivilegeSet, &cbPrivilegeSet,
  603. &dwGrantedAccess, &fAccessStatus )
  604. ||
  605. !fAccessStatus )
  606. {
  607. if( i > 0 || ERROR_INSUFFICIENT_BUFFER != GetLastError() )
  608. {
  609. TrkLog((TRKDBG_ERROR, TEXT("Couldn't perform AccessCheck for %s (%08x)"),
  610. GetShareName(), HRESULT_FROM_WIN32(GetLastError()) ));
  611. TrkRaiseLastError( );
  612. }
  613. TrkLog(( TRKDBG_MEND, TEXT("Realloc pPrivilegeSet") ));
  614. pPrivilegeSet = (PRIVILEGE_SET*) new BYTE[ cbPrivilegeSet ];
  615. if( NULL == pPrivilegeSet )
  616. {
  617. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't alloc pPrivilegeSet") ));
  618. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  619. }
  620. }
  621. }
  622. // Reduce this complete list of accesses to a synopsis
  623. if( AreAllAccessesGranted( dwGrantedAccess, FILE_ALL_ACCESS ))
  624. AccessLevel = AL_FULL_ACCESS;
  625. else if( AreAllAccessesGranted( dwGrantedAccess, FILE_GENERIC_READ | FILE_GENERIC_WRITE ))
  626. AccessLevel = AL_READ_WRITE_ACCESS;
  627. else if( AreAllAccessesGranted( dwGrantedAccess, FILE_GENERIC_READ ))
  628. AccessLevel = AL_READ_ACCESS;
  629. else if( AreAllAccessesGranted( dwGrantedAccess, FILE_GENERIC_WRITE ))
  630. AccessLevel = AL_WRITE_ACCESS;
  631. else
  632. AccessLevel = AL_NO_ACCESS;
  633. }
  634. __finally
  635. {
  636. csdAdministrators.UnInitialize();
  637. csidAdministrators.UnInitialize();
  638. if( fAccessToken )
  639. CloseHandle( hAccessToken );
  640. if( fImpersonating )
  641. {
  642. if( RpcSecurityEnabled() )
  643. RpcRevertToSelf();
  644. else
  645. RevertToSelf();
  646. }
  647. if( rgPrivilegeSet != pPrivilegeSet )
  648. delete[] pPrivilegeSet;
  649. if( rgbTokenUser != (BYTE*) pTokenUser )
  650. delete[] pTokenUser;
  651. if( rgbTokenGroups != (BYTE*) pTokenGroups )
  652. delete[] pTokenGroups;
  653. if( rgbSDAbs != (BYTE*) pSDAbs )
  654. delete[] pSDAbs;
  655. if( rgbDaclAbs != (BYTE*) pDaclAbs )
  656. delete[] pDaclAbs;
  657. if( rgbSaclAbs != (BYTE*) pSaclAbs )
  658. delete[] pSaclAbs;
  659. if( rgbSidOwnerAbs != (BYTE*) pSidOwnerAbs )
  660. delete[] pSidOwnerAbs;
  661. if( rgbSidGroupAbs != (BYTE*) pSidGroupAbs )
  662. delete[] pSidGroupAbs;
  663. }
  664. return( AccessLevel );
  665. }
  666. //+-------------------------------------------------------------------
  667. //
  668. // Function: CShareEnumerator::GenerateUNCPath
  669. //
  670. // Synopsis: Generate a UNC path to the give drive-based path
  671. // WRT to the current share.
  672. //
  673. // Arguments: [ptszUNCPath] (out)
  674. // Filled with the generated UNC path. This
  675. // is assumed to be at least MAX_PATH+1 characters.
  676. //
  677. // [ptszDrivePath] (in)
  678. // The drive-based path to the file.
  679. // E.g. "c:\my documents\wordfile.doc".
  680. //
  681. // Returns: FALSE if the current share doesn't cover the
  682. // file, TRUE otherwise.
  683. //
  684. // Raises: On error.
  685. //
  686. //--------------------------------------------------------------------
  687. BOOL
  688. CShareEnumerator::GenerateUNCPath( TCHAR *ptszUNCPath, const TCHAR * ptszDrivePath )
  689. {
  690. TrkAssert( _fInitialized );
  691. TrkAssert( TEXT(':') == ptszDrivePath[1] );
  692. // Ensure that this share covers the drive-based path.
  693. if( !CoversDrivePath( ptszDrivePath ))
  694. return( FALSE );
  695. // Start out the UNC name with the \\machine\share.
  696. _tcscpy( ptszUNCPath, _tszMachineName );
  697. _tcscat( ptszUNCPath, TEXT("\\") );
  698. _tcscat( ptszUNCPath, GetShareName() );
  699. _tcscat( ptszUNCPath, TEXT("\\") );
  700. // Finish the UNC name with the portion of the
  701. // volume path which is under the share path.
  702. _tcscat( ptszUNCPath, &ptszDrivePath[ QueryCCHSharePath() ] );
  703. return( TRUE );
  704. }