VOID NTAPI PspCheckProcessList() { PLIST_ENTRY Entry; KeAcquireGuardedMutex(&PspActiveProcessMutex); DbgPrint("# checking PsActiveProcessHead @ %p\n", &PsActiveProcessHead); for (Entry = PsActiveProcessHead.Flink; Entry != &PsActiveProcessHead; Entry = Entry->Flink) { PEPROCESS Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks); POBJECT_HEADER Header; PVOID Info, HeaderLocation; /* Get the header and assume this is what we'll free */ Header = OBJECT_TO_OBJECT_HEADER(Process); HeaderLocation = Header; /* To find the header, walk backwards from how we allocated */ if ((Info = OBJECT_HEADER_TO_CREATOR_INFO(Header))) { HeaderLocation = Info; } if ((Info = OBJECT_HEADER_TO_NAME_INFO(Header))) { HeaderLocation = Info; } if ((Info = OBJECT_HEADER_TO_HANDLE_INFO(Header))) { HeaderLocation = Info; } if ((Info = OBJECT_HEADER_TO_QUOTA_INFO(Header))) { HeaderLocation = Info; } ExpCheckPoolAllocation(HeaderLocation, NonPagedPool, 'corP'); } KeReleaseGuardedMutex(&PspActiveProcessMutex); }
VOID FASTCALL ObpFreeObject ( IN PVOID Object ) /*++ Routine Description: This routine undoes ObpAllocateObject. It returns the object back to free pool. Arguments: Object - Supplies a pointer to the body of the object being freed. Return Value: None. --*/ { POBJECT_HEADER ObjectHeader; POBJECT_TYPE ObjectType; POBJECT_HEADER_QUOTA_INFO QuotaInfo; POBJECT_HEADER_HANDLE_INFO HandleInfo; POBJECT_HEADER_NAME_INFO NameInfo; POBJECT_HEADER_CREATOR_INFO CreatorInfo; PVOID FreeBuffer; ULONG NonPagedPoolCharge; ULONG PagedPoolCharge; PAGED_CODE(); // // Get the address of the object header. // ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); ObjectType = ObjectHeader->Type; // // Now from the header determine the start of the allocation. We need // to backup based on what precedes the header. The order is very // important and must be the inverse of that used by ObpAllocateObject // FreeBuffer = ObjectHeader; CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader ); if (CreatorInfo != NULL) { FreeBuffer = CreatorInfo; } NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader ); if (NameInfo != NULL) { FreeBuffer = NameInfo; } HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO( ObjectHeader ); if (HandleInfo != NULL) { FreeBuffer = HandleInfo; } QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader ); if (QuotaInfo != NULL) { FreeBuffer = QuotaInfo; } #if DBG // // On a checked build echo out frees // if (ObpShowAllocAndFree) { DbgPrint( "OB: Free %lx (%lx) - Type: %wZ\n", ObjectHeader, ObjectHeader, &ObjectType->Name ); } #endif // // Decrement the number of objects of this type // InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfObjects); // // Check where we were in the object initialization phase. This // flag really only tests if we have charged quota for this object. // This is because the object create info and the quota block charged // are unioned together. // if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) { if (ObjectHeader->ObjectCreateInfo != NULL) { ObpFreeObjectCreateInformation( ObjectHeader->ObjectCreateInfo ); ObjectHeader->ObjectCreateInfo = NULL; } } else { if (ObjectHeader->QuotaBlockCharged != NULL) { if (QuotaInfo != NULL) { PagedPoolCharge = QuotaInfo->PagedPoolCharge + QuotaInfo->SecurityDescriptorCharge; NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge; } else { PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge; if (ObjectHeader->Flags & OB_FLAG_DEFAULT_SECURITY_QUOTA ) { PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA; } NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge; } PsReturnSharedPoolQuota( ObjectHeader->QuotaBlockCharged, PagedPoolCharge, NonPagedPoolCharge ); ObjectHeader->QuotaBlockCharged = NULL; } } if ((HandleInfo != NULL) && ((ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) == 0)) { // // If a handle database has been allocated, then free the memory. // ExFreePool( HandleInfo->HandleCountDataBase ); HandleInfo->HandleCountDataBase = NULL; } // // If a name string buffer has been allocated, then free the memory. // if (NameInfo != NULL && NameInfo->Name.Buffer != NULL) { ExFreePool( NameInfo->Name.Buffer ); NameInfo->Name.Buffer = NULL; } PERFINFO_REMOVE_OBJECT_FROM_ALLOCATED_TYPE_LIST(CreatorInfo, ObjectHeader); // // Trash type field so we don't get far if we attempt to // use a stale object pointer to this object. // // Win64 Note: trash it by zero-extended it. // sign-extension will create a valid kernel address. ObjectHeader->Type = UIntToPtr(0xBAD0B0B0); ExFreePoolWithTag( FreeBuffer, (ObjectType == NULL ? 'TjbO' : ObjectType->Key) | PROTECTED_POOL ); return; }
BOOLEAN INIT_FUNCTION NTAPI ObInitSystem(VOID) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING Name; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; OBP_LOOKUP_CONTEXT Context; HANDLE Handle; PKPRCB Prcb = KeGetCurrentPrcb(); PLIST_ENTRY ListHead, NextEntry; POBJECT_HEADER Header; POBJECT_HEADER_CREATOR_INFO CreatorInfo; POBJECT_HEADER_NAME_INFO NameInfo; NTSTATUS Status; /* Check if this is actually Phase 1 initialization */ if (ObpInitializationPhase != 0) goto ObPostPhase0; /* Initialize the OBJECT_CREATE_INFORMATION List */ ExInitializeSystemLookasideList(&ObpCreateInfoLookasideList, NonPagedPool, sizeof(OBJECT_CREATE_INFORMATION), 'ICbO', 32, &ExSystemLookasideListHead); /* Set the captured UNICODE_STRING Object Name List */ ExInitializeSystemLookasideList(&ObpNameBufferLookasideList, PagedPool, 248, 'MNbO', 16, &ExSystemLookasideListHead); /* Temporarily setup both pointers to the shared list */ Prcb->PPLookasideList[LookasideCreateInfoList].L = &ObpCreateInfoLookasideList; Prcb->PPLookasideList[LookasideCreateInfoList].P = &ObpCreateInfoLookasideList; Prcb->PPLookasideList[LookasideNameBufferList].L = &ObpNameBufferLookasideList; Prcb->PPLookasideList[LookasideNameBufferList].P = &ObpNameBufferLookasideList; /* Initialize the security descriptor cache */ ObpInitSdCache(); /* Initialize the Default Event */ KeInitializeEvent(&ObpDefaultObject, NotificationEvent, TRUE); /* Initialize the Dos Device Map mutex */ KeInitializeGuardedMutex(&ObpDeviceMapLock); /* Setup default access for the system process */ PsGetCurrentProcess()->GrantedAccess = PROCESS_ALL_ACCESS; PsGetCurrentThread()->GrantedAccess = THREAD_ALL_ACCESS; /* Setup the Object Reaper */ ExInitializeWorkItem(&ObpReaperWorkItem, ObpReapObject, NULL); /* Initialize default Quota block */ PsInitializeQuotaSystem(); /* Create kernel handle table */ PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable(NULL); ObpKernelHandleTable = PsGetCurrentProcess()->ObjectTable; /* Create the Type Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"Type"); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS; ObjectTypeInitializer.UseDefaultObject = TRUE; ObjectTypeInitializer.MaintainTypeList = TRUE; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.GenericMapping = ObpTypeMapping; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.DeleteProcedure = ObpDeleteObjectType; ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ObpTypeObjectType); /* Create the Directory Type */ RtlInitUnicodeString(&Name, L"Directory"); ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS; ObjectTypeInitializer.CaseInsensitive = TRUE; ObjectTypeInitializer.MaintainTypeList = FALSE; ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping; ObjectTypeInitializer.DeleteProcedure = NULL; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_DIRECTORY); ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ObDirectoryType); /* Create 'symbolic link' object type */ RtlInitUnicodeString(&Name, L"SymbolicLink"); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_SYMBOLIC_LINK); ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping; ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS; ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink; ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink; ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ObSymbolicLinkType); /* Phase 0 initialization complete */ ObpInitializationPhase++; return TRUE; ObPostPhase0: /* Re-initialize lookaside lists */ ObInit2(); /* Initialize Object Types directory attributes */ RtlInitUnicodeString(&Name, L"\\"); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, SePublicDefaultUnrestrictedSd); /* Create the directory */ Status = NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return FALSE; /* Get a handle to it */ Status = ObReferenceObjectByHandle(Handle, 0, ObDirectoryType, KernelMode, (PVOID*)&ObpRootDirectoryObject, NULL); if (!NT_SUCCESS(Status)) return FALSE; /* Close the extra handle */ Status = NtClose(Handle); if (!NT_SUCCESS(Status)) return FALSE; /* Initialize Object Types directory attributes */ RtlInitUnicodeString(&Name, L"\\KernelObjects"); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); /* Create the directory */ Status = NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return FALSE; /* Close the extra handle */ Status = NtClose(Handle); if (!NT_SUCCESS(Status)) return FALSE; /* Initialize Object Types directory attributes */ RtlInitUnicodeString(&Name, L"\\ObjectTypes"); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); /* Create the directory */ Status = NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return FALSE; /* Get a handle to it */ Status = ObReferenceObjectByHandle(Handle, 0, ObDirectoryType, KernelMode, (PVOID*)&ObpTypeDirectoryObject, NULL); if (!NT_SUCCESS(Status)) return FALSE; /* Close the extra handle */ Status = NtClose(Handle); if (!NT_SUCCESS(Status)) return FALSE; /* Initialize lookup context */ ObpInitializeLookupContext(&Context); /* Lock it */ ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context); /* Loop the object types */ ListHead = &ObpTypeObjectType->TypeList; NextEntry = ListHead->Flink; while (ListHead != NextEntry) { /* Get the creator info from the list */ CreatorInfo = CONTAINING_RECORD(NextEntry, OBJECT_HEADER_CREATOR_INFO, TypeList); /* Recover the header and the name header from the creator info */ Header = (POBJECT_HEADER)(CreatorInfo + 1); NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header); /* Make sure we have a name, and aren't inserted yet */ if ((NameInfo) && !(NameInfo->Directory)) { /* Do the initial lookup to setup the context */ if (!ObpLookupEntryDirectory(ObpTypeDirectoryObject, &NameInfo->Name, OBJ_CASE_INSENSITIVE, FALSE, &Context)) { /* Insert this object type */ ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header); } } /* Move to the next entry */ NextEntry = NextEntry->Flink; } /* Cleanup after lookup */ ObpReleaseLookupContext(&Context); /* Initialize DOS Devices Directory and related Symbolic Links */ Status = ObpCreateDosDevicesDirectory(); if (!NT_SUCCESS(Status)) return FALSE; return TRUE; }
BOOLEAN ObInitSystem( VOID ) /*++ Routine Description: This function performs the system initialization for the object manager. The object manager data structures are self describing with the exception of the root directory, the type object type and the directory object type. The initialization code then constructs these objects by hand to get the ball rolling. Arguments: None. Return Value: TRUE if successful and FALSE if an error occurred. The following errors can occur: - insufficient memory --*/ { USHORT CreateInfoMaxDepth; USHORT NameBufferMaxDepth; ULONG RegionSegmentSize; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING TypeTypeName; UNICODE_STRING SymbolicLinkTypeName; UNICODE_STRING DosDevicesDirectoryName; UNICODE_STRING DirectoryTypeName; UNICODE_STRING RootDirectoryName; UNICODE_STRING TypeDirectoryName; NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE RootDirectoryHandle; HANDLE TypeDirectoryHandle; PLIST_ENTRY Next, Head; POBJECT_HEADER ObjectTypeHeader; POBJECT_HEADER_CREATOR_INFO CreatorInfo; POBJECT_HEADER_NAME_INFO NameInfo; MM_SYSTEMSIZE SystemSize; SECURITY_DESCRIPTOR AuditSd; PSECURITY_DESCRIPTOR EffectiveSd; PACL AuditAllAcl; UCHAR AuditAllBuffer[250]; // Ample room for the ACL ULONG AuditAllLength; PACE_HEADER Ace; // // PHASE 0 Initialization // if (InitializationPhase == 0) { // // Determine the the size of the object creation and the name buffer // lookaside lists. // SystemSize = MmQuerySystemSize(); if (SystemSize == MmLargeSystem) { if (MmIsThisAnNtAsSystem()) { CreateInfoMaxDepth = 64; NameBufferMaxDepth = 32; } else { CreateInfoMaxDepth = 32; NameBufferMaxDepth = 16; } } else { CreateInfoMaxDepth = 3; NameBufferMaxDepth = 3; } // // Initialize the object creation lookaside list. // ExInitializeNPagedLookasideList(&ObpCreateInfoLookasideList, NULL, NULL, 0, sizeof(OBJECT_CREATE_INFORMATION), 'iCbO', CreateInfoMaxDepth); // // Initialize the name buffer lookaside list. // ExInitializeNPagedLookasideList(&ObpNameBufferLookasideList, NULL, NULL, 0, OBJECT_NAME_BUFFER_SIZE, 'mNbO', NameBufferMaxDepth); InitializeListHead( &ObpRemoveObjectQueue ); // // Initialize security descriptor cache // ObpInitSecurityDescriptorCache(); KeInitializeMutant( &ObpInitKillMutant, FALSE ); KeInitializeEvent( &ObpDefaultObject, NotificationEvent, TRUE ); KeInitializeSpinLock( &ObpLock ); PsGetCurrentProcess()->GrantedAccess = PROCESS_ALL_ACCESS; PsGetCurrentThread()->GrantedAccess = THREAD_ALL_ACCESS; // // Initialize the quota block // KeInitializeSpinLock(&PspDefaultQuotaBlock.QuotaLock); PspDefaultQuotaBlock.ReferenceCount = 1; PspDefaultQuotaBlock.QuotaPoolLimit[PagedPool] = (ULONG)-1; PspDefaultQuotaBlock.QuotaPoolLimit[NonPagedPool] = (ULONG)-1; PspDefaultQuotaBlock.PagefileLimit = (ULONG)-1; PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock; PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable( NULL, 0, 0 ); RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer ) ); ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer ); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.PoolType = NonPagedPool; RtlInitUnicodeString( &TypeTypeName, L"Type" ); ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = ObpTypeMapping; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_TYPE ); ObjectTypeInitializer.MaintainTypeList = TRUE; ObjectTypeInitializer.UseDefaultObject = TRUE; ObCreateObjectType( &TypeTypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObpTypeObjectType ); RtlInitUnicodeString( &DirectoryTypeName, L"Directory" ); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_DIRECTORY ); ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping; ObjectTypeInitializer.MaintainTypeList = FALSE; ObCreateObjectType( &DirectoryTypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObpDirectoryObjectType ); RtlInitUnicodeString( &SymbolicLinkTypeName, L"SymbolicLink" ); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_SYMBOLIC_LINK ); ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS; ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping; ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink; ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink; ObCreateObjectType( &SymbolicLinkTypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObpSymbolicLinkObjectType ); ExInitializeResourceLite( &ObpRootDirectoryMutex ); #if i386 && !FPO ObpCurCachedGrantedAccessIndex = 0; ObpMaxCachedGrantedAccessIndex = PAGE_SIZE / sizeof( ACCESS_MASK ); ObpCachedGrantedAccesses = ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE, 'gAbO' ); #endif // i386 && !FPO #if DBG ObpCreateObjectEventId = RtlCreateEventId( NULL, 0, "CreateObject", 6, RTL_EVENT_ULONG_PARAM, "Object", 0, RTL_EVENT_PUNICODE_STRING_PARAM, "Type", 0, RTL_EVENT_ULONG_PARAM, "PagedPool", 0, RTL_EVENT_ULONG_PARAM, "NonPagedPool", 0, RTL_EVENT_PUNICODE_STRING_PARAM, "Name", 0, RTL_EVENT_FLAGS_PARAM, "", 5, OBJ_INHERIT, "Inherit", OBJ_PERMANENT, "Permanent", OBJ_OPENIF, "OpenIf", OBJ_CASE_INSENSITIVE, "CaseInsenitive", OBJ_EXCLUSIVE, "Exclusive" ); ObpFreeObjectEventId = RtlCreateEventId( NULL, 0, "FreeObject", 3, RTL_EVENT_ULONG_PARAM, "Object", 0, RTL_EVENT_ULONG_PARAM, "Type", 0, RTL_EVENT_PUNICODE_STRING_PARAM, "Name", 0 ); #endif // DBG } // End of Phase 0 Initializtion // // PHASE 1 Initialization // if (InitializationPhase == 1) { EffectiveSd = SePublicDefaultSd; // // This code is only executed if base auditing is turned on. // if ((ObpAuditBaseDirectories != 0) || (ObpAuditBaseObjects != 0)) { // // build an SACL to audit // AuditAllAcl = (PACL)AuditAllBuffer; AuditAllLength = (ULONG)sizeof(ACL) + ((ULONG)sizeof(SYSTEM_AUDIT_ACE)) + SeLengthSid(SeWorldSid); ASSERT( sizeof(AuditAllBuffer) > AuditAllLength ); Status = RtlCreateAcl( AuditAllAcl, AuditAllLength, ACL_REVISION2); ASSERT( NT_SUCCESS(Status) ); Status = RtlAddAuditAccessAce ( AuditAllAcl, ACL_REVISION2, GENERIC_ALL, SeWorldSid, TRUE, TRUE //Audit success and failure ); ASSERT( NT_SUCCESS(Status) ); Status = RtlGetAce( AuditAllAcl, 0, (PVOID)&Ace ); ASSERT( NT_SUCCESS(Status) ); if (ObpAuditBaseDirectories != 0) { Ace->AceFlags |= (CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); } if (ObpAuditBaseObjects != 0) { Ace->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); } // // Now create a security descriptor that looks just like // the public default, but has auditing in it as well. EffectiveSd = (PSECURITY_DESCRIPTOR)&AuditSd; Status = RtlCreateSecurityDescriptor( EffectiveSd, SECURITY_DESCRIPTOR_REVISION1 ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetDaclSecurityDescriptor( EffectiveSd, TRUE, // DaclPresent SePublicDefaultDacl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); Status = RtlSetSaclSecurityDescriptor( EffectiveSd, TRUE, // DaclPresent AuditAllAcl, FALSE // DaclDefaulted ); ASSERT( NT_SUCCESS(Status) ); } // // We only need to use the EffectiveSd on the root. The SACL // will be inherited by all other objects. // RtlInitUnicodeString( &RootDirectoryName, L"\\" ); InitializeObjectAttributes( &ObjectAttributes, &RootDirectoryName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, EffectiveSd ); Status = NtCreateDirectoryObject( &RootDirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = ObReferenceObjectByHandle( RootDirectoryHandle, 0, ObpDirectoryObjectType, KernelMode, (PVOID *)&ObpRootDirectoryObject, NULL ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = NtClose( RootDirectoryHandle ); if (!NT_SUCCESS( Status )) { return( FALSE ); } RtlInitUnicodeString( &TypeDirectoryName, L"\\ObjectTypes" ); InitializeObjectAttributes( &ObjectAttributes, &TypeDirectoryName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL ); Status = NtCreateDirectoryObject( &TypeDirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = ObReferenceObjectByHandle( TypeDirectoryHandle, 0, ObpDirectoryObjectType, KernelMode, (PVOID *)&ObpTypeDirectoryObject, NULL ); if (!NT_SUCCESS( Status )) { return( FALSE ); } Status = NtClose( TypeDirectoryHandle ); if (!NT_SUCCESS( Status )) { return( FALSE ); } ObpEnterRootDirectoryMutex(); Head = &ObpTypeObjectType->TypeList; Next = Head->Flink; while (Next != Head) { CreatorInfo = CONTAINING_RECORD( Next, OBJECT_HEADER_CREATOR_INFO, TypeList ); ObjectTypeHeader = (POBJECT_HEADER)(CreatorInfo+1); NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectTypeHeader ); if (NameInfo != NULL && NameInfo->Directory == NULL) { if (!ObpLookupDirectoryEntry( ObpTypeDirectoryObject, &NameInfo->Name, OBJ_CASE_INSENSITIVE ) ) { ObpInsertDirectoryEntry( ObpTypeDirectoryObject, &ObjectTypeHeader->Body ); } } Next = Next->Flink; } ObpLeaveRootDirectoryMutex(); // // Create \DosDevices object directory for drive letters and Win32 device names // Status = ObpCreateDosDevicesDirectory(); if (!NT_SUCCESS( Status )) { return FALSE; } } return TRUE; }
VOID ObpHandleDosDeviceName( POBJECT_SYMBOLIC_LINK SymbolicLink ) /*++ Routine Description: This routine does extra processing symbolic links being created in the \?? object directory. This processing consists of: 1. Determine if the name of the symbolic link is of the form \??\x: where x can be any upper or lower case letter. If this is the case then we need to set the bit in KUSER_SHARED_DATA.DosDeviceMap to indicate that the drive letter exists. We also set KUSER_SHARED_DATA.DosDeviceDriveType to unknown for now. 2. Process the link target, trying to resolve it into a pointer to an object other than a object directory object. All object directories traversed must grant world traverse access other wise we bail out. If we successfully find a non object directory object, then reference the object pointer and store it in the symbolic link object, along with a remaining string if any. ObpLookupObjectName will used this cache object pointer to short circuit the name lookup directly to the cached object's parse routine. For any object directory objects traversed along the way, increment their symbolic link SymbolicLinkUsageCount field. This field is used whenever an object directory is deleted or its security is changed such that it no longer grants world traverse access. In either case, if the field is non-zero we walk all the symbolic links and resnap them. Arguments: SymbolicLink - pointer to symbolic link object being created. Name - pointer to the name of this symbolic link Return Value: None. --*/ { POBJECT_HEADER ObjectHeader; POBJECT_HEADER_NAME_INFO NameInfo; WCHAR DosDeviceDriveLetter; ULONG DosDeviceDriveIndex; // // Now see if this symbolic link is being created in the \?? object directory // Since we are only called from NtCreateSymbolicLinkObject, after the handle // to this symbolic link has been created but before it is returned to the caller // the handle can't be closed while we are executing, unless via a random close // So no need to hold the type specific mutex while we look at the name. // ObjectHeader = OBJECT_TO_OBJECT_HEADER( SymbolicLink ); NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader ); if (NameInfo == NULL || NameInfo->Directory != ObpDosDevicesDirectoryObject) { return; } // // Here if we are creating a symbolic link in the \?? object directory // See if this is a drive letter definition. If so set the bit in // KUSER_SHARED_DATA.DosDeviceMap // DosDeviceDriveIndex = 0; if (NameInfo->Name.Length == 2 * sizeof( WCHAR ) && NameInfo->Name.Buffer[ 1 ] == L':' ) { DosDeviceDriveLetter = RtlUpcaseUnicodeChar( NameInfo->Name.Buffer[ 0 ] ); if (DosDeviceDriveLetter >= L'A' && DosDeviceDriveLetter <= L'Z') { DosDeviceDriveIndex = DosDeviceDriveLetter - L'A'; DosDeviceDriveIndex += 1; SymbolicLink->DosDeviceDriveIndex = DosDeviceDriveIndex; } } // // Now traverse the target path seeing if we can snap the link now. // ObpEnterRootDirectoryMutex(); ObpEnterObjectTypeMutex( ObpSymbolicLinkObjectType ); ObpProcessDosDeviceSymbolicLink( SymbolicLink, CREATE_SYMBOLIC_LINK ); ObpLeaveRootDirectoryMutex(); ObpLeaveObjectTypeMutex( ObpSymbolicLinkObjectType ); return; }