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.

989 lines
24 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Predefh.c
  5. Abstract:
  6. This module contains the client side support for managing the Win32
  7. Registry API's predefined handles. This support is supplied via a
  8. table, which maps (a) predefined handles to real handles and (b)
  9. the server side routine which opens the handle.
  10. Author:
  11. David J. Gilman (davegi) 15-Nov-1991
  12. Notes:
  13. See the notes in server\predefh.c.
  14. --*/
  15. #include <rpc.h>
  16. #include "regrpc.h"
  17. #include "client.h"
  18. #if defined(LEAK_TRACK)
  19. NTSTATUS TrackObject(HKEY hKey);
  20. #endif // LEAK_TRACK
  21. RTL_CRITICAL_SECTION PredefinedHandleTableCriticalSection;
  22. //
  23. // For each predefined handle an entry is maintained in an array. Each of
  24. // these structures contains a real (context) handle and a pointer to a
  25. // function that knows how to map the predefined handle to the Registry name
  26. // space.
  27. //
  28. //
  29. // Pointer to function to open predefined handles.
  30. //
  31. typedef
  32. error_status_t
  33. ( *OPEN_FUNCTION ) (
  34. PREGISTRY_SERVER_NAME,
  35. REGSAM,
  36. PRPC_HKEY
  37. );
  38. //
  39. // Table entry for a predefined handle.
  40. //
  41. typedef struct _PRDEFINED_HANDLE {
  42. RPC_HKEY Handle;
  43. OPEN_FUNCTION OpenFunc;
  44. BOOLEAN Disabled; // tells whether the handle should be cached or not.
  45. #if DBG
  46. ULONG Callers;
  47. PVOID CallerAddress[10];
  48. #endif
  49. } PREDEFINED_HANDLE, *PPREDEFINED_HANDLE;
  50. //
  51. // Initialize predefined handle table.
  52. //
  53. PREDEFINED_HANDLE PredefinedHandleTable[ ] = {
  54. NULL, LocalOpenClassesRoot, FALSE
  55. #if DBG
  56. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  57. #endif
  58. ,
  59. NULL, LocalOpenCurrentUser, FALSE
  60. #if DBG
  61. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  62. #endif
  63. ,
  64. NULL, LocalOpenLocalMachine, FALSE
  65. #if DBG
  66. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  67. #endif
  68. ,
  69. NULL, LocalOpenUsers, FALSE
  70. #if DBG
  71. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  72. #endif
  73. ,
  74. NULL, LocalOpenPerformanceData, FALSE
  75. #if DBG
  76. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  77. #endif
  78. ,
  79. NULL, LocalOpenPerformanceText, FALSE
  80. #if DBG
  81. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  82. #endif
  83. ,
  84. NULL, LocalOpenPerformanceNlsText, FALSE
  85. #if DBG
  86. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  87. #endif
  88. ,
  89. NULL, LocalOpenCurrentConfig, FALSE
  90. #if DBG
  91. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  92. #endif
  93. ,
  94. NULL, LocalOpenDynData, FALSE
  95. #if DBG
  96. , 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  97. #endif
  98. };
  99. #define MAX_PREDEFINED_HANDLES \
  100. ( sizeof( PredefinedHandleTable ) / sizeof( PREDEFINED_HANDLE ))
  101. //
  102. // Predefined HKEY values are defined in Winreg.x. They MUST be kept in
  103. // synch with the following constants and macros.
  104. //
  105. //
  106. // Mark Registry handles so that we can recognize predefined handles.
  107. //
  108. #define PREDEFINED_REGISTRY_HANDLE_SIGNATURE ( 0x80000000 )
  109. NTSTATUS
  110. SetHandleProtection(
  111. IN HANDLE Handle,
  112. IN LONG Index,
  113. IN BOOLEAN Protect
  114. )
  115. /*++
  116. Routine Description:
  117. Changes the handle ProtectFromClose attribute. To be used for predefined handles,
  118. to prevent abnormal closure.
  119. Arguments:
  120. Handle - Supplies the handle who's protection to be changed.
  121. Index - Index in the predefined handle table
  122. Return Value:
  123. Status of the NtSetInformationObject call
  124. --*/
  125. {
  126. NTSTATUS Status;
  127. OBJECT_HANDLE_FLAG_INFORMATION Ohfi = { FALSE,
  128. FALSE
  129. };
  130. ULONG PredefHandle;
  131. PredefHandle = ((ULONG)Index) | PREDEFINED_REGISTRY_HANDLE_SIGNATURE;
  132. switch (PredefHandle) {
  133. case (ULONG)((ULONG_PTR)HKEY_CLASSES_ROOT):
  134. case (ULONG)((ULONG_PTR)HKEY_CURRENT_USER):
  135. case (ULONG)((ULONG_PTR)HKEY_LOCAL_MACHINE):
  136. case (ULONG)((ULONG_PTR)HKEY_USERS):
  137. //
  138. // go change the protection
  139. //
  140. break;
  141. default:
  142. //
  143. // The supplied handle might not be a real handle
  144. //
  145. return STATUS_INVALID_HANDLE;
  146. }
  147. Ohfi.ProtectFromClose = Protect;
  148. Status = NtSetInformationObject(Handle,
  149. ObjectHandleFlagInformation,
  150. &Ohfi,
  151. sizeof (OBJECT_HANDLE_FLAG_INFORMATION));
  152. #if DBG
  153. if (!NT_SUCCESS(Status)) {
  154. DbgPrint( "WINREG: SetHandleProtection (%u) on %lx failed. Status = %lx \n",Protect, Handle, Status );
  155. }
  156. #endif
  157. return Status;
  158. }
  159. LONG
  160. MapPredefinedRegistryHandleToIndex(
  161. IN ULONG Handle
  162. )
  163. /*++
  164. Routine Description:
  165. Maps a predefined handle to an index into the predefined handle table.
  166. Arguments:
  167. Handle - Supplies the handle to be mapped.
  168. Return Value:
  169. An index into the predefined handle table
  170. -1 if the handle is not a predefined handle
  171. --*/
  172. {
  173. LONG Index;
  174. switch (Handle) {
  175. case (ULONG)((ULONG_PTR)HKEY_CLASSES_ROOT):
  176. case (ULONG)((ULONG_PTR)HKEY_CURRENT_USER):
  177. case (ULONG)((ULONG_PTR)HKEY_LOCAL_MACHINE):
  178. case (ULONG)((ULONG_PTR)HKEY_USERS):
  179. case (ULONG)((ULONG_PTR)HKEY_PERFORMANCE_DATA):
  180. Index = (Handle & ~PREDEFINED_REGISTRY_HANDLE_SIGNATURE);
  181. break;
  182. case (ULONG)((ULONG_PTR)HKEY_PERFORMANCE_TEXT):
  183. Index = 5;
  184. break;
  185. case (ULONG)((ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT):
  186. Index = 6;
  187. break;
  188. case (ULONG)((ULONG_PTR)HKEY_CURRENT_CONFIG):
  189. Index = 7;
  190. break;
  191. case (ULONG)((ULONG_PTR)HKEY_DYN_DATA):
  192. Index = 8;
  193. break;
  194. default:
  195. //
  196. // The supplied handle is not predefined, so return it.
  197. //
  198. Index = -1;
  199. break;
  200. }
  201. return(Index);
  202. }
  203. NTSTATUS
  204. RemapPredefinedHandle(
  205. IN RPC_HKEY Handle,
  206. IN RPC_HKEY NewHandle
  207. )
  208. /*++
  209. Routine Description:
  210. Override the current predefined handle. If it is already open, close it,
  211. then set the new handle
  212. Arguments:
  213. Handle - Supplies a handle which must be a predefined handle
  214. NewHandle - an already open registry key to override the special key
  215. Return Value:
  216. ERROR_SUCCESS - no problems
  217. --*/
  218. {
  219. LONG Index;
  220. LONG Error;
  221. NTSTATUS Status;
  222. HANDLE hCurrentProcess;
  223. HKEY hkTableHandle = NULL;
  224. //
  225. // If the high bit is not set, we know it's not a predefined handle
  226. // so take a quick out.
  227. //
  228. if (((ULONG_PTR)Handle & 0x80000000) == 0) {
  229. return(STATUS_INVALID_HANDLE);
  230. }
  231. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  232. ASSERT( NT_SUCCESS( Status ) );
  233. if ( !NT_SUCCESS( Status ) ) {
  234. #if DBG
  235. DbgPrint( "WINREG: RtlEnterCriticalSection() on RemapPredefinedHandle() failed. Status = %lx \n", Status );
  236. #endif
  237. Status = ERROR_INVALID_HANDLE;
  238. goto cleanup_and_exit;
  239. }
  240. Index = MapPredefinedRegistryHandleToIndex((ULONG)(ULONG_PTR)Handle);
  241. if (Index == -1) {
  242. Status = STATUS_INVALID_HANDLE;
  243. goto leave_crit_sect;
  244. }
  245. ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
  246. if( PredefinedHandleTable[ Index ].Disabled == TRUE ) {
  247. //
  248. // predefined table is disabled for this key
  249. //
  250. // nobody is allowed to write here
  251. ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
  252. // refuse the request
  253. Status = STATUS_INVALID_HANDLE;
  254. goto leave_crit_sect;
  255. }
  256. hCurrentProcess = NtCurrentProcess();
  257. //
  258. // see if we can duplicate this handle so we can place it
  259. // in the table
  260. //
  261. if (NewHandle && !NT_SUCCESS(Status = NtDuplicateObject (hCurrentProcess,
  262. NewHandle,
  263. hCurrentProcess,
  264. &hkTableHandle,
  265. 0,
  266. FALSE,
  267. DUPLICATE_SAME_ACCESS))) {
  268. goto leave_crit_sect;
  269. }
  270. if (NewHandle && IsSpecialClassesHandle(NewHandle)) {
  271. TagSpecialClassesHandle( &hkTableHandle );
  272. }
  273. //
  274. // If the predefined handle has already been opened try
  275. // and close the key now.
  276. //
  277. if( PredefinedHandleTable[ Index ].Handle != NULL ) {
  278. // make sure the handle CAN be closed.
  279. SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,FALSE);
  280. #if DBG
  281. PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
  282. #endif
  283. Error = (LONG) RegCloseKey( PredefinedHandleTable[ Index ].Handle );
  284. #if DBG
  285. if ( Error != ERROR_SUCCESS ) {
  286. DbgPrint( "Winreg.dll: Cannot close predefined handle\n" );
  287. DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
  288. Handle, Index, Error );
  289. }
  290. #endif
  291. }
  292. PredefinedHandleTable[ Index ].Handle = hkTableHandle;
  293. // make sure the handle CANNOT be closed.
  294. SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,TRUE);
  295. leave_crit_sect:
  296. #if DBG
  297. {
  298. NTSTATUS Status =
  299. #endif DBG
  300. RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  301. ASSERT( NT_SUCCESS( Status ) );
  302. #if DBG
  303. if ( !NT_SUCCESS( Status ) ) {
  304. DbgPrint( "WINREG: RtlLeaveCriticalSection() on RemapPredefinedHandle() failed. Status = %lx \n", Status );
  305. }
  306. }
  307. #endif
  308. cleanup_and_exit:
  309. if (!NT_SUCCESS(Status) && hkTableHandle)
  310. {
  311. RegCloseKey(hkTableHandle);
  312. }
  313. return( Status );
  314. }
  315. RPC_HKEY
  316. MapPredefinedHandle(
  317. IN RPC_HKEY Handle,
  318. OUT PRPC_HKEY HandleToClose
  319. )
  320. /*++
  321. Routine Description:
  322. Attempt to map a predefined handle to a RPC context handle. This in
  323. turn will map to a real Nt Registry handle.
  324. Arguments:
  325. Handle - Supplies a handle which may be a predefined handle or a handle
  326. returned from a previous call to any flavour of RegCreateKey,
  327. RegOpenKey or RegConnectRegistry.
  328. HandleToClose - When not NULL, this is the same as the result.
  329. Used to implement the DisablePredefinedCache feature.
  330. Return Value:
  331. RPC_HKEY- Returns the supplied handle argument if it not predefined,
  332. a RPC context handle if possible (i.e. it was previously
  333. opened or can be opened now), NULL otherwise.
  334. --*/
  335. {
  336. LONG Index;
  337. LONG Error;
  338. NTSTATUS Status;
  339. HANDLE ResultHandle;
  340. *HandleToClose = NULL;
  341. // reject outrageous calls
  342. if( Handle == INVALID_HANDLE_VALUE ) {
  343. return( NULL );
  344. }
  345. //
  346. // If the high bit is not set, we know it's not a predefined handle
  347. // so take a quick out.
  348. //
  349. if (((ULONG_PTR)Handle & 0x80000000) == 0) {
  350. return(Handle);
  351. }
  352. Index = MapPredefinedRegistryHandleToIndex((ULONG)(ULONG_PTR)Handle);
  353. if (Index == -1) {
  354. return(Handle);
  355. }
  356. ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
  357. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  358. ASSERT( NT_SUCCESS( Status ) );
  359. if ( !NT_SUCCESS( Status ) ) {
  360. #if DBG
  361. DbgPrint( "WINREG: RtlEnterCriticalSection() on MapPredefinedHandle() failed. Status = %lx \n", Status );
  362. #endif
  363. return( NULL );
  364. }
  365. if( PredefinedHandleTable[ Index ].Disabled == TRUE ) {
  366. //
  367. // for this handle the predefined feature has been disabled
  368. //
  369. // nobody is allowed to write here
  370. ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
  371. //
  372. // open a new handle for this request and store it in "toClose"
  373. // argument so the caller knows that should close it
  374. //
  375. ( *PredefinedHandleTable[ Index ].OpenFunc )(
  376. NULL,
  377. MAXIMUM_ALLOWED,
  378. HandleToClose
  379. );
  380. // return the new handle to the caller
  381. ResultHandle = *HandleToClose;
  382. } else {
  383. //
  384. // If the predefined handle has not already been openend try
  385. // and open the key now.
  386. //
  387. if( PredefinedHandleTable[ Index ].Handle == NULL ) {
  388. Error = (LONG)( *PredefinedHandleTable[ Index ].OpenFunc )(
  389. NULL,
  390. MAXIMUM_ALLOWED,
  391. &PredefinedHandleTable[ Index ].Handle
  392. );
  393. if( Error == ERROR_SUCCESS ) {
  394. // make sure the handle CANNOT be closed.
  395. SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,TRUE);
  396. }
  397. #if defined(LEAK_TRACK)
  398. if (g_RegLeakTraceInfo.bEnableLeakTrack) {
  399. (void) TrackObject(PredefinedHandleTable[ Index ].Handle);
  400. }
  401. #endif // defined(LEAK_TRACK)
  402. #if DBG
  403. if ( Error != ERROR_SUCCESS ) {
  404. DbgPrint( "Winreg.dll: Cannot map predefined handle\n" );
  405. DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
  406. Handle, Index, Error );
  407. } else {
  408. ASSERT( IsLocalHandle( PredefinedHandleTable[ Index ].Handle ));
  409. }
  410. #endif
  411. }
  412. //
  413. // Map the predefined handle to a real handle (may be NULL
  414. // if key could not be opened).
  415. //
  416. ResultHandle = PredefinedHandleTable[ Index ].Handle;
  417. ASSERT(*HandleToClose == NULL);
  418. }
  419. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  420. ASSERT( NT_SUCCESS( Status ) );
  421. #if DBG
  422. if ( !NT_SUCCESS( Status ) ) {
  423. DbgPrint( "WINREG: RtlLeaveCriticalSection() on MapPredefinedHandle() failed. Status = %lx \n", Status );
  424. }
  425. #endif
  426. return( ResultHandle );
  427. }
  428. BOOL
  429. CleanupPredefinedHandles(
  430. VOID
  431. )
  432. /*++
  433. Routine Description:
  434. Runs down the list of predefined handles and closes any that have been opened.
  435. Arguments:
  436. None.
  437. Return Value:
  438. TRUE - success
  439. FALSE - failure
  440. --*/
  441. {
  442. LONG i;
  443. NTSTATUS Status;
  444. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  445. ASSERT( NT_SUCCESS( Status ) );
  446. #if DBG
  447. if ( !NT_SUCCESS( Status ) ) {
  448. DbgPrint( "WINREG: RtlEnterCriticalSection() on CleanupPredefinedHandles() failed. Status = %lx \n", Status );
  449. }
  450. #endif
  451. for (i=0;i<sizeof(PredefinedHandleTable)/sizeof(PREDEFINED_HANDLE);i++) {
  452. //
  453. // consistency check
  454. //
  455. if( PredefinedHandleTable[ i ].Disabled == TRUE ) {
  456. //
  457. // predefined table is disabled for this key
  458. //
  459. // nobody is allowed to write here
  460. ASSERT( PredefinedHandleTable[ i ].Handle == NULL );
  461. } else if (PredefinedHandleTable[i].Handle != NULL) {
  462. // make sure the handle CAN be closed.
  463. SetHandleProtection(PredefinedHandleTable[ i ].Handle,i,FALSE);
  464. #if DBG
  465. PredefinedHandleTable[ i ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ i ].CallerAddress[0]), 10, 0);
  466. #endif
  467. LocalBaseRegCloseKey(&PredefinedHandleTable[i].Handle);
  468. PredefinedHandleTable[i].Handle = NULL;
  469. }
  470. }
  471. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  472. ASSERT( NT_SUCCESS( Status ) );
  473. #if DBG
  474. if ( !NT_SUCCESS( Status ) ) {
  475. DbgPrint( "WINREG: RtlLeaveCriticalSection() on CleanupPredefinedHandles() failed. Status = %lx \n", Status );
  476. }
  477. #endif
  478. return(TRUE);
  479. }
  480. LONG
  481. ClosePredefinedHandle(
  482. IN RPC_HKEY Handle
  483. )
  484. /*++
  485. Routine Description:
  486. Zero out the predefined handles entry in the predefined handle table
  487. so that subsequent opens will call the server.
  488. Arguments:
  489. Handle - Supplies a predefined handle.
  490. Return Value:
  491. None.
  492. --*/
  493. {
  494. NTSTATUS Status;
  495. HKEY hKey1;
  496. LONG Error;
  497. LONG Index;
  498. ASSERT( IsPredefinedRegistryHandle( Handle ));
  499. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  500. ASSERT( NT_SUCCESS( Status ) );
  501. #if DBG
  502. if ( !NT_SUCCESS( Status ) ) {
  503. DbgPrint( "WINREG: RtlEnterCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
  504. }
  505. #endif
  506. Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
  507. ASSERT( Index != -1 );
  508. hKey1 = PredefinedHandleTable[ Index ].Handle;
  509. if( hKey1 == NULL ) {
  510. //
  511. // If the handle was already closed, then return ERROR_SUCCESS.
  512. // This is because an application may already have called RegCloseKey
  513. // on a predefined key, and is now callig RegOpenKey on the same
  514. // predefined key. RegOpenKeyEx will try to close the predefined handle
  515. // and open a new one, in order to re-impersonate the client. If we don't
  516. // return ERROR_SUCCESS, then RegOpenKeyEx will not open a new predefined
  517. // handle, and the API will fail.
  518. //
  519. Error = ERROR_SUCCESS;
  520. } else {
  521. // if there is a handle here, the predefined handle is not disabled.
  522. ASSERT(PredefinedHandleTable[ Index ].Disabled == FALSE);
  523. PredefinedHandleTable[ Index ].Handle = NULL;
  524. #if DBG
  525. PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
  526. #endif
  527. }
  528. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  529. ASSERT( NT_SUCCESS( Status ) );
  530. #if DBG
  531. if ( !NT_SUCCESS( Status ) ) {
  532. DbgPrint( "WINREG: RtlLeaveCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
  533. }
  534. #endif
  535. if( hKey1 != NULL ) {
  536. //
  537. // close the key now (after leaving critical region to prevent deadlock
  538. // with dumb heads calling reg apis from DllInit.
  539. //
  540. // make sure the handle CAN be closed.
  541. SetHandleProtection(hKey1,Index,FALSE);
  542. Error = ( LONG ) LocalBaseRegCloseKey( &hKey1 );
  543. }
  544. return( Error );
  545. }
  546. LONG
  547. OpenPredefinedKeyForSpecialAccess(
  548. IN RPC_HKEY Handle,
  549. IN REGSAM AccessMask,
  550. OUT PRPC_HKEY pKey
  551. )
  552. /*++
  553. Routine Description:
  554. Attempt to open a predefined key with SYSTEM_SECURITY_ACCESS.
  555. Such an access is not included on MAXIMUM_ALLOWED, and is needed
  556. by RegGetKeySecurity and RegSetKeySecurity, in order to retrieve
  557. and save the SACL of a predefined key.
  558. WHEN USING A HANDLE WITH SPECIAL ACCESS, IT IS IMPORTANT TO FOLLOW
  559. THE RULES BELOW:
  560. - HANDLES OPENED FOR SPECIAL ACCESS ARE NEVER SAVED ON THE
  561. PredefinedHandleTable.
  562. - SUCH HANDLES SHOULD BE USED ONLY INTERNALY TO THE CLIENT
  563. SIDE OF WINREG APIs.
  564. THEY SHOULD NEVER BE RETURNED TO THE OUTSIDE WORLD.
  565. - IT IS THE RESPONSIBILITY OF THE CALLER OF THIS FUNCTION TO CLOSE
  566. THE HANDLES OPENED BY THIS FUNCTION.
  567. RegCloseKey() SHOULD BE USED TO CLOSE SUCH HANDLES.
  568. This function should be called only by the following APIs:
  569. RegGetKeySecurity -> So that it can retrieve the SACL of a predefined key
  570. RegSetKeySecurity -> So that it can save the SACL of a predefined key
  571. RegOpenKeyEx -> So that it can determine wheteher or not the caller of
  572. RegOpenKeyEx is able to save and restore SACL of
  573. predefined keys.
  574. Arguments:
  575. Handle - Supplies one of the predefined handle of the local machine.
  576. AccessMask - Suplies an access mask that contains the special access
  577. desired (the ones not included in MAXIMUM_ALLOWED).
  578. On NT 1.0, ACCESS_SYSTEM_SECURITY is the only one of such
  579. access.
  580. pKey - Pointer to the variable that will contain the handle opened with
  581. the special access.
  582. Return Value:
  583. LONG - Returns a DosErrorCode (ERROR_SUCCESS if the operation succeeds).
  584. --*/
  585. {
  586. LONG Index;
  587. LONG Error;
  588. ASSERT( pKey );
  589. ASSERT( AccessMask & ACCESS_SYSTEM_SECURITY );
  590. ASSERT( IsPredefinedRegistryHandle( Handle ) );
  591. //
  592. // Check if the Handle is a predefined handle.
  593. //
  594. if( IsPredefinedRegistryHandle( Handle )) {
  595. if( ( ( AccessMask & ACCESS_SYSTEM_SECURITY ) == 0 ) ||
  596. ( pKey == NULL ) ) {
  597. return( ERROR_INVALID_PARAMETER );
  598. }
  599. //
  600. // Convert the handle to an index.
  601. //
  602. Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
  603. ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
  604. //
  605. // If the predefined handle has not already been openend try
  606. // and open the key now.
  607. //
  608. Error = (LONG)( *PredefinedHandleTable[ Index ].OpenFunc )(
  609. NULL,
  610. AccessMask,
  611. pKey
  612. );
  613. /*
  614. #if DBG
  615. if ( Error != ERROR_SUCCESS ) {
  616. DbgPrint( "Winreg.dll: Cannot map predefined handle\n" );
  617. DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
  618. Handle, Index, Error );
  619. } else {
  620. ASSERT( IsLocalHandle( PredefinedHandleTable[ Index ].Handle ));
  621. }
  622. #endif
  623. */
  624. return Error;
  625. } else {
  626. return( ERROR_BADKEY );
  627. }
  628. }
  629. // #endif
  630. BOOL
  631. InitializePredefinedHandlesTable(
  632. )
  633. /*++
  634. Routine Description:
  635. Initialize the critical section used by the functions that access
  636. PredefinedHandleTable.
  637. This critical section is needed to avoid that a thread closes a predefined
  638. key, while other threads are accessing the predefined key
  639. Arguments:
  640. None.
  641. Return Value:
  642. Returns TRUE if the initialization succeeds.
  643. --*/
  644. {
  645. NTSTATUS NtStatus;
  646. NtStatus = RtlInitializeCriticalSection(
  647. &PredefinedHandleTableCriticalSection
  648. );
  649. ASSERT( NT_SUCCESS( NtStatus ) );
  650. if ( !NT_SUCCESS( NtStatus ) ) {
  651. return FALSE;
  652. }
  653. return( TRUE );
  654. }
  655. BOOL
  656. CleanupPredefinedHandlesTable(
  657. )
  658. /*++
  659. Routine Description:
  660. Delete the critical section used by the functions that access the
  661. PredefinedHandleTable.
  662. Arguments:
  663. None.
  664. Return Value:
  665. Returns TRUE if the cleanup succeeds.
  666. --*/
  667. {
  668. NTSTATUS NtStatus;
  669. //
  670. // Delete the critical section
  671. //
  672. NtStatus = RtlDeleteCriticalSection(
  673. &PredefinedHandleTableCriticalSection
  674. );
  675. ASSERT( NT_SUCCESS( NtStatus ) );
  676. if ( !NT_SUCCESS( NtStatus ) ) {
  677. return FALSE;
  678. }
  679. return( TRUE );
  680. }
  681. NTSTATUS
  682. DisablePredefinedHandleTable(
  683. HKEY Handle
  684. )
  685. /*++
  686. Routine Description:
  687. Disables the predefined handle table for the current user
  688. key. Eventually closes the handle in predefined handle, if already open
  689. Arguments:
  690. Handle - predefined handle for which to disable (now only current user)
  691. Return Value:
  692. --*/
  693. {
  694. NTSTATUS Status;
  695. LONG Index;
  696. if( Handle != HKEY_CURRENT_USER ) {
  697. //
  698. // feature enabled only for current user at this time
  699. //
  700. return STATUS_INVALID_HANDLE;
  701. }
  702. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  703. ASSERT( NT_SUCCESS( Status ) );
  704. #if DBG
  705. if ( !NT_SUCCESS( Status ) ) {
  706. DbgPrint( "WINREG: RtlEnterCriticalSection() on DisablePredefinedHandleTable() failed. Status = %lx \n", Status );
  707. }
  708. #endif
  709. Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
  710. ASSERT( Index != -1 );
  711. if(PredefinedHandleTable[ Index ].Disabled == TRUE) {
  712. // already called
  713. ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
  714. } else {
  715. if( PredefinedHandleTable[ Index ].Handle != NULL ) {
  716. // make sure the handle CAN be closed.
  717. SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,FALSE);
  718. #if DBG
  719. PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
  720. #endif
  721. LocalBaseRegCloseKey( &(PredefinedHandleTable[ Index ].Handle) );
  722. }
  723. PredefinedHandleTable[ Index ].Handle = NULL;
  724. PredefinedHandleTable[ Index ].Disabled = TRUE;
  725. }
  726. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  727. ASSERT( NT_SUCCESS( Status ) );
  728. #if DBG
  729. if ( !NT_SUCCESS( Status ) ) {
  730. DbgPrint( "WINREG: RtlLeaveCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
  731. }
  732. #endif
  733. return Status;
  734. }