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.

988 lines
25 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 Status2 =
  299. #endif DBG
  300. RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  301. ASSERT( NT_SUCCESS( Status2 ) );
  302. #if DBG
  303. if ( !NT_SUCCESS( Status2 ) ) {
  304. DbgPrint( "WINREG: RtlLeaveCriticalSection() on RemapPredefinedHandle() failed. Status = %lx \n", Status2 );
  305. }
  306. }
  307. #endif
  308. cleanup_and_exit:
  309. if (!NT_SUCCESS(Status) && hkTableHandle) {
  310. RegCloseKey(hkTableHandle);
  311. }
  312. return( Status );
  313. }
  314. RPC_HKEY
  315. MapPredefinedHandle(
  316. IN RPC_HKEY Handle,
  317. OUT PRPC_HKEY HandleToClose
  318. )
  319. /*++
  320. Routine Description:
  321. Attempt to map a predefined handle to a RPC context handle. This in
  322. turn will map to a real Nt Registry handle.
  323. Arguments:
  324. Handle - Supplies a handle which may be a predefined handle or a handle
  325. returned from a previous call to any flavour of RegCreateKey,
  326. RegOpenKey or RegConnectRegistry.
  327. HandleToClose - When not NULL, this is the same as the result.
  328. Used to implement the DisablePredefinedCache feature.
  329. Return Value:
  330. RPC_HKEY- Returns the supplied handle argument if it not predefined,
  331. a RPC context handle if possible (i.e. it was previously
  332. opened or can be opened now), NULL otherwise.
  333. --*/
  334. {
  335. LONG Index;
  336. LONG Error;
  337. NTSTATUS Status;
  338. HANDLE ResultHandle;
  339. *HandleToClose = NULL;
  340. // reject outrageous calls
  341. if( Handle == INVALID_HANDLE_VALUE ) {
  342. return( NULL );
  343. }
  344. //
  345. // If the high bit is not set, we know it's not a predefined handle
  346. // so take a quick out.
  347. //
  348. if (((ULONG_PTR)Handle & 0x80000000) == 0) {
  349. return(Handle);
  350. }
  351. Index = MapPredefinedRegistryHandleToIndex((ULONG)(ULONG_PTR)Handle);
  352. if (Index == -1) {
  353. return(Handle);
  354. }
  355. ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
  356. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  357. ASSERT( NT_SUCCESS( Status ) );
  358. if ( !NT_SUCCESS( Status ) ) {
  359. #if DBG
  360. DbgPrint( "WINREG: RtlEnterCriticalSection() on MapPredefinedHandle() failed. Status = %lx \n", Status );
  361. #endif
  362. return( NULL );
  363. }
  364. if( PredefinedHandleTable[ Index ].Disabled == TRUE ) {
  365. //
  366. // for this handle the predefined feature has been disabled
  367. //
  368. // nobody is allowed to write here
  369. ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
  370. //
  371. // open a new handle for this request and store it in "toClose"
  372. // argument so the caller knows that should close it
  373. //
  374. ( *PredefinedHandleTable[ Index ].OpenFunc )(
  375. NULL,
  376. MAXIMUM_ALLOWED,
  377. HandleToClose
  378. );
  379. // return the new handle to the caller
  380. ResultHandle = *HandleToClose;
  381. } else {
  382. //
  383. // If the predefined handle has not already been openend try
  384. // and open the key now.
  385. //
  386. if( PredefinedHandleTable[ Index ].Handle == NULL ) {
  387. Error = (LONG)( *PredefinedHandleTable[ Index ].OpenFunc )(
  388. NULL,
  389. MAXIMUM_ALLOWED,
  390. &PredefinedHandleTable[ Index ].Handle
  391. );
  392. if( Error == ERROR_SUCCESS ) {
  393. // make sure the handle CANNOT be closed.
  394. SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,TRUE);
  395. }
  396. #if defined(LEAK_TRACK)
  397. if (g_RegLeakTraceInfo.bEnableLeakTrack) {
  398. (void) TrackObject(PredefinedHandleTable[ Index ].Handle);
  399. }
  400. #endif // defined(LEAK_TRACK)
  401. #if DBG
  402. if ( Error != ERROR_SUCCESS ) {
  403. DbgPrint( "Winreg.dll: Cannot map predefined handle\n" );
  404. DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
  405. Handle, Index, Error );
  406. } else {
  407. ASSERT( IsLocalHandle( PredefinedHandleTable[ Index ].Handle ));
  408. }
  409. #endif
  410. }
  411. //
  412. // Map the predefined handle to a real handle (may be NULL
  413. // if key could not be opened).
  414. //
  415. ResultHandle = PredefinedHandleTable[ Index ].Handle;
  416. ASSERT(*HandleToClose == NULL);
  417. }
  418. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  419. ASSERT( NT_SUCCESS( Status ) );
  420. #if DBG
  421. if ( !NT_SUCCESS( Status ) ) {
  422. DbgPrint( "WINREG: RtlLeaveCriticalSection() on MapPredefinedHandle() failed. Status = %lx \n", Status );
  423. }
  424. #endif
  425. return( ResultHandle );
  426. }
  427. BOOL
  428. CleanupPredefinedHandles(
  429. VOID
  430. )
  431. /*++
  432. Routine Description:
  433. Runs down the list of predefined handles and closes any that have been opened.
  434. Arguments:
  435. None.
  436. Return Value:
  437. TRUE - success
  438. FALSE - failure
  439. --*/
  440. {
  441. LONG i;
  442. NTSTATUS Status;
  443. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  444. ASSERT( NT_SUCCESS( Status ) );
  445. #if DBG
  446. if ( !NT_SUCCESS( Status ) ) {
  447. DbgPrint( "WINREG: RtlEnterCriticalSection() on CleanupPredefinedHandles() failed. Status = %lx \n", Status );
  448. }
  449. #endif
  450. for (i=0;i<sizeof(PredefinedHandleTable)/sizeof(PREDEFINED_HANDLE);i++) {
  451. //
  452. // consistency check
  453. //
  454. if( PredefinedHandleTable[ i ].Disabled == TRUE ) {
  455. //
  456. // predefined table is disabled for this key
  457. //
  458. // nobody is allowed to write here
  459. ASSERT( PredefinedHandleTable[ i ].Handle == NULL );
  460. } else if (PredefinedHandleTable[i].Handle != NULL) {
  461. // make sure the handle CAN be closed.
  462. SetHandleProtection(PredefinedHandleTable[ i ].Handle,i,FALSE);
  463. #if DBG
  464. PredefinedHandleTable[ i ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ i ].CallerAddress[0]), 10, 0);
  465. #endif
  466. LocalBaseRegCloseKey(&PredefinedHandleTable[i].Handle);
  467. PredefinedHandleTable[i].Handle = NULL;
  468. }
  469. }
  470. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  471. ASSERT( NT_SUCCESS( Status ) );
  472. #if DBG
  473. if ( !NT_SUCCESS( Status ) ) {
  474. DbgPrint( "WINREG: RtlLeaveCriticalSection() on CleanupPredefinedHandles() failed. Status = %lx \n", Status );
  475. }
  476. #endif
  477. return(TRUE);
  478. }
  479. LONG
  480. ClosePredefinedHandle(
  481. IN RPC_HKEY Handle
  482. )
  483. /*++
  484. Routine Description:
  485. Zero out the predefined handles entry in the predefined handle table
  486. so that subsequent opens will call the server.
  487. Arguments:
  488. Handle - Supplies a predefined handle.
  489. Return Value:
  490. None.
  491. --*/
  492. {
  493. NTSTATUS Status;
  494. HKEY hKey1;
  495. LONG Error;
  496. LONG Index;
  497. ASSERT( IsPredefinedRegistryHandle( Handle ));
  498. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  499. ASSERT( NT_SUCCESS( Status ) );
  500. #if DBG
  501. if ( !NT_SUCCESS( Status ) ) {
  502. DbgPrint( "WINREG: RtlEnterCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
  503. }
  504. #endif
  505. Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
  506. ASSERT( Index != -1 );
  507. hKey1 = PredefinedHandleTable[ Index ].Handle;
  508. if( hKey1 == NULL ) {
  509. //
  510. // If the handle was already closed, then return ERROR_SUCCESS.
  511. // This is because an application may already have called RegCloseKey
  512. // on a predefined key, and is now callig RegOpenKey on the same
  513. // predefined key. RegOpenKeyEx will try to close the predefined handle
  514. // and open a new one, in order to re-impersonate the client. If we don't
  515. // return ERROR_SUCCESS, then RegOpenKeyEx will not open a new predefined
  516. // handle, and the API will fail.
  517. //
  518. Error = ERROR_SUCCESS;
  519. } else {
  520. // if there is a handle here, the predefined handle is not disabled.
  521. ASSERT(PredefinedHandleTable[ Index ].Disabled == FALSE);
  522. PredefinedHandleTable[ Index ].Handle = NULL;
  523. #if DBG
  524. PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
  525. #endif
  526. }
  527. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  528. ASSERT( NT_SUCCESS( Status ) );
  529. #if DBG
  530. if ( !NT_SUCCESS( Status ) ) {
  531. DbgPrint( "WINREG: RtlLeaveCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
  532. }
  533. #endif
  534. if( hKey1 != NULL ) {
  535. //
  536. // close the key now (after leaving critical region to prevent deadlock
  537. // with dumb heads calling reg apis from DllInit.
  538. //
  539. // make sure the handle CAN be closed.
  540. SetHandleProtection(hKey1,Index,FALSE);
  541. Error = ( LONG ) LocalBaseRegCloseKey( &hKey1 );
  542. }
  543. return( Error );
  544. }
  545. LONG
  546. OpenPredefinedKeyForSpecialAccess(
  547. IN RPC_HKEY Handle,
  548. IN REGSAM AccessMask,
  549. OUT PRPC_HKEY pKey
  550. )
  551. /*++
  552. Routine Description:
  553. Attempt to open a predefined key with SYSTEM_SECURITY_ACCESS.
  554. Such an access is not included on MAXIMUM_ALLOWED, and is needed
  555. by RegGetKeySecurity and RegSetKeySecurity, in order to retrieve
  556. and save the SACL of a predefined key.
  557. WHEN USING A HANDLE WITH SPECIAL ACCESS, IT IS IMPORTANT TO FOLLOW
  558. THE RULES BELOW:
  559. - HANDLES OPENED FOR SPECIAL ACCESS ARE NEVER SAVED ON THE
  560. PredefinedHandleTable.
  561. - SUCH HANDLES SHOULD BE USED ONLY INTERNALY TO THE CLIENT
  562. SIDE OF WINREG APIs.
  563. THEY SHOULD NEVER BE RETURNED TO THE OUTSIDE WORLD.
  564. - IT IS THE RESPONSIBILITY OF THE CALLER OF THIS FUNCTION TO CLOSE
  565. THE HANDLES OPENED BY THIS FUNCTION.
  566. RegCloseKey() SHOULD BE USED TO CLOSE SUCH HANDLES.
  567. This function should be called only by the following APIs:
  568. RegGetKeySecurity -> So that it can retrieve the SACL of a predefined key
  569. RegSetKeySecurity -> So that it can save the SACL of a predefined key
  570. RegOpenKeyEx -> So that it can determine wheteher or not the caller of
  571. RegOpenKeyEx is able to save and restore SACL of
  572. predefined keys.
  573. Arguments:
  574. Handle - Supplies one of the predefined handle of the local machine.
  575. AccessMask - Suplies an access mask that contains the special access
  576. desired (the ones not included in MAXIMUM_ALLOWED).
  577. On NT 1.0, ACCESS_SYSTEM_SECURITY is the only one of such
  578. access.
  579. pKey - Pointer to the variable that will contain the handle opened with
  580. the special access.
  581. Return Value:
  582. LONG - Returns a DosErrorCode (ERROR_SUCCESS if the operation succeeds).
  583. --*/
  584. {
  585. LONG Index;
  586. LONG Error;
  587. ASSERT( pKey );
  588. ASSERT( AccessMask & ACCESS_SYSTEM_SECURITY );
  589. ASSERT( IsPredefinedRegistryHandle( Handle ) );
  590. //
  591. // Check if the Handle is a predefined handle.
  592. //
  593. if( IsPredefinedRegistryHandle( Handle )) {
  594. if( ( ( AccessMask & ACCESS_SYSTEM_SECURITY ) == 0 ) ||
  595. ( pKey == NULL ) ) {
  596. return( ERROR_INVALID_PARAMETER );
  597. }
  598. //
  599. // Convert the handle to an index.
  600. //
  601. Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
  602. ASSERT(( 0 <= Index ) && ( Index < MAX_PREDEFINED_HANDLES ));
  603. //
  604. // If the predefined handle has not already been openend try
  605. // and open the key now.
  606. //
  607. Error = (LONG)( *PredefinedHandleTable[ Index ].OpenFunc )(
  608. NULL,
  609. AccessMask,
  610. pKey
  611. );
  612. /*
  613. #if DBG
  614. if ( Error != ERROR_SUCCESS ) {
  615. DbgPrint( "Winreg.dll: Cannot map predefined handle\n" );
  616. DbgPrint( " Handle: 0x%x Index: %d Error: %d\n",
  617. Handle, Index, Error );
  618. } else {
  619. ASSERT( IsLocalHandle( PredefinedHandleTable[ Index ].Handle ));
  620. }
  621. #endif
  622. */
  623. return Error;
  624. } else {
  625. return( ERROR_BADKEY );
  626. }
  627. }
  628. // #endif
  629. BOOL
  630. InitializePredefinedHandlesTable(
  631. )
  632. /*++
  633. Routine Description:
  634. Initialize the critical section used by the functions that access
  635. PredefinedHandleTable.
  636. This critical section is needed to avoid that a thread closes a predefined
  637. key, while other threads are accessing the predefined key
  638. Arguments:
  639. None.
  640. Return Value:
  641. Returns TRUE if the initialization succeeds.
  642. --*/
  643. {
  644. NTSTATUS NtStatus;
  645. NtStatus = RtlInitializeCriticalSection(
  646. &PredefinedHandleTableCriticalSection
  647. );
  648. ASSERT( NT_SUCCESS( NtStatus ) );
  649. if ( !NT_SUCCESS( NtStatus ) ) {
  650. return FALSE;
  651. }
  652. return( TRUE );
  653. }
  654. BOOL
  655. CleanupPredefinedHandlesTable(
  656. )
  657. /*++
  658. Routine Description:
  659. Delete the critical section used by the functions that access the
  660. PredefinedHandleTable.
  661. Arguments:
  662. None.
  663. Return Value:
  664. Returns TRUE if the cleanup succeeds.
  665. --*/
  666. {
  667. NTSTATUS NtStatus;
  668. //
  669. // Delete the critical section
  670. //
  671. NtStatus = RtlDeleteCriticalSection(
  672. &PredefinedHandleTableCriticalSection
  673. );
  674. ASSERT( NT_SUCCESS( NtStatus ) );
  675. if ( !NT_SUCCESS( NtStatus ) ) {
  676. return FALSE;
  677. }
  678. return( TRUE );
  679. }
  680. NTSTATUS
  681. DisablePredefinedHandleTable(
  682. HKEY Handle
  683. )
  684. /*++
  685. Routine Description:
  686. Disables the predefined handle table for the current user
  687. key. Eventually closes the handle in predefined handle, if already open
  688. Arguments:
  689. Handle - predefined handle for which to disable (now only current user)
  690. Return Value:
  691. --*/
  692. {
  693. NTSTATUS Status;
  694. LONG Index;
  695. if( Handle != HKEY_CURRENT_USER ) {
  696. //
  697. // feature enabled only for current user at this time
  698. //
  699. return STATUS_INVALID_HANDLE;
  700. }
  701. Status = RtlEnterCriticalSection( &PredefinedHandleTableCriticalSection );
  702. ASSERT( NT_SUCCESS( Status ) );
  703. #if DBG
  704. if ( !NT_SUCCESS( Status ) ) {
  705. DbgPrint( "WINREG: RtlEnterCriticalSection() on DisablePredefinedHandleTable() failed. Status = %lx \n", Status );
  706. }
  707. #endif
  708. Index = MapPredefinedRegistryHandleToIndex( (ULONG)(ULONG_PTR)Handle );
  709. ASSERT( Index != -1 );
  710. if(PredefinedHandleTable[ Index ].Disabled == TRUE) {
  711. // already called
  712. ASSERT( PredefinedHandleTable[ Index ].Handle == NULL );
  713. } else {
  714. if( PredefinedHandleTable[ Index ].Handle != NULL ) {
  715. // make sure the handle CAN be closed.
  716. SetHandleProtection(PredefinedHandleTable[ Index ].Handle,Index,FALSE);
  717. #if DBG
  718. PredefinedHandleTable[ Index ].Callers = RtlWalkFrameChain(&(PredefinedHandleTable[ Index ].CallerAddress[0]), 10, 0);
  719. #endif
  720. LocalBaseRegCloseKey( &(PredefinedHandleTable[ Index ].Handle) );
  721. }
  722. PredefinedHandleTable[ Index ].Handle = NULL;
  723. PredefinedHandleTable[ Index ].Disabled = TRUE;
  724. }
  725. Status = RtlLeaveCriticalSection( &PredefinedHandleTableCriticalSection );
  726. ASSERT( NT_SUCCESS( Status ) );
  727. #if DBG
  728. if ( !NT_SUCCESS( Status ) ) {
  729. DbgPrint( "WINREG: RtlLeaveCriticalSection() on ClosePredefinedHandle() failed. Status = %lx \n", Status );
  730. }
  731. #endif
  732. return Status;
  733. }