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.

267 lines
7.9 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1998.
  5. //
  6. // File: seccache.cxx
  7. //
  8. // Contents: Security descriptor cache that maps SDIDs to granted/denied
  9. //
  10. // Class: CSecurityCache
  11. //
  12. // History: 25-Sep-95 dlee Created
  13. // 22 Jan 96 Alanw Modified for use in user mode
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. // Local includes:
  19. #include <seccache.hxx>
  20. #include <catalog.hxx>
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Method: CSecurityCache::CSecurityCache, public
  24. //
  25. // Synopsis: Creates a CSecurityCache. In user mode, an
  26. // impersonation token to use with the AccessCheck call is
  27. // obtained.
  28. //
  29. // History: 22 Jan 96 Alanw Created
  30. //
  31. //----------------------------------------------------------------------------
  32. CSecurityCache::CSecurityCache( PCatalog & rCat ) :
  33. _aEntries( cDefaultSecurityDescriptorEntries ),
  34. _hToken( INVALID_HANDLE_VALUE ),
  35. _Cat( rCat )
  36. {
  37. InitToken();
  38. }
  39. //+---------------------------------------------------------------------------
  40. //
  41. // Method: CSecurityCache::InitToken, public
  42. //
  43. // Synopsis: Captures an impersonation token to use with the AccessCheck
  44. // call.
  45. //
  46. // History: 15 Feb 96 Alanw Created
  47. //
  48. //----------------------------------------------------------------------------
  49. void CSecurityCache::InitToken( )
  50. {
  51. DWORD ReturnLength;
  52. NTSTATUS status;
  53. TOKEN_STATISTICS TokenInformation;
  54. status = NtOpenThreadToken( GetCurrentThread(),
  55. TOKEN_QUERY | TOKEN_DUPLICATE |
  56. TOKEN_IMPERSONATE, // Desired Access
  57. TRUE, // OpenAsSelf
  58. &_hToken);
  59. if (!NT_SUCCESS(status)) {
  60. if (status == STATUS_NO_TOKEN)
  61. {
  62. status = NtOpenProcessToken( GetCurrentProcess(),
  63. TOKEN_QUERY | TOKEN_DUPLICATE |
  64. TOKEN_IMPERSONATE, // Desired Access
  65. &_hToken);
  66. }
  67. if (!NT_SUCCESS(status))
  68. {
  69. vqDebugOut(( DEB_ERROR,
  70. "CSecurityCache: failed to get token handle, %x\n",
  71. status ));
  72. THROW(CException( status ));
  73. }
  74. }
  75. status = NtQueryInformationToken ( _hToken,
  76. TokenStatistics,
  77. (LPVOID)&TokenInformation,
  78. sizeof TokenInformation,
  79. &ReturnLength);
  80. if (!NT_SUCCESS(status))
  81. {
  82. vqDebugOut(( DEB_ERROR,
  83. "CSecurityCache: failed to get token info, %x\n",
  84. status ));
  85. THROW(CException( status ));
  86. }
  87. if ( TokenInformation.TokenType != TokenImpersonation )
  88. {
  89. HANDLE hNewToken = INVALID_HANDLE_VALUE;
  90. OBJECT_ATTRIBUTES ObjA;
  91. SECURITY_QUALITY_OF_SERVICE SecurityQOS;
  92. SecurityQOS.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  93. SecurityQOS.ImpersonationLevel = SecurityIdentification;
  94. SecurityQOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  95. SecurityQOS.EffectiveOnly = FALSE;
  96. InitializeObjectAttributes( &ObjA,
  97. NULL,
  98. 0,
  99. NULL,
  100. NULL );
  101. ObjA.SecurityQualityOfService = &SecurityQOS;
  102. status = NtDuplicateToken( _hToken,
  103. TOKEN_IMPERSONATE | TOKEN_QUERY,
  104. &ObjA,
  105. FALSE,
  106. TokenImpersonation,
  107. &hNewToken );
  108. if (! NT_SUCCESS( status ) )
  109. {
  110. vqDebugOut(( DEB_ERROR,
  111. "CSecurityCache: failed to duplicate token, %x\n",
  112. status ));
  113. THROW(CException( status ));
  114. }
  115. NtClose( _hToken );
  116. _hToken = hNewToken;
  117. }
  118. }
  119. CSecurityCache::~CSecurityCache()
  120. {
  121. if ( INVALID_HANDLE_VALUE != _hToken )
  122. NtClose( _hToken );
  123. }
  124. //+---------------------------------------------------------------------------
  125. //
  126. // Method: CSecurityCache::_IsCached, private
  127. //
  128. // Synopsis: Determines whether a sdid is granted access given the
  129. // cache's security context.
  130. //
  131. // Arguments: [sdidOrd] -- security descriptor ordinal to test
  132. // [am] -- access mask of the request
  133. // [fGranted] -- if return value is TRUE, this is either
  134. // TRUE (if access is granted) or FALSE.
  135. //
  136. // Returns: TRUE if sdid was in the cache and fGranted is set
  137. // FALSE if sdid is not cached and fGranted should be ignored
  138. //
  139. // History: 25-Sep-95 dlee Created
  140. //
  141. //----------------------------------------------------------------------------
  142. inline BOOL CSecurityCache::_IsCached(
  143. ULONG sdidOrd,
  144. ACCESS_MASK am,
  145. BOOL & fGranted ) const
  146. {
  147. // Look for the sdid in the cache
  148. for ( unsigned i = 0; i < _aEntries.Count(); i++ )
  149. {
  150. if ( ( _aEntries[i].sdidOrd == sdidOrd ) &&
  151. ( _aEntries[i].am == am ) )
  152. {
  153. fGranted = _aEntries[i].fGranted;
  154. return TRUE;
  155. }
  156. }
  157. return FALSE;
  158. } //_IsCached
  159. //+---------------------------------------------------------------------------
  160. //
  161. // Method: CSecurityCache::IsGranted, public
  162. //
  163. // Synopsis: Determines whether a security ordinal is granted access given
  164. // the cache's security context, and caches the result.
  165. //
  166. // Arguments: [sdidOrdinal] -- security descriptor ordinal to test
  167. // [am] -- access mask of the request, one or more of
  168. // FILE_READ_ATTRIBUTES
  169. // FILE_READ_DATA / FILE_LIST_DIRECTORY
  170. // FILE_TRAVERSE
  171. //
  172. // Returns: TRUE if sdid was granted access, FALSE otherwise
  173. //
  174. // History: 25-Sep-95 dlee Created
  175. // 22 Jan 96 Alanw Modified for use in user mode
  176. //
  177. //----------------------------------------------------------------------------
  178. BOOL CSecurityCache::IsGranted(
  179. ULONG sdidOrdinal,
  180. ACCESS_MASK am )
  181. {
  182. // if nothing asked for, grant
  183. if ( 0 == am )
  184. return TRUE;
  185. if ( sdidNull == sdidOrdinal )
  186. return TRUE;
  187. if ( sdidInvalid == sdidOrdinal )
  188. return FALSE;
  189. BOOL fGranted;
  190. {
  191. CLock lock( _mutex );
  192. if ( _IsCached( sdidOrdinal, am, fGranted ) )
  193. return fGranted;
  194. }
  195. // do the security check
  196. fGranted = FALSE;
  197. BOOL fResult = _Cat.AccessCheck( sdidOrdinal,
  198. GetToken(),
  199. am,
  200. fGranted);
  201. if (! fResult)
  202. {
  203. DWORD dwError = GetLastError();
  204. Win4Assert( fResult && dwError == NO_ERROR );
  205. }
  206. // Not cached yet -- do so
  207. vqDebugOut(( DEB_ITRACE, "cacheing sdid %x, granted: %x\n",
  208. sdidOrdinal, fGranted ));
  209. {
  210. CLock lock( _mutex );
  211. // check the cache again -- it may have slipped in via a different
  212. // thread while we weren't holding the lock.
  213. if ( !_IsCached( sdidOrdinal, am, fGranted ) )
  214. {
  215. unsigned i = _aEntries.Count();
  216. _aEntries[i].sdidOrd = sdidOrdinal;
  217. _aEntries[i].am = am;
  218. _aEntries[i].fGranted = fGranted;
  219. }
  220. }
  221. return fGranted;
  222. } //IsGranted