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.

534 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. SafeHand.c (WinSAFER Handle Operations)
  5. Abstract:
  6. This module implements the WinSAFER APIs to open and close handles
  7. to SAFER Code Authorization Levels.
  8. Author:
  9. Jeffrey Lawson (JLawson) - Nov 1999
  10. Environment:
  11. User mode only.
  12. Exported Functions:
  13. CodeAuthzHandleToLevelStruct
  14. CodeAuthzpOpenPolicyRootKey
  15. CodeAuthzCreateLevelHandle
  16. CodeAuthzCloseLevelHandle
  17. SaferCreateLevel (public win32 api)
  18. SaferCloseLevel (public win32 api)
  19. Revision History:
  20. Created - Nov 1999
  21. --*/
  22. #include "pch.h"
  23. #pragma hdrstop
  24. #include <winsafer.h>
  25. #include <winsaferp.h>
  26. #include "saferp.h"
  27. //
  28. // All handles have a bit pattern OR-ed onto them to serve both
  29. // as a debugging aid in distinguishing obvious non-handles,
  30. // and also to ensure that a zero handle is never given back.
  31. //
  32. #define LEVEL_HANDLE_BITS 0x74000000
  33. #define LEVEL_HANDLE_MASK 0xFF000000
  34. NTSTATUS NTAPI
  35. CodeAuthzpCreateLevelHandleFromRecord(
  36. IN PAUTHZLEVELTABLERECORD pLevelRecord,
  37. IN DWORD dwScopeId,
  38. IN DWORD dwSaferFlags OPTIONAL,
  39. IN DWORD dwExtendedError,
  40. IN SAFER_IDENTIFICATION_TYPES IdentificationType,
  41. IN REFGUID refIdentGuid OPTIONAL,
  42. OUT SAFER_LEVEL_HANDLE *pLevelHandle
  43. )
  44. /*++
  45. Routine Description:
  46. Converts a level record to an opaque SAFER_LEVEL_HANDLE handle.
  47. Note that although this function assumes that the global
  48. critical section has already been obtained by the caller.
  49. Arguments:
  50. pLevelRecord - specifies the level record for which the
  51. request is being made. It is assumed that this record
  52. is valid and exists within the g_CodeLevelObjTable.
  53. dwScopeId - indicates the scope that will be stored within
  54. the opened handle. This scope affects the behavior of
  55. Get/SetInfoCodeAuthzLevel for code identifiers.
  56. dwSaferFlags - indicates any optional Safer flags that were
  57. derived from the matching code identifier. These bits
  58. will be bitwise ORed in SaferComputeTokenFromLevel.
  59. dwExtendedError - Error returned by WinVerifyTrust.
  60. IdentificationType - Rule that identified this level.
  61. refIdentGuid - indicates the Code Identifier record that was
  62. used to match the given level. This may be NULL.
  63. pLevelHandle - receives the resulting opaque Level handle.
  64. Return Value:
  65. Returns STATUS_SUCCESS on success.
  66. --*/
  67. {
  68. NTSTATUS Status;
  69. ULONG ulHandleIndex;
  70. PAUTHZLEVELHANDLESTRUCT pLevelStruct;
  71. ASSERT(ARGUMENT_PRESENT(pLevelRecord) &&
  72. ARGUMENT_PRESENT(pLevelHandle));
  73. //
  74. // Validate the value passed within the dwScope argument.
  75. //
  76. if (g_hKeyCustomRoot != NULL) {
  77. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  78. Status = STATUS_INVALID_PARAMETER_MIX;
  79. goto ExitHandler;
  80. }
  81. } else {
  82. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  83. dwScopeId != SAFER_SCOPEID_USER) {
  84. Status = STATUS_INVALID_PARAMETER_MIX;
  85. goto ExitHandler;
  86. }
  87. }
  88. //
  89. // Allocate a handle to represent this level.
  90. //
  91. pLevelStruct = (PAUTHZLEVELHANDLESTRUCT) RtlAllocateHandle(
  92. &g_LevelHandleTable,
  93. &ulHandleIndex);
  94. if (!pLevelStruct) {
  95. Status = STATUS_INSUFFICIENT_RESOURCES;
  96. goto ExitHandler;
  97. }
  98. ASSERT((ulHandleIndex & LEVEL_HANDLE_MASK) == 0);
  99. *pLevelHandle = UlongToPtr(ulHandleIndex | LEVEL_HANDLE_BITS);
  100. //
  101. // Fill in the handle structure to represent this level.
  102. //
  103. RtlZeroMemory(pLevelStruct, sizeof(AUTHZLEVELHANDLESTRUCT));
  104. pLevelStruct->HandleHeader.Flags = RTL_HANDLE_ALLOCATED;
  105. pLevelStruct->dwLevelId = pLevelRecord->dwLevelId;
  106. pLevelStruct->dwScopeId = dwScopeId;
  107. pLevelStruct->dwSaferFlags = dwSaferFlags;
  108. pLevelStruct->dwHandleSequence = g_dwLevelHandleSequence;
  109. pLevelStruct->dwExtendedError = dwExtendedError;
  110. pLevelStruct->IdentificationType = IdentificationType;
  111. if (ARGUMENT_PRESENT(refIdentGuid)) {
  112. RtlCopyMemory(&pLevelStruct->identGuid, refIdentGuid, sizeof(GUID));
  113. } else {
  114. ASSERT(IsZeroGUID(&pLevelStruct->identGuid));
  115. }
  116. Status = STATUS_SUCCESS;
  117. ExitHandler:
  118. return Status;
  119. }
  120. NTSTATUS NTAPI
  121. CodeAuthzHandleToLevelStruct(
  122. IN SAFER_LEVEL_HANDLE hLevelObject,
  123. OUT PAUTHZLEVELHANDLESTRUCT *pLevelStruct)
  124. /*++
  125. Routine Description:
  126. Converts an opaque SAFER_LEVEL_HANDLE handle into a pointer to the
  127. internal handle structure.
  128. Note that although this function gains and releases access to
  129. the critical section during the API execution, the caller is
  130. expected to have already entered the critical section and
  131. maintain the critical section for the entire duration under
  132. which the return pLevelStruct will be used. Otherwise, the
  133. pLevelStruct can potentially become invalid if another thread
  134. reloads the cache tables and invalidates all handles.
  135. Arguments:
  136. hLevelObject - specifies the handle to the AuthzObject for which the
  137. request is being made.
  138. lpLevelObjectStruct - receives a pointer to the internal handle
  139. structure that represents the specified AuthzLevelObject.
  140. Return Value:
  141. Returns STATUS_SUCCESS on success.
  142. --*/
  143. {
  144. NTSTATUS Status;
  145. ULONG ulHandleIndex;
  146. if (!g_bInitializedFirstTime) {
  147. return STATUS_UNSUCCESSFUL;
  148. }
  149. if (!ARGUMENT_PRESENT(hLevelObject)) {
  150. return STATUS_INVALID_HANDLE;
  151. }
  152. if (!ARGUMENT_PRESENT(pLevelStruct)) {
  153. return STATUS_ACCESS_VIOLATION;
  154. }
  155. RtlEnterCriticalSection(&g_TableCritSec);
  156. ASSERT(!g_bNeedCacheReload);
  157. //
  158. // Translate the handle index into a pointer to the handle structure.
  159. //
  160. ulHandleIndex = PtrToUlong(hLevelObject);
  161. if ( (ulHandleIndex & LEVEL_HANDLE_MASK) != LEVEL_HANDLE_BITS) {
  162. Status = STATUS_INVALID_HANDLE;
  163. goto ExitHandler;
  164. }
  165. ulHandleIndex &= ~LEVEL_HANDLE_MASK;
  166. if (!RtlIsValidIndexHandle(&g_LevelHandleTable, ulHandleIndex,
  167. (PRTL_HANDLE_TABLE_ENTRY*) pLevelStruct)) {
  168. Status = STATUS_INVALID_HANDLE;
  169. goto ExitHandler;
  170. }
  171. //
  172. // Verify some additional sanity checks on the handle structure
  173. // that was mapped. Ensure that it was not a handle that was
  174. // opened, but invalidated because CodeAuthzReloadCacheTables was
  175. // called before closing then Level handle.
  176. //
  177. if (*pLevelStruct == NULL ||
  178. (*pLevelStruct)->dwHandleSequence != g_dwLevelHandleSequence ||
  179. !CodeAuthzLevelObjpLookupByLevelId(
  180. &g_CodeLevelObjTable, (*pLevelStruct)->dwLevelId ) )
  181. {
  182. Status = STATUS_INVALID_HANDLE;
  183. goto ExitHandler;
  184. }
  185. Status = STATUS_SUCCESS;
  186. ExitHandler:
  187. RtlLeaveCriticalSection(&g_TableCritSec);
  188. return Status;
  189. }
  190. NTSTATUS NTAPI
  191. CodeAuthzCreateLevelHandle(
  192. IN DWORD dwLevelId,
  193. IN DWORD OpenFlags,
  194. IN DWORD dwScopeId,
  195. IN DWORD dwSaferFlags OPTIONAL,
  196. OUT SAFER_LEVEL_HANDLE *pLevelHandle)
  197. /*++
  198. Routine Description:
  199. Internal function to open a handle to a WinSafer Level.
  200. Arguments:
  201. dwLevelId - input level of the WinSafer Level to open.
  202. Note that the dwScopeId argument does not affect the scope
  203. of the level that is opened itself.
  204. OpenFlags - flags that affect how the object is opened.
  205. dwScopeId - input scope identifier that is stored within the
  206. resulting handle. This scope identifier is used to affect
  207. the behavior of SaferGet/SetLevelInformation for code identifier.
  208. dwSaferFlags - flags that are stored within the resulting handle.
  209. These flags are usually derived from the code identifier
  210. that matched, and will be used in the final call to
  211. SaferComputeTokenFromLevel.
  212. pLevelHandle - receives the new handle.
  213. Return Value:
  214. Returns STATUS_SUCCESS on success.
  215. --*/
  216. {
  217. NTSTATUS Status;
  218. PAUTHZLEVELTABLERECORD pLevelRecord;
  219. //
  220. // Verify our input arguments are okay.
  221. //
  222. if (!ARGUMENT_PRESENT(pLevelHandle)) {
  223. Status = STATUS_ACCESS_VIOLATION;
  224. goto ExitHandler;
  225. }
  226. if ((OpenFlags & SAFER_LEVEL_CREATE) != 0 ||
  227. (OpenFlags & SAFER_LEVEL_DELETE) != 0) {
  228. // BLACKCOMB TODO: need to support creation or deletion.
  229. Status = STATUS_NOT_IMPLEMENTED;
  230. goto ExitHandler;
  231. }
  232. if (!g_bInitializedFirstTime) {
  233. Status = STATUS_UNSUCCESSFUL;
  234. goto ExitHandler;
  235. }
  236. RtlEnterCriticalSection(&g_TableCritSec);
  237. if (g_bNeedCacheReload) {
  238. Status = CodeAuthzpImmediateReloadCacheTables();
  239. if (!NT_SUCCESS(Status)) {
  240. goto ExitHandler2;
  241. }
  242. }
  243. //
  244. // Find the cached record for the requested level.
  245. //
  246. pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  247. &g_CodeLevelObjTable,
  248. dwLevelId);
  249. if (!pLevelRecord) {
  250. Status = STATUS_NOT_FOUND;
  251. goto ExitHandler2;
  252. }
  253. ASSERT(pLevelRecord->dwLevelId == dwLevelId);
  254. //
  255. // Actually create a Level handle for this record.
  256. //
  257. Status = CodeAuthzpCreateLevelHandleFromRecord(
  258. pLevelRecord, dwScopeId,
  259. dwSaferFlags, ERROR_SUCCESS, SaferIdentityDefault, NULL, pLevelHandle);
  260. //
  261. // Handle cleanup and error handling.
  262. //
  263. ExitHandler2:
  264. RtlLeaveCriticalSection(&g_TableCritSec);
  265. ExitHandler:
  266. return Status;
  267. }
  268. NTSTATUS NTAPI
  269. CodeAuthzCloseLevelHandle(
  270. IN SAFER_LEVEL_HANDLE hLevelObject)
  271. /*++
  272. Routine Description:
  273. Internal function to close an AuthzObject handle.
  274. Arguments:
  275. hLevelObject - the AuthzObject handle to close.
  276. Return Value:
  277. Returns STATUS_SUCCESS on success.
  278. --*/
  279. {
  280. NTSTATUS Status;
  281. ULONG ulHandleIndex;
  282. PAUTHZLEVELHANDLESTRUCT pLevelStruct;
  283. if (!ARGUMENT_PRESENT(hLevelObject)) {
  284. Status = STATUS_INVALID_HANDLE;
  285. goto ExitHandler;
  286. }
  287. if (!g_bInitializedFirstTime) {
  288. Status = STATUS_UNSUCCESSFUL;
  289. goto ExitHandler;
  290. }
  291. RtlEnterCriticalSection(&g_TableCritSec);
  292. ulHandleIndex = PtrToUlong(hLevelObject);
  293. if ( (ulHandleIndex & LEVEL_HANDLE_MASK) != LEVEL_HANDLE_BITS) {
  294. Status = STATUS_INVALID_HANDLE;
  295. goto ExitHandler2;
  296. }
  297. ulHandleIndex &= ~LEVEL_HANDLE_MASK;
  298. if (!RtlIsValidIndexHandle(&g_LevelHandleTable, ulHandleIndex,
  299. (PRTL_HANDLE_TABLE_ENTRY *) &pLevelStruct)) {
  300. Status = STATUS_INVALID_HANDLE;
  301. goto ExitHandler2;
  302. }
  303. if (!RtlFreeHandle(&g_LevelHandleTable,
  304. (PRTL_HANDLE_TABLE_ENTRY) pLevelStruct)) {
  305. Status = STATUS_INVALID_HANDLE;
  306. goto ExitHandler2;
  307. }
  308. Status = STATUS_SUCCESS;
  309. ExitHandler2:
  310. RtlLeaveCriticalSection(&g_TableCritSec);
  311. ExitHandler:
  312. return Status;
  313. }
  314. BOOL WINAPI
  315. SaferCreateLevel(
  316. IN DWORD dwScopeId,
  317. IN DWORD dwLevelId,
  318. IN DWORD OpenFlags,
  319. OUT SAFER_LEVEL_HANDLE *pLevelObject,
  320. IN LPVOID lpReserved)
  321. /*++
  322. Routine Description:
  323. Public function implementing the Unicode version of this API,
  324. allowing the user to create or open an Authorization Object
  325. and receive a handle representing the object.
  326. Arguments:
  327. dwScopeId - not used (anymore), reserved for future use.
  328. dwLevelId - input object level of the AuthzObject to create/open.
  329. OpenFlags - flags to control opening, creation, or deletion.
  330. lpReserved - not used, reserved for future use.
  331. pLevelObject - receives the new handle.
  332. Return Value:
  333. Returns FALSE on error, TRUE on success. Sets GetLastError() on error.
  334. --*/
  335. {
  336. NTSTATUS Status;
  337. //
  338. // Verify the arguments were all supplied.
  339. //
  340. UNREFERENCED_PARAMETER(lpReserved);
  341. if (!g_bInitializedFirstTime) {
  342. Status = STATUS_UNSUCCESSFUL;
  343. goto ExitHandler;
  344. }
  345. if (!ARGUMENT_PRESENT(pLevelObject)) {
  346. Status = STATUS_ACCESS_VIOLATION;
  347. goto ExitHandler;
  348. }
  349. RtlEnterCriticalSection(&g_TableCritSec);
  350. if (g_hKeyCustomRoot != NULL) {
  351. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  352. Status = STATUS_INVALID_PARAMETER_MIX;
  353. goto ExitHandler2;
  354. }
  355. } else {
  356. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  357. dwScopeId != SAFER_SCOPEID_USER) {
  358. Status = STATUS_INVALID_PARAMETER_MIX;
  359. goto ExitHandler2;
  360. }
  361. }
  362. //
  363. // Actually call the worker functions to get it done.
  364. //
  365. Status = CodeAuthzCreateLevelHandle(
  366. dwLevelId,
  367. OpenFlags,
  368. dwScopeId,
  369. 0,
  370. pLevelObject);
  371. //
  372. // Set the error result.
  373. //
  374. ExitHandler2:
  375. RtlLeaveCriticalSection(&g_TableCritSec);
  376. ExitHandler:
  377. if ( NT_SUCCESS( Status ) ) {
  378. return TRUE;
  379. }
  380. BaseSetLastNTError(Status);
  381. return FALSE;
  382. }
  383. BOOL WINAPI
  384. SaferCloseLevel(
  385. IN SAFER_LEVEL_HANDLE hLevelObject)
  386. /*++
  387. Routine Description:
  388. Public function to close a handle to an Authorization Level Object.
  389. Arguments:
  390. hLevelObject - the AuthzObject handle to close.
  391. Return Value:
  392. Returns FALSE on error, TRUE on success.
  393. --*/
  394. {
  395. NTSTATUS Status;
  396. Status = CodeAuthzCloseLevelHandle(hLevelObject);
  397. if (! NT_SUCCESS(Status) ) {
  398. BaseSetLastNTError(Status);
  399. return FALSE;
  400. }
  401. return TRUE;
  402. }