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.

2458 lines
73 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Abstract:
  4. @doc
  5. @module security.cxx | Implementation of IsAdministrator
  6. @end
  7. Author:
  8. Adi Oltean [aoltean] 07/09/1999
  9. TBD:
  10. Add comments.
  11. Revision History:
  12. Name Date Comments
  13. aoltean 07/09/1999 Created
  14. aoltean 08/26/1999 Adding RegisterProvider
  15. aoltean 08/26/1999 Adding UnregisterProvider
  16. aoltean 08/27/1999 Adding IsAdministrator,
  17. Adding unique provider name test.
  18. aoltean 08/30/1999 Calling OnUnregister on un-registering
  19. Improving IsProviderNameAlreadyUsed.
  20. aoltean 09/09/1999 dss -> vss
  21. aoltean 09/21/1999 Adding a new header for the "ptr" class.
  22. aoltean 09/27/1999 Adding new headers
  23. aoltean 10/15/1999 Moving declaration in security.hxx
  24. aoltean 01/18/2000 Moved into a separate directory
  25. brianb 04/04/2000 Add IsBackupOperator
  26. brianb 04/27/2000 Change IsBackupOperator to check SE_BACKUP_NAME privilege
  27. brianb 05/03/2000 Added GetClientTokenOwner method
  28. brianb 05/10/2000 fix problem with uninitialized variable
  29. brianb 05/12/2000 handle in proc case for impersonation failures
  30. --*/
  31. /////////////////////////////////////////////////////////////////////////////
  32. // Includes
  33. #include "stdafx.hxx"
  34. // This must be included before vs_inc.h since contains the NetApiXXX
  35. #include <lm.h>
  36. #include "vs_inc.hxx"
  37. #include "vs_sec.hxx"
  38. #include "sddl.h"
  39. #include "vs_reg.hxx"
  40. #include "vssmsg.h"
  41. ////////////////////////////////////////////////////////////////////////
  42. // Standard foo for file name aliasing. This code block must be after
  43. // all includes of VSS header files.
  44. //
  45. #ifdef VSS_FILE_ALIAS
  46. #undef VSS_FILE_ALIAS
  47. #endif
  48. #define VSS_FILE_ALIAS "SECSECRC"
  49. //
  50. ////////////////////////////////////////////////////////////////////////
  51. BOOL GetCurrentAccessToken
  52. (
  53. IN BOOL bPerformImpersonation,
  54. OUT HANDLE *phToken
  55. )
  56. {
  57. CVssFunctionTracer ft(VSSDBG_GEN, L"GetCurrentAccessToken");
  58. BS_ASSERT(phToken);
  59. if (bPerformImpersonation)
  60. {
  61. // Impersonate the client to get its identity access token.
  62. // The client should not have RPC_C_IMP_LEVEL_ANONYMOUS otherwise an error will be returned
  63. ft.hr = ::CoImpersonateClient();
  64. if (ft.HrFailed())
  65. {
  66. if (ft.hr != RPC_E_CALL_COMPLETE)
  67. ft.TranslateGenericError( VSSDBG_GEN, ft.hr, L"CoImpersonateClient");
  68. // this means that the call came from the same thread
  69. // Do not perform impersonation. Just use the process
  70. // token
  71. if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, phToken))
  72. ft.TranslateWin32Error(VSSDBG_GEN,L"OpenProcessToken");
  73. ft.hr = S_OK;
  74. return FALSE;
  75. }
  76. BOOL bRes = ::OpenThreadToken
  77. (
  78. GetCurrentThread(), // IN HANDLE ThreadHandle,
  79. TOKEN_QUERY, // IN DWORD DesiredAccess,
  80. TRUE, // IN BOOL OpenAsSelf
  81. phToken // OUT PHANDLE TokenHandle
  82. );
  83. HRESULT hrErr = HRESULT_FROM_WIN32(GetLastError());
  84. // Revert the thread's access token - finish the impersonation
  85. ft.hr = ::CoRevertToSelf();
  86. if (ft.HrFailed())
  87. ft.TranslateWin32Error(VSSDBG_GEN,L"CoRevertToSelf");
  88. if (!bRes)
  89. ft.TranslateGenericError(VSSDBG_GEN, hrErr, L"OpenThreadToken");
  90. return TRUE;
  91. }
  92. else // i.e. if (!bPerformImpersonation)
  93. {
  94. // First try to get the thread token. (assuming we are already impersonating)
  95. // If we succeed, we will go with this.
  96. // If we fail, we ignore the error and proceed with OpenProcessToken (who must succeed).
  97. if (::OpenThreadToken
  98. (
  99. GetCurrentThread(), // IN HANDLE ThreadHandle,
  100. TOKEN_QUERY, // IN DWORD DesiredAccess,
  101. TRUE, // IN BOOL OpenAsSelf
  102. phToken // OUT PHANDLE TokenHandle
  103. ))
  104. return TRUE;
  105. // We don't have a thread token (so we cannot be under impersonation).
  106. // Now try to get the process token
  107. if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, phToken))
  108. ft.TranslateWin32Error(VSSDBG_GEN, L"OpenProcessToken");
  109. return FALSE;
  110. }
  111. }
  112. bool IsInGroup(DWORD dwGroup, bool bImpersonate)
  113. /*++
  114. Routine Description:
  115. Return TRUE if the current thread/process is running under the context of an administrator
  116. Arguments:
  117. none
  118. Remarks:
  119. The current impersonation thread is asked for the access token.
  120. After that we check if the specified group is between token groups.
  121. Return Value:
  122. true, if the caller thread is running under the context of the specified group
  123. false, otherwise
  124. Thrown exceptions:
  125. E_UNEXPECTED // Runtime error
  126. E_OUTOFMEMORY // Memory allocation error
  127. --*/
  128. {
  129. CVssFunctionTracer ft( VSSDBG_GEN, L"IsInGroup" );
  130. BOOL bIsInGroup = FALSE;
  131. PSID psidGroup = NULL;
  132. BOOL bRes;
  133. // Reset the error code
  134. ft.hr = S_OK;
  135. // Build the SID for the Administrators group
  136. SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY;
  137. bRes = AllocateAndInitializeSid
  138. (
  139. &SidAuth, // IN PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  140. 2, // IN BYTE nSubAuthorityCount,
  141. SECURITY_BUILTIN_DOMAIN_RID, // IN DWORD nSubAuthority0,
  142. dwGroup, // IN DWORD nSubAuthority1,
  143. 0, // IN DWORD nSubAuthority2,
  144. 0, // IN DWORD nSubAuthority3,
  145. 0, // IN DWORD nSubAuthority4,
  146. 0, // IN DWORD nSubAuthority5,
  147. 0, // IN DWORD nSubAuthority6,
  148. 0, // IN DWORD nSubAuthority7,
  149. &psidGroup // OUT PSID *pSid
  150. );
  151. if (!bRes)
  152. ft.TranslateError
  153. (
  154. VSSDBG_GEN,
  155. HRESULT_FROM_WIN32(GetLastError()),
  156. L"AllocateAndInitializeSid"
  157. );
  158. try
  159. {
  160. if (!bImpersonate)
  161. bRes = CheckTokenMembership(NULL, psidGroup, &bIsInGroup);
  162. else
  163. {
  164. CVssAutoWin32Handle hToken;
  165. // impersonate client (or get process token)
  166. if (GetCurrentAccessToken(true, hToken.ResetAndGetAddress()))
  167. // check token membership
  168. bRes = CheckTokenMembership(hToken, psidGroup, &bIsInGroup);
  169. else
  170. // called from same thread
  171. bRes = CheckTokenMembership(NULL, psidGroup, &bIsInGroup);
  172. }
  173. if (!bRes)
  174. ft.TranslateError
  175. (
  176. VSSDBG_GEN,
  177. HRESULT_FROM_WIN32(GetLastError()),
  178. L"CheckTokenMembership"
  179. );
  180. }
  181. VSS_STANDARD_CATCH(ft)
  182. HRESULT hr = ft.hr;
  183. // Catch possible AVs
  184. try
  185. {
  186. // Free the previously allocated SID
  187. if (psidGroup)
  188. ::FreeSid( psidGroup );
  189. }
  190. VSS_STANDARD_CATCH(ft)
  191. // Pass down the exception, if any
  192. if (FAILED(hr))
  193. throw(hr);
  194. return bIsInGroup ? true : false;
  195. }
  196. bool HasPrivilege(LPWSTR wszPriv, bool bImpersonate)
  197. /*++
  198. Routine Description:
  199. Return TRUE if the current thread/process has a specific privilege
  200. Arguments:
  201. none
  202. Remarks:
  203. The current impersonation thread is asked for the access token.
  204. After that we check if the specified group is between token groups.
  205. Return Value:
  206. true, if the caller thread is running under the context of the specified group
  207. false, otherwise
  208. Thrown exceptions:
  209. E_UNEXPECTED // Runtime error
  210. E_OUTOFMEMORY // Memory allocation error
  211. --*/
  212. {
  213. CVssFunctionTracer ft( VSSDBG_GEN, L"HasPrivilege" );
  214. BOOL bHasPrivilege = false;
  215. CVssAutoWin32Handle hToken;
  216. LUID TokenValue;
  217. if (!LookupPrivilegeValue (NULL, wszPriv, &TokenValue))
  218. ft.TranslateError
  219. (
  220. VSSDBG_GEN,
  221. HRESULT_FROM_WIN32(GetLastError()),
  222. L"LookupPrivilegeValue"
  223. );
  224. GetCurrentAccessToken(bImpersonate, hToken.ResetAndGetAddress());
  225. BYTE rgb[sizeof(LUID_AND_ATTRIBUTES) + sizeof(PRIVILEGE_SET)];
  226. PRIVILEGE_SET *pSet = (PRIVILEGE_SET *) rgb;
  227. pSet->PrivilegeCount = 1;
  228. pSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
  229. pSet->Privilege[0].Luid = TokenValue;
  230. pSet->Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
  231. if (!PrivilegeCheck(hToken, pSet, &bHasPrivilege))
  232. ft.TranslateError
  233. (
  234. VSSDBG_GEN,
  235. HRESULT_FROM_WIN32(GetLastError()),
  236. L"PrivilegeCheck"
  237. );
  238. return bHasPrivilege ? true : false;
  239. }
  240. TOKEN_USER * GetClientTokenUser(BOOL bImpersonate)
  241. /*++
  242. Routine Description:
  243. Return TOKEN_USER of client process
  244. Arguments:
  245. bImpersonate - TRUE iif an impersonation is required.
  246. Remarks:
  247. The current impersonation thread is asked for the access token.
  248. After that we return the client sid of that token
  249. Return Value:
  250. SID of client thread
  251. Thrown exceptions:
  252. E_UNEXPECTED // Runtime error
  253. E_OUTOFMEMORY // Memory allocation error
  254. --*/
  255. {
  256. CVssFunctionTracer ft( VSSDBG_GEN, L"GetClientTokenUser" );
  257. BOOL bRes;
  258. CVssAutoWin32Handle hToken;
  259. GetCurrentAccessToken(bImpersonate, hToken.ResetAndGetAddress());
  260. DWORD cbSid;
  261. bRes = ::GetTokenInformation
  262. (
  263. hToken, // IN HANDLE TokenHandle,
  264. TokenUser, // IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  265. NULL, // OUT LPVOID TokenInformation,
  266. 0, // IN DWORD TokenInformationLength,
  267. &cbSid // OUT PDWORD ReturnLength
  268. );
  269. BS_ASSERT( bRes == FALSE );
  270. DWORD dwError = GetLastError();
  271. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  272. {
  273. ft.LogError(VSS_ERROR_EXPECTED_INSUFFICENT_BUFFER, VSSDBG_GEN << (HRESULT) dwError);
  274. ft.Throw
  275. (
  276. VSSDBG_GEN,
  277. E_UNEXPECTED,
  278. L"ERROR_INSUFFICIENT_BUFFER expected error . [0x%08lx]",
  279. dwError
  280. );
  281. }
  282. // Allocate the buffer needed to get the Token Groups information
  283. CVssAutoCppPtr<TOKEN_USER*> ptrTokenUser;
  284. ptrTokenUser.AllocateBytes(cbSid);
  285. // Get the all Group SIDs in the token
  286. DWORD cbTokenObtained;
  287. bRes = ::GetTokenInformation
  288. (
  289. hToken, // IN HANDLE TokenHandle,
  290. TokenUser, // IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  291. ptrTokenUser, // OUT LPVOID TokenInformation,
  292. cbSid, // IN DWORD TokenInformationLength,
  293. &cbTokenObtained // OUT PDWORD ReturnLength
  294. );
  295. if ( !bRes )
  296. ft.TranslateError
  297. (
  298. VSSDBG_GEN,
  299. HRESULT_FROM_WIN32(GetLastError()),
  300. L"GetTokenInformation"
  301. );
  302. if (cbTokenObtained != cbSid)
  303. {
  304. ft.LogError(VSS_ERROR_GET_TOKEN_INFORMATION_BUFFER_SIZE_MISMATCH, VSSDBG_GEN << (INT) cbTokenObtained << (INT) cbSid);
  305. ft.Throw
  306. (
  307. VSSDBG_GEN,
  308. E_UNEXPECTED,
  309. L"Unexpected error. Final buffer size = %lu, original size was %lu",
  310. cbTokenObtained,
  311. cbSid
  312. );
  313. }
  314. return ptrTokenUser.Detach();
  315. }
  316. TOKEN_OWNER * GetClientTokenOwner(BOOL bImpersonate)
  317. /*++
  318. Routine Description:
  319. Return TOKEN_OWNER of client process
  320. Arguments:
  321. none
  322. Remarks:
  323. The current impersonation thread is asked for the access token.
  324. After that we return the client sid of that token
  325. Return Value:
  326. SID of client thread
  327. Thrown exceptions:
  328. E_UNEXPECTED // Runtime error
  329. E_OUTOFMEMORY // Memory allocation error
  330. --*/
  331. {
  332. CVssFunctionTracer ft( VSSDBG_GEN, L"GetClientTokenOwner" );
  333. BOOL bRes;
  334. CVssAutoWin32Handle hToken;
  335. GetCurrentAccessToken(bImpersonate, hToken.ResetAndGetAddress());
  336. DWORD cbSid;
  337. bRes = ::GetTokenInformation
  338. (
  339. hToken, // IN HANDLE TokenHandle,
  340. TokenOwner, // IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  341. NULL, // OUT LPVOID TokenInformation,
  342. 0, // IN DWORD TokenInformationLength,
  343. &cbSid // OUT PDWORD ReturnLength
  344. );
  345. BS_ASSERT( bRes == FALSE );
  346. DWORD dwError = GetLastError();
  347. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  348. {
  349. ft.LogError(VSS_ERROR_EXPECTED_INSUFFICENT_BUFFER, VSSDBG_GEN << (HRESULT) dwError);
  350. ft.Throw
  351. (
  352. VSSDBG_GEN,
  353. E_UNEXPECTED,
  354. L"ERROR_INSUFFICIENT_BUFFER expected error . [0x%08lx]",
  355. dwError
  356. );
  357. }
  358. // Allocate the buffer needed to get the Token Groups information
  359. CVssAutoCppPtr<TOKEN_OWNER*> ptrTokenOwner;
  360. ptrTokenOwner.AllocateBytes(cbSid);
  361. // Get the all Group SIDs in the token
  362. DWORD cbTokenObtained;
  363. bRes = ::GetTokenInformation
  364. (
  365. hToken, // IN HANDLE TokenHandle,
  366. TokenOwner, // IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  367. ptrTokenOwner, // OUT LPVOID TokenInformation,
  368. cbSid, // IN DWORD TokenInformationLength,
  369. &cbTokenObtained // OUT PDWORD ReturnLength
  370. );
  371. if ( !bRes )
  372. ft.TranslateError
  373. (
  374. VSSDBG_GEN,
  375. HRESULT_FROM_WIN32(GetLastError()),
  376. L"GetTokenInformation"
  377. );
  378. if (cbTokenObtained != cbSid)
  379. {
  380. ft.LogError(VSS_ERROR_GET_TOKEN_INFORMATION_BUFFER_SIZE_MISMATCH, VSSDBG_GEN << (INT) cbTokenObtained << (INT) cbSid);
  381. ft.Throw
  382. (
  383. VSSDBG_GEN,
  384. E_UNEXPECTED,
  385. L"Unexpected error. Final buffer size = %lu, original size was %lu",
  386. cbTokenObtained,
  387. cbSid
  388. );
  389. }
  390. return ptrTokenOwner.Detach();
  391. }
  392. bool IsAdministrator()
  393. /*++
  394. Routine Description:
  395. Return TRUE if the current thread/process is running under the context of an administrator
  396. Arguments:
  397. none
  398. Remarks:
  399. The current impersonation thread is asked for the access token.
  400. After that we check if the Administrators group is between token groups.
  401. Return Value:
  402. true, if the caller thread is running under the context of an administrator
  403. false, otherwise
  404. Thrown exceptions:
  405. E_UNEXPECTED // Runtime error
  406. E_OUTOFMEMORY // Memory allocation error
  407. --*/
  408. {
  409. return IsInGroup(DOMAIN_ALIAS_RID_ADMINS, true);
  410. }
  411. bool IsProcessAdministrator()
  412. /*++
  413. Routine Description:
  414. Return TRUE if the current process is running under the context of an administrator
  415. Arguments:
  416. none
  417. Remarks:
  418. The current process is asked for the access token.
  419. After that we check if the Administrators group is between token groups.
  420. Return Value:
  421. true, if the process is running under the context of an administrator
  422. false, otherwise
  423. Thrown exceptions:
  424. E_UNEXPECTED // Runtime error
  425. E_OUTOFMEMORY // Memory allocation error
  426. --*/
  427. {
  428. return IsInGroup(DOMAIN_ALIAS_RID_ADMINS, false);
  429. }
  430. bool IsBackupOperator()
  431. /*++
  432. Routine Description:
  433. Return TRUE if the current thread/process is running under the context of a backup operator
  434. Arguments:
  435. none
  436. Remarks:
  437. The current impersonation thread is asked for the access token.
  438. After that we check if the Administrators group is in the groups token
  439. or the backup privilege is enabled
  440. Return Value:
  441. true, if the caller thread is running under the context of an administrator
  442. false, otherwise
  443. Thrown exceptions:
  444. E_UNEXPECTED // Runtime error
  445. E_OUTOFMEMORY // Memory allocation error
  446. --*/
  447. {
  448. // Bug #554480 VSS: Authorize backup operators based on group membership not privilege
  449. // return HasPrivilege(SE_BACKUP_NAME, true) || IsAdministrator();
  450. return HasPrivilege(SE_BACKUP_NAME, true)
  451. || IsInGroup(DOMAIN_ALIAS_RID_BACKUP_OPS, true)
  452. || IsAdministrator();
  453. }
  454. bool IsRestoreOperator()
  455. /*++
  456. Routine Description:
  457. Return TRUE if the current thread/process is running under the context of a restore operator
  458. Arguments:
  459. none
  460. Remarks:
  461. The current impersonation thread is asked for the access token.
  462. After that we check if the Administrators group is in the token groups or
  463. if the restore privilege is enabled.
  464. Return Value:
  465. true, if the caller thread is running under the context of an administrator
  466. false, otherwise
  467. Thrown exceptions:
  468. E_UNEXPECTED // Runtime error
  469. E_OUTOFMEMORY // Memory allocation error
  470. --*/
  471. {
  472. return HasPrivilege(SE_RESTORE_NAME, true) || IsAdministrator();
  473. }
  474. bool IsProcessBackupOperator()
  475. /*++
  476. Routine Description:
  477. Return TRUE if the current process is running under the context of a backup operator
  478. Arguments:
  479. none
  480. Remarks:
  481. Return Value:
  482. true, if the process is running under the context of an administrator or
  483. has SE_BACKUP_NAME privilege enabled
  484. false, otherwise
  485. Thrown exceptions:
  486. E_UNEXPECTED // Runtime error
  487. E_OUTOFMEMORY // Memory allocation error
  488. --*/
  489. {
  490. // Bug #554480 VSS: Authorize backup operators based on group membership not privilege
  491. // (We still keep the check for backup privilege, for safety)
  492. // return HasPrivilege(SE_BACKUP_NAME, false) || IsProcessAdministrator();
  493. return HasPrivilege(SE_BACKUP_NAME, false)
  494. || IsInGroup(DOMAIN_ALIAS_RID_BACKUP_OPS, false)
  495. || IsProcessAdministrator();
  496. }
  497. bool IsProcessRestoreOperator()
  498. /*++
  499. Routine Description:
  500. Return TRUE if the current process is running under the context of a restore operator
  501. Arguments:
  502. none
  503. Remarks:
  504. Return Value:
  505. true, if the process is running under the context of an administrator
  506. or has the SE_RESTORE_NAME privilege; false otherwise
  507. Thrown exceptions:
  508. E_UNEXPECTED // Runtime error
  509. E_OUTOFMEMORY // Memory allocation error
  510. --*/
  511. {
  512. return HasPrivilege(SE_RESTORE_NAME, false) || IsProcessAdministrator();
  513. }
  514. // turn on a particular security privilege
  515. HRESULT TurnOnSecurityPrivilege(LPCWSTR wszPriv)
  516. /*++
  517. Routine Description:
  518. sets the specified privilege on the process token
  519. Arguments:
  520. none
  521. Remarks:
  522. Return Value:
  523. status code for operation
  524. Thrown exceptions:
  525. none
  526. --*/
  527. {
  528. CVssFunctionTracer ft(VSSDBG_GEN, L"TurnOnSecurityPrivilege");
  529. CVssAutoWin32Handle hProcessToken;
  530. try
  531. {
  532. LUID TokenValue = {0, 0};
  533. if (!OpenProcessToken (
  534. GetCurrentProcess(),
  535. TOKEN_ADJUST_PRIVILEGES,
  536. hProcessToken.ResetAndGetAddress()
  537. ))
  538. ft.TranslateWin32Error(VSSDBG_GEN, L"OpenProcessToken");
  539. if (!LookupPrivilegeValue (NULL, wszPriv, &TokenValue))
  540. ft.TranslateWin32Error(VSSDBG_GEN, L"LookupPrivilegeValue(%s)", wszPriv);
  541. TOKEN_PRIVILEGES NewTokenPrivileges;
  542. NewTokenPrivileges.PrivilegeCount = 1;
  543. NewTokenPrivileges.Privileges[0].Luid = TokenValue;
  544. NewTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  545. // AdjustTokenPrivileges succeeds even the token isn't set
  546. SetLastError(ERROR_SUCCESS);
  547. if (!AdjustTokenPrivileges(
  548. hProcessToken,
  549. FALSE,
  550. &NewTokenPrivileges,
  551. sizeof (NewTokenPrivileges),
  552. NULL,
  553. NULL
  554. ))
  555. ft.TranslateWin32Error(VSSDBG_GEN, L"AdjustTokenPrivileges");
  556. }
  557. VSS_STANDARD_CATCH(ft)
  558. return ft.hr;
  559. }
  560. // turn on backup security privilege
  561. HRESULT TurnOnSecurityPrivilegeBackup()
  562. {
  563. return TurnOnSecurityPrivilege(SE_BACKUP_NAME);
  564. }
  565. // turn on restore security privilege
  566. HRESULT TurnOnSecurityPrivilegeRestore()
  567. {
  568. return TurnOnSecurityPrivilege(SE_RESTORE_NAME);
  569. }
  570. // create a basic well known sid such as LOCAL_SERVICE, LOCAL_SYSTEM,
  571. // or NETWORK_SERVICE.
  572. void CAutoSid::CreateBasicSid(WELL_KNOWN_SID_TYPE type)
  573. {
  574. CVssFunctionTracer ft(VSSDBG_GEN, L"CAutoSid::CreateBasicSid");
  575. BS_ASSERT(!Base::IsValid());
  576. DWORD cbSid = 0;
  577. CreateWellKnownSid(type, NULL, NULL, &cbSid);
  578. DWORD dwErr = GetLastError();
  579. if (dwErr != ERROR_INSUFFICIENT_BUFFER)
  580. {
  581. ft.hr = HRESULT_FROM_WIN32(dwErr);
  582. ft.CheckForError(VSSDBG_GEN, L"CreateWellKnownSidType");
  583. }
  584. CVssAutoLocalPtr<SID*> pSid;
  585. pSid.AllocateBytes(cbSid);
  586. if (!CreateWellKnownSid(type, NULL, pSid, &cbSid))
  587. {
  588. ft.hr = HRESULT_FROM_WIN32(GetLastError());
  589. ft.CheckForError(VSSDBG_GEN, L"CreateWellKnownSidType");
  590. }
  591. Base::Attach(pSid.Detach());
  592. }
  593. // create a sid based on a STRING sid
  594. void CAutoSid::CreateFromString(LPCWSTR wsz)
  595. {
  596. CVssFunctionTracer ft(VSSDBG_GEN, L"CAutoSid::CreateFromString");
  597. BS_ASSERT(!Base::IsValid());
  598. if (!ConvertStringSidToSid (wsz, (PSID*)&Base::GetPtrObject()))
  599. {
  600. ft.hr = HRESULT_FROM_WIN32(GetLastError());
  601. ft.CheckForError(VSSDBG_GEN, L"ConvertStringSidToSid");
  602. }
  603. }
  604. //////////////////////////////////////////////////////////////////////////////
  605. // CVssSecurityDescriptor
  606. //
  607. CVssSecurityDescriptor::CVssSecurityDescriptor()
  608. {
  609. m_pSD = NULL;
  610. m_pOwner = NULL;
  611. m_pGroup = NULL;
  612. m_pDACL = NULL;
  613. m_pSACL= NULL;
  614. }
  615. CVssSecurityDescriptor::~CVssSecurityDescriptor()
  616. {
  617. if (m_pSD)
  618. delete m_pSD;
  619. if (m_pOwner)
  620. free(m_pOwner);
  621. if (m_pGroup)
  622. free(m_pGroup);
  623. if (m_pDACL)
  624. free(m_pDACL);
  625. if (m_pSACL)
  626. free(m_pSACL);
  627. }
  628. HRESULT CVssSecurityDescriptor::Initialize()
  629. {
  630. if (m_pSD)
  631. {
  632. delete m_pSD;
  633. m_pSD = NULL;
  634. }
  635. if (m_pOwner)
  636. {
  637. free(m_pOwner);
  638. m_pOwner = NULL;
  639. }
  640. if (m_pGroup)
  641. {
  642. free(m_pGroup);
  643. m_pGroup = NULL;
  644. }
  645. if (m_pDACL)
  646. {
  647. free(m_pDACL);
  648. m_pDACL = NULL;
  649. }
  650. if (m_pSACL)
  651. {
  652. free(m_pSACL);
  653. m_pSACL = NULL;
  654. }
  655. ATLTRY(m_pSD = new SECURITY_DESCRIPTOR);
  656. if (m_pSD == NULL)
  657. return E_OUTOFMEMORY;
  658. if (!InitializeSecurityDescriptor(m_pSD, SECURITY_DESCRIPTOR_REVISION))
  659. {
  660. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  661. delete m_pSD;
  662. m_pSD = NULL;
  663. ATLASSERT(FALSE);
  664. return hr;
  665. }
  666. return S_OK;
  667. }
  668. HRESULT CVssSecurityDescriptor::InitializeFromProcessToken(BOOL bDefaulted)
  669. {
  670. PSID pUserSid = NULL;
  671. PSID pGroupSid = NULL;
  672. HRESULT hr;
  673. Initialize();
  674. hr = GetProcessSids(&pUserSid, &pGroupSid);
  675. if (SUCCEEDED(hr))
  676. {
  677. hr = SetOwner(pUserSid, bDefaulted);
  678. if (SUCCEEDED(hr))
  679. hr = SetGroup(pGroupSid, bDefaulted);
  680. }
  681. if (pUserSid != NULL)
  682. free(pUserSid);
  683. if (pGroupSid != NULL)
  684. free(pGroupSid);
  685. return hr;
  686. }
  687. HRESULT CVssSecurityDescriptor::InitializeFromThreadToken(BOOL bDefaulted, BOOL bRevertToProcessToken)
  688. {
  689. PSID pUserSid = NULL;
  690. PSID pGroupSid = NULL;
  691. HRESULT hr;
  692. Initialize();
  693. hr = GetThreadSids(&pUserSid, &pGroupSid);
  694. if (HRESULT_CODE(hr) == ERROR_NO_TOKEN && bRevertToProcessToken)
  695. hr = GetProcessSids(&pUserSid, &pGroupSid);
  696. if (SUCCEEDED(hr))
  697. {
  698. hr = SetOwner(pUserSid, bDefaulted);
  699. if (SUCCEEDED(hr))
  700. hr = SetGroup(pGroupSid, bDefaulted);
  701. }
  702. if (pUserSid != NULL)
  703. free(pUserSid);
  704. if (pGroupSid != NULL)
  705. free(pGroupSid);
  706. return hr;
  707. }
  708. HRESULT CVssSecurityDescriptor::SetOwner(PSID pOwnerSid, BOOL bDefaulted)
  709. {
  710. ATLASSERT(m_pSD);
  711. // Mark the SD as having no owner
  712. if (!SetSecurityDescriptorOwner(m_pSD, NULL, bDefaulted))
  713. {
  714. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  715. ATLASSERT(FALSE);
  716. return hr;
  717. }
  718. if (m_pOwner)
  719. {
  720. free(m_pOwner);
  721. m_pOwner = NULL;
  722. }
  723. // If they asked for no owner don't do the copy
  724. if (pOwnerSid == NULL)
  725. return S_OK;
  726. // Make a copy of the Sid for the return value
  727. DWORD dwSize = GetLengthSid(pOwnerSid);
  728. m_pOwner = (PSID) malloc(dwSize);
  729. if (m_pOwner == NULL)
  730. return E_OUTOFMEMORY;
  731. if (!CopySid(dwSize, m_pOwner, pOwnerSid))
  732. {
  733. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  734. ATLASSERT(FALSE);
  735. free(m_pOwner);
  736. m_pOwner = NULL;
  737. return hr;
  738. }
  739. ATLASSERT(IsValidSid(m_pOwner));
  740. if (!SetSecurityDescriptorOwner(m_pSD, m_pOwner, bDefaulted))
  741. {
  742. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  743. ATLASSERT(FALSE);
  744. free(m_pOwner);
  745. m_pOwner = NULL;
  746. return hr;
  747. }
  748. return S_OK;
  749. }
  750. HRESULT CVssSecurityDescriptor::SetGroup(PSID pGroupSid, BOOL bDefaulted)
  751. {
  752. ATLASSERT(m_pSD);
  753. // Mark the SD as having no Group
  754. if (!SetSecurityDescriptorGroup(m_pSD, NULL, bDefaulted))
  755. {
  756. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  757. ATLASSERT(FALSE);
  758. return hr;
  759. }
  760. if (m_pGroup)
  761. {
  762. free(m_pGroup);
  763. m_pGroup = NULL;
  764. }
  765. // If they asked for no Group don't do the copy
  766. if (pGroupSid == NULL)
  767. return S_OK;
  768. // Make a copy of the Sid for the return value
  769. DWORD dwSize = GetLengthSid(pGroupSid);
  770. m_pGroup = (PSID) malloc(dwSize);
  771. if (m_pGroup == NULL)
  772. return E_OUTOFMEMORY;
  773. if (!CopySid(dwSize, m_pGroup, pGroupSid))
  774. {
  775. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  776. ATLASSERT(FALSE);
  777. free(m_pGroup);
  778. m_pGroup = NULL;
  779. return hr;
  780. }
  781. ATLASSERT(IsValidSid(m_pGroup));
  782. if (!SetSecurityDescriptorGroup(m_pSD, m_pGroup, bDefaulted))
  783. {
  784. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  785. ATLASSERT(FALSE);
  786. free(m_pGroup);
  787. m_pGroup = NULL;
  788. return hr;
  789. }
  790. return S_OK;
  791. }
  792. HRESULT CVssSecurityDescriptor::Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask, DWORD dwAceFlags)
  793. {
  794. HRESULT hr = AddAccessAllowedACEToACL(&m_pDACL, pszPrincipal, dwAccessMask, dwAceFlags);
  795. if (SUCCEEDED(hr))
  796. SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  797. return hr;
  798. }
  799. HRESULT CVssSecurityDescriptor::Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask, DWORD dwAceFlags)
  800. {
  801. HRESULT hr = AddAccessDeniedACEToACL(&m_pDACL, pszPrincipal, dwAccessMask, dwAceFlags);
  802. if (SUCCEEDED(hr))
  803. SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  804. return hr;
  805. }
  806. HRESULT CVssSecurityDescriptor::Allow(PSID pSid, DWORD dwAccessMask, DWORD dwAceFlags)
  807. {
  808. HRESULT hr = AddAccessAllowedACEToACL(&m_pDACL, pSid, dwAccessMask, dwAceFlags);
  809. if (SUCCEEDED(hr))
  810. SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  811. return hr;
  812. }
  813. HRESULT CVssSecurityDescriptor::Deny(PSID pSid, DWORD dwAccessMask, DWORD dwAceFlags)
  814. {
  815. HRESULT hr = AddAccessDeniedACEToACL(&m_pDACL, pSid, dwAccessMask, dwAceFlags);
  816. if (SUCCEEDED(hr))
  817. SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  818. return hr;
  819. }
  820. HRESULT CVssSecurityDescriptor::Revoke(LPCTSTR pszPrincipal)
  821. {
  822. HRESULT hr = RemovePrincipalFromACL(m_pDACL, pszPrincipal);
  823. if (SUCCEEDED(hr))
  824. SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  825. return hr;
  826. }
  827. HRESULT CVssSecurityDescriptor::GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid)
  828. {
  829. BOOL bRes;
  830. HRESULT hr;
  831. HANDLE hToken = NULL;
  832. if (ppUserSid)
  833. *ppUserSid = NULL;
  834. if (ppGroupSid)
  835. *ppGroupSid = NULL;
  836. bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
  837. if (!bRes)
  838. {
  839. // Couldn't open process token
  840. hr = HRESULT_FROM_WIN32(GetLastError());
  841. ATLASSERT(FALSE);
  842. return hr;
  843. }
  844. hr = GetTokenSids(hToken, ppUserSid, ppGroupSid);
  845. CloseHandle(hToken);
  846. return hr;
  847. }
  848. HRESULT CVssSecurityDescriptor::GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid, BOOL bOpenAsSelf)
  849. {
  850. BOOL bRes;
  851. HRESULT hr;
  852. HANDLE hToken = NULL;
  853. if (ppUserSid)
  854. *ppUserSid = NULL;
  855. if (ppGroupSid)
  856. *ppGroupSid = NULL;
  857. bRes = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, bOpenAsSelf, &hToken);
  858. if (!bRes)
  859. {
  860. // Couldn't open thread token
  861. hr = HRESULT_FROM_WIN32(GetLastError());
  862. return hr;
  863. }
  864. hr = GetTokenSids(hToken, ppUserSid, ppGroupSid);
  865. CloseHandle(hToken);
  866. return hr;
  867. }
  868. HRESULT CVssSecurityDescriptor::GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid)
  869. {
  870. DWORD dwSize;
  871. HRESULT hr;
  872. PTOKEN_USER ptkUser = NULL;
  873. PTOKEN_PRIMARY_GROUP ptkGroup = NULL;
  874. if (ppUserSid)
  875. *ppUserSid = NULL;
  876. if (ppGroupSid)
  877. *ppGroupSid = NULL;
  878. if (ppUserSid)
  879. {
  880. // Get length required for TokenUser by specifying buffer length of 0
  881. GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
  882. hr = GetLastError();
  883. if (hr != ERROR_INSUFFICIENT_BUFFER)
  884. {
  885. // Expected ERROR_INSUFFICIENT_BUFFER
  886. ATLASSERT(FALSE);
  887. hr = HRESULT_FROM_WIN32(hr);
  888. goto failed;
  889. }
  890. ptkUser = (TOKEN_USER*) malloc(dwSize);
  891. if (ptkUser == NULL)
  892. {
  893. hr = E_OUTOFMEMORY;
  894. goto failed;
  895. }
  896. // Get Sid of process token.
  897. if (!GetTokenInformation(hToken, TokenUser, ptkUser, dwSize, &dwSize))
  898. {
  899. // Couldn't get user info
  900. hr = HRESULT_FROM_WIN32(GetLastError());
  901. ATLASSERT(FALSE);
  902. goto failed;
  903. }
  904. // Make a copy of the Sid for the return value
  905. dwSize = GetLengthSid(ptkUser->User.Sid);
  906. PSID pSid;
  907. pSid = (PSID) malloc(dwSize);
  908. if (pSid == NULL)
  909. {
  910. hr = E_OUTOFMEMORY;
  911. goto failed;
  912. }
  913. if (!CopySid(dwSize, pSid, ptkUser->User.Sid))
  914. {
  915. hr = HRESULT_FROM_WIN32(GetLastError());
  916. ATLASSERT(FALSE);
  917. goto failed;
  918. }
  919. ATLASSERT(IsValidSid(pSid));
  920. *ppUserSid = pSid;
  921. free(ptkUser);
  922. ptkUser = NULL;
  923. }
  924. if (ppGroupSid)
  925. {
  926. // Get length required for TokenPrimaryGroup by specifying buffer length of 0
  927. GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwSize);
  928. hr = GetLastError();
  929. if (hr != ERROR_INSUFFICIENT_BUFFER)
  930. {
  931. // Expected ERROR_INSUFFICIENT_BUFFER
  932. ATLASSERT(FALSE);
  933. hr = HRESULT_FROM_WIN32(hr);
  934. goto failed;
  935. }
  936. ptkGroup = (TOKEN_PRIMARY_GROUP*) malloc(dwSize);
  937. if (ptkGroup == NULL)
  938. {
  939. hr = E_OUTOFMEMORY;
  940. goto failed;
  941. }
  942. // Get Sid of process token.
  943. if (!GetTokenInformation(hToken, TokenPrimaryGroup, ptkGroup, dwSize, &dwSize))
  944. {
  945. // Couldn't get user info
  946. hr = HRESULT_FROM_WIN32(GetLastError());
  947. ATLASSERT(FALSE);
  948. goto failed;
  949. }
  950. // Make a copy of the Sid for the return value
  951. dwSize = GetLengthSid(ptkGroup->PrimaryGroup);
  952. PSID pSid;
  953. pSid = (PSID) malloc(dwSize);
  954. if (pSid == NULL)
  955. {
  956. hr = E_OUTOFMEMORY;
  957. goto failed;
  958. }
  959. if (!CopySid(dwSize, pSid, ptkGroup->PrimaryGroup))
  960. {
  961. hr = HRESULT_FROM_WIN32(GetLastError());
  962. ATLASSERT(FALSE);
  963. goto failed;
  964. }
  965. ATLASSERT(IsValidSid(pSid));
  966. *ppGroupSid = pSid;
  967. free(ptkGroup);
  968. ptkGroup = NULL;
  969. }
  970. return S_OK;
  971. failed:
  972. if (ptkUser)
  973. free(ptkUser);
  974. if (ptkGroup)
  975. free (ptkGroup);
  976. return hr;
  977. }
  978. HRESULT CVssSecurityDescriptor::GetCurrentUserSID(PSID *ppSid)
  979. {
  980. HANDLE tkHandle;
  981. if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tkHandle))
  982. {
  983. TOKEN_USER *tkUser;
  984. DWORD tkSize;
  985. DWORD sidLength;
  986. // Call to get size information for alloc
  987. GetTokenInformation(tkHandle, TokenUser, NULL, 0, &tkSize);
  988. tkUser = (TOKEN_USER *) malloc(tkSize);
  989. if (tkUser == NULL)
  990. return E_OUTOFMEMORY;
  991. // Now make the real call
  992. if (GetTokenInformation(tkHandle, TokenUser, tkUser, tkSize, &tkSize))
  993. {
  994. sidLength = GetLengthSid(tkUser->User.Sid);
  995. *ppSid = (PSID) malloc(sidLength);
  996. if (*ppSid == NULL)
  997. return E_OUTOFMEMORY;
  998. memcpy(*ppSid, tkUser->User.Sid, sidLength);
  999. CloseHandle(tkHandle);
  1000. free(tkUser);
  1001. return S_OK;
  1002. }
  1003. else
  1004. {
  1005. free(tkUser);
  1006. return HRESULT_FROM_WIN32(GetLastError());
  1007. }
  1008. }
  1009. return HRESULT_FROM_WIN32(GetLastError());
  1010. }
  1011. HRESULT CVssSecurityDescriptor::GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid)
  1012. {
  1013. HRESULT hr;
  1014. LPTSTR pszRefDomain = NULL;
  1015. DWORD dwDomainSize = 0;
  1016. DWORD dwSidSize = 0;
  1017. SID_NAME_USE snu;
  1018. // Call to get size info for alloc
  1019. LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu);
  1020. hr = GetLastError();
  1021. if (hr != ERROR_INSUFFICIENT_BUFFER)
  1022. return HRESULT_FROM_WIN32(hr);
  1023. ATLTRY(pszRefDomain = new TCHAR[dwDomainSize]);
  1024. if (pszRefDomain == NULL)
  1025. return E_OUTOFMEMORY;
  1026. *ppSid = (PSID) malloc(dwSidSize);
  1027. if (*ppSid != NULL)
  1028. {
  1029. if (!LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu))
  1030. {
  1031. free(*ppSid);
  1032. *ppSid = NULL;
  1033. delete[] pszRefDomain;
  1034. return HRESULT_FROM_WIN32(GetLastError());
  1035. }
  1036. delete[] pszRefDomain;
  1037. return S_OK;
  1038. }
  1039. delete[] pszRefDomain;
  1040. return E_OUTOFMEMORY;
  1041. }
  1042. HRESULT CVssSecurityDescriptor::Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD)
  1043. {
  1044. PACL pDACL = NULL;
  1045. PACL pSACL = NULL;
  1046. BOOL bDACLPresent, bSACLPresent;
  1047. BOOL bDefaulted;
  1048. ACCESS_ALLOWED_ACE* pACE;
  1049. HRESULT hr;
  1050. PSID pUserSid;
  1051. PSID pGroupSid;
  1052. hr = Initialize();
  1053. if(FAILED(hr))
  1054. return hr;
  1055. // get the existing DACL.
  1056. if (!GetSecurityDescriptorDacl(pSelfRelativeSD, &bDACLPresent, &pDACL, &bDefaulted))
  1057. goto failed;
  1058. if (bDACLPresent)
  1059. {
  1060. if (pDACL)
  1061. {
  1062. // allocate new DACL.
  1063. m_pDACL = (PACL) malloc(pDACL->AclSize);
  1064. if (m_pDACL == NULL)
  1065. {
  1066. hr = E_OUTOFMEMORY;
  1067. goto failedMemory;
  1068. }
  1069. // initialize the DACL
  1070. if (!InitializeAcl(m_pDACL, pDACL->AclSize, ACL_REVISION))
  1071. goto failed;
  1072. // copy the ACES
  1073. for (int i = 0; i < pDACL->AceCount; i++)
  1074. {
  1075. if (!GetAce(pDACL, i, (void **)&pACE))
  1076. goto failed;
  1077. if (!AddAccessAllowedAce(m_pDACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart)))
  1078. goto failed;
  1079. }
  1080. if (!IsValidAcl(m_pDACL))
  1081. goto failed;
  1082. }
  1083. // set the DACL
  1084. if (!SetSecurityDescriptorDacl(m_pSD, m_pDACL ? TRUE : FALSE, m_pDACL, bDefaulted))
  1085. goto failed;
  1086. }
  1087. // get the existing SACL.
  1088. if (!GetSecurityDescriptorSacl(pSelfRelativeSD, &bSACLPresent, &pSACL, &bDefaulted))
  1089. goto failed;
  1090. if (bSACLPresent)
  1091. {
  1092. if (pSACL)
  1093. {
  1094. // allocate new SACL.
  1095. m_pSACL = (PACL) malloc(pSACL->AclSize);
  1096. if (m_pSACL == NULL)
  1097. {
  1098. hr = E_OUTOFMEMORY;
  1099. goto failedMemory;
  1100. }
  1101. // initialize the SACL
  1102. if (!InitializeAcl(m_pSACL, pSACL->AclSize, ACL_REVISION))
  1103. goto failed;
  1104. // copy the ACES
  1105. for (int i = 0; i < pSACL->AceCount; i++)
  1106. {
  1107. if (!GetAce(pSACL, i, (void **)&pACE))
  1108. goto failed;
  1109. if (!AddAccessAllowedAce(m_pSACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart)))
  1110. goto failed;
  1111. }
  1112. if (!IsValidAcl(m_pSACL))
  1113. goto failed;
  1114. }
  1115. // set the SACL
  1116. if (!SetSecurityDescriptorSacl(m_pSD, m_pSACL ? TRUE : FALSE, m_pSACL, bDefaulted))
  1117. goto failed;
  1118. }
  1119. if (!GetSecurityDescriptorOwner(m_pSD, &pUserSid, &bDefaulted))
  1120. goto failed;
  1121. if (FAILED(SetOwner(pUserSid, bDefaulted)))
  1122. goto failed;
  1123. if (!GetSecurityDescriptorGroup(m_pSD, &pGroupSid, &bDefaulted))
  1124. goto failed;
  1125. if (FAILED(SetGroup(pGroupSid, bDefaulted)))
  1126. goto failed;
  1127. if (!IsValidSecurityDescriptor(m_pSD))
  1128. goto failed;
  1129. return hr;
  1130. failed:
  1131. hr = HRESULT_FROM_WIN32(hr);
  1132. failedMemory:
  1133. if (m_pDACL)
  1134. {
  1135. free(m_pDACL);
  1136. m_pDACL = NULL;
  1137. }
  1138. if (m_pSD)
  1139. {
  1140. free(m_pSD);
  1141. m_pSD = NULL;
  1142. }
  1143. return hr;
  1144. }
  1145. HRESULT CVssSecurityDescriptor::AttachObject(HANDLE hObject)
  1146. {
  1147. HRESULT hr;
  1148. DWORD dwSize = 0;
  1149. PSECURITY_DESCRIPTOR pSD = NULL;
  1150. GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  1151. DACL_SECURITY_INFORMATION, pSD, 0, &dwSize);
  1152. hr = GetLastError();
  1153. if (hr != ERROR_INSUFFICIENT_BUFFER)
  1154. return HRESULT_FROM_WIN32(hr);
  1155. pSD = (PSECURITY_DESCRIPTOR) malloc(dwSize);
  1156. if (pSD == NULL)
  1157. return E_OUTOFMEMORY;
  1158. if (!GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  1159. DACL_SECURITY_INFORMATION, pSD, dwSize, &dwSize))
  1160. {
  1161. hr = HRESULT_FROM_WIN32(GetLastError());
  1162. free(pSD);
  1163. return hr;
  1164. }
  1165. hr = Attach(pSD);
  1166. free(pSD);
  1167. return hr;
  1168. }
  1169. HRESULT CVssSecurityDescriptor::CopyACL(PACL pDest, PACL pSrc)
  1170. {
  1171. ACL_SIZE_INFORMATION aclSizeInfo;
  1172. LPVOID pAce;
  1173. ACE_HEADER *aceHeader;
  1174. if (pSrc == NULL)
  1175. return S_OK;
  1176. if (!GetAclInformation(pSrc, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
  1177. return HRESULT_FROM_WIN32(GetLastError());
  1178. // Copy all of the ACEs to the new ACL
  1179. for (UINT i = 0; i < aclSizeInfo.AceCount; i++)
  1180. {
  1181. if (!GetAce(pSrc, i, &pAce))
  1182. return HRESULT_FROM_WIN32(GetLastError());
  1183. aceHeader = (ACE_HEADER *) pAce;
  1184. if (!AddAce(pDest, ACL_REVISION, 0xffffffff, pAce, aceHeader->AceSize))
  1185. return HRESULT_FROM_WIN32(GetLastError());
  1186. }
  1187. return S_OK;
  1188. }
  1189. HRESULT CVssSecurityDescriptor::AddAccessDeniedACEToACL(PACL *ppAcl, LPCTSTR pszPrincipal, DWORD dwAccessMask, DWORD dwAceFlags)
  1190. {
  1191. ACL_SIZE_INFORMATION aclSizeInfo;
  1192. int aclSize;
  1193. DWORD returnValue;
  1194. PSID principalSID;
  1195. PACL oldACL, newACL = NULL;
  1196. oldACL = *ppAcl;
  1197. returnValue = GetPrincipalSID(pszPrincipal, &principalSID);
  1198. if (FAILED(returnValue))
  1199. return returnValue;
  1200. aclSizeInfo.AclBytesInUse = 0;
  1201. if (*ppAcl != NULL)
  1202. GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1203. aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD);
  1204. ATLTRY(newACL = (PACL) new BYTE[aclSize]);
  1205. if (newACL == NULL)
  1206. return E_OUTOFMEMORY;
  1207. if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  1208. {
  1209. free(principalSID);
  1210. delete [] newACL;
  1211. return HRESULT_FROM_WIN32(GetLastError());
  1212. }
  1213. if (!AddAccessDeniedAceEx(newACL, ACL_REVISION2, dwAceFlags, dwAccessMask, principalSID))
  1214. {
  1215. free(principalSID);
  1216. delete [] newACL;
  1217. return HRESULT_FROM_WIN32(GetLastError());
  1218. }
  1219. returnValue = CopyACL(newACL, oldACL);
  1220. if (FAILED(returnValue))
  1221. {
  1222. free(principalSID);
  1223. delete [] newACL;
  1224. return returnValue;
  1225. }
  1226. *ppAcl = newACL;
  1227. newACL = NULL;
  1228. if (oldACL != NULL)
  1229. free(oldACL);
  1230. free(principalSID);
  1231. return S_OK;
  1232. }
  1233. HRESULT CVssSecurityDescriptor::AddAccessAllowedACEToACL(PACL *ppAcl, LPCTSTR pszPrincipal, DWORD dwAccessMask, DWORD dwAceFlags)
  1234. {
  1235. ACL_SIZE_INFORMATION aclSizeInfo;
  1236. int aclSize;
  1237. DWORD returnValue;
  1238. PSID principalSID;
  1239. PACL oldACL, newACL = NULL;
  1240. oldACL = *ppAcl;
  1241. returnValue = GetPrincipalSID(pszPrincipal, &principalSID);
  1242. if (FAILED(returnValue))
  1243. return returnValue;
  1244. aclSizeInfo.AclBytesInUse = 0;
  1245. if (*ppAcl != NULL)
  1246. GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1247. aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD);
  1248. ATLTRY(newACL = (PACL) new BYTE[aclSize]);
  1249. if (newACL == NULL)
  1250. return E_OUTOFMEMORY;
  1251. if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  1252. {
  1253. free(principalSID);
  1254. delete [] newACL;
  1255. return HRESULT_FROM_WIN32(GetLastError());
  1256. }
  1257. returnValue = CopyACL(newACL, oldACL);
  1258. if (FAILED(returnValue))
  1259. {
  1260. free(principalSID);
  1261. delete [] newACL;
  1262. return returnValue;
  1263. }
  1264. if (!AddAccessAllowedAceEx(newACL, ACL_REVISION2, dwAceFlags, dwAccessMask, principalSID))
  1265. {
  1266. free(principalSID);
  1267. delete [] newACL;
  1268. return HRESULT_FROM_WIN32(GetLastError());
  1269. }
  1270. *ppAcl = newACL;
  1271. newACL = NULL;
  1272. if (oldACL != NULL)
  1273. free(oldACL);
  1274. free(principalSID);
  1275. return S_OK;
  1276. }
  1277. HRESULT CVssSecurityDescriptor::AddAccessDeniedACEToACL(PACL *ppAcl, PSID principalSID, DWORD dwAccessMask, DWORD dwAceFlags)
  1278. {
  1279. ACL_SIZE_INFORMATION aclSizeInfo;
  1280. int aclSize;
  1281. DWORD returnValue;
  1282. PACL oldACL, newACL = NULL;
  1283. oldACL = *ppAcl;
  1284. aclSizeInfo.AclBytesInUse = 0;
  1285. if (*ppAcl != NULL)
  1286. GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1287. aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD);
  1288. ATLTRY(newACL = (PACL) new BYTE[aclSize]);
  1289. if (newACL == NULL)
  1290. return E_OUTOFMEMORY;
  1291. if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  1292. {
  1293. delete [] newACL;
  1294. return HRESULT_FROM_WIN32(GetLastError());
  1295. }
  1296. if (!AddAccessDeniedAceEx(newACL, ACL_REVISION2, dwAceFlags, dwAccessMask, principalSID))
  1297. {
  1298. delete [] newACL;
  1299. return HRESULT_FROM_WIN32(GetLastError());
  1300. }
  1301. returnValue = CopyACL(newACL, oldACL);
  1302. if (FAILED(returnValue))
  1303. {
  1304. delete [] newACL;
  1305. return returnValue;
  1306. }
  1307. *ppAcl = newACL;
  1308. newACL = NULL;
  1309. if (oldACL != NULL)
  1310. free(oldACL);
  1311. return S_OK;
  1312. }
  1313. HRESULT CVssSecurityDescriptor::AddAccessAllowedACEToACL(PACL *ppAcl, PSID principalSID, DWORD dwAccessMask, DWORD dwAceFlags)
  1314. {
  1315. ACL_SIZE_INFORMATION aclSizeInfo;
  1316. int aclSize;
  1317. DWORD returnValue;
  1318. PACL oldACL, newACL = NULL;
  1319. oldACL = *ppAcl;
  1320. aclSizeInfo.AclBytesInUse = 0;
  1321. if (*ppAcl != NULL)
  1322. GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1323. aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD);
  1324. ATLTRY(newACL = (PACL) new BYTE[aclSize]);
  1325. if (newACL == NULL)
  1326. return E_OUTOFMEMORY;
  1327. if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  1328. {
  1329. delete [] newACL;
  1330. return HRESULT_FROM_WIN32(GetLastError());
  1331. }
  1332. returnValue = CopyACL(newACL, oldACL);
  1333. if (FAILED(returnValue))
  1334. {
  1335. delete [] newACL;
  1336. return returnValue;
  1337. }
  1338. if (!AddAccessAllowedAceEx(newACL, ACL_REVISION2, dwAceFlags, dwAccessMask, principalSID))
  1339. {
  1340. delete [] newACL;
  1341. return HRESULT_FROM_WIN32(GetLastError());
  1342. }
  1343. *ppAcl = newACL;
  1344. newACL = NULL;
  1345. if (oldACL != NULL)
  1346. free(oldACL);
  1347. return S_OK;
  1348. }
  1349. HRESULT CVssSecurityDescriptor::RemovePrincipalFromACL(PACL pAcl, LPCTSTR pszPrincipal)
  1350. {
  1351. ACL_SIZE_INFORMATION aclSizeInfo;
  1352. ULONG i;
  1353. LPVOID ace;
  1354. ACCESS_ALLOWED_ACE *accessAllowedAce;
  1355. ACCESS_DENIED_ACE *accessDeniedAce;
  1356. SYSTEM_AUDIT_ACE *systemAuditAce;
  1357. PSID principalSID;
  1358. DWORD returnValue;
  1359. ACE_HEADER *aceHeader;
  1360. returnValue = GetPrincipalSID(pszPrincipal, &principalSID);
  1361. if (FAILED(returnValue))
  1362. return returnValue;
  1363. GetAclInformation(pAcl, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1364. for (i = 0; i < aclSizeInfo.AceCount; i++)
  1365. {
  1366. if (!GetAce(pAcl, i, &ace))
  1367. {
  1368. free(principalSID);
  1369. return HRESULT_FROM_WIN32(GetLastError());
  1370. }
  1371. aceHeader = (ACE_HEADER *) ace;
  1372. if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
  1373. {
  1374. accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace;
  1375. if (EqualSid(principalSID, (PSID) &accessAllowedAce->SidStart))
  1376. {
  1377. DeleteAce(pAcl, i);
  1378. free(principalSID);
  1379. return S_OK;
  1380. }
  1381. } else
  1382. if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE)
  1383. {
  1384. accessDeniedAce = (ACCESS_DENIED_ACE *) ace;
  1385. if (EqualSid(principalSID, (PSID) &accessDeniedAce->SidStart))
  1386. {
  1387. DeleteAce(pAcl, i);
  1388. free(principalSID);
  1389. return S_OK;
  1390. }
  1391. } else
  1392. if (aceHeader->AceType == SYSTEM_AUDIT_ACE_TYPE)
  1393. {
  1394. systemAuditAce = (SYSTEM_AUDIT_ACE *) ace;
  1395. if (EqualSid(principalSID, (PSID) &systemAuditAce->SidStart))
  1396. {
  1397. DeleteAce(pAcl, i);
  1398. free(principalSID);
  1399. return S_OK;
  1400. }
  1401. }
  1402. }
  1403. free(principalSID);
  1404. return S_OK;
  1405. }
  1406. HRESULT CVssSecurityDescriptor::SetPrivilege(LPCTSTR privilege, BOOL bEnable, HANDLE hToken)
  1407. {
  1408. HRESULT hr;
  1409. TOKEN_PRIVILEGES tpPrevious;
  1410. TOKEN_PRIVILEGES tp;
  1411. DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
  1412. LUID luid;
  1413. HANDLE hTokenUsed;
  1414. // if no token specified open process token
  1415. if (hToken == 0)
  1416. {
  1417. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hTokenUsed))
  1418. {
  1419. hr = HRESULT_FROM_WIN32(GetLastError());
  1420. ATLASSERT(FALSE);
  1421. return hr;
  1422. }
  1423. }
  1424. else
  1425. hTokenUsed = hToken;
  1426. if (!LookupPrivilegeValue(NULL, privilege, &luid ))
  1427. {
  1428. hr = HRESULT_FROM_WIN32(GetLastError());
  1429. ATLASSERT(FALSE);
  1430. if (hToken == 0)
  1431. CloseHandle(hTokenUsed);
  1432. return hr;
  1433. }
  1434. tp.PrivilegeCount = 1;
  1435. tp.Privileges[0].Luid = luid;
  1436. tp.Privileges[0].Attributes = 0;
  1437. if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious))
  1438. {
  1439. hr = HRESULT_FROM_WIN32(GetLastError());
  1440. ATLASSERT(FALSE);
  1441. if (hToken == 0)
  1442. CloseHandle(hTokenUsed);
  1443. return hr;
  1444. }
  1445. tpPrevious.PrivilegeCount = 1;
  1446. tpPrevious.Privileges[0].Luid = luid;
  1447. if (bEnable)
  1448. tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  1449. else
  1450. tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes);
  1451. if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tpPrevious, cbPrevious, NULL, NULL))
  1452. {
  1453. hr = HRESULT_FROM_WIN32(GetLastError());
  1454. ATLASSERT(FALSE);
  1455. if (hToken == 0)
  1456. CloseHandle(hTokenUsed);
  1457. return hr;
  1458. }
  1459. return S_OK;
  1460. }
  1461. /////////////////////////////////////////////////////////////////////////////////////
  1462. // Class - CVssSidCollection
  1463. //
  1464. CVssSidCollection::CVssSidCollection()
  1465. {
  1466. m_bInitialized = false;
  1467. }
  1468. CVssSidCollection::~CVssSidCollection()
  1469. {
  1470. for(INT nIndex = 0; nIndex < m_SidArray.GetSize(); nIndex++) {
  1471. LocalFree(m_SidArray.GetKeyAt(nIndex));
  1472. LocalFree((m_SidArray.GetValueAt(nIndex)).GetSid());
  1473. LocalFree((m_SidArray.GetValueAt(nIndex)).GetName());
  1474. LocalFree((m_SidArray.GetValueAt(nIndex)).GetDomain());
  1475. }
  1476. }
  1477. // Get the total count of stored SIDs
  1478. INT CVssSidCollection::GetSidCount()
  1479. {
  1480. BS_ASSERT(m_bInitialized);
  1481. return m_SidArray.GetSize();
  1482. }
  1483. // Get the SID with the given index (starts with 0)
  1484. PSID CVssSidCollection::GetSid(INT nIndex) throw(HRESULT)
  1485. {
  1486. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::GetSid");
  1487. BS_ASSERT(m_bInitialized);
  1488. if ((nIndex < 0) || (nIndex >= GetSidCount()))
  1489. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Index out of range %ld", nIndex);
  1490. return (m_SidArray.GetValueAt(nIndex)).GetSid();
  1491. }
  1492. // Get the SID use with the given index
  1493. SID_NAME_USE CVssSidCollection::GetSidUse(INT nIndex) throw(HRESULT)
  1494. {
  1495. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::GetSidUse");
  1496. BS_ASSERT(m_bInitialized);
  1497. if ((nIndex < 0) || (nIndex >= GetSidCount()))
  1498. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Index out of range %ld", nIndex);
  1499. return (m_SidArray.GetValueAt(nIndex)).GetUse();
  1500. }
  1501. // Check if the the SID is allowed
  1502. bool CVssSidCollection::IsSidAllowed(INT nIndex) throw(HRESULT)
  1503. {
  1504. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::IsSidAllowed");
  1505. BS_ASSERT(m_bInitialized);
  1506. if ((nIndex < 0) || (nIndex >= GetSidCount()))
  1507. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Index out of range %ld", nIndex);
  1508. return (m_SidArray.GetValueAt(nIndex)).IsSidAllowed();
  1509. }
  1510. // Check if the the SID is local
  1511. bool CVssSidCollection::IsLocal(INT nIndex) throw(HRESULT)
  1512. {
  1513. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::IsLocal");
  1514. BS_ASSERT(m_bInitialized);
  1515. if ((nIndex < 0) || (nIndex >= GetSidCount()))
  1516. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Index out of range %ld", nIndex);
  1517. return (m_SidArray.GetValueAt(nIndex)).IsLocal();
  1518. }
  1519. // Get the SID with the given index (starts with 0)
  1520. LPWSTR CVssSidCollection::GetPrincipal(INT nIndex) throw(HRESULT)
  1521. {
  1522. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::GetPrincipal");
  1523. BS_ASSERT(m_bInitialized);
  1524. if ((nIndex < 0) || (nIndex >= GetSidCount()))
  1525. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Index out of range %ld", nIndex);
  1526. return m_SidArray.GetKeyAt(nIndex);
  1527. }
  1528. LPWSTR CVssSidCollection::GetName(INT nIndex) throw(HRESULT)
  1529. {
  1530. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::GetName");
  1531. BS_ASSERT(m_bInitialized);
  1532. if ((nIndex < 0) || (nIndex >= GetSidCount()))
  1533. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Index out of range %ld", nIndex);
  1534. return (m_SidArray.GetValueAt(nIndex)).GetName();;
  1535. }
  1536. LPWSTR CVssSidCollection::GetDomain(INT nIndex) throw(HRESULT)
  1537. {
  1538. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::GetDomain");
  1539. BS_ASSERT(m_bInitialized);
  1540. if ((nIndex < 0) || (nIndex >= GetSidCount()))
  1541. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Index out of range %ld", nIndex);
  1542. return (m_SidArray.GetValueAt(nIndex)).GetDomain();;
  1543. }
  1544. // Add a well-known SID to the internal map
  1545. void CVssSidCollection::AddWellKnownSid(
  1546. IN WELL_KNOWN_SID_TYPE type
  1547. )
  1548. {
  1549. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::AddWellKnownSid");
  1550. // Get the SID size
  1551. DWORD cbSid = 0;
  1552. if (CreateWellKnownSid(type, NULL, NULL, &cbSid))
  1553. ft.TranslateWin32Error(VSSDBG_GEN, L"CreateWellKnownSid(type, NULL, NULL, &dwSid)");
  1554. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  1555. ft.TranslateWin32Error(VSSDBG_GEN, L"CreateWellKnownSid(type, NULL, NULL, &dwSid)");
  1556. // Allocate the SID
  1557. CVssAutoLocalPtr<PSID> pSID;
  1558. pSID.AllocateBytes(cbSid);
  1559. // Create the SID
  1560. if (!CreateWellKnownSid(type, NULL, pSID, &cbSid))
  1561. ft.TranslateWin32Error(VSSDBG_GEN, L"CreateWellKnownSid(type, NULL, pSID, [%ld])", cbSid);
  1562. // Get the string representation in the "domain\name" format
  1563. // First get the sizes
  1564. DWORD cchName = 0;
  1565. DWORD cchDomain = 0;
  1566. SID_NAME_USE peUse;
  1567. if (LookupAccountSid(NULL, pSID, NULL, &cchName, NULL, &cchDomain, &peUse))
  1568. ft.TranslateWin32Error(VSSDBG_GEN, L"LookupAccountSid()");
  1569. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  1570. ft.TranslateWin32Error(VSSDBG_GEN, L"LookupAccountSid()");
  1571. // Now allocate the buffers
  1572. CVssAutoLocalString pwszName, pwszDomain, pwszComposedName;
  1573. pwszName.AllocateString(cchName);
  1574. pwszDomain.AllocateString(cchDomain);
  1575. // Try again
  1576. if (!LookupAccountSid(NULL, pSID, pwszName, &cchName, pwszDomain, &cchDomain, &peUse))
  1577. ft.TranslateWin32Error(VSSDBG_GEN, L"LookupAccountSid()");
  1578. // Check to see if the account is local.
  1579. // and also complete the m_pwszBuiltinDomain if the sid is for Adminstrators
  1580. bool bLocalAccount = VerifyIsLocal(pwszDomain, (WinBuiltinAdministratorsSid == type));
  1581. // Compose the big name ("domain\name")
  1582. pwszComposedName.CopyFrom(pwszDomain);
  1583. pwszComposedName.Append(L"\\");
  1584. pwszComposedName.Append(pwszName);
  1585. // Now add it to the array
  1586. if (!m_SidArray.Add(pwszComposedName,
  1587. CVssSidWrapper(true, pSID, peUse, pwszName, pwszDomain, bLocalAccount)))
  1588. ft.ThrowOutOfMemory(VSSDBG_GEN);
  1589. // Transfer ownership into the array
  1590. pSID.Detach();
  1591. pwszComposedName.Detach();
  1592. pwszName.Detach();
  1593. pwszDomain.Detach();
  1594. }
  1595. // Add a user to the internal map based on the user name
  1596. // Return "false" if the user name does not correspond to a real user.
  1597. bool CVssSidCollection::AddUser(
  1598. IN LPCWSTR pwszUser,
  1599. IN bool bAllow
  1600. )
  1601. {
  1602. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::AddSidOrUser");
  1603. if ( (pwszUser == NULL) || (pwszUser[0] == L'\0'))
  1604. ft.Throw( VSSDBG_GEN, E_UNEXPECTED, L"Invalid argument '%s'", pwszUser);
  1605. // First, check to see if this is a valid user name
  1606. DWORD cbSid = 0;
  1607. DWORD cchDomain = 0;
  1608. SID_NAME_USE sbUse;
  1609. if (LookupAccountName( NULL, pwszUser, NULL, &cbSid, NULL, &cchDomain, &sbUse))
  1610. ft.TranslateWin32Error(VSSDBG_GEN, L"LookupAccountName( NULL, %s, NULL, p, NULL, p, p)", pwszUser);
  1611. // If the user does not exist, return false
  1612. if (GetLastError() == ERROR_NONE_MAPPED)
  1613. return false;
  1614. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  1615. ft.TranslateWin32Error(VSSDBG_GEN, L"LookupAccountName( NULL, %s, NULL, p, NULL, p, p)", pwszUser);
  1616. // It appears we are on the correct path.
  1617. // Allocate the SID and the domain
  1618. CVssAutoLocalPtr<PSID> pSID;
  1619. pSID.AllocateBytes(cbSid);
  1620. CVssAutoLocalString pwszDomain;
  1621. pwszDomain.AllocateString(cchDomain);
  1622. // Retrieve the SID
  1623. if (!LookupAccountName( NULL, pwszUser,
  1624. pSID, &cbSid, pwszDomain, &cchDomain, &sbUse))
  1625. ft.TranslateWin32Error(VSSDBG_GEN, L"LookupAccountName( NULL, %s,...)", pwszUser);
  1626. // Check to see if the account is local.
  1627. bool bLocalAccount = VerifyIsLocal(pwszDomain, false);
  1628. // Now we are sure that the user is real
  1629. CVssAutoLocalString pwszComposedName, pwszUserName;
  1630. pwszUserName.CopyFrom(pwszUser);
  1631. // Compose the big name ("domain\name")
  1632. pwszComposedName.CopyFrom(pwszDomain);
  1633. pwszComposedName.Append(L"\\");
  1634. pwszComposedName.Append(pwszUserName);
  1635. // Now we have both the string and the SID. Add them into the array.
  1636. if (!m_SidArray.Add(pwszComposedName,
  1637. CVssSidWrapper(bAllow, pSID, sbUse, pwszUserName, pwszDomain, bLocalAccount)))
  1638. ft.ThrowOutOfMemory(VSSDBG_GEN);
  1639. // Transfer ownership into the array
  1640. pSID.Detach();
  1641. pwszComposedName.Detach();
  1642. pwszUserName.Detach();
  1643. pwszDomain.Detach();
  1644. return true;
  1645. }
  1646. // Return "true" if the user name with the given domain is local user/group
  1647. bool CVssSidCollection::VerifyIsLocal(
  1648. IN LPCWSTR pwszDomain,
  1649. IN bool bIsAdministratorsAccount
  1650. )
  1651. {
  1652. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::VerifyIsLocal");
  1653. // If this is the Administrators SID, then complete the m_pwszBuiltinDomain field.
  1654. // Otherwise check to see if the account is local.
  1655. if (bIsAdministratorsAccount)
  1656. {
  1657. BS_ASSERT(!m_pwszBuiltinDomain.IsValid());
  1658. BS_ASSERT(m_SidArray.GetSize() == 0);
  1659. m_pwszBuiltinDomain.CopyFrom(pwszDomain);
  1660. return true;
  1661. }
  1662. else
  1663. {
  1664. BS_ASSERT(m_pwszBuiltinDomain.IsValid());
  1665. BS_ASSERT(m_SidArray.GetSize() != 0);
  1666. // we consider it local if the domain is "BUILTIN" or the computer name
  1667. if(0 == _wcsicmp(pwszDomain, m_pwszBuiltinDomain))
  1668. return true;
  1669. // get the computer name
  1670. WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1671. DWORD dwSize = SIZEOF_ARRAY(wszComputerName);
  1672. if (0 == GetComputerNameW(wszComputerName, &dwSize))
  1673. ft.TranslateWin32Error(VSSDBG_GEN, L"GetComputerNameW");
  1674. // If this is the computer name, return TRUE
  1675. if(0 == _wcsicmp(pwszDomain, wszComputerName))
  1676. return true;
  1677. }
  1678. return false;
  1679. }
  1680. //
  1681. // Initialize the security descriptor from registry
  1682. // Contents: Admin, BO, System always enabled.
  1683. // The rest of users are read from the SYSTEM\\CurrentControlSet\\Services\\VSS\\VssAccessControl key
  1684. // The format of this registry key is a set of values of the form:
  1685. // REG_DWORD Name "domain1\user1", 1
  1686. // REG_DWORD Name "domain2\user2", 1
  1687. // REG_DWORD Name "domain3\user3", 0
  1688. // where 1 means "Allow" and 0 means "Deny"
  1689. //
  1690. void CVssSidCollection::Initialize()
  1691. {
  1692. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::Initialize");
  1693. // only initialize once
  1694. if (m_bInitialized)
  1695. return;
  1696. //
  1697. // Add well-known SIDs
  1698. //
  1699. // This MUST be added first since fills out the m_pwszBuiltinDomain member
  1700. AddWellKnownSid(WinBuiltinAdministratorsSid);
  1701. AddWellKnownSid(WinBuiltinBackupOperatorsSid);
  1702. AddWellKnownSid(WinLocalSystemSid);
  1703. //
  1704. // Add other users from registry
  1705. //
  1706. // Open the registry and enumerate all users specified there
  1707. CVssRegistryKey keyUserList(KEY_READ);
  1708. if (keyUserList.Open(HKEY_LOCAL_MACHINE, x_wszVssAccessControlKey))
  1709. {
  1710. CVssRegistryValueIterator iterator;
  1711. iterator.Attach(keyUserList);
  1712. // for each value take the value name as the user name (in the "domain\user" format)
  1713. for(;!iterator.IsEOF();iterator.MoveNext())
  1714. {
  1715. // Check to see ifthe value is of the right type
  1716. if (iterator.GetCurrentValueType() != REG_DWORD) {
  1717. ft.LogError(VSS_ERROR_WRONG_REG_USER_VALUE_TYPE,
  1718. VSSDBG_GEN << iterator.GetCurrentValueName() << x_wszVssAccessControlKey);
  1719. continue;
  1720. }
  1721. // Get the allow/deny flag
  1722. DWORD dwValue = 0;
  1723. iterator.GetCurrentValueContent(dwValue);
  1724. // Interpret the allow/deny flag
  1725. bool bIsAllowed;
  1726. switch(dwValue) {
  1727. case 0:
  1728. bIsAllowed = false;
  1729. break;
  1730. case 1:
  1731. bIsAllowed = true;
  1732. break;
  1733. default:
  1734. ft.LogError(VSS_ERROR_WRONG_REG_USER_VALUE,
  1735. VSSDBG_GEN << iterator.GetCurrentValueName()
  1736. << x_wszVssAccessControlKey << (INT)dwValue);
  1737. continue;
  1738. }
  1739. // Add the user (if exists)
  1740. if (!AddUser(iterator.GetCurrentValueName(), bIsAllowed )) {
  1741. ft.LogError(VSS_ERROR_WRONG_USER_NAME,
  1742. VSSDBG_GEN << iterator.GetCurrentValueName() << x_wszVssAccessControlKey);
  1743. continue;
  1744. }
  1745. }
  1746. }
  1747. // Build the security descriptor
  1748. m_SD.Initialize();
  1749. // Add a valid owner (the value does not matter)
  1750. CAutoSid userSid;
  1751. userSid.CreateBasicSid(WinLocalSystemSid);
  1752. ft.hr = m_SD.SetOwner(userSid.Get());
  1753. if (ft.HrFailed())
  1754. ft.TranslateGenericError( VSSDBG_COORD, ft.hr, L"SetOwner");
  1755. // Add a valid group (the value does not matter)
  1756. CAutoSid groupSid;
  1757. groupSid.CreateBasicSid(WinBuiltinAdministratorsSid);
  1758. ft.hr = m_SD.SetGroup(groupSid.Get());
  1759. if (ft.HrFailed())
  1760. ft.TranslateGenericError( VSSDBG_COORD, ft.hr, L"SetGroup");
  1761. // Make sure the SACL is NULL (not supported by COM)
  1762. if (m_SD.m_pSACL) {
  1763. free(m_SD.m_pSACL);
  1764. m_SD.m_pSACL= NULL;
  1765. }
  1766. // Add principals to the DACL
  1767. for (INT nIndex = 0; nIndex < m_SidArray.GetSize(); nIndex++)
  1768. {
  1769. if ((m_SidArray.GetValueAt(nIndex)).IsSidAllowed())
  1770. {
  1771. ft.hr = m_SD.Allow((m_SidArray.GetValueAt(nIndex)).GetSid(),
  1772. COM_RIGHTS_EXECUTE);
  1773. if (ft.HrFailed())
  1774. ft.TranslateGenericError( VSSDBG_GEN, ft.hr,
  1775. L"m_SD.Allow(%s, COM_RIGHTS_EXECUTE);",
  1776. m_SidArray.GetKeyAt(nIndex));
  1777. }
  1778. else
  1779. {
  1780. ft.hr = m_SD.Deny((m_SidArray.GetValueAt(nIndex)).GetSid(),
  1781. COM_RIGHTS_EXECUTE);
  1782. if (ft.HrFailed())
  1783. ft.TranslateGenericError( VSSDBG_GEN, ft.hr,
  1784. L"m_SD.Deny(%s, COM_RIGHTS_EXECUTE);",
  1785. m_SidArray.GetKeyAt(nIndex));
  1786. }
  1787. }
  1788. BS_ASSERT(::IsValidSecurityDescriptor(m_SD));
  1789. // We mark object as initialized (since we need it in GetXXX routines)
  1790. m_bInitialized = true;
  1791. }
  1792. // determine if the process is a valid writer
  1793. bool CVssSidCollection::IsProcessValidWriter()
  1794. {
  1795. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::IsProcessValidWriter");
  1796. CVssAutoCppPtr<TOKEN_USER*> ptrTokenOwner = GetClientTokenUser(FALSE);
  1797. return IsSidAllowedToFire(ptrTokenOwner.Get()->User.Sid);
  1798. }
  1799. bool CVssSidCollection::IsSidAllowedToFire(
  1800. IN PSID psid
  1801. )
  1802. {
  1803. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::IsSidAllowedToFire");
  1804. BS_ASSERT(psid);
  1805. // First check if the SID is explicitely dissalowed
  1806. if (CheckIfExplicitelySpecified(psid, false))
  1807. {
  1808. if ( g_cDbgTrace.IsTracingEnabled() ) {
  1809. CVssAutoLocalString aszWriterSid;
  1810. if (ConvertSidToStringSid( psid, aszWriterSid.ResetAndGetAddress()))
  1811. ft.Trace( VSSDBG_XML, L"WriterSid: %s was explicitely denied to fire", aszWriterSid.Get() );
  1812. }
  1813. return false;
  1814. }
  1815. // Then check if the SID is explicitely allowed
  1816. if (CheckIfExplicitelySpecified(psid, true))
  1817. return true;
  1818. if ( g_cDbgTrace.IsTracingEnabled() ) {
  1819. CVssAutoLocalString aszWriterSid;
  1820. if (ConvertSidToStringSid( psid, aszWriterSid.ResetAndGetAddress()))
  1821. ft.Trace( VSSDBG_XML, L"WriterSid: %s was implicitely denied to fire", aszWriterSid.Get() );
  1822. }
  1823. // Check failed
  1824. return false;
  1825. }
  1826. //
  1827. // if (bCheckToBeDone == false) check if the SID is explicitely denied to fire
  1828. // if (bCheckToBeDone == true) check if the SID is explicitely allowed to fire
  1829. //
  1830. // Return true if the check succeeded or false otherwise
  1831. //
  1832. bool CVssSidCollection::CheckIfExplicitelySpecified(
  1833. IN PSID psid,
  1834. IN bool bCheckToBeDone
  1835. )
  1836. {
  1837. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::CheckIfExplicitelySpecified");
  1838. BS_ASSERT(psid);
  1839. // Now look only for the checked SIDs
  1840. for (INT nIndex = 0; nIndex < GetSidCount(); nIndex++)
  1841. {
  1842. // Ignore opposite checks
  1843. if (bCheckToBeDone != IsSidAllowed(nIndex))
  1844. continue;
  1845. switch(GetSidUse(nIndex))
  1846. {
  1847. case SidTypeUser:
  1848. case SidTypeComputer:
  1849. if (EqualSid(psid, GetSid(nIndex)))
  1850. return true;
  1851. break;
  1852. case SidTypeAlias:
  1853. case SidTypeWellKnownGroup:
  1854. if (IsLocal(nIndex)) {
  1855. if (IsSidRelatedWithLocalSid(psid, GetName(nIndex), GetSid(nIndex)))
  1856. return true;
  1857. }
  1858. else {
  1859. if (EqualSid(psid, GetSid(nIndex)))
  1860. return true;
  1861. }
  1862. break;
  1863. default:
  1864. // Unknown SID type in the collection. Ignoring.
  1865. ft.Trace(VSSDBG_GEN,
  1866. L"Unknown SID %s with type %ld in the SID collection. Ignoring. [%d]",
  1867. GetPrincipal(nIndex), GetSidUse(nIndex), nIndex);
  1868. BS_ASSERT(false);
  1869. break;
  1870. }
  1871. }
  1872. return false;
  1873. }
  1874. // is a local group mentioned in the SID collection or is even a member of the SID collection
  1875. bool CVssSidCollection::IsSidRelatedWithLocalSid(
  1876. IN PSID pSid,
  1877. IN LPWSTR pwszWellKnownPrincipal,
  1878. IN PSID pWellKnownSid
  1879. )
  1880. {
  1881. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssSidCollection::IsSidRelatedWithLocalSid");
  1882. // Assert parameters
  1883. BS_ASSERT(pSid);
  1884. BS_ASSERT(pwszWellKnownPrincipal);
  1885. BS_ASSERT(pWellKnownSid);
  1886. if (EqualSid(pSid, pWellKnownSid) == TRUE)
  1887. return true;
  1888. // get list of local group members
  1889. CVssAutoNetApiPtr apBuffer;
  1890. DWORD_PTR ResumeHandle = NULL;
  1891. DWORD cEntriesRead = 0, cEntriesTotal = 0;
  1892. NET_API_STATUS status =
  1893. NetLocalGroupGetMembers(
  1894. NULL,
  1895. pwszWellKnownPrincipal,
  1896. 0,
  1897. apBuffer.ResetAndGetAddress(),
  1898. MAX_PREFERRED_LENGTH,
  1899. &cEntriesRead,
  1900. &cEntriesTotal,
  1901. &ResumeHandle
  1902. );
  1903. // If this is not a group - then compare SIDs directly
  1904. // (for example for LocalSystem account)
  1905. if (status == NERR_GroupNotFound)
  1906. return false;
  1907. // We have a different error?
  1908. if (status != NERR_Success)
  1909. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(status),
  1910. L"NetGroupGetUsers(%s)", pwszWellKnownPrincipal);
  1911. BS_ASSERT(cEntriesRead == cEntriesTotal);
  1912. // loop through member list to see if any sids mach the sid of the owner
  1913. // of the subscription
  1914. LOCALGROUP_MEMBERS_INFO_0 *rgMembers = (LOCALGROUP_MEMBERS_INFO_0 *) apBuffer.Get();
  1915. for(DWORD iEntry = 0; iEntry < cEntriesRead; iEntry++)
  1916. {
  1917. PSID psidMember = rgMembers[iEntry].lgrmi0_sid;
  1918. if (EqualSid(psidMember, pSid))
  1919. return true;
  1920. }
  1921. return false;
  1922. }