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.

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