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.

2610 lines
74 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. obinit.c
  5. Abstract:
  6. Initialization module for the OB subcomponent of NTOS
  7. Author:
  8. Steve Wood (stevewo) 31-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "obp.h"
  12. //
  13. // Define date structures for the object creation information region.
  14. //
  15. GENERAL_LOOKASIDE ObpCreateInfoLookasideList;
  16. //
  17. // Define data structures for the object name buffer lookaside list.
  18. //
  19. #define OBJECT_NAME_BUFFER_SIZE 248
  20. GENERAL_LOOKASIDE ObpNameBufferLookasideList;
  21. //
  22. // Form some default access masks for the various object types
  23. //
  24. #ifdef ALLOC_DATA_PRAGMA
  25. #pragma const_seg("INITCONST")
  26. #endif
  27. const GENERIC_MAPPING ObpTypeMapping = {
  28. STANDARD_RIGHTS_READ,
  29. STANDARD_RIGHTS_WRITE,
  30. STANDARD_RIGHTS_EXECUTE,
  31. OBJECT_TYPE_ALL_ACCESS
  32. };
  33. const GENERIC_MAPPING ObpDirectoryMapping = {
  34. STANDARD_RIGHTS_READ |
  35. DIRECTORY_QUERY |
  36. DIRECTORY_TRAVERSE,
  37. STANDARD_RIGHTS_WRITE |
  38. DIRECTORY_CREATE_OBJECT |
  39. DIRECTORY_CREATE_SUBDIRECTORY,
  40. STANDARD_RIGHTS_EXECUTE |
  41. DIRECTORY_QUERY |
  42. DIRECTORY_TRAVERSE,
  43. DIRECTORY_ALL_ACCESS
  44. };
  45. const GENERIC_MAPPING ObpSymbolicLinkMapping = {
  46. STANDARD_RIGHTS_READ |
  47. SYMBOLIC_LINK_QUERY,
  48. STANDARD_RIGHTS_WRITE,
  49. STANDARD_RIGHTS_EXECUTE |
  50. SYMBOLIC_LINK_QUERY,
  51. SYMBOLIC_LINK_ALL_ACCESS
  52. };
  53. //
  54. // Local procedure prototypes
  55. //
  56. NTSTATUS
  57. ObpCreateDosDevicesDirectory (
  58. VOID
  59. );
  60. NTSTATUS
  61. ObpGetDosDevicesProtection (
  62. PSECURITY_DESCRIPTOR SecurityDescriptor
  63. );
  64. VOID
  65. ObpFreeDosDevicesProtection (
  66. PSECURITY_DESCRIPTOR SecurityDescriptor
  67. );
  68. BOOLEAN
  69. ObpShutdownCloseHandleProcedure (
  70. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  71. IN HANDLE HandleId,
  72. IN PVOID EnumParameter
  73. );
  74. #ifdef ALLOC_PRAGMA
  75. BOOLEAN
  76. ObDupHandleProcedure (
  77. PEPROCESS Process,
  78. PHANDLE_TABLE OldObjectTable,
  79. PHANDLE_TABLE_ENTRY OldObjectTableEntry,
  80. PHANDLE_TABLE_ENTRY ObjectTableEntry
  81. );
  82. BOOLEAN
  83. ObAuditInheritedHandleProcedure (
  84. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  85. IN HANDLE HandleId,
  86. IN PVOID EnumParameter
  87. );
  88. VOID
  89. ObDestroyHandleProcedure (
  90. IN HANDLE HandleIndex
  91. );
  92. BOOLEAN
  93. ObpEnumFindHandleProcedure (
  94. PHANDLE_TABLE_ENTRY ObjectTableEntry,
  95. HANDLE HandleId,
  96. PVOID EnumParameter
  97. );
  98. BOOLEAN
  99. ObpCloseHandleProcedure (
  100. IN PHANDLE_TABLE_ENTRY HandleTableEntry,
  101. IN HANDLE Handle,
  102. IN PVOID EnumParameter
  103. );
  104. #pragma alloc_text(INIT,ObInitSystem)
  105. #pragma alloc_text(PAGE,ObDupHandleProcedure)
  106. #pragma alloc_text(PAGE,ObAuditInheritedHandleProcedure)
  107. #pragma alloc_text(PAGE,ObInitProcess)
  108. #pragma alloc_text(PAGE,ObInitProcess2)
  109. #pragma alloc_text(PAGE,ObDestroyHandleProcedure)
  110. #pragma alloc_text(PAGE,ObKillProcess)
  111. #pragma alloc_text(PAGE,ObClearProcessHandleTable)
  112. #pragma alloc_text(PAGE,ObpCloseHandleProcedure)
  113. #pragma alloc_text(PAGE,ObpEnumFindHandleProcedure)
  114. #pragma alloc_text(PAGE,ObFindHandleForObject)
  115. #pragma alloc_text(PAGE,ObpShutdownCloseHandleProcedure)
  116. #pragma alloc_text(PAGE,ObShutdownSystem)
  117. #pragma alloc_text(INIT,ObpCreateDosDevicesDirectory)
  118. #pragma alloc_text(INIT,ObpGetDosDevicesProtection)
  119. #pragma alloc_text(INIT,ObpFreeDosDevicesProtection)
  120. #endif
  121. //
  122. // The default quota block is setup by obinitsystem
  123. //
  124. ULONG ObpAccessProtectCloseBit = MAXIMUM_ALLOWED;
  125. PDEVICE_MAP ObSystemDeviceMap = NULL;
  126. //
  127. // CurrentControlSet values set by code in config\cmdat3.c at system load time
  128. // These are private variables within obinit.c
  129. //
  130. ULONG ObpProtectionMode;
  131. ULONG ObpLUIDDeviceMapsDisabled;
  132. ULONG ObpAuditBaseDirectories;
  133. ULONG ObpAuditBaseObjects;
  134. //
  135. // ObpLUIDDeviceMapsEnabled holds the result of "Is LUID device maps enabled?"
  136. // Depends on the DWORD registry keys, ProtectionMode & LUIDDeviceMapsDisabled:
  137. // location: \Registry\Machine\System\CurrentControlSet\Control\Session Manager
  138. //
  139. // Enabling/Disabling works as follows:
  140. // if ((ProtectionMode == 0) || (LUIDDeviceMapsDisabled !=0)) {
  141. // // LUID device maps are disabled
  142. // // ObpLUIDDeviceMapsEnabled == 0
  143. // }
  144. // else {
  145. // // LUID device maps are enabled
  146. // // ObpLUIDDeviceMapsEnabled == 1
  147. // }
  148. //
  149. ULONG ObpLUIDDeviceMapsEnabled;
  150. //
  151. // MmNumberOfPagingFiles is used in shutdown, to make sure we're not
  152. // leaking any kernel handles.
  153. //
  154. extern ULONG MmNumberOfPagingFiles;
  155. //
  156. // These are global variables
  157. //
  158. #ifdef ALLOC_DATA_PRAGMA
  159. #pragma data_seg("PAGEDATA")
  160. #pragma const_seg("PAGECONST")
  161. #endif
  162. //
  163. // A ULONGLONG aligned global variable
  164. // for use by ObpLookupObjectName for quick comparisons.
  165. //
  166. const ALIGNEDNAME ObpDosDevicesShortNamePrefix = { L'\\',L'?',L'?',L'\\' }; // L"\??\"
  167. const ALIGNEDNAME ObpDosDevicesShortNameRoot = { L'\\',L'?',L'?',L'\0' }; // L"\??"
  168. const UNICODE_STRING ObpDosDevicesShortName = {
  169. sizeof(ObpDosDevicesShortNamePrefix),
  170. sizeof(ObpDosDevicesShortNamePrefix),
  171. (PWSTR)&ObpDosDevicesShortNamePrefix
  172. };
  173. #define ObpGlobalDosDevicesShortName L"\\GLOBAL??" // \GLOBAL??
  174. #ifdef ALLOC_DATA_PRAGMA
  175. #pragma data_seg()
  176. #pragma const_seg()
  177. #endif
  178. BOOLEAN
  179. ObInitSystem (
  180. VOID
  181. )
  182. /*++
  183. Routine Description:
  184. This function performs the system initialization for the object
  185. manager. The object manager data structures are self describing
  186. with the exception of the root directory, the type object type and
  187. the directory object type. The initialization code then constructs
  188. these objects by hand to get the ball rolling.
  189. Arguments:
  190. None.
  191. Return Value:
  192. TRUE if successful and FALSE if an error occurred.
  193. The following errors can occur:
  194. - insufficient memory
  195. --*/
  196. {
  197. USHORT CreateInfoMaxDepth;
  198. USHORT NameBufferMaxDepth;
  199. ULONG RegionSegmentSize;
  200. OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
  201. UNICODE_STRING TypeTypeName;
  202. UNICODE_STRING SymbolicLinkTypeName;
  203. UNICODE_STRING DosDevicesDirectoryName;
  204. UNICODE_STRING DirectoryTypeName;
  205. UNICODE_STRING RootDirectoryName;
  206. UNICODE_STRING TypeDirectoryName;
  207. NTSTATUS Status;
  208. OBJECT_ATTRIBUTES ObjectAttributes;
  209. HANDLE RootDirectoryHandle;
  210. HANDLE TypeDirectoryHandle;
  211. PLIST_ENTRY Next, Head;
  212. POBJECT_HEADER ObjectTypeHeader;
  213. POBJECT_HEADER_CREATOR_INFO CreatorInfo;
  214. POBJECT_HEADER_NAME_INFO NameInfo;
  215. MM_SYSTEMSIZE SystemSize;
  216. SECURITY_DESCRIPTOR AuditSd;
  217. PSECURITY_DESCRIPTOR EffectiveSd;
  218. PACL AuditAllAcl;
  219. UCHAR AuditAllBuffer[250]; // Ample room for the ACL
  220. ULONG AuditAllLength;
  221. PACE_HEADER Ace;
  222. PGENERAL_LOOKASIDE Lookaside;
  223. ULONG Index;
  224. PKPRCB Prcb;
  225. OBP_LOOKUP_CONTEXT LookupContext;
  226. PACL Dacl;
  227. ULONG DaclLength;
  228. HANDLE EventHandle;
  229. SECURITY_DESCRIPTOR SecurityDescriptor;
  230. //
  231. // Determine the the size of the object creation and the name buffer
  232. // lookaside lists.
  233. //
  234. SystemSize = MmQuerySystemSize();
  235. if (SystemSize == MmLargeSystem) {
  236. if (MmIsThisAnNtAsSystem()) {
  237. CreateInfoMaxDepth = 64;
  238. NameBufferMaxDepth = 32;
  239. } else {
  240. CreateInfoMaxDepth = 32;
  241. NameBufferMaxDepth = 16;
  242. }
  243. } else {
  244. CreateInfoMaxDepth = 3;
  245. NameBufferMaxDepth = 3;
  246. }
  247. //
  248. // PHASE 0 Initialization
  249. //
  250. if (InitializationPhase == 0) {
  251. //
  252. // Initialize the object creation lookaside list.
  253. //
  254. ExInitializeSystemLookasideList( &ObpCreateInfoLookasideList,
  255. NonPagedPool,
  256. sizeof(OBJECT_CREATE_INFORMATION),
  257. 'iCbO',
  258. CreateInfoMaxDepth,
  259. &ExSystemLookasideListHead );
  260. //
  261. // Initialize the name buffer lookaside list.
  262. //
  263. ExInitializeSystemLookasideList( &ObpNameBufferLookasideList,
  264. #ifndef OBP_PAGEDPOOL_NAMESPACE
  265. NonPagedPool,
  266. #else
  267. PagedPool,
  268. #endif
  269. OBJECT_NAME_BUFFER_SIZE,
  270. 'mNbO',
  271. NameBufferMaxDepth,
  272. &ExSystemLookasideListHead );
  273. //
  274. // Initialize the system create info and name buffer lookaside lists
  275. // for the current processor.
  276. //
  277. // N.B. Temporarily during the initialization of the system both
  278. // lookaside list pointers in the processor block point to
  279. // the same lookaside list structure. Later in initialization
  280. // another lookaside list structure is allocated and filled
  281. // for the per processor list.
  282. //
  283. Prcb = KeGetCurrentPrcb();
  284. Prcb->PPLookasideList[LookasideCreateInfoList].L = &ObpCreateInfoLookasideList;
  285. Prcb->PPLookasideList[LookasideCreateInfoList].P = &ObpCreateInfoLookasideList;
  286. Prcb->PPLookasideList[LookasideNameBufferList].L = &ObpNameBufferLookasideList;
  287. Prcb->PPLookasideList[LookasideNameBufferList].P = &ObpNameBufferLookasideList;
  288. //
  289. // Initialize the object removal queue listhead.
  290. //
  291. ObpRemoveObjectList = NULL;
  292. //
  293. // Initialize security descriptor cache
  294. //
  295. ObpInitSecurityDescriptorCache();
  296. KeInitializeEvent( &ObpDefaultObject, NotificationEvent, TRUE );
  297. ExInitializePushLock( &ObpLock );
  298. PsGetCurrentProcess()->GrantedAccess = PROCESS_ALL_ACCESS;
  299. PsGetCurrentThread()->GrantedAccess = THREAD_ALL_ACCESS;
  300. #ifndef OBP_PAGEDPOOL_NAMESPACE
  301. KeInitializeSpinLock( &ObpDeviceMapLock );
  302. #else
  303. ExInitializeFastMutex( &ObpDeviceMapLock );
  304. #endif // OBP_PAGEDPOOL_NAMESPACE
  305. //
  306. // Initialize the quota system
  307. //
  308. PsInitializeQuotaSystem ();
  309. //
  310. // Initialize the handle table for the system process and also the global
  311. // kernel handle table
  312. //
  313. ObpKernelHandleTable = PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable( NULL );
  314. #if DBG
  315. //
  316. // On checked make handle reuse take much longer
  317. //
  318. ExSetHandleTableStrictFIFO (ObpKernelHandleTable);
  319. #endif
  320. //
  321. // Initialize the deferred delete work item.
  322. //
  323. ExInitializeWorkItem( &ObpRemoveObjectWorkItem,
  324. ObpProcessRemoveObjectQueue,
  325. NULL );
  326. //
  327. // Create an object type for the "Type" object. This is the start of
  328. // of the object types and goes in the ObpTypeDirectoryObject.
  329. //
  330. RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer ) );
  331. ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer );
  332. ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
  333. ObjectTypeInitializer.PoolType = NonPagedPool;
  334. RtlInitUnicodeString( &TypeTypeName, L"Type" );
  335. ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
  336. ObjectTypeInitializer.GenericMapping = ObpTypeMapping;
  337. ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_TYPE );
  338. ObjectTypeInitializer.MaintainTypeList = TRUE;
  339. ObjectTypeInitializer.UseDefaultObject = TRUE;
  340. ObjectTypeInitializer.DeleteProcedure = &ObpDeleteObjectType;
  341. ObCreateObjectType( &TypeTypeName,
  342. &ObjectTypeInitializer,
  343. (PSECURITY_DESCRIPTOR)NULL,
  344. &ObpTypeObjectType );
  345. //
  346. // Create the object type for the "Directory" object.
  347. //
  348. ObjectTypeInitializer.PoolType = OB_NAMESPACE_POOL_TYPE;
  349. RtlInitUnicodeString( &DirectoryTypeName, L"Directory" );
  350. ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_DIRECTORY );
  351. ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS;
  352. ObjectTypeInitializer.CaseInsensitive = TRUE;
  353. ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping;
  354. ObjectTypeInitializer.UseDefaultObject = TRUE;
  355. ObjectTypeInitializer.MaintainTypeList = FALSE;
  356. ObjectTypeInitializer.DeleteProcedure = NULL;
  357. ObCreateObjectType( &DirectoryTypeName,
  358. &ObjectTypeInitializer,
  359. (PSECURITY_DESCRIPTOR)NULL,
  360. &ObpDirectoryObjectType );
  361. //
  362. // Clear SYNCHRONIZE from the access mask to not allow
  363. // synchronization on directory objects
  364. //
  365. ObpDirectoryObjectType->TypeInfo.ValidAccessMask &= ~SYNCHRONIZE;
  366. //
  367. // Create the object type for the "SymbolicLink" object.
  368. //
  369. RtlInitUnicodeString( &SymbolicLinkTypeName, L"SymbolicLink" );
  370. ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_SYMBOLIC_LINK );
  371. ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
  372. ObjectTypeInitializer.CaseInsensitive = TRUE;
  373. ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
  374. ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink;
  375. ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink;
  376. ObCreateObjectType( &SymbolicLinkTypeName,
  377. &ObjectTypeInitializer,
  378. (PSECURITY_DESCRIPTOR)NULL,
  379. &ObpSymbolicLinkObjectType );
  380. //
  381. // Clear SYNCHRONIZE from the access mask to not allow
  382. // synchronization on symbolic link objects objects
  383. //
  384. ObpSymbolicLinkObjectType->TypeInfo.ValidAccessMask &= ~SYNCHRONIZE;
  385. #ifdef POOL_TAGGING
  386. //
  387. // Initialize the ref/deref object-tracing mechanism
  388. //
  389. ObpInitStackTrace();
  390. #endif //POOL_TAGGING
  391. #if i386
  392. //
  393. // Initialize the cached granted access structure. These variables are used
  394. // in place of the access mask in the object table entry.
  395. //
  396. ObpCurCachedGrantedAccessIndex = 0;
  397. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  398. ObpMaxCachedGrantedAccessIndex = 2*PAGE_SIZE / sizeof( ACCESS_MASK );
  399. ObpCachedGrantedAccesses = ExAllocatePoolWithTag( PagedPool, 2*PAGE_SIZE, 'gAbO' );
  400. ObpAccessProtectCloseBit = 0x80000000;
  401. } else {
  402. ObpMaxCachedGrantedAccessIndex = 0;
  403. ObpCachedGrantedAccesses = NULL;
  404. }
  405. #endif // i386
  406. } // End of Phase 0 Initialization
  407. //
  408. // PHASE 1 Initialization
  409. //
  410. if (InitializationPhase == 1) {
  411. //
  412. // Initialize the per processor nonpaged lookaside lists and descriptors.
  413. //
  414. for (Index = 0; Index < (ULONG)KeNumberProcessors; Index += 1) {
  415. Prcb = KiProcessorBlock[Index];
  416. //
  417. // Initialize the create information per processor lookaside pointers.
  418. //
  419. Prcb->PPLookasideList[LookasideCreateInfoList].L = &ObpCreateInfoLookasideList;
  420. Lookaside = ExAllocatePoolWithTag( NonPagedPool,
  421. sizeof(GENERAL_LOOKASIDE),
  422. 'ICbO');
  423. if (Lookaside != NULL) {
  424. ExInitializeSystemLookasideList( Lookaside,
  425. NonPagedPool,
  426. sizeof(OBJECT_CREATE_INFORMATION),
  427. 'ICbO',
  428. CreateInfoMaxDepth,
  429. &ExSystemLookasideListHead );
  430. } else {
  431. Lookaside = &ObpCreateInfoLookasideList;
  432. }
  433. Prcb->PPLookasideList[LookasideCreateInfoList].P = Lookaside;
  434. //
  435. // Initialize the name buffer per processor lookaside pointers.
  436. //
  437. Prcb->PPLookasideList[LookasideNameBufferList].L = &ObpNameBufferLookasideList;
  438. Lookaside = ExAllocatePoolWithTag( NonPagedPool,
  439. sizeof(GENERAL_LOOKASIDE),
  440. 'MNbO');
  441. if (Lookaside != NULL) {
  442. ExInitializeSystemLookasideList( Lookaside,
  443. #ifndef OBP_PAGEDPOOL_NAMESPACE
  444. NonPagedPool,
  445. #else
  446. PagedPool,
  447. #endif
  448. OBJECT_NAME_BUFFER_SIZE,
  449. 'MNbO',
  450. NameBufferMaxDepth,
  451. &ExSystemLookasideListHead );
  452. } else {
  453. Lookaside = &ObpNameBufferLookasideList;
  454. }
  455. Prcb->PPLookasideList[LookasideNameBufferList].P = Lookaside;
  456. }
  457. EffectiveSd = SePublicDefaultUnrestrictedSd;
  458. //
  459. // This code is only executed if base auditing is turned on.
  460. //
  461. if ((ObpAuditBaseDirectories != 0) || (ObpAuditBaseObjects != 0)) {
  462. //
  463. // build an SACL to audit
  464. //
  465. AuditAllAcl = (PACL)AuditAllBuffer;
  466. AuditAllLength = (ULONG)sizeof(ACL) +
  467. ((ULONG)sizeof(SYSTEM_AUDIT_ACE)) +
  468. SeLengthSid(SeWorldSid);
  469. ASSERT( sizeof(AuditAllBuffer) > AuditAllLength );
  470. Status = RtlCreateAcl( AuditAllAcl, AuditAllLength, ACL_REVISION2);
  471. ASSERT( NT_SUCCESS(Status) );
  472. Status = RtlAddAuditAccessAce ( AuditAllAcl,
  473. ACL_REVISION2,
  474. GENERIC_ALL,
  475. SeWorldSid,
  476. TRUE, TRUE ); //Audit success and failure
  477. ASSERT( NT_SUCCESS(Status) );
  478. Status = RtlGetAce( AuditAllAcl, 0, (PVOID)&Ace );
  479. ASSERT( NT_SUCCESS(Status) );
  480. if (ObpAuditBaseDirectories != 0) {
  481. Ace->AceFlags |= (CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  482. }
  483. if (ObpAuditBaseObjects != 0) {
  484. Ace->AceFlags |= (OBJECT_INHERIT_ACE |
  485. CONTAINER_INHERIT_ACE |
  486. INHERIT_ONLY_ACE);
  487. }
  488. //
  489. // Now create a security descriptor that looks just like
  490. // the public default, but has auditing in it as well.
  491. //
  492. EffectiveSd = (PSECURITY_DESCRIPTOR)&AuditSd;
  493. Status = RtlCreateSecurityDescriptor( EffectiveSd,
  494. SECURITY_DESCRIPTOR_REVISION1 );
  495. ASSERT( NT_SUCCESS(Status) );
  496. Status = RtlSetDaclSecurityDescriptor( EffectiveSd,
  497. TRUE, // DaclPresent
  498. SePublicDefaultUnrestrictedDacl,
  499. FALSE ); // DaclDefaulted
  500. ASSERT( NT_SUCCESS(Status) );
  501. Status = RtlSetSaclSecurityDescriptor( EffectiveSd,
  502. TRUE, // DaclPresent
  503. AuditAllAcl,
  504. FALSE ); // DaclDefaulted
  505. ASSERT( NT_SUCCESS(Status) );
  506. }
  507. //
  508. // We only need to use the EffectiveSd on the root. The SACL
  509. // will be inherited by all other objects.
  510. //
  511. //
  512. // Create a directory object for the root directory
  513. //
  514. RtlInitUnicodeString( &RootDirectoryName, L"\\" );
  515. InitializeObjectAttributes( &ObjectAttributes,
  516. &RootDirectoryName,
  517. OBJ_CASE_INSENSITIVE |
  518. OBJ_PERMANENT,
  519. NULL,
  520. EffectiveSd );
  521. Status = NtCreateDirectoryObject( &RootDirectoryHandle,
  522. DIRECTORY_ALL_ACCESS,
  523. &ObjectAttributes );
  524. if (!NT_SUCCESS( Status )) {
  525. return( FALSE );
  526. }
  527. Status = ObReferenceObjectByHandle( RootDirectoryHandle,
  528. 0,
  529. ObpDirectoryObjectType,
  530. KernelMode,
  531. (PVOID *)&ObpRootDirectoryObject,
  532. NULL );
  533. if (!NT_SUCCESS( Status )) {
  534. return( FALSE );
  535. }
  536. Status = NtClose( RootDirectoryHandle );
  537. if (!NT_SUCCESS( Status )) {
  538. return( FALSE );
  539. }
  540. //
  541. // Create a directory object for the directory of kernel objects
  542. //
  543. Status = RtlCreateSecurityDescriptor (&SecurityDescriptor,
  544. SECURITY_DESCRIPTOR_REVISION);
  545. if (!NT_SUCCESS (Status)) {
  546. return( FALSE );
  547. }
  548. DaclLength = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) * 3 +
  549. RtlLengthSid (SeLocalSystemSid) +
  550. RtlLengthSid (SeAliasAdminsSid) +
  551. RtlLengthSid (SeWorldSid);
  552. Dacl = ExAllocatePoolWithTag (PagedPool, DaclLength, 'lcaD');
  553. if (Dacl == NULL) {
  554. return( FALSE );
  555. }
  556. Status = RtlCreateAcl (Dacl, DaclLength, ACL_REVISION);
  557. if (!NT_SUCCESS (Status)) {
  558. ExFreePool (Dacl);
  559. return( FALSE );
  560. }
  561. Status = RtlAddAccessAllowedAce (Dacl,
  562. ACL_REVISION,
  563. DIRECTORY_ALL_ACCESS,
  564. SeAliasAdminsSid);
  565. if (!NT_SUCCESS (Status)) {
  566. ExFreePool (Dacl);
  567. return( FALSE );
  568. }
  569. Status = RtlAddAccessAllowedAce (Dacl,
  570. ACL_REVISION,
  571. DIRECTORY_ALL_ACCESS,
  572. SeLocalSystemSid);
  573. if (!NT_SUCCESS (Status)) {
  574. ExFreePool (Dacl);
  575. return( FALSE );
  576. }
  577. Status = RtlAddAccessAllowedAce (Dacl,
  578. ACL_REVISION,
  579. DIRECTORY_QUERY|DIRECTORY_TRAVERSE|READ_CONTROL,
  580. SeWorldSid);
  581. if (!NT_SUCCESS (Status)) {
  582. ExFreePool (Dacl);
  583. return( FALSE );
  584. }
  585. Status = RtlSetDaclSecurityDescriptor (&SecurityDescriptor,
  586. TRUE,
  587. Dacl,
  588. FALSE);
  589. if (!NT_SUCCESS (Status)) {
  590. ExFreePool (Dacl);
  591. return( FALSE );
  592. }
  593. RtlInitUnicodeString( &TypeDirectoryName, L"\\KernelObjects" );
  594. InitializeObjectAttributes( &ObjectAttributes,
  595. &TypeDirectoryName,
  596. OBJ_CASE_INSENSITIVE |
  597. OBJ_PERMANENT,
  598. NULL,
  599. &SecurityDescriptor );
  600. Status = NtCreateDirectoryObject( &TypeDirectoryHandle,
  601. DIRECTORY_ALL_ACCESS,
  602. &ObjectAttributes );
  603. if (!NT_SUCCESS( Status )) {
  604. return( FALSE );
  605. }
  606. Status = NtClose( TypeDirectoryHandle );
  607. if (!NT_SUCCESS( Status )) {
  608. return( FALSE );
  609. }
  610. //
  611. // Create a directory object for the directory of object types
  612. //
  613. RtlInitUnicodeString( &TypeDirectoryName, L"\\ObjectTypes" );
  614. InitializeObjectAttributes( &ObjectAttributes,
  615. &TypeDirectoryName,
  616. OBJ_CASE_INSENSITIVE |
  617. OBJ_PERMANENT,
  618. NULL,
  619. NULL );
  620. Status = NtCreateDirectoryObject( &TypeDirectoryHandle,
  621. DIRECTORY_ALL_ACCESS,
  622. &ObjectAttributes );
  623. if (!NT_SUCCESS( Status )) {
  624. return( FALSE );
  625. }
  626. Status = ObReferenceObjectByHandle( TypeDirectoryHandle,
  627. 0,
  628. ObpDirectoryObjectType,
  629. KernelMode,
  630. (PVOID *)&ObpTypeDirectoryObject,
  631. NULL );
  632. if (!NT_SUCCESS( Status )) {
  633. return( FALSE );
  634. }
  635. Status = NtClose( TypeDirectoryHandle );
  636. if (!NT_SUCCESS( Status )) {
  637. return( FALSE );
  638. }
  639. //
  640. // For every object type that has already been created we will
  641. // insert it in the type directory. We do this looking down the
  642. // linked list of type objects and for every one that has a name
  643. // and isn't already in a directory we'll look the name up and
  644. // then put it in the directory. Be sure to skip the first
  645. // entry in the type object types lists.
  646. //
  647. ObpInitializeLookupContext( &LookupContext );
  648. ObpLockLookupContext ( &LookupContext, ObpTypeDirectoryObject );
  649. Head = &ObpTypeObjectType->TypeList;
  650. Next = Head->Flink;
  651. while (Next != Head) {
  652. //
  653. // Right after the creator info is the object header. Get
  654. // the object header and then see if there is a name.
  655. //
  656. CreatorInfo = CONTAINING_RECORD( Next,
  657. OBJECT_HEADER_CREATOR_INFO,
  658. TypeList );
  659. ObjectTypeHeader = (POBJECT_HEADER)(CreatorInfo+1);
  660. NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectTypeHeader );
  661. //
  662. // Check if we have a name and we're not in a directory
  663. //
  664. if ((NameInfo != NULL) && (NameInfo->Directory == NULL)) {
  665. if (!ObpLookupDirectoryEntry( ObpTypeDirectoryObject,
  666. &NameInfo->Name,
  667. OBJ_CASE_INSENSITIVE,
  668. FALSE,
  669. &LookupContext)) {
  670. ObpInsertDirectoryEntry( ObpTypeDirectoryObject,
  671. &LookupContext,
  672. ObjectTypeHeader );
  673. }
  674. }
  675. Next = Next->Flink;
  676. }
  677. ObpReleaseLookupContext(&LookupContext);
  678. //
  679. // Create \DosDevices object directory for drive letters and Win32 device names
  680. //
  681. Status = ObpCreateDosDevicesDirectory();
  682. if (!NT_SUCCESS( Status )) {
  683. return FALSE;
  684. }
  685. }
  686. return TRUE;
  687. }
  688. BOOLEAN
  689. ObDupHandleProcedure (
  690. PEPROCESS Process,
  691. PHANDLE_TABLE OldObjectTable,
  692. PHANDLE_TABLE_ENTRY OldObjectTableEntry,
  693. PHANDLE_TABLE_ENTRY ObjectTableEntry
  694. )
  695. /*++
  696. Routine Description:
  697. This is the worker routine for ExDupHandleTable and
  698. is invoked via ObInitProcess.
  699. Arguments:
  700. Process - Supplies a pointer to the new process
  701. HandleTable - Old handle table we are duplicating
  702. ObjectTableEntry - Supplies a pointer to the newly
  703. created handle table entry
  704. Return Value:
  705. TRUE if the item can be inserted in the new table
  706. and FALSE otherwise
  707. --*/
  708. {
  709. NTSTATUS Status;
  710. POBJECT_HEADER ObjectHeader;
  711. PVOID Object;
  712. ACCESS_STATE AccessState;
  713. //
  714. // If the object table should not be inherited then return false
  715. //
  716. if (!(ObjectTableEntry->ObAttributes & OBJ_INHERIT)) {
  717. ExUnlockHandleTableEntry (OldObjectTable, OldObjectTableEntry);
  718. return( FALSE );
  719. }
  720. //
  721. // Get a pointer to the object header and body
  722. //
  723. ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
  724. Object = &ObjectHeader->Body;
  725. //
  726. // Increment the pointer count to the object before we unlock the old entry
  727. //
  728. ObpIncrPointerCount (ObjectHeader);
  729. ExUnlockHandleTableEntry (OldObjectTable, OldObjectTableEntry);
  730. //
  731. // If we are tracing the call stacks for cached security indices then
  732. // we have a translation to do. Otherwise the table entry contains
  733. // straight away the granted access mask.
  734. //
  735. #if i386
  736. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  737. AccessState.PreviouslyGrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
  738. } else {
  739. AccessState.PreviouslyGrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  740. }
  741. #else
  742. AccessState.PreviouslyGrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  743. #endif // i386
  744. //
  745. // Increment the handle count on the object because we've just added
  746. // another handle to it.
  747. //
  748. Status = ObpIncrementHandleCount( ObInheritHandle,
  749. Process,
  750. Object,
  751. ObjectHeader->Type,
  752. &AccessState,
  753. KernelMode,
  754. 0 );
  755. if (!NT_SUCCESS( Status )) {
  756. ObDereferenceObject (Object);
  757. return( FALSE );
  758. }
  759. return( TRUE );
  760. }
  761. BOOLEAN
  762. ObAuditInheritedHandleProcedure (
  763. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  764. IN HANDLE HandleId,
  765. IN PVOID EnumParameter
  766. )
  767. /*++
  768. Routine Description:
  769. ExEnumHandleTable worker routine to generate audits when handles are
  770. inherited. An audit is generated if the handle attributes indicate
  771. that the handle is to be audited on close.
  772. Arguments:
  773. ObjectTableEntry - Points to the handle table entry of interest.
  774. HandleId - Supplies the handle.
  775. EnumParameter - Supplies information about the source and target processes.
  776. Return Value:
  777. FALSE, which tells ExEnumHandleTable to continue iterating through the
  778. handle table.
  779. --*/
  780. {
  781. PSE_PROCESS_AUDIT_INFO ProcessAuditInfo = EnumParameter;
  782. //
  783. // Check if we have to do an audit
  784. //
  785. if (!(ObjectTableEntry->ObAttributes & OBJ_AUDIT_OBJECT_CLOSE)) {
  786. return( FALSE );
  787. }
  788. //
  789. // Do the audit then return for more
  790. //
  791. SeAuditHandleDuplication( HandleId,
  792. HandleId,
  793. ProcessAuditInfo->Parent,
  794. ProcessAuditInfo->Process );
  795. return( FALSE );
  796. }
  797. NTSTATUS
  798. ObInitProcess (
  799. PEPROCESS ParentProcess OPTIONAL,
  800. PEPROCESS NewProcess
  801. )
  802. /*++
  803. Routine Description:
  804. This function initializes a process object table. If the ParentProcess
  805. is specified, then all object handles with the OBJ_INHERIT attribute are
  806. copied from the parent object table to the new process' object table.
  807. The HandleCount field of each object copied is incremented by one. Both
  808. object table mutexes remained locked for the duration of the copy
  809. operation.
  810. Arguments:
  811. ParentProcess - optional pointer to a process object that is the
  812. parent process to inherit object handles from.
  813. NewProcess - pointer to the process object being initialized.
  814. Return Value:
  815. Status code.
  816. The following errors can occur:
  817. - insufficient memory
  818. - STATUS_PROCESS_IS_TERMINATING if the parent process is terminating
  819. --*/
  820. {
  821. PHANDLE_TABLE OldObjectTable;
  822. PHANDLE_TABLE NewObjectTable;
  823. SE_PROCESS_AUDIT_INFO ProcessAuditInfo;
  824. //
  825. // If we have a parent process then we need to lock it down
  826. // check that it is not going away and then make a copy
  827. // of its handle table. If there isn't a parent then
  828. // we'll start with an empty handle table.
  829. //
  830. if (ARGUMENT_PRESENT( ParentProcess )) {
  831. OldObjectTable = ObReferenceProcessHandleTable (ParentProcess);
  832. if ( !OldObjectTable ) {
  833. return STATUS_PROCESS_IS_TERMINATING;
  834. }
  835. NewObjectTable = ExDupHandleTable( NewProcess,
  836. OldObjectTable,
  837. ObDupHandleProcedure );
  838. } else {
  839. OldObjectTable = NULL;
  840. NewObjectTable = ExCreateHandleTable( NewProcess );
  841. }
  842. //
  843. // Check that we really have a new handle table otherwise
  844. // we must be out of resources
  845. //
  846. if ( NewObjectTable ) {
  847. //
  848. // Set the new processes object table and if we are
  849. // auditing then enumerate the new table calling
  850. // the audit procedure
  851. //
  852. NewProcess->ObjectTable = NewObjectTable;
  853. if ( SeDetailedAuditing ) {
  854. ProcessAuditInfo.Process = NewProcess;
  855. ProcessAuditInfo.Parent = ParentProcess;
  856. ExEnumHandleTable( NewObjectTable,
  857. ObAuditInheritedHandleProcedure,
  858. (PVOID)&ProcessAuditInfo,
  859. (PHANDLE)NULL );
  860. }
  861. //
  862. // Free the old table if it exists and then
  863. // return to our caller
  864. //
  865. if ( OldObjectTable ) {
  866. ObDereferenceProcessHandleTable( ParentProcess );
  867. }
  868. return (STATUS_SUCCESS);
  869. } else {
  870. //
  871. // We're out of resources to null out the new object table field,
  872. // unlock the old object table, and tell our caller that this
  873. // didn't work
  874. //
  875. NewProcess->ObjectTable = NULL;
  876. if ( OldObjectTable ) {
  877. ObDereferenceProcessHandleTable( ParentProcess );
  878. }
  879. return (STATUS_INSUFFICIENT_RESOURCES);
  880. }
  881. }
  882. VOID
  883. ObInitProcess2 (
  884. PEPROCESS NewProcess
  885. )
  886. /*++
  887. Routine Description:
  888. This function is called after an image file has been mapped into the address
  889. space of a newly created process. Allows the object manager to set LIFO/FIFO
  890. ordering for handle allocation based on the SubSystemVersion number in the
  891. image.
  892. Arguments:
  893. NewProcess - pointer to the process object being initialized.
  894. Return Value:
  895. None.
  896. --*/
  897. {
  898. //
  899. // Set LIFO ordering of handles for images <= SubSystemVersion 3.50
  900. //
  901. if (NewProcess->ObjectTable) {
  902. ExSetHandleTableOrder( NewProcess->ObjectTable, (BOOLEAN)(NewProcess->SubSystemVersion <= 0x332) );
  903. }
  904. return;
  905. }
  906. VOID
  907. ObDestroyHandleProcedure (
  908. IN HANDLE HandleIndex
  909. )
  910. /*++
  911. Routine Description:
  912. This function is used to close a handle but takes as input a
  913. handle table index that it first translates to an handle
  914. before calling close. Note that the handle index is really
  915. just the offset within the handle table entries.
  916. Arguments:
  917. HandleIndex - Supplies a handle index for the handle being closed.
  918. Return Value:
  919. None.
  920. --*/
  921. {
  922. ZwClose( HandleIndex );
  923. return;
  924. }
  925. BOOLEAN
  926. ObpCloseHandleProcedure (
  927. IN PHANDLE_TABLE_ENTRY HandleTableEntry,
  928. IN HANDLE Handle,
  929. IN PVOID EnumParameter
  930. )
  931. /*++
  932. Routine Description:
  933. This function is used to close all the handles in a table
  934. Arguments:
  935. HandleTableEntry - Current handle entry
  936. Handle - Handle for the entry
  937. EnumParameter - Sweep context, table and mode
  938. Return Value:
  939. None.
  940. --*/
  941. {
  942. POBP_SWEEP_CONTEXT SweepContext;
  943. SweepContext = EnumParameter;
  944. ObpCloseHandleTableEntry (SweepContext->HandleTable,
  945. HandleTableEntry,
  946. Handle,
  947. SweepContext->PreviousMode,
  948. TRUE,
  949. TRUE);
  950. return TRUE;
  951. }
  952. VOID
  953. ObClearProcessHandleTable (
  954. PEPROCESS Process
  955. )
  956. /*++
  957. Routine Description:
  958. This function marks the process handle table for deletion and clears out all the handles.
  959. Arguments:
  960. Process - Pointer to the process that is to be acted on.
  961. --*/
  962. {
  963. PHANDLE_TABLE ObjectTable;
  964. BOOLEAN AttachedToProcess = FALSE;
  965. KAPC_STATE ApcState;
  966. PETHREAD CurrentThread;
  967. OBP_SWEEP_CONTEXT SweepContext;
  968. ObjectTable = ObReferenceProcessHandleTable (Process);
  969. if (ObjectTable == NULL) {
  970. return;
  971. }
  972. CurrentThread = PsGetCurrentThread ();
  973. if (PsGetCurrentProcessByThread(CurrentThread) != Process) {
  974. KeStackAttachProcess (&Process->Pcb, &ApcState);
  975. AttachedToProcess = TRUE;
  976. }
  977. KeEnterCriticalRegionThread(&CurrentThread->Tcb);
  978. //
  979. // Close all the handles
  980. //
  981. SweepContext.PreviousMode = UserMode;
  982. SweepContext.HandleTable = ObjectTable;
  983. ExSweepHandleTable (ObjectTable,
  984. ObpCloseHandleProcedure,
  985. &SweepContext);
  986. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  987. if (AttachedToProcess == TRUE) {
  988. KeUnstackDetachProcess (&ApcState);
  989. }
  990. ObDereferenceProcessHandleTable (Process);
  991. return;
  992. }
  993. VOID
  994. ObKillProcess (
  995. PEPROCESS Process
  996. )
  997. /*++
  998. Routine Description:
  999. This function is called whenever a process is destroyed. It loops over
  1000. the process' object table and closes all the handles.
  1001. Arguments:
  1002. Process - Pointer to the process that is being destroyed.
  1003. Return Value:
  1004. None.
  1005. --*/
  1006. {
  1007. PHANDLE_TABLE ObjectTable;
  1008. BOOLEAN PreviousIOHardError;
  1009. PKTHREAD CurrentThread;
  1010. OBP_SWEEP_CONTEXT SweepContext;
  1011. PAGED_CODE();
  1012. ObpValidateIrql( "ObKillProcess" );
  1013. //
  1014. // Wait for any cross process references to finish
  1015. //
  1016. ExWaitForRundownProtectionRelease (&Process->RundownProtect);
  1017. //
  1018. // This routine gets recalled multiple times for the same object so just mark the object so future waits
  1019. // work ok.
  1020. //
  1021. ExRundownCompleted (&Process->RundownProtect);
  1022. //
  1023. // If the process does NOT have an object table, return
  1024. //
  1025. ObjectTable = Process->ObjectTable;
  1026. if (ObjectTable != NULL) {
  1027. PreviousIOHardError = IoSetThreadHardErrorMode(FALSE);
  1028. //
  1029. // For each valid entry in the object table, close the handle
  1030. // that points to that entry.
  1031. //
  1032. //
  1033. // Close all the handles
  1034. //
  1035. CurrentThread = KeGetCurrentThread ();
  1036. KeEnterCriticalRegionThread(CurrentThread);
  1037. SweepContext.PreviousMode = KernelMode;
  1038. SweepContext.HandleTable = ObjectTable;
  1039. ExSweepHandleTable (ObjectTable,
  1040. ObpCloseHandleProcedure,
  1041. &SweepContext);
  1042. ASSERT (ObjectTable->HandleCount == 0);
  1043. KeLeaveCriticalRegionThread(CurrentThread);
  1044. IoSetThreadHardErrorMode( PreviousIOHardError );
  1045. Process->ObjectTable = NULL;
  1046. ExDestroyHandleTable( ObjectTable, NULL );
  1047. }
  1048. //
  1049. // And return to our caller
  1050. //
  1051. return;
  1052. }
  1053. //
  1054. // The following structure is only used by the enumeration routine
  1055. // and the callback. It provides context for the comparison of
  1056. // the objects.
  1057. //
  1058. typedef struct _OBP_FIND_HANDLE_DATA {
  1059. POBJECT_HEADER ObjectHeader;
  1060. POBJECT_TYPE ObjectType;
  1061. POBJECT_HANDLE_INFORMATION HandleInformation;
  1062. } OBP_FIND_HANDLE_DATA, *POBP_FIND_HANDLE_DATA;
  1063. BOOLEAN
  1064. ObpEnumFindHandleProcedure (
  1065. PHANDLE_TABLE_ENTRY ObjectTableEntry,
  1066. HANDLE HandleId,
  1067. PVOID EnumParameter
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. Call back routine when enumerating an object table to find a handle
  1072. for a particular object
  1073. Arguments:
  1074. HandleTableEntry - Supplies a pointer to the handle table entry
  1075. being examined.
  1076. HandleId - Supplies the actual handle value for the preceding entry
  1077. EnumParameter - Supplies context for the matching.
  1078. Return Value:
  1079. Returns TRUE if a match is found and the enumeration should stop. Returns FALSE
  1080. otherwise, so the enumeration will continue.
  1081. --*/
  1082. {
  1083. POBJECT_HEADER ObjectHeader;
  1084. ACCESS_MASK GrantedAccess;
  1085. ULONG HandleAttributes;
  1086. POBP_FIND_HANDLE_DATA MatchCriteria = EnumParameter;
  1087. //
  1088. // Get the object header from the table entry and see if
  1089. // object types and headers match if specified.
  1090. //
  1091. ObjectHeader = (POBJECT_HEADER)((ULONG_PTR)ObjectTableEntry->Object & ~OBJ_HANDLE_ATTRIBUTES);
  1092. if ((MatchCriteria->ObjectHeader != NULL) &&
  1093. (MatchCriteria->ObjectHeader != ObjectHeader)) {
  1094. return FALSE;
  1095. }
  1096. if ((MatchCriteria->ObjectType != NULL) &&
  1097. (MatchCriteria->ObjectType != ObjectHeader->Type)) {
  1098. return FALSE;
  1099. }
  1100. //
  1101. // Check if we have handle information that we need to compare
  1102. //
  1103. if (ARGUMENT_PRESENT( MatchCriteria->HandleInformation )) {
  1104. //
  1105. // If we are tracing the call stacks for cached security indices then
  1106. // we have a translation to do. Otherwise the table entry contains
  1107. // straight away the granted access mask.
  1108. //
  1109. #if i386
  1110. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  1111. GrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
  1112. } else {
  1113. GrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  1114. }
  1115. #else
  1116. GrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  1117. #endif // i386
  1118. //
  1119. // Get the handle attributes from table entry and see if the
  1120. // fields match. If they do not match we will return false to
  1121. // continue the search.
  1122. //
  1123. HandleAttributes = ObpGetHandleAttributes(ObjectTableEntry);
  1124. if (MatchCriteria->HandleInformation->HandleAttributes != HandleAttributes ||
  1125. MatchCriteria->HandleInformation->GrantedAccess != GrantedAccess ) {
  1126. return FALSE;
  1127. }
  1128. }
  1129. //
  1130. // We found something that matches our criteria so return true to
  1131. // our caller to stop the enumeration
  1132. //
  1133. return TRUE;
  1134. }
  1135. BOOLEAN
  1136. ObFindHandleForObject (
  1137. IN PEPROCESS Process,
  1138. IN PVOID Object OPTIONAL,
  1139. IN POBJECT_TYPE ObjectType OPTIONAL,
  1140. IN POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL,
  1141. OUT PHANDLE Handle
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. This routine searches the handle table for the specified process,
  1146. looking for a handle table entry that matches the passed parameters.
  1147. If an an Object pointer is specified it must match. If an
  1148. ObjectType is specified it must match. If HandleInformation is
  1149. specified, then both the HandleAttributes and GrantedAccess mask
  1150. must match. If all three match parameters are NULL, then will
  1151. match the first allocated handle for the specified process that
  1152. matches the specified object pointer.
  1153. Arguments:
  1154. Process - Specifies the process whose object table is to be searched.
  1155. Object - Specifies the object pointer to look for.
  1156. ObjectType - Specifies the object type to look for.
  1157. HandleInformation - Specifies additional match criteria to look for.
  1158. Handle - Specifies the location to receive the handle value whose handle
  1159. entry matches the supplied object pointer and optional match criteria.
  1160. Return Value:
  1161. TRUE if a match was found and FALSE otherwise.
  1162. --*/
  1163. {
  1164. HANDLE_TABLE_ENTRY ObjectTableEntry;
  1165. PHANDLE_TABLE ObjectTable;
  1166. OBP_FIND_HANDLE_DATA EnumParameter;
  1167. BOOLEAN Result;
  1168. Result = FALSE;
  1169. //
  1170. // Lock the object object name space
  1171. //
  1172. ObjectTable = ObReferenceProcessHandleTable (Process);
  1173. //
  1174. // We only do the work if the process has an object table meaning
  1175. // it isn't going away
  1176. //
  1177. if (ObjectTable != NULL) {
  1178. //
  1179. // Set the match parameters that our caller supplied
  1180. //
  1181. if (ARGUMENT_PRESENT( Object )) {
  1182. EnumParameter.ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1183. } else {
  1184. EnumParameter.ObjectHeader = NULL;
  1185. }
  1186. EnumParameter.ObjectType = ObjectType;
  1187. EnumParameter.HandleInformation = HandleInformation;
  1188. //
  1189. // Call the routine the enumerate the object table, this will
  1190. // return true if we get match. The enumeration routine really
  1191. // returns a index into the object table entries we need to
  1192. // translate it to a real handle before returning.
  1193. //
  1194. if (ExEnumHandleTable( ObjectTable,
  1195. ObpEnumFindHandleProcedure,
  1196. &EnumParameter,
  1197. Handle )) {
  1198. Result = TRUE;
  1199. }
  1200. ObDereferenceProcessHandleTable( Process );
  1201. }
  1202. return Result;
  1203. }
  1204. //
  1205. // Local support routine
  1206. //
  1207. NTSTATUS
  1208. ObpCreateDosDevicesDirectory (
  1209. VOID
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. This routine creates the directory object for the dos devices and sets
  1214. the device map for the system process.
  1215. Arguments:
  1216. None.
  1217. Return Value:
  1218. STATUS_SUCCESS or an appropriate error
  1219. --*/
  1220. {
  1221. NTSTATUS Status;
  1222. UNICODE_STRING NameString;
  1223. UNICODE_STRING RootNameString;
  1224. UNICODE_STRING TargetString;
  1225. OBJECT_ATTRIBUTES ObjectAttributes;
  1226. HANDLE DirectoryHandle;
  1227. HANDLE SymbolicLinkHandle;
  1228. SECURITY_DESCRIPTOR DosDevicesSD;
  1229. //
  1230. // Determine if LUID device maps are enabled or disabled
  1231. // Store the result in ObpLUIDDeviceMapsEnabled
  1232. // 0 - LUID device maps are disabled
  1233. // 1 - LUID device maps are enabled
  1234. //
  1235. if ((ObpProtectionMode == 0) || (ObpLUIDDeviceMapsDisabled != 0)) {
  1236. ObpLUIDDeviceMapsEnabled = 0;
  1237. }
  1238. else {
  1239. ObpLUIDDeviceMapsEnabled = 1;
  1240. }
  1241. //
  1242. // Create the security descriptor to use for the \?? directory
  1243. //
  1244. Status = ObpGetDosDevicesProtection( &DosDevicesSD );
  1245. if (!NT_SUCCESS( Status )) {
  1246. return Status;
  1247. }
  1248. //
  1249. // Create the root directory object for the global \?? directory.
  1250. //
  1251. RtlInitUnicodeString( &RootNameString, ObpGlobalDosDevicesShortName );
  1252. InitializeObjectAttributes( &ObjectAttributes,
  1253. &RootNameString,
  1254. OBJ_PERMANENT,
  1255. (HANDLE) NULL,
  1256. &DosDevicesSD );
  1257. Status = NtCreateDirectoryObject( &DirectoryHandle,
  1258. DIRECTORY_ALL_ACCESS,
  1259. &ObjectAttributes );
  1260. if (!NT_SUCCESS( Status )) {
  1261. return Status;
  1262. }
  1263. //
  1264. // Create a device map that will control this directory. It will be
  1265. // stored in the each EPROCESS for use by ObpLookupObjectName when
  1266. // translating names that begin with \??\
  1267. // With LUID device maps, the device map is stored in the each EPROCESS
  1268. // upon the first reference to the device map, and the EPROCESS
  1269. // device map field is cleared when the EPROCESS access token is set.
  1270. //
  1271. Status = ObSetDeviceMap( NULL, DirectoryHandle );
  1272. //
  1273. // Now create a symbolic link, \??\GLOBALROOT, that points to \
  1274. // WorkStation service needs some mechanism to access a session specific
  1275. // DosDevicesDirectory. DosPathToSessionPath API will take a DosPath
  1276. // e.g (C:) and convert it into session specific path
  1277. // (e.g GLOBALROOT\Sessions\6\DosDevices\C:). The GLOBALROOT symbolic
  1278. // link is used to escape out of the current process's DosDevices directory
  1279. //
  1280. RtlInitUnicodeString( &NameString, L"GLOBALROOT" );
  1281. RtlInitUnicodeString( &TargetString, L"" );
  1282. InitializeObjectAttributes( &ObjectAttributes,
  1283. &NameString,
  1284. OBJ_PERMANENT,
  1285. DirectoryHandle,
  1286. &DosDevicesSD );
  1287. Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle,
  1288. SYMBOLIC_LINK_ALL_ACCESS,
  1289. &ObjectAttributes,
  1290. &TargetString );
  1291. if (NT_SUCCESS( Status )) {
  1292. NtClose( SymbolicLinkHandle );
  1293. }
  1294. //
  1295. // Create a symbolic link, \??\Global, that points to the global \??
  1296. // Drivers loaded dynamically create the symbolic link in the global
  1297. // DosDevices directory. User mode components need some way to access this
  1298. // symbolic link in the global dosdevices directory. The Global symbolic
  1299. // link is used to escape out of the current sessions's DosDevices directory
  1300. // and use the global dosdevices directory. e.g CreateFile("\\\\.\\Global\\NMDev"..);
  1301. //
  1302. RtlInitUnicodeString( &NameString, L"Global" );
  1303. InitializeObjectAttributes( &ObjectAttributes,
  1304. &NameString,
  1305. OBJ_PERMANENT,
  1306. DirectoryHandle,
  1307. &DosDevicesSD );
  1308. Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle,
  1309. SYMBOLIC_LINK_ALL_ACCESS,
  1310. &ObjectAttributes,
  1311. &RootNameString );
  1312. if (NT_SUCCESS( Status )) {
  1313. NtClose( SymbolicLinkHandle );
  1314. }
  1315. NtClose( DirectoryHandle );
  1316. if (!NT_SUCCESS( Status )) {
  1317. return Status;
  1318. }
  1319. //
  1320. // Now create a symbolic link, \DosDevices, that points to \??
  1321. // for backwards compatibility with old drivers that use the old
  1322. // name.
  1323. //
  1324. RtlInitUnicodeString( &RootNameString, (PWCHAR)&ObpDosDevicesShortNameRoot );
  1325. RtlCreateUnicodeString( &NameString, L"\\DosDevices" );
  1326. InitializeObjectAttributes( &ObjectAttributes,
  1327. &NameString,
  1328. OBJ_PERMANENT,
  1329. (HANDLE) NULL,
  1330. &DosDevicesSD );
  1331. Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle,
  1332. SYMBOLIC_LINK_ALL_ACCESS,
  1333. &ObjectAttributes,
  1334. &RootNameString );
  1335. if (NT_SUCCESS( Status )) {
  1336. NtClose( SymbolicLinkHandle );
  1337. }
  1338. //
  1339. // All done with the security descriptor for \??
  1340. //
  1341. ObpFreeDosDevicesProtection( &DosDevicesSD );
  1342. return STATUS_SUCCESS;
  1343. }
  1344. //
  1345. // Local support routine
  1346. //
  1347. NTSTATUS
  1348. ObpGetDosDevicesProtection (
  1349. PSECURITY_DESCRIPTOR SecurityDescriptor
  1350. )
  1351. /*++
  1352. Routine Description:
  1353. This routine builds a security descriptor for use in creating
  1354. the \DosDevices object directory. The protection of \DosDevices
  1355. must establish inheritable protection which will dictate how
  1356. dos devices created via the DefineDosDevice() and
  1357. IoCreateUnprotectedSymbolicLink() apis can be managed.
  1358. The protection assigned is dependent upon an administrable registry
  1359. key:
  1360. Key: \hkey_local_machine\System\CurrentControlSet\Control\Session Manager
  1361. Value: [REG_DWORD] ProtectionMode
  1362. If this value is 0x1, then
  1363. Administrators may control all Dos devices,
  1364. Anyone may create new Dos devices (such as net drives
  1365. or additional printers),
  1366. Anyone may use any Dos device,
  1367. The creator of a Dos device may delete it.
  1368. Note that this protects system-defined LPTs and COMs so that only
  1369. administrators may redirect them. However, anyone may add
  1370. additional printers and direct them to wherever they would
  1371. like.
  1372. This is achieved with the following protection for the DosDevices
  1373. Directory object:
  1374. Grant: World: Execute | Read (No Inherit)
  1375. Grant: System: All Access (No Inherit)
  1376. Grant: World: Execute (Inherit Only)
  1377. Grant: Admins: All Access (Inherit Only)
  1378. Grant: System: All Access (Inherit Only)
  1379. Grant: Owner: All Access (Inherit Only)
  1380. If this value is 0x0, or not present, then
  1381. Administrators may control all Dos devices,
  1382. Anyone may create new Dos devices (such as net drives
  1383. or additional printers),
  1384. Anyone may use any Dos device,
  1385. Anyone may delete Dos devices created with either DefineDosDevice()
  1386. or IoCreateUnprotectedSymbolicLink(). This is how network drives
  1387. and LPTs are created (but not COMs).
  1388. This is achieved with the following protection for the DosDevices
  1389. Directory object:
  1390. Grant: World: Execute | Read | Write (No Inherit)
  1391. Grant: System: All Access (No Inherit)
  1392. Grant: World: All Access (Inherit Only)
  1393. Arguments:
  1394. SecurityDescriptor - The address of a security descriptor to be
  1395. initialized and filled in. When this security descriptor is no
  1396. longer needed, you should call ObpFreeDosDevicesProtection() to
  1397. free the protection information.
  1398. Return Value:
  1399. Returns one of the following status codes:
  1400. STATUS_SUCCESS - normal, successful completion.
  1401. STATUS_NO_MEMORY - not enough memory
  1402. --*/
  1403. {
  1404. NTSTATUS Status;
  1405. ULONG aceIndex, aclLength;
  1406. PACL dacl;
  1407. PACE_HEADER ace;
  1408. ACCESS_MASK accessMask;
  1409. UCHAR inheritOnlyFlags = (OBJECT_INHERIT_ACE |
  1410. CONTAINER_INHERIT_ACE |
  1411. INHERIT_ONLY_ACE
  1412. );
  1413. //
  1414. // NOTE: This routine expects the value of ObpProtectionMode to have been set
  1415. //
  1416. Status = RtlCreateSecurityDescriptor( SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  1417. ASSERT( NT_SUCCESS( Status ) );
  1418. if (ObpProtectionMode & 0x00000001) {
  1419. //
  1420. // Dacl:
  1421. // Grant: World: Execute | Read (No Inherit)
  1422. // Grant: System: All Access (No Inherit)
  1423. // Grant: World: Execute (Inherit Only)
  1424. // Grant: Admins: All Access (Inherit Only)
  1425. // Grant: System: All Access (Inherit Only)
  1426. // Grant: Owner: All Access (Inherit Only)
  1427. //
  1428. aclLength = sizeof( ACL ) +
  1429. 6 * sizeof( ACCESS_ALLOWED_ACE ) +
  1430. (2*RtlLengthSid( SeWorldSid )) +
  1431. (2*RtlLengthSid( SeLocalSystemSid )) +
  1432. RtlLengthSid( SeAliasAdminsSid ) +
  1433. RtlLengthSid( SeCreatorOwnerSid );
  1434. dacl = (PACL)ExAllocatePool(PagedPool, aclLength );
  1435. if (dacl == NULL) {
  1436. return STATUS_NO_MEMORY;
  1437. }
  1438. Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2);
  1439. ASSERT( NT_SUCCESS( Status ) );
  1440. //
  1441. // Non-inheritable ACEs first
  1442. // World
  1443. // System
  1444. //
  1445. aceIndex = 0;
  1446. accessMask = (GENERIC_READ | GENERIC_EXECUTE);
  1447. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid );
  1448. ASSERT( NT_SUCCESS( Status ) );
  1449. aceIndex++;
  1450. accessMask = (GENERIC_ALL);
  1451. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeLocalSystemSid );
  1452. ASSERT( NT_SUCCESS( Status ) );
  1453. //
  1454. // Inheritable ACEs at the end of the ACL
  1455. // World
  1456. // Admins
  1457. // System
  1458. // Owner
  1459. //
  1460. aceIndex++;
  1461. accessMask = (GENERIC_EXECUTE);
  1462. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid );
  1463. ASSERT( NT_SUCCESS( Status ) );
  1464. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1465. ASSERT( NT_SUCCESS( Status ) );
  1466. ace->AceFlags |= inheritOnlyFlags;
  1467. aceIndex++;
  1468. accessMask = (GENERIC_ALL);
  1469. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeAliasAdminsSid );
  1470. ASSERT( NT_SUCCESS( Status ) );
  1471. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1472. ASSERT( NT_SUCCESS( Status ) );
  1473. ace->AceFlags |= inheritOnlyFlags;
  1474. aceIndex++;
  1475. accessMask = (GENERIC_ALL);
  1476. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeLocalSystemSid );
  1477. ASSERT( NT_SUCCESS( Status ) );
  1478. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1479. ASSERT( NT_SUCCESS( Status ) );
  1480. ace->AceFlags |= inheritOnlyFlags;
  1481. aceIndex++;
  1482. accessMask = (GENERIC_ALL);
  1483. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeCreatorOwnerSid );
  1484. ASSERT( NT_SUCCESS( Status ) );
  1485. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1486. ASSERT( NT_SUCCESS( Status ) );
  1487. ace->AceFlags |= inheritOnlyFlags;
  1488. Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor,
  1489. TRUE, //DaclPresent,
  1490. dacl, //Dacl
  1491. FALSE ); //!DaclDefaulted
  1492. ASSERT( NT_SUCCESS( Status ) );
  1493. } else {
  1494. //
  1495. // DACL:
  1496. // Grant: World: Execute | Read | Write (No Inherit)
  1497. // Grant: System: All Access (No Inherit)
  1498. // Grant: World: All Access (Inherit Only)
  1499. //
  1500. aclLength = sizeof( ACL ) +
  1501. 3 * sizeof( ACCESS_ALLOWED_ACE ) +
  1502. (2*RtlLengthSid( SeWorldSid )) +
  1503. RtlLengthSid( SeLocalSystemSid );
  1504. dacl = (PACL)ExAllocatePool(PagedPool, aclLength );
  1505. if (dacl == NULL) {
  1506. return STATUS_NO_MEMORY;
  1507. }
  1508. Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2);
  1509. ASSERT( NT_SUCCESS( Status ) );
  1510. //
  1511. // Non-inheritable ACEs first
  1512. // World
  1513. // System
  1514. //
  1515. aceIndex = 0;
  1516. accessMask = (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
  1517. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid );
  1518. ASSERT( NT_SUCCESS( Status ) );
  1519. aceIndex++;
  1520. accessMask = (GENERIC_ALL);
  1521. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeLocalSystemSid );
  1522. ASSERT( NT_SUCCESS( Status ) );
  1523. //
  1524. // Inheritable ACEs at the end of the ACL
  1525. // World
  1526. //
  1527. aceIndex++;
  1528. accessMask = (GENERIC_ALL);
  1529. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, SeWorldSid );
  1530. ASSERT( NT_SUCCESS( Status ) );
  1531. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1532. ASSERT( NT_SUCCESS( Status ) );
  1533. ace->AceFlags |= inheritOnlyFlags;
  1534. Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor,
  1535. TRUE, //DaclPresent,
  1536. dacl, //Dacl
  1537. FALSE ); //!DaclDefaulted
  1538. ASSERT( NT_SUCCESS( Status ) );
  1539. }
  1540. return STATUS_SUCCESS;
  1541. }
  1542. //
  1543. // Local support routine
  1544. //
  1545. VOID
  1546. ObpFreeDosDevicesProtection (
  1547. PSECURITY_DESCRIPTOR SecurityDescriptor
  1548. )
  1549. /*++
  1550. Routine Description:
  1551. This routine frees memory allocated via ObpGetDosDevicesProtection().
  1552. Arguments:
  1553. SecurityDescriptor - The address of a security descriptor initialized by
  1554. ObpGetDosDevicesProtection().
  1555. Return Value:
  1556. None.
  1557. --*/
  1558. {
  1559. NTSTATUS Status;
  1560. PACL Dacl;
  1561. BOOLEAN DaclPresent, Defaulted;
  1562. Status = RtlGetDaclSecurityDescriptor ( SecurityDescriptor,
  1563. &DaclPresent,
  1564. &Dacl,
  1565. &Defaulted );
  1566. ASSERT( NT_SUCCESS( Status ) );
  1567. ASSERT( DaclPresent );
  1568. ASSERT( Dacl != NULL );
  1569. ExFreePool( (PVOID)Dacl );
  1570. return;
  1571. }
  1572. BOOLEAN
  1573. ObpShutdownCloseHandleProcedure (
  1574. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  1575. IN HANDLE HandleId,
  1576. IN PVOID EnumParameter
  1577. )
  1578. /*++
  1579. Routine Description:
  1580. ExEnumHandleTable worker routine will call this routine for each
  1581. valid handle into the kernel table at shutdown
  1582. Arguments:
  1583. ObjectTableEntry - Points to the handle table entry of interest.
  1584. HandleId - Supplies the handle.
  1585. EnumParameter - Supplies information about the source and target processes.
  1586. Return Value:
  1587. FALSE, which tells ExEnumHandleTable to continue iterating through the
  1588. handle table.
  1589. --*/
  1590. {
  1591. POBJECT_HEADER ObjectHeader;
  1592. PULONG NumberOfOpenHandles;
  1593. //
  1594. // Get the object header from the table entry and then copy over the information
  1595. //
  1596. ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
  1597. //
  1598. // Dump the leak info for the checked build
  1599. //
  1600. KdPrint(("\tFound object %p (handle %08lx)\n",
  1601. &ObjectHeader->Body,
  1602. HandleId
  1603. ));
  1604. NumberOfOpenHandles = (PULONG)EnumParameter;
  1605. ASSERT(NumberOfOpenHandles);
  1606. ++*NumberOfOpenHandles;
  1607. return( FALSE );
  1608. }
  1609. extern PLIST_ENTRY *ObsSecurityDescriptorCache;
  1610. //
  1611. // Object manager shutdown routine
  1612. //
  1613. VOID
  1614. ObShutdownSystem (
  1615. IN ULONG Phase
  1616. )
  1617. /*++
  1618. Routine Description:
  1619. This routine frees the objects created by the object manager.
  1620. Arguments:
  1621. Return Value:
  1622. None.
  1623. --*/
  1624. {
  1625. switch (Phase) {
  1626. case 0:
  1627. {
  1628. ULONG Bucket,
  1629. Depth,
  1630. SymlinkHitDepth;
  1631. POBJECT_TYPE ObjectType;
  1632. POBJECT_HEADER_NAME_INFO NameInfo;
  1633. KIRQL SaveIrql;
  1634. POBJECT_HEADER ObjectHeader;
  1635. POBJECT_DIRECTORY Directory,
  1636. DescentDirectory;
  1637. POBJECT_DIRECTORY_ENTRY OldDirectoryEntry,
  1638. *DirectoryEntryPtr;
  1639. PVOID Object;
  1640. Directory = ObpRootDirectoryObject;
  1641. DescentDirectory = NULL;
  1642. // The starting depth is completely arbitrary, but not using
  1643. // zero as a valid depth lets us use it as a sentinel to
  1644. // ensure we haven't over-decremented it, and as a check at
  1645. // the end (where it should be one less than its starting value).
  1646. Depth = 1;
  1647. SymlinkHitDepth = 1;
  1648. while (Directory) {
  1649. ASSERT(Depth);
  1650. restart_dir_walk:
  1651. ASSERT(Directory);
  1652. for (Bucket = 0;
  1653. Bucket < NUMBER_HASH_BUCKETS;
  1654. Bucket++) {
  1655. DirectoryEntryPtr = Directory->HashBuckets + Bucket;
  1656. while (*DirectoryEntryPtr) {
  1657. Object = (*DirectoryEntryPtr)->Object;
  1658. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1659. ObjectType = ObjectHeader->Type;
  1660. NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
  1661. if (DescentDirectory) {
  1662. // We're recovering from a descent; we want to
  1663. // iterate forward until we're past the
  1664. // directory which we were just processing.
  1665. if (Object == DescentDirectory) {
  1666. DescentDirectory = NULL;
  1667. if (SymlinkHitDepth > Depth) {
  1668. // We hit a symlink in that descent, which
  1669. // potentially rearranged the buckets in
  1670. // this chain; we need to rescan the
  1671. // entire chain.
  1672. DirectoryEntryPtr =
  1673. Directory->HashBuckets + Bucket;
  1674. SymlinkHitDepth = Depth;
  1675. continue;
  1676. }
  1677. }
  1678. // Either we haven't found the descent dir
  1679. // yet, or we did (and set it to NULL, so
  1680. // we'll stop skipping things), and don't have
  1681. // to deal with a symlink readjustment --
  1682. // either way, march forward.
  1683. DirectoryEntryPtr =
  1684. &(*DirectoryEntryPtr)->ChainLink;
  1685. continue;
  1686. }
  1687. if (ObjectType == ObpTypeObjectType) {
  1688. // We'll clean these up later
  1689. // Keep going down the chain
  1690. DirectoryEntryPtr =
  1691. &(*DirectoryEntryPtr)->ChainLink;
  1692. continue;
  1693. } else if (ObjectType == ObpDirectoryObjectType) {
  1694. // Iteratively descend
  1695. Directory = Object;
  1696. Depth++;
  1697. goto restart_dir_walk;
  1698. } else {
  1699. // It's an object not related to Ob object
  1700. // management; mark it non-permanent, and if
  1701. // it doesn't have any handles, remove it from
  1702. // the directory (delete the name and
  1703. // dereference it once).
  1704. ObpLockObject( ObjectHeader );
  1705. ObjectHeader->Flags &= ~OB_FLAG_PERMANENT_OBJECT;
  1706. ObpUnlockObject( ObjectHeader );
  1707. if (ObjectHeader->HandleCount == 0) {
  1708. OldDirectoryEntry = *DirectoryEntryPtr;
  1709. *DirectoryEntryPtr = OldDirectoryEntry->ChainLink;
  1710. ExFreePool(OldDirectoryEntry);
  1711. if ( !ObjectType->TypeInfo.SecurityRequired ) {
  1712. ObpBeginTypeSpecificCallOut( SaveIrql );
  1713. (ObjectType->TypeInfo.SecurityProcedure)( Object,
  1714. DeleteSecurityDescriptor,
  1715. NULL,
  1716. NULL,
  1717. NULL,
  1718. &ObjectHeader->SecurityDescriptor,
  1719. ObjectType->TypeInfo.PoolType,
  1720. NULL );
  1721. ObpEndTypeSpecificCallOut( SaveIrql, "Security", ObjectType, Object );
  1722. }
  1723. //
  1724. // If this is a symbolic link object then we also need to
  1725. // delete the symbolic link
  1726. //
  1727. if (ObjectType == ObpSymbolicLinkObjectType) {
  1728. SymlinkHitDepth = Depth;
  1729. ObpDeleteSymbolicLinkName( (POBJECT_SYMBOLIC_LINK)Object );
  1730. // Since ObpDeleteSymbolicLinkName may
  1731. // potentially rearrange our buckets,
  1732. // we need to rescan from the
  1733. // beginning of this hash chain.
  1734. DirectoryEntryPtr =
  1735. Directory->HashBuckets + Bucket;
  1736. }
  1737. //
  1738. // Free the name buffer and zero out the name data fields
  1739. //
  1740. ExFreePool( NameInfo->Name.Buffer );
  1741. NameInfo->Name.Buffer = NULL;
  1742. NameInfo->Name.Length = 0;
  1743. NameInfo->Name.MaximumLength = 0;
  1744. NameInfo->Directory = NULL;
  1745. ObDereferenceObject( Object );
  1746. ObDereferenceObject( Directory );
  1747. } else {
  1748. // Keep going down the chain
  1749. DirectoryEntryPtr = &(*DirectoryEntryPtr)->ChainLink;
  1750. }
  1751. }
  1752. } // while *DirectoryObjectPtr
  1753. } // loop over buckets
  1754. // Well -- we're done with this directory. We might have
  1755. // been processing it as a child directory, though -- so
  1756. // if it has a parent, we need to go back up to it, and
  1757. // reset our iteration.
  1758. Depth--;
  1759. ObjectHeader = OBJECT_TO_OBJECT_HEADER(Directory);
  1760. NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
  1761. // We always assign DescentDirectory and Directory here; if
  1762. // the current directory does not have a parent (i.e. it's
  1763. // the root), this will terminate the iteration.
  1764. DescentDirectory = Directory;
  1765. Directory = NameInfo->Directory;
  1766. } // while (Directory)
  1767. ASSERT(Depth == 0);
  1768. break;
  1769. } // Phase 0
  1770. case 1:
  1771. {
  1772. ULONG NumberOfOpenKernelHandles = 0,
  1773. NumberOfOpenSystemHandles = 0;
  1774. //
  1775. // Iterate through the handle tables, and look for existing handles
  1776. //
  1777. KdPrint(("Scanning open system handles...\n"));
  1778. ExEnumHandleTable ( PsInitialSystemProcess->ObjectTable,
  1779. ObpShutdownCloseHandleProcedure,
  1780. &NumberOfOpenSystemHandles,
  1781. NULL );
  1782. ASSERT(NumberOfOpenKernelHandles == MmNumberOfPagingFiles);
  1783. // ISSUE-2000/03/30-earhart: Destroy the kernel handle table?
  1784. // We really can't do this until the paging files are
  1785. // closed... and once we do, we can't really touch pagable
  1786. // memory. Hrm.
  1787. // ExDestroyHandleTable( ObpKernelHandleTable, NULL );
  1788. break;
  1789. } // Phase 1
  1790. default:
  1791. {
  1792. NTSTATUS Status;
  1793. EXHANDLE Handle;
  1794. PHANDLE_TABLE_ENTRY HandleTableEntry;
  1795. UNICODE_STRING RootNameString;
  1796. PLIST_ENTRY Next, Head;
  1797. POBJECT_HEADER_CREATOR_INFO CreatorInfo;
  1798. POBJECT_HEADER ObjectTypeHeader, ObjectHeader;
  1799. POBJECT_HEADER_NAME_INFO NameInfo;
  1800. PVOID Object;
  1801. ASSERT(Phase == 2);
  1802. //
  1803. // Free the SecurityDescriptor chche
  1804. //
  1805. //
  1806. // Remove all types from the object type directory
  1807. //
  1808. Head = &ObpTypeObjectType->TypeList;
  1809. Next = Head->Flink;
  1810. while (Next != Head) {
  1811. PVOID Object;
  1812. //
  1813. // Right after the creator info is the object header. Get\
  1814. // the object header and then see if there is a name
  1815. //
  1816. CreatorInfo = CONTAINING_RECORD( Next,
  1817. OBJECT_HEADER_CREATOR_INFO,
  1818. TypeList );
  1819. ObjectTypeHeader = (POBJECT_HEADER)(CreatorInfo+1);
  1820. Object = &ObjectTypeHeader->Body;
  1821. Next = Next->Flink;
  1822. ObMakeTemporaryObject(Object);
  1823. }
  1824. RtlInitUnicodeString( &RootNameString, L"DosDevices" );
  1825. Status = ObReferenceObjectByName( &RootNameString,
  1826. OBJ_CASE_INSENSITIVE,
  1827. 0L,
  1828. 0,
  1829. ObpSymbolicLinkObjectType,
  1830. KernelMode,
  1831. NULL,
  1832. &Object
  1833. );
  1834. if ( NT_SUCCESS( Status ) ) {
  1835. ObMakeTemporaryObject(Object);
  1836. ObDereferenceObject( Object );
  1837. }
  1838. RtlInitUnicodeString( &RootNameString, L"Global" );
  1839. Status = ObReferenceObjectByName( &RootNameString,
  1840. OBJ_CASE_INSENSITIVE,
  1841. 0L,
  1842. 0,
  1843. ObpSymbolicLinkObjectType,
  1844. KernelMode,
  1845. NULL,
  1846. &Object
  1847. );
  1848. if ( NT_SUCCESS( Status ) ) {
  1849. ObMakeTemporaryObject(Object);
  1850. ObDereferenceObject( Object );
  1851. }
  1852. RtlInitUnicodeString( &RootNameString, L"GLOBALROOT" );
  1853. Status = ObReferenceObjectByName( &RootNameString,
  1854. OBJ_CASE_INSENSITIVE,
  1855. 0L,
  1856. 0,
  1857. ObpSymbolicLinkObjectType,
  1858. KernelMode,
  1859. NULL,
  1860. &Object
  1861. );
  1862. if ( NT_SUCCESS( Status ) ) {
  1863. ObMakeTemporaryObject(Object);
  1864. ObDereferenceObject( Object );
  1865. }
  1866. //
  1867. // Destroy the root directory
  1868. //
  1869. ObDereferenceObject( ObpRootDirectoryObject );
  1870. //
  1871. // Destroy the ObpDirectoryObjectType object
  1872. //
  1873. ObDereferenceObject( ObpDirectoryObjectType );
  1874. //
  1875. // Destroy the ObpSymbolicLinkObjectType
  1876. //
  1877. ObDereferenceObject( ObpSymbolicLinkObjectType );
  1878. //
  1879. // Destroy the type directory object
  1880. //
  1881. ObDereferenceObject( ObpTypeDirectoryObject );
  1882. //
  1883. // Destroy the ObpTypeObjectType
  1884. //
  1885. ObDereferenceObject( ObpTypeObjectType );
  1886. //
  1887. // Free the ObpCachedGrantedAccesses pool
  1888. //
  1889. #if i386
  1890. if (ObpCachedGrantedAccesses) {
  1891. ExFreePool( ObpCachedGrantedAccesses );
  1892. }
  1893. #endif // i386
  1894. } // default Phase (2)
  1895. } // switch (Phase)
  1896. }