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.

722 lines
17 KiB

  1. /************************************************************************
  2. Copyright (c) 2000 - 2000 Microsoft Corporation
  3. Module Name :
  4. csd.cpp
  5. Abstract :
  6. Main code file for SID and SECURITY_DESCRIPTOR abstraction.
  7. Author :
  8. Revision History :
  9. ***********************************************************************/
  10. #include "stdafx.h"
  11. #include <accctrl.h>
  12. #include <malloc.h>
  13. #include <aclapi.h>
  14. #if !defined(BITS_V12_ON_NT4)
  15. #include "csd.tmh"
  16. #endif
  17. //------------------------------------------------------------------------
  18. CNestedImpersonation::CNestedImpersonation(
  19. SidHandle sid
  20. )
  21. : m_Sid( sid ),
  22. m_ImpersonationToken( NULL ),
  23. m_fImpersonated( false ),
  24. m_fDeleteToken( true )
  25. {
  26. try
  27. {
  28. THROW_HRESULT( g_Manager->CloneUserToken( m_Sid, ANY_SESSION, &m_ImpersonationToken ));
  29. Impersonate();
  30. }
  31. catch( ComError Error )
  32. {
  33. Revert();
  34. if (m_ImpersonationToken && m_fDeleteToken)
  35. {
  36. CloseHandle( m_ImpersonationToken );
  37. }
  38. throw;
  39. }
  40. }
  41. CNestedImpersonation::CNestedImpersonation(
  42. HANDLE token
  43. )
  44. : m_ImpersonationToken( token ),
  45. m_fImpersonated( false ),
  46. m_fDeleteToken( false )
  47. {
  48. Impersonate();
  49. }
  50. CNestedImpersonation::CNestedImpersonation()
  51. : m_ImpersonationToken( NULL ),
  52. m_fImpersonated( false ),
  53. m_fDeleteToken( true )
  54. {
  55. //
  56. // Failure will cause the base object's destructor to restore the old thread token.
  57. //
  58. try
  59. {
  60. HRESULT hr = CoImpersonateClient();
  61. switch (hr)
  62. {
  63. case S_OK:
  64. {
  65. m_fImpersonated = true;
  66. m_ImpersonationToken = CopyThreadToken();
  67. #if defined(BITS_V12_ON_NT4)
  68. RTL_VERIFY( SUCCEEDED( CoRevertToSelf() ) );
  69. m_fImpersonated = false;
  70. RTL_VERIFY( SetThreadToken( NULL, m_ImpersonationToken ) );
  71. m_fImpersonated = true;
  72. #endif
  73. break;
  74. }
  75. case RPC_E_CALL_COMPLETE:
  76. {
  77. m_ImpersonationToken = CopyThreadToken();
  78. if (m_ImpersonationToken)
  79. {
  80. //
  81. // thread was already impersonating someone when it called the BITS routine.
  82. //
  83. m_fImpersonated = true;
  84. }
  85. else
  86. {
  87. //
  88. // Thread is not impersonating. Impersonate the process owner.
  89. //
  90. if (!ImpersonateSelf( SecurityImpersonation ))
  91. {
  92. throw ComError( HRESULT_FROM_WIN32( GetLastError() ));
  93. }
  94. m_fImpersonated = true;
  95. m_ImpersonationToken = CopyThreadToken();
  96. }
  97. break;
  98. }
  99. default:
  100. throw ComError( hr );
  101. }
  102. }
  103. catch( ComError err )
  104. {
  105. if (m_ImpersonationToken)
  106. {
  107. CloseHandle( m_ImpersonationToken );
  108. m_ImpersonationToken = NULL;
  109. }
  110. throw;
  111. }
  112. }
  113. void
  114. CNestedImpersonation::SwitchToLogonToken()
  115. {
  116. HANDLE token = m_ImpersonationToken;
  117. SidHandle sid = CopyTokenSid( m_ImpersonationToken );
  118. THROW_HRESULT( g_Manager->CloneUserToken( sid,
  119. GetSession(),
  120. &m_ImpersonationToken ));
  121. m_fImpersonated = false;
  122. if (m_fDeleteToken)
  123. {
  124. CloseHandle( token );
  125. }
  126. m_fDeleteToken = true;
  127. Impersonate();
  128. }
  129. DWORD
  130. CNestedImpersonation::GetSession()
  131. {
  132. #if defined(BITS_V12_ON_NT4)
  133. return 0;
  134. #else
  135. DWORD session;
  136. DWORD used;
  137. if (!GetTokenInformation( m_ImpersonationToken,
  138. TokenSessionId,
  139. &session,
  140. sizeof(DWORD),
  141. &used))
  142. {
  143. ThrowLastError();
  144. }
  145. return session;
  146. #endif
  147. }
  148. //------------------------------------------------------------------------
  149. GENERIC_MAPPING CJobSecurityDescriptor::s_AccessMapping =
  150. {
  151. STANDARD_RIGHTS_READ,
  152. STANDARD_RIGHTS_WRITE,
  153. STANDARD_RIGHTS_EXECUTE,
  154. STANDARD_RIGHTS_ALL
  155. };
  156. CJobSecurityDescriptor::CJobSecurityDescriptor(
  157. SidHandle OwnerSid
  158. )
  159. {
  160. PACL pACL = NULL;
  161. PSECURITY_DESCRIPTOR pSD = 0;
  162. try
  163. {
  164. EXPLICIT_ACCESS ea[2];
  165. size_t SizeNeeded;
  166. pSD = (PSECURITY_DESCRIPTOR) new char[SECURITY_DESCRIPTOR_MIN_LENGTH];
  167. if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
  168. {
  169. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  170. LogError( "InitializeSecurityDescriptor Error %!winerr!", HrError );
  171. throw ComError( HrError );
  172. }
  173. if (!SetSecurityDescriptorOwner( pSD, OwnerSid.get(), TRUE))
  174. {
  175. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  176. LogError( "SetSecurityDescriptorOwner Error %!winerr!", HrError );
  177. throw ComError( HrError );
  178. }
  179. if (!SetSecurityDescriptorGroup( pSD, OwnerSid.get(), TRUE))
  180. {
  181. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  182. LogError( "SetSecurityDescriptorGroup Error %!winerr!", HrError );
  183. throw ComError( HrError );
  184. }
  185. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  186. // The ACE will allow the Administrators group full access to the key.
  187. memset(ea, 0, sizeof(ea));
  188. ea[0].grfAccessPermissions = KEY_ALL_ACCESS;
  189. ea[0].grfAccessMode = SET_ACCESS;
  190. ea[0].grfInheritance= NO_INHERITANCE;
  191. ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  192. ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
  193. ea[0].Trustee.ptstrName = (LPTSTR) OwnerSid.get();
  194. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  195. // The ACE will allow the Administrators group full access to the key.
  196. ea[1].grfAccessPermissions = KEY_ALL_ACCESS;
  197. ea[1].grfAccessMode = SET_ACCESS;
  198. ea[1].grfInheritance= NO_INHERITANCE;
  199. ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  200. ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  201. ea[1].Trustee.ptstrName = (LPTSTR) g_GlobalInfo->m_AdministratorsSid.get();
  202. // Create a new ACL that contains the new ACEs.
  203. DWORD s = SetEntriesInAcl(2, ea, NULL, &pACL);
  204. if (s != ERROR_SUCCESS)
  205. {
  206. HRESULT HrError = HRESULT_FROM_WIN32( s );
  207. LogError( "create SD : SetEntriesInAcl failed %!winerr!", HrError );
  208. throw ComError( HrError );
  209. }
  210. // Add the ACL to the security descriptor.
  211. if (!SetSecurityDescriptorDacl( pSD,
  212. TRUE, // fDaclPresent flag
  213. pACL,
  214. TRUE)) // a default DACL
  215. {
  216. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  217. LogError( "SetSecurityDescriptorDacl Error %!winerr!", HrError );
  218. throw ComError( HrError );
  219. }
  220. //
  221. // Add the pointers our object.
  222. //
  223. m_sd = pSD;
  224. m_sdOwnerSid = OwnerSid;
  225. m_sdGroupSid = OwnerSid;
  226. m_Dacl = pACL;
  227. }
  228. catch( ComError exception )
  229. {
  230. if (pACL)
  231. LocalFree(pACL);
  232. if (pSD)
  233. delete[] ((char*)pSD);
  234. throw;
  235. }
  236. }
  237. CJobSecurityDescriptor::CJobSecurityDescriptor(
  238. PSECURITY_DESCRIPTOR sd,
  239. SidHandle sdOwnerSid,
  240. SidHandle sdGroupSid,
  241. PACL sdDacl
  242. )
  243. {
  244. m_sd = sd;
  245. m_sdOwnerSid = sdOwnerSid;
  246. m_sdGroupSid = sdGroupSid;
  247. m_Dacl = sdDacl;
  248. }
  249. CJobSecurityDescriptor::~CJobSecurityDescriptor()
  250. {
  251. if (m_Dacl)
  252. LocalFree(m_Dacl);
  253. delete m_sd;
  254. }
  255. HRESULT
  256. CJobSecurityDescriptor::_ModifyAcl(
  257. PSID sid,
  258. BOOL fGroupSid,
  259. DWORD access,
  260. BOOL fAdd
  261. )
  262. {
  263. HRESULT hr;
  264. DWORD dwRes;
  265. PACL pNewAcl = NULL;
  266. EXPLICIT_ACCESS ea;
  267. // Initialize an EXPLICIT_ACCESS structure for the new ACE.
  268. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  269. ea.grfAccessPermissions = access;
  270. ea.grfAccessMode = (fAdd) ? SET_ACCESS : REVOKE_ACCESS;
  271. ea.grfInheritance = NO_INHERITANCE;
  272. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  273. ea.Trustee.TrusteeType = (fGroupSid) ? TRUSTEE_IS_GROUP : TRUSTEE_IS_USER;
  274. ea.Trustee.ptstrName = LPTSTR(sid);
  275. // Create a new ACL that merges the new ACE
  276. // into the existing DACL.
  277. dwRes = SetEntriesInAcl( 1, &ea, m_Dacl, &pNewAcl );
  278. if (ERROR_SUCCESS != dwRes)
  279. {
  280. hr = HRESULT_FROM_WIN32( dwRes );
  281. goto Cleanup;
  282. }
  283. // Attach the new ACL as the object's DACL.
  284. if (!SetSecurityDescriptorDacl( m_sd,
  285. TRUE, // fDaclPresent flag
  286. pNewAcl,
  287. FALSE )) // a default DACL
  288. {
  289. hr = HRESULT_FROM_WIN32( GetLastError() );
  290. LogError( "SetSecurityDescriptorDacl Error %!winerr!", hr );
  291. goto Cleanup;
  292. }
  293. LocalFree( m_Dacl );
  294. m_Dacl = pNewAcl;
  295. pNewAcl = NULL;
  296. hr = S_OK;
  297. Cleanup:
  298. if(pNewAcl)
  299. LocalFree((HLOCAL) pNewAcl);
  300. return hr;
  301. }
  302. HRESULT
  303. CJobSecurityDescriptor::CheckTokenAccess(
  304. HANDLE hToken,
  305. DWORD RequestedAccess,
  306. DWORD * pAllowedAccess,
  307. BOOL * pSuccess
  308. )
  309. {
  310. PRIVILEGE_SET * PrivilegeSet = 0;
  311. DWORD PrivilegeSetSize;
  312. //
  313. // Get space for the privilege set. I don't expect to use any...
  314. //
  315. PrivilegeSetSize = sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES);
  316. auto_ptr<char> Buffer;
  317. try
  318. {
  319. Buffer = auto_ptr<char>( new char[ PrivilegeSetSize ] );
  320. }
  321. catch( ComError Error )
  322. {
  323. return Error.Error();
  324. }
  325. PrivilegeSet = (PRIVILEGE_SET *) Buffer.get();
  326. //
  327. // See whether the security descriptor allows access.
  328. //
  329. if (!AccessCheck( m_sd,
  330. hToken,
  331. RequestedAccess,
  332. &s_AccessMapping,
  333. PrivilegeSet,
  334. &PrivilegeSetSize,
  335. pAllowedAccess,
  336. pSuccess
  337. ))
  338. {
  339. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  340. LogError( "AccessCheck failed, error %!winerr!", HrError );
  341. return HrError;
  342. }
  343. return S_OK;
  344. }
  345. HRESULT
  346. CJobSecurityDescriptor::Serialize(
  347. HANDLE hFile
  348. )
  349. {
  350. try
  351. {
  352. ULONG SdSize;
  353. auto_ptr<char> pSD; // auto_ptr<void> apparently doesn't work
  354. //
  355. // Convert the security descriptor into self-relative format for storage.
  356. //
  357. SdSize = 0;
  358. MakeSelfRelativeSD( m_sd, NULL, &SdSize );
  359. if (SdSize == 0)
  360. {
  361. throw ComError( HRESULT_FROM_WIN32(GetLastError()) );
  362. }
  363. pSD = auto_ptr<char>( new char[ SdSize ] );
  364. if (!MakeSelfRelativeSD( m_sd, pSD.get(), &SdSize ))
  365. {
  366. throw ComError( HRESULT_FROM_WIN32(GetLastError()) );
  367. }
  368. SafeWriteFile( hFile, SdSize );
  369. SafeWriteFile( hFile, pSD.get(), SdSize );
  370. }
  371. catch( ComError err )
  372. {
  373. LogError("SD serialize failed with %!winerr!", err.Error() );
  374. throw;
  375. }
  376. return S_OK;
  377. }
  378. CJobSecurityDescriptor *
  379. CJobSecurityDescriptor::Unserialize(
  380. HANDLE hFile
  381. )
  382. {
  383. //
  384. // Allocations here must match the deletes in the destructor.
  385. //
  386. char * SdBuf = 0;
  387. char * DaclBuf = 0;
  388. CJobSecurityDescriptor * pObject = NULL;
  389. try
  390. {
  391. DWORD SdSize = 0;
  392. DWORD DaclSize = 0;
  393. DWORD SaclSize = 0;
  394. DWORD OwnerSize = 0;
  395. DWORD GroupSize = 0;
  396. PSECURITY_DESCRIPTOR sd;
  397. auto_ptr<char> pSD; // auto_ptr<void> apparently doesn't work
  398. PACL sdDacl;
  399. PACL sdSacl;
  400. SafeReadFile( hFile, &SdSize );
  401. pSD = auto_ptr<char>( new char[ SdSize ] );
  402. SafeReadFile( hFile, pSD.get(), SdSize );
  403. MakeAbsoluteSD( pSD.get(),
  404. NULL, &SdSize,
  405. NULL, &DaclSize,
  406. NULL, &SaclSize,
  407. NULL, &OwnerSize,
  408. NULL, &GroupSize
  409. );
  410. if (!SdSize || !DaclSize || !OwnerSize || !GroupSize)
  411. {
  412. throw ComError( HRESULT_FROM_WIN32(GetLastError()));
  413. }
  414. SdBuf = new char[ SdSize + SaclSize ];
  415. SidHandle OwnerSid = new char[ OwnerSize ];
  416. SidHandle GroupSid = new char[ GroupSize ];
  417. DaclBuf = (char *) LocalAlloc( LMEM_FIXED, DaclSize );
  418. sdDacl = (PACL) DaclBuf;
  419. sd = (PSECURITY_DESCRIPTOR) SdBuf;
  420. sdSacl = (PACL) (SdBuf+SdSize);
  421. if (!MakeAbsoluteSD( pSD.get(),
  422. sd, &SdSize,
  423. sdDacl, &DaclSize,
  424. sdSacl, &SaclSize,
  425. OwnerSid.get(), &OwnerSize,
  426. GroupSid.get(), &GroupSize
  427. ))
  428. {
  429. throw ComError( HRESULT_FROM_WIN32(GetLastError()));
  430. }
  431. pObject = new CJobSecurityDescriptor( sd,
  432. OwnerSid,
  433. GroupSid,
  434. sdDacl
  435. );
  436. }
  437. catch (ComError exception)
  438. {
  439. delete[] SdBuf;
  440. LocalFree( DaclBuf );
  441. delete pObject;
  442. throw;
  443. }
  444. return pObject;
  445. }
  446. //------------------------------------------------------------------------
  447. PSID
  448. CopyTokenSid(
  449. HANDLE Token
  450. )
  451. {
  452. TOKEN_USER * TokenData;
  453. DWORD SizeNeeded;
  454. // Get the size first.
  455. if (!GetTokenInformation(
  456. Token,
  457. TokenUser,
  458. 0,
  459. 0,
  460. &SizeNeeded
  461. ))
  462. {
  463. DWORD dwLastError = GetLastError();
  464. if (ERROR_INSUFFICIENT_BUFFER != dwLastError)
  465. {
  466. THROW_HRESULT( HRESULT_FROM_WIN32( GetLastError()));
  467. }
  468. }
  469. auto_ptr<char> Buffer( new char[ SizeNeeded ] );
  470. TokenData = (TOKEN_USER *) Buffer.get();
  471. if (!GetTokenInformation(
  472. Token,
  473. TokenUser,
  474. TokenData,
  475. SizeNeeded,
  476. &SizeNeeded
  477. ))
  478. {
  479. THROW_HRESULT( HRESULT_FROM_WIN32( GetLastError()));
  480. }
  481. PSID sid = DuplicateSid( TokenData->User.Sid );
  482. if (sid == NULL)
  483. {
  484. THROW_HRESULT( E_OUTOFMEMORY);
  485. }
  486. return sid;
  487. }
  488. HANDLE
  489. CopyThreadToken()
  490. /*
  491. Makes a copy of the current thread's impersonation token.
  492. Returns NULL if not impersonating.
  493. Throws an exception if an error occurs.
  494. */
  495. {
  496. HANDLE token = NULL;
  497. if (OpenThreadToken( GetCurrentThread(),
  498. MAXIMUM_ALLOWED,
  499. TRUE,
  500. &token))
  501. {
  502. return token;
  503. }
  504. else if (GetLastError() == ERROR_NO_TOKEN)
  505. {
  506. return NULL;
  507. }
  508. else
  509. {
  510. throw ComError( HRESULT_FROM_WIN32( GetLastError() ));
  511. }
  512. }
  513. SidHandle
  514. GetThreadClientSid()
  515. /*
  516. Returns the SID of the current thread's COM client.
  517. Throws an exception if an error occurs.
  518. */
  519. {
  520. CNestedImpersonation imp;
  521. return imp.CopySid();
  522. }
  523. HRESULT
  524. IsRemoteUser()
  525. {
  526. return CheckClientGroupMembership( g_GlobalInfo->m_NetworkUsersSid );
  527. }
  528. HRESULT
  529. CheckClientGroupMembership(
  530. SidHandle group
  531. )
  532. {
  533. try
  534. {
  535. BOOL fIsMember;
  536. CNestedImpersonation imp;
  537. if (!CheckTokenMembership( imp.QueryToken(),
  538. group.get(),
  539. &fIsMember))
  540. {
  541. return HRESULT_FROM_WIN32( GetLastError() );
  542. }
  543. if (fIsMember)
  544. {
  545. return S_OK;
  546. }
  547. return S_FALSE;
  548. }
  549. catch( ComError Error )
  550. {
  551. return Error.Error();
  552. }
  553. }
  554. HRESULT
  555. DenyRemoteAccess()
  556. {
  557. HRESULT hr = CheckClientGroupMembership( g_GlobalInfo->m_NetworkUsersSid );
  558. if (FAILED(hr))
  559. {
  560. return hr;
  561. }
  562. if (hr == S_OK)
  563. {
  564. return BG_E_REMOTE_NOT_SUPPORTED;
  565. }
  566. return S_OK;
  567. }
  568. HRESULT
  569. DenyNonAdminAccess()
  570. {
  571. HRESULT hr = CheckClientGroupMembership( g_GlobalInfo->m_AdministratorsSid );
  572. if (FAILED(hr))
  573. {
  574. return hr;
  575. }
  576. if (hr == S_FALSE)
  577. {
  578. return E_ACCESSDENIED;
  579. }
  580. return S_OK;
  581. }