diff --git a/reactos/ntoskrnl/ob/obdir.c b/reactos/ntoskrnl/ob/obdir.c index acf3911f24e..92229c96dfc 100644 --- a/reactos/ntoskrnl/ob/obdir.c +++ b/reactos/ntoskrnl/ob/obdir.c @@ -1,626 +1,626 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/ob/dirobj.c - * PURPOSE: Manages the Object Manager's Directory Implementation, - * such as functions for addition, deletion and lookup into - * the Object Manager's namespace. These routines are separate - * from the Namespace Implementation because they are largely - * independent and could be used for other namespaces. - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - * Thomas Weidenmueller (w3seek@reactos.org) - */ - -/* INCLUDES ***************************************************************/ - -#define NTDDI_VERSION NTDDI_WS03 -#include -#define NDEBUG -#include - -#define OBP_PROFILE -#ifdef OBP_PROFILE - -LARGE_INTEGER ObpProfileTime; -BOOLEAN ObpProfileComplete; - -#define ObpStartProfile() \ - LARGE_INTEGER StartTime; \ - LARGE_INTEGER EndTime; \ - StartTime = KeQueryPerformanceCounter(NULL); - -#define ObpEndProfile() \ - EndTime = KeQueryPerformanceCounter(NULL); \ - ObpProfileTime.QuadPart += (EndTime.QuadPart - \ - StartTime.QuadPart); - -#define ObpCompleteProfile() \ - if (!wcscmp(Name, L"NlsSectionCP1252") && \ - !ObpProfileComplete) \ - { \ - DPRINT1("******************************\n");\ - DPRINT1("Obp Profiling1 Complete: %I64d\n", \ - ObpProfileTime.QuadPart); \ - DPRINT1("******************************\n");\ - ObpProfileComplete = TRUE; \ - } - -#else - -#define ObpStartProfile() -#define ObpEndProfile() -#define ObpCompleteProfile() - -#endif - -POBJECT_TYPE ObDirectoryType = NULL; - -/* PRIVATE FUNCTIONS ******************************************************/ - -BOOLEAN -NTAPI -ObpInsertEntryDirectory(IN POBJECT_DIRECTORY Parent, - IN POBP_LOOKUP_CONTEXT Context, - IN POBJECT_HEADER ObjectHeader) -{ - POBJECT_DIRECTORY_ENTRY *AllocatedEntry; - POBJECT_DIRECTORY_ENTRY NewEntry; - POBJECT_HEADER_NAME_INFO HeaderNameInfo; - - /* Make sure we have a name */ - ASSERT(ObjectHeader->NameInfoOffset != 0); - - /* Validate the context */ - if ((Context->Object) || !(Context->DirectoryLocked) || !Parent) - { - DbgPrint("OB: ObpInsertEntryDirectory - invalid context %p %ld\n", - Context, Context->DirectoryLocked); - DbgBreakPoint(); - return FALSE; - } - - /* Allocate a new Directory Entry */ - NewEntry = ExAllocatePoolWithTag(PagedPool, - sizeof(OBJECT_DIRECTORY_ENTRY), - TAG('O', 'b', 'D', 'i')); - if (!NewEntry) return FALSE; - - /* Save the hash */ - NewEntry->HashValue = Context->HashValue; - - /* Get the Object Name Information */ - HeaderNameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); - - /* Get the Allocated entry */ - AllocatedEntry = &Parent->HashBuckets[Context->HashIndex]; - DPRINT("ADD: Allocated Entry: %p. NewEntry: %p\n", AllocatedEntry, NewEntry); - DPRINT("ADD: Name: %wZ, Hash: %lx\n", &HeaderNameInfo->Name, Context->HashIndex); - DPRINT("ADD: Parent: %p. Name: %wZ\n", - Parent, - HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Parent)) ? - &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Parent))->Name : NULL); - - /* Set it */ - NewEntry->ChainLink = *AllocatedEntry; - *AllocatedEntry = NewEntry; - - /* Associate the Object */ - NewEntry->Object = &ObjectHeader->Body; - - /* Associate the Directory */ - HeaderNameInfo->Directory = Parent; - return TRUE; -} - -PVOID -NTAPI -ObpLookupEntryDirectory(IN POBJECT_DIRECTORY Directory, - IN PUNICODE_STRING Name, - IN ULONG Attributes, - IN UCHAR SearchShadow, - IN POBP_LOOKUP_CONTEXT Context) -{ - BOOLEAN CaseInsensitive = FALSE; - POBJECT_HEADER_NAME_INFO HeaderNameInfo; - ULONG HashValue; - ULONG HashIndex; - LONG TotalChars; - WCHAR CurrentChar; - POBJECT_DIRECTORY_ENTRY *AllocatedEntry; - POBJECT_DIRECTORY_ENTRY *LookupBucket; - POBJECT_DIRECTORY_ENTRY CurrentEntry; - PVOID FoundObject = NULL; - PWSTR Buffer; - PAGED_CODE(); - - /* Always disable this until we have LUID Device Maps */ - SearchShadow = FALSE; - - /* Fail the following cases */ - TotalChars = Name->Length / sizeof(WCHAR); - if (!(Directory) || !(Name) || !(Name->Buffer) || !(TotalChars)) - { - goto Quickie; - } - - /* Set up case-sensitivity */ - if (Attributes & OBJ_CASE_INSENSITIVE) CaseInsensitive = TRUE; - - /* Create the Hash */ - Buffer = Name->Buffer; - for (HashValue = 0; TotalChars; TotalChars--) - { - /* Go to the next Character */ - CurrentChar = *Buffer++; - - /* Prepare the Hash */ - HashValue += (HashValue << 1) + (HashValue >> 1); - - /* Create the rest based on the name */ - if (CurrentChar < 'a') HashValue += CurrentChar; - else if (CurrentChar > 'z') HashValue += RtlUpcaseUnicodeChar(CurrentChar); - else HashValue += (CurrentChar - ('a'-'A')); - } - - /* Merge it with our number of hash buckets */ - HashIndex = HashValue % 37; - DPRINT("LOOKUP: ObjectName: %wZ\n", Name); - DPRINT("LOOKUP: Generated Hash: 0x%x. Generated Id: 0x%x\n", HashValue, HashIndex); - - /* Save the result */ - Context->HashValue = HashValue; - Context->HashIndex = HashIndex; - - /* Get the root entry and set it as our lookup bucket */ - AllocatedEntry = &Directory->HashBuckets[HashIndex]; - LookupBucket = AllocatedEntry; - DPRINT("LOOKUP: Allocated Entry: %p. LookupBucket: %p\n", AllocatedEntry, LookupBucket); - - /* Check if the directory is already locked */ - if (!Context->DirectoryLocked) - { - /* Lock it */ - KeEnterCriticalRegion(); - ExAcquireResourceSharedLite(&Directory->Lock, TRUE); - Context->LockStateSignature = 0xDDDD1234; - } - - /* Start looping */ - while ((CurrentEntry = *AllocatedEntry)) - { - /* Do the hashes match? */ - DPRINT("CurrentEntry: %p. CurrentHash: %lx\n", CurrentEntry, CurrentEntry->HashValue); - if (CurrentEntry->HashValue == HashValue) - { - /* Make sure that it has a name */ - ASSERT(BODY_TO_HEADER(CurrentEntry->Object)->NameInfoOffset != 0); - - /* Get the name information */ - HeaderNameInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(CurrentEntry->Object)); - - /* Do the names match? */ - DPRINT("NameCheck: %wZ, %wZ\n", Name, &HeaderNameInfo->Name); - if ((Name->Length == HeaderNameInfo->Name.Length) && - (RtlEqualUnicodeString(Name, &HeaderNameInfo->Name, CaseInsensitive))) - { - DPRINT("Found Name Match\n"); - break; - } - } - - /* Move to the next entry */ - AllocatedEntry = &CurrentEntry->ChainLink; - } - - /* Check if we still have an entry */ - if (CurrentEntry) - { - /* Set this entry as the first, to speed up incoming insertion */ - if (AllocatedEntry != LookupBucket) - { - /* Set the Current Entry */ - *AllocatedEntry = CurrentEntry->ChainLink; - - /* Link to the old Hash Entry */ - CurrentEntry->ChainLink = *LookupBucket; - - /* Set the new Hash Entry */ - *LookupBucket = CurrentEntry; - } - - /* Save the found object */ - FoundObject = CurrentEntry->Object; - if (!FoundObject) goto Quickie; - - /* Add a reference to the object */ - ObReferenceObject(FoundObject); - } - - /* Check if the directory was unlocked (which means we locked it) */ - if (!Context->DirectoryLocked) - { - /* Lock it */ - ExReleaseResourceLite(&Directory->Lock); - KeLeaveCriticalRegion(); - Context->LockStateSignature = 0xEEEE1234; - } - -Quickie: - /* Return the object we found */ - DPRINT("Object Found: %p Context: %p\n", FoundObject, Context); - Context->Object = FoundObject; - return FoundObject; -} - -BOOLEAN -NTAPI -ObpDeleteEntryDirectory(POBP_LOOKUP_CONTEXT Context) -{ - POBJECT_DIRECTORY Directory; - POBJECT_DIRECTORY_ENTRY *AllocatedEntry; - POBJECT_DIRECTORY_ENTRY CurrentEntry; - - /* Get the Directory */ - Directory = Context->Directory; - if (!Directory) return FALSE; - - /* Get the Entry */ - AllocatedEntry = &Directory->HashBuckets[Context->HashIndex]; - CurrentEntry = *AllocatedEntry; - DPRINT("DEL: Parent: %p, Hash: %lx, AllocatedEntry: %p, CurrentEntry: %p\n", - Directory, Context->HashIndex, AllocatedEntry, CurrentEntry); - - /* Unlink the Entry */ - *AllocatedEntry = CurrentEntry->ChainLink; - CurrentEntry->ChainLink = NULL; - - /* Free it */ - ExFreePool(CurrentEntry); - - /* Return */ - return TRUE; -} - -NTSTATUS -NTAPI -ObpParseDirectory(PVOID Object, - PVOID * NextObject, - PUNICODE_STRING FullPath, - PWSTR * Path, - ULONG Attributes, - POBP_LOOKUP_CONTEXT Context) -{ - PWSTR Start; - PWSTR End; - PVOID FoundObject; - //KIRQL oldlvl; - UNICODE_STRING StartUs; - - *NextObject = NULL; - - if ((*Path) == NULL) - { - return STATUS_UNSUCCESSFUL; - } - - Start = *Path; - if (*Start == L'\\') - Start++; - - End = wcschr(Start, L'\\'); - if (End != NULL) - { - *End = 0; - } - - //KeAcquireSpinLock(&(((PDIRECTORY_OBJECT)Object)->Lock), &oldlvl); - RtlInitUnicodeString(&StartUs, Start); - Context->DirectoryLocked = TRUE; - Context->Directory = Object; - FoundObject = ObpLookupEntryDirectory(Object, &StartUs, Attributes, FALSE, Context); - if (FoundObject == NULL) - { - //KeReleaseSpinLock(&(((PDIRECTORY_OBJECT)Object)->Lock), oldlvl); - if (End != NULL) - { - *End = L'\\'; - } - return STATUS_UNSUCCESSFUL; - } - - ObReferenceObjectByPointer(FoundObject, - STANDARD_RIGHTS_REQUIRED, - NULL, - UserMode); - //KeReleaseSpinLock(&(((PDIRECTORY_OBJECT)Object)->Lock), oldlvl); - if (End != NULL) - { - *End = L'\\'; - *Path = End; - } - else - { - *Path = NULL; - } - - *NextObject = FoundObject; - - return STATUS_SUCCESS; -} - -/* FUNCTIONS **************************************************************/ - -/*++ -* @name NtOpenDirectoryObject -* @implemented NT4 -* -* The NtOpenDirectoryObject opens a namespace directory object. -* -* @param DirectoryHandle -* Variable which receives the directory handle. -* -* @param DesiredAccess -* Desired access to the directory. -* -* @param ObjectAttributes -* Structure describing the directory. -* -* @return STATUS_SUCCESS or appropriate error value. -* -* @remarks None. -* -*--*/ -NTSTATUS -NTAPI -NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) -{ - HANDLE hDirectory; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForWriteHandle(DirectoryHandle); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - DPRINT1("NtOpenDirectoryObject failed, Status: 0x%x\n", Status); - return Status; - } - } - - Status = ObOpenObjectByName(ObjectAttributes, - ObDirectoryType, - NULL, - PreviousMode, - DesiredAccess, - NULL, - &hDirectory); - if(NT_SUCCESS(Status)) - { - _SEH_TRY - { - *DirectoryHandle = hDirectory; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - - return Status; -} - -/*++ -* @name NtQueryDirectoryObject -* @implemented NT4 -* -* The NtQueryDirectoryObject Reads information from a directory in -* the system namespace. -* -* @param DirectoryHandle -* Handle obtained with NtOpenDirectoryObject which -* must grant DIRECTORY_QUERY access to the directory object. -* -* @param Buffer -* Buffer to hold the data read. -* -* @param BufferLength -* Size of the buffer in bytes. -* -* @param ReturnSingleEntry -* When TRUE, only 1 entry is written in DirObjInformation; -* otherwise as many as will fit in the buffer. -* -* @param RestartScan -* If TRUE start reading at index 0. -* If FALSE start reading at the index specified by *ObjectIndex. -* -* @param Context -* Zero based index into the directory, interpretation -* depends on RestartScan. -* -* @param ReturnLength -* Caller supplied storage for the number of bytes -* written (or NULL). -* -* @return STATUS_SUCCESS or appropriate error value. -* -* @remarks Although you can iterate over the directory by calling this -* function multiple times, the directory is unlocked between -* calls. This means that another thread can change the directory -* and so iterating doesn't guarantee a consistent picture of the -* directory. Best thing is to retrieve all directory entries in -* one call. -* -*--*/ -NTSTATUS -NTAPI -NtQueryDirectoryObject(IN HANDLE DirectoryHandle, - OUT PVOID Buffer, - IN ULONG BufferLength, - IN BOOLEAN ReturnSingleEntry, - IN BOOLEAN RestartScan, - IN OUT PULONG Context, - OUT PULONG ReturnLength OPTIONAL) -{ - POBJECT_DIRECTORY Directory; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - ULONG SkipEntries = 0; - NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - /* a test showed that the Buffer pointer just has to be 16 bit aligned, - propably due to the fact that most information that needs to be copied - is unicode strings */ - ProbeForWrite(Buffer, BufferLength, sizeof(WCHAR)); - ProbeForWriteUlong(Context); - if(!RestartScan) - { - SkipEntries = *Context; - } - if(ReturnLength != NULL) - { - ProbeForWriteUlong(ReturnLength); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - DPRINT1("NtQueryDirectoryObject failed, Status: 0x%x\n", Status); - return Status; - } - } - else if(!RestartScan) - { - SkipEntries = *Context; - } - - Status = ObReferenceObjectByHandle(DirectoryHandle, - DIRECTORY_QUERY, - ObDirectoryType, - PreviousMode, - (PVOID*)&Directory, - NULL); - if(NT_SUCCESS(Status)) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - - return Status; -} - -/*++ -* @name NtCreateDirectoryObject -* @implemented NT4 -* -* The NtOpenDirectoryObject creates or opens a directory object. -* -* @param DirectoryHandle -* Variable which receives the directory handle. -* -* @param DesiredAccess -* Desired access to the directory. -* -* @param ObjectAttributes -* Structure describing the directory. -* -* @return STATUS_SUCCESS or appropriate error value. -* -* @remarks None. -* -*--*/ -NTSTATUS -NTAPI -NtCreateDirectoryObject(OUT PHANDLE DirectoryHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) -{ - POBJECT_DIRECTORY Directory; - HANDLE hDirectory; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, " - "DesiredAccess %x, ObjectAttributes %x\n", - DirectoryHandle, DesiredAccess, ObjectAttributes); - - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForWriteHandle(DirectoryHandle); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - DPRINT1("NtCreateDirectoryObject failed, Status: 0x%x\n", Status); - return Status; - } - } - - Status = ObCreateObject(PreviousMode, - ObDirectoryType, - ObjectAttributes, - PreviousMode, - NULL, - sizeof(OBJECT_DIRECTORY), - 0, - 0, - (PVOID*)&Directory); - - if(NT_SUCCESS(Status)) - { - Status = ObInsertObject((PVOID)Directory, - NULL, - DesiredAccess, - 0, - NULL, - &hDirectory); - if(NT_SUCCESS(Status)) - { - _SEH_TRY - { - *DirectoryHandle = hDirectory; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - - ObDereferenceObject(Directory); - } - - return Status; -} - -/* EOF */ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ob/dirobj.c + * PURPOSE: Manages the Object Manager's Directory Implementation, + * such as functions for addition, deletion and lookup into + * the Object Manager's namespace. These routines are separate + * from the Namespace Implementation because they are largely + * independent and could be used for other namespaces. + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Thomas Weidenmueller (w3seek@reactos.org) + */ + +/* INCLUDES ***************************************************************/ + +#define NTDDI_VERSION NTDDI_WS03 +#include +#define NDEBUG +#include + +#define OBP_PROFILE +#ifdef OBP_PROFILE + +LARGE_INTEGER ObpProfileTime; +BOOLEAN ObpProfileComplete; + +#define ObpStartProfile() \ + LARGE_INTEGER StartTime; \ + LARGE_INTEGER EndTime; \ + StartTime = KeQueryPerformanceCounter(NULL); + +#define ObpEndProfile() \ + EndTime = KeQueryPerformanceCounter(NULL); \ + ObpProfileTime.QuadPart += (EndTime.QuadPart - \ + StartTime.QuadPart); + +#define ObpCompleteProfile() \ + if (!wcscmp(Name, L"NlsSectionCP1252") && \ + !ObpProfileComplete) \ + { \ + DPRINT1("******************************\n");\ + DPRINT1("Obp Profiling1 Complete: %I64d\n", \ + ObpProfileTime.QuadPart); \ + DPRINT1("******************************\n");\ + ObpProfileComplete = TRUE; \ + } + +#else + +#define ObpStartProfile() +#define ObpEndProfile() +#define ObpCompleteProfile() + +#endif + +POBJECT_TYPE ObDirectoryType = NULL; + +/* PRIVATE FUNCTIONS ******************************************************/ + +BOOLEAN +NTAPI +ObpInsertEntryDirectory(IN POBJECT_DIRECTORY Parent, + IN POBP_LOOKUP_CONTEXT Context, + IN POBJECT_HEADER ObjectHeader) +{ + POBJECT_DIRECTORY_ENTRY *AllocatedEntry; + POBJECT_DIRECTORY_ENTRY NewEntry; + POBJECT_HEADER_NAME_INFO HeaderNameInfo; + + /* Make sure we have a name */ + ASSERT(ObjectHeader->NameInfoOffset != 0); + + /* Validate the context */ + if ((Context->Object) || !(Context->DirectoryLocked) || !Parent) + { + DbgPrint("OB: ObpInsertEntryDirectory - invalid context %p %ld\n", + Context, Context->DirectoryLocked); + DbgBreakPoint(); + return FALSE; + } + + /* Allocate a new Directory Entry */ + NewEntry = ExAllocatePoolWithTag(PagedPool, + sizeof(OBJECT_DIRECTORY_ENTRY), + TAG('O', 'b', 'D', 'i')); + if (!NewEntry) return FALSE; + + /* Save the hash */ + NewEntry->HashValue = Context->HashValue; + + /* Get the Object Name Information */ + HeaderNameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + + /* Get the Allocated entry */ + AllocatedEntry = &Parent->HashBuckets[Context->HashIndex]; + DPRINT("ADD: Allocated Entry: %p. NewEntry: %p\n", AllocatedEntry, NewEntry); + DPRINT("ADD: Name: %wZ, Hash: %lx\n", &HeaderNameInfo->Name, Context->HashIndex); + DPRINT("ADD: Parent: %p. Name: %wZ\n", + Parent, + HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Parent)) ? + &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Parent))->Name : NULL); + + /* Set it */ + NewEntry->ChainLink = *AllocatedEntry; + *AllocatedEntry = NewEntry; + + /* Associate the Object */ + NewEntry->Object = &ObjectHeader->Body; + + /* Associate the Directory */ + HeaderNameInfo->Directory = Parent; + return TRUE; +} + +PVOID +NTAPI +ObpLookupEntryDirectory(IN POBJECT_DIRECTORY Directory, + IN PUNICODE_STRING Name, + IN ULONG Attributes, + IN UCHAR SearchShadow, + IN POBP_LOOKUP_CONTEXT Context) +{ + BOOLEAN CaseInsensitive = FALSE; + POBJECT_HEADER_NAME_INFO HeaderNameInfo; + ULONG HashValue; + ULONG HashIndex; + LONG TotalChars; + WCHAR CurrentChar; + POBJECT_DIRECTORY_ENTRY *AllocatedEntry; + POBJECT_DIRECTORY_ENTRY *LookupBucket; + POBJECT_DIRECTORY_ENTRY CurrentEntry; + PVOID FoundObject = NULL; + PWSTR Buffer; + PAGED_CODE(); + + /* Always disable this until we have LUID Device Maps */ + SearchShadow = FALSE; + + /* Fail the following cases */ + TotalChars = Name->Length / sizeof(WCHAR); + if (!(Directory) || !(Name) || !(Name->Buffer) || !(TotalChars)) + { + goto Quickie; + } + + /* Set up case-sensitivity */ + if (Attributes & OBJ_CASE_INSENSITIVE) CaseInsensitive = TRUE; + + /* Create the Hash */ + Buffer = Name->Buffer; + for (HashValue = 0; TotalChars; TotalChars--) + { + /* Go to the next Character */ + CurrentChar = *Buffer++; + + /* Prepare the Hash */ + HashValue += (HashValue << 1) + (HashValue >> 1); + + /* Create the rest based on the name */ + if (CurrentChar < 'a') HashValue += CurrentChar; + else if (CurrentChar > 'z') HashValue += RtlUpcaseUnicodeChar(CurrentChar); + else HashValue += (CurrentChar - ('a'-'A')); + } + + /* Merge it with our number of hash buckets */ + HashIndex = HashValue % 37; + DPRINT("LOOKUP: ObjectName: %wZ\n", Name); + DPRINT("LOOKUP: Generated Hash: 0x%x. Generated Id: 0x%x\n", HashValue, HashIndex); + + /* Save the result */ + Context->HashValue = HashValue; + Context->HashIndex = HashIndex; + + /* Get the root entry and set it as our lookup bucket */ + AllocatedEntry = &Directory->HashBuckets[HashIndex]; + LookupBucket = AllocatedEntry; + DPRINT("LOOKUP: Allocated Entry: %p. LookupBucket: %p\n", AllocatedEntry, LookupBucket); + + /* Check if the directory is already locked */ + if (!Context->DirectoryLocked) + { + /* Lock it */ + KeEnterCriticalRegion(); + ExAcquireResourceSharedLite(&Directory->Lock, TRUE); + Context->LockStateSignature = 0xDDDD1234; + } + + /* Start looping */ + while ((CurrentEntry = *AllocatedEntry)) + { + /* Do the hashes match? */ + DPRINT("CurrentEntry: %p. CurrentHash: %lx\n", CurrentEntry, CurrentEntry->HashValue); + if (CurrentEntry->HashValue == HashValue) + { + /* Make sure that it has a name */ + ASSERT(BODY_TO_HEADER(CurrentEntry->Object)->NameInfoOffset != 0); + + /* Get the name information */ + HeaderNameInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(CurrentEntry->Object)); + + /* Do the names match? */ + DPRINT("NameCheck: %wZ, %wZ\n", Name, &HeaderNameInfo->Name); + if ((Name->Length == HeaderNameInfo->Name.Length) && + (RtlEqualUnicodeString(Name, &HeaderNameInfo->Name, CaseInsensitive))) + { + DPRINT("Found Name Match\n"); + break; + } + } + + /* Move to the next entry */ + AllocatedEntry = &CurrentEntry->ChainLink; + } + + /* Check if we still have an entry */ + if (CurrentEntry) + { + /* Set this entry as the first, to speed up incoming insertion */ + if (AllocatedEntry != LookupBucket) + { + /* Set the Current Entry */ + *AllocatedEntry = CurrentEntry->ChainLink; + + /* Link to the old Hash Entry */ + CurrentEntry->ChainLink = *LookupBucket; + + /* Set the new Hash Entry */ + *LookupBucket = CurrentEntry; + } + + /* Save the found object */ + FoundObject = CurrentEntry->Object; + if (!FoundObject) goto Quickie; + + /* Add a reference to the object */ + ObReferenceObject(FoundObject); + } + + /* Check if the directory was unlocked (which means we locked it) */ + if (!Context->DirectoryLocked) + { + /* Lock it */ + ExReleaseResourceLite(&Directory->Lock); + KeLeaveCriticalRegion(); + Context->LockStateSignature = 0xEEEE1234; + } + +Quickie: + /* Return the object we found */ + DPRINT("Object Found: %p Context: %p\n", FoundObject, Context); + Context->Object = FoundObject; + return FoundObject; +} + +BOOLEAN +NTAPI +ObpDeleteEntryDirectory(POBP_LOOKUP_CONTEXT Context) +{ + POBJECT_DIRECTORY Directory; + POBJECT_DIRECTORY_ENTRY *AllocatedEntry; + POBJECT_DIRECTORY_ENTRY CurrentEntry; + + /* Get the Directory */ + Directory = Context->Directory; + if (!Directory) return FALSE; + + /* Get the Entry */ + AllocatedEntry = &Directory->HashBuckets[Context->HashIndex]; + CurrentEntry = *AllocatedEntry; + DPRINT("DEL: Parent: %p, Hash: %lx, AllocatedEntry: %p, CurrentEntry: %p\n", + Directory, Context->HashIndex, AllocatedEntry, CurrentEntry); + + /* Unlink the Entry */ + *AllocatedEntry = CurrentEntry->ChainLink; + CurrentEntry->ChainLink = NULL; + + /* Free it */ + ExFreePool(CurrentEntry); + + /* Return */ + return TRUE; +} + +NTSTATUS +NTAPI +ObpParseDirectory(PVOID Object, + PVOID * NextObject, + PUNICODE_STRING FullPath, + PWSTR * Path, + ULONG Attributes, + POBP_LOOKUP_CONTEXT Context) +{ + PWSTR Start; + PWSTR End; + PVOID FoundObject; + //KIRQL oldlvl; + UNICODE_STRING StartUs; + + *NextObject = NULL; + + if ((*Path) == NULL) + { + return STATUS_UNSUCCESSFUL; + } + + Start = *Path; + if (*Start == L'\\') + Start++; + + End = wcschr(Start, L'\\'); + if (End != NULL) + { + *End = 0; + } + + //KeAcquireSpinLock(&(((PDIRECTORY_OBJECT)Object)->Lock), &oldlvl); + RtlInitUnicodeString(&StartUs, Start); + Context->DirectoryLocked = TRUE; + Context->Directory = Object; + FoundObject = ObpLookupEntryDirectory(Object, &StartUs, Attributes, FALSE, Context); + if (FoundObject == NULL) + { + //KeReleaseSpinLock(&(((PDIRECTORY_OBJECT)Object)->Lock), oldlvl); + if (End != NULL) + { + *End = L'\\'; + } + return STATUS_UNSUCCESSFUL; + } + + ObReferenceObjectByPointer(FoundObject, + STANDARD_RIGHTS_REQUIRED, + NULL, + UserMode); + //KeReleaseSpinLock(&(((PDIRECTORY_OBJECT)Object)->Lock), oldlvl); + if (End != NULL) + { + *End = L'\\'; + *Path = End; + } + else + { + *Path = NULL; + } + + *NextObject = FoundObject; + + return STATUS_SUCCESS; +} + +/* FUNCTIONS **************************************************************/ + +/*++ +* @name NtOpenDirectoryObject +* @implemented NT4 +* +* The NtOpenDirectoryObject opens a namespace directory object. +* +* @param DirectoryHandle +* Variable which receives the directory handle. +* +* @param DesiredAccess +* Desired access to the directory. +* +* @param ObjectAttributes +* Structure describing the directory. +* +* @return STATUS_SUCCESS or appropriate error value. +* +* @remarks None. +* +*--*/ +NTSTATUS +NTAPI +NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hDirectory; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + + if(PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForWriteHandle(DirectoryHandle); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtOpenDirectoryObject failed, Status: 0x%x\n", Status); + return Status; + } + } + + Status = ObOpenObjectByName(ObjectAttributes, + ObDirectoryType, + NULL, + PreviousMode, + DesiredAccess, + NULL, + &hDirectory); + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *DirectoryHandle = hDirectory; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + return Status; +} + +/*++ +* @name NtQueryDirectoryObject +* @implemented NT4 +* +* The NtQueryDirectoryObject Reads information from a directory in +* the system namespace. +* +* @param DirectoryHandle +* Handle obtained with NtOpenDirectoryObject which +* must grant DIRECTORY_QUERY access to the directory object. +* +* @param Buffer +* Buffer to hold the data read. +* +* @param BufferLength +* Size of the buffer in bytes. +* +* @param ReturnSingleEntry +* When TRUE, only 1 entry is written in DirObjInformation; +* otherwise as many as will fit in the buffer. +* +* @param RestartScan +* If TRUE start reading at index 0. +* If FALSE start reading at the index specified by *ObjectIndex. +* +* @param Context +* Zero based index into the directory, interpretation +* depends on RestartScan. +* +* @param ReturnLength +* Caller supplied storage for the number of bytes +* written (or NULL). +* +* @return STATUS_SUCCESS or appropriate error value. +* +* @remarks Although you can iterate over the directory by calling this +* function multiple times, the directory is unlocked between +* calls. This means that another thread can change the directory +* and so iterating doesn't guarantee a consistent picture of the +* directory. Best thing is to retrieve all directory entries in +* one call. +* +*--*/ +NTSTATUS +NTAPI +NtQueryDirectoryObject(IN HANDLE DirectoryHandle, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturnLength OPTIONAL) +{ + POBJECT_DIRECTORY Directory; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + ULONG SkipEntries = 0; + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + + if(PreviousMode != KernelMode) + { + _SEH_TRY + { + /* a test showed that the Buffer pointer just has to be 16 bit aligned, + propably due to the fact that most information that needs to be copied + is unicode strings */ + ProbeForWrite(Buffer, BufferLength, sizeof(WCHAR)); + ProbeForWriteUlong(Context); + if(!RestartScan) + { + SkipEntries = *Context; + } + if(ReturnLength != NULL) + { + ProbeForWriteUlong(ReturnLength); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtQueryDirectoryObject failed, Status: 0x%x\n", Status); + return Status; + } + } + else if(!RestartScan) + { + SkipEntries = *Context; + } + + Status = ObReferenceObjectByHandle(DirectoryHandle, + DIRECTORY_QUERY, + ObDirectoryType, + PreviousMode, + (PVOID*)&Directory, + NULL); + if(NT_SUCCESS(Status)) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + return Status; +} + +/*++ +* @name NtCreateDirectoryObject +* @implemented NT4 +* +* The NtOpenDirectoryObject creates or opens a directory object. +* +* @param DirectoryHandle +* Variable which receives the directory handle. +* +* @param DesiredAccess +* Desired access to the directory. +* +* @param ObjectAttributes +* Structure describing the directory. +* +* @return STATUS_SUCCESS or appropriate error value. +* +* @remarks None. +* +*--*/ +NTSTATUS +NTAPI +NtCreateDirectoryObject(OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + POBJECT_DIRECTORY Directory; + HANDLE hDirectory; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + + DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, " + "DesiredAccess %x, ObjectAttributes %x\n", + DirectoryHandle, DesiredAccess, ObjectAttributes); + + if(PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForWriteHandle(DirectoryHandle); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtCreateDirectoryObject failed, Status: 0x%x\n", Status); + return Status; + } + } + + Status = ObCreateObject(PreviousMode, + ObDirectoryType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID*)&Directory); + + if(NT_SUCCESS(Status)) + { + Status = ObInsertObject((PVOID)Directory, + NULL, + DesiredAccess, + 0, + NULL, + &hDirectory); + if(NT_SUCCESS(Status)) + { + _SEH_TRY + { + *DirectoryHandle = hDirectory; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + ObDereferenceObject(Directory); + } + + return Status; +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ob/obhandle.c b/reactos/ntoskrnl/ob/obhandle.c index 8810cb8aba6..5e0cf631bff 100644 --- a/reactos/ntoskrnl/ob/obhandle.c +++ b/reactos/ntoskrnl/ob/obhandle.c @@ -1,1407 +1,1407 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/ob/obhandle.c - * PURPOSE: Manages all functions related to the Object Manager handle - * implementation, including creating and destroying handles - * and/or handle tables, duplicating objects, and setting the - * permanent or temporary flags. - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - * Eric Kohl - * Thomas Weidenmueller (w3seek@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include - -PHANDLE_TABLE ObpKernelHandleTable = NULL; - -/* TEMPORARY HACK. DO NOT REMOVE -- Alex */ -NTSTATUS -STDCALL -ExpDesktopCreate(PVOID ObjectBody, - PVOID Parent, - PWSTR RemainingPath, - POBJECT_CREATE_INFORMATION ObjectCreateInformation); - -/* PRIVATE FUNCTIONS *********************************************************/ - -/*++ -* @name ObpSetPermanentObject -* -* The ObpSetPermanentObject routine -* -* @param ObjectBody -* -* -* @param Permanent -* -* -* @return None. -* -* @remarks None. -* -*--*/ -VOID -FASTCALL -ObpSetPermanentObject(IN PVOID ObjectBody, - IN BOOLEAN Permanent) -{ - POBJECT_HEADER ObjectHeader; - OBP_LOOKUP_CONTEXT Context; - - ObjectHeader = BODY_TO_HEADER(ObjectBody); - ASSERT (ObjectHeader->PointerCount > 0); - if (Permanent) - { - ObjectHeader->Flags |= OB_FLAG_PERMANENT; - } - else - { - ObjectHeader->Flags &= ~OB_FLAG_PERMANENT; - if (ObjectHeader->HandleCount == 0 && - HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory) - { - /* Make sure it's still inserted */ - Context.Directory = HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory; - Context.DirectoryLocked = TRUE; - if (ObpLookupEntryDirectory(HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory, - &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name, - 0, - FALSE, - &Context)) - { - ObpDeleteEntryDirectory(&Context); - } - } - } -} - -ULONG -NTAPI -ObpGetHandleCountByHandleTable(PHANDLE_TABLE HandleTable) -{ - return HandleTable->HandleCount; -} - -VOID -ObpGetNextHandleByProcessCount(PSYSTEM_HANDLE_TABLE_ENTRY_INFO pshi, - PEPROCESS Process, - int Count) -{ - ULONG P; - // KIRQL oldIrql; - - // pshi->HandleValue; - - /* - This will never work with ROS! M$, I guess uses 0 -> 65535. - Ros uses 0 -> 4294967295! - */ - - P = (ULONG) Process->UniqueProcessId; - pshi->UniqueProcessId = (USHORT) P; - - // KeAcquireSpinLock( &Process->HandleTable.ListLock, &oldIrql ); - - // pshi->GrantedAccess; - // pshi->Object; - // pshi->TypeIndex; - // pshi->HandleAttributes; - - // KeReleaseSpinLock( &Process->HandleTable.ListLock, oldIrql ); - - return; -} -static VOID -ObpDecrementHandleCount(PVOID ObjectBody) -{ - POBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody); - LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount); - OBP_LOOKUP_CONTEXT Context; - DPRINT("Header: %x\n", ObjectHeader); - DPRINT("NewHandleCount: %x\n", NewHandleCount); - DPRINT("HEADER_TO_OBJECT_NAME: %x\n", HEADER_TO_OBJECT_NAME(ObjectHeader)); - - if ((ObjectHeader->Type != NULL) && - (ObjectHeader->Type->TypeInfo.CloseProcedure != NULL)) - { - /* the handle count should be decremented but we pass the previous value - to the callback */ - ObjectHeader->Type->TypeInfo.CloseProcedure(NULL, ObjectBody, 0, NewHandleCount + 1, NewHandleCount + 1); - } - - if(NewHandleCount == 0) - { - if(HEADER_TO_OBJECT_NAME(ObjectHeader) && - HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory != NULL && - !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) - { - /* delete the object from the namespace when the last handle got closed. - Only do this if it's actually been inserted into the namespace and - if it's not a permanent object. */ - - /* Make sure it's still inserted */ - Context.Directory = HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory; - Context.DirectoryLocked = TRUE; - if (ObpLookupEntryDirectory(HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory, - &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name, - 0, - FALSE, - &Context)) - { - ObpDeleteEntryDirectory(&Context); - } - } - - /* remove the keep-alive reference */ - ObDereferenceObject(ObjectBody); - } -} - -NTSTATUS -NTAPI -ObpQueryHandleAttributes(HANDLE Handle, - POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo) -{ - PHANDLE_TABLE_ENTRY HandleTableEntry; - PEPROCESS Process, CurrentProcess; - KAPC_STATE ApcState; - BOOLEAN AttachedToProcess = FALSE; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - DPRINT("ObpQueryHandleAttributes(Handle %p)\n", Handle); - CurrentProcess = PsGetCurrentProcess(); - - KeEnterCriticalRegion(); - - if(ObIsKernelHandle(Handle, ExGetPreviousMode())) - { - Process = PsInitialSystemProcess; - Handle = ObKernelHandleToHandle(Handle); - - if (Process != CurrentProcess) - { - KeStackAttachProcess(&Process->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - } - else - { - Process = CurrentProcess; - } - - HandleTableEntry = ExMapHandleToPointer(Process->ObjectTable, - Handle); - if (HandleTableEntry != NULL) - { - HandleInfo->Inherit = (HandleTableEntry->ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0; - HandleInfo->ProtectFromClose = (HandleTableEntry->ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) != 0; - - ExUnlockHandleTableEntry(Process->ObjectTable, - HandleTableEntry); - } - else - Status = STATUS_INVALID_HANDLE; - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - KeLeaveCriticalRegion(); - - return Status; -} - -NTSTATUS -NTAPI -ObpSetHandleAttributes(HANDLE Handle, - POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo) -{ - PHANDLE_TABLE_ENTRY HandleTableEntry; - PEPROCESS Process, CurrentProcess; - KAPC_STATE ApcState; - BOOLEAN AttachedToProcess = FALSE; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - DPRINT("ObpSetHandleAttributes(Handle %p)\n", Handle); - CurrentProcess = PsGetCurrentProcess(); - - KeEnterCriticalRegion(); - - if(ObIsKernelHandle(Handle, ExGetPreviousMode())) - { - Process = PsInitialSystemProcess; - Handle = ObKernelHandleToHandle(Handle); - - if (Process != CurrentProcess) - { - KeStackAttachProcess(&Process->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - } - else - { - Process = CurrentProcess; - } - - HandleTableEntry = ExMapHandleToPointer(Process->ObjectTable, - Handle); - if (HandleTableEntry != NULL) - { - if (HandleInfo->Inherit) - HandleTableEntry->ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE; - else - HandleTableEntry->ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE; - - if (HandleInfo->ProtectFromClose) - HandleTableEntry->ObAttributes |= EX_HANDLE_ENTRY_PROTECTFROMCLOSE; - else - HandleTableEntry->ObAttributes &= ~EX_HANDLE_ENTRY_PROTECTFROMCLOSE; - - /* FIXME: Do we need to set anything in the object header??? */ - - ExUnlockHandleTableEntry(Process->ObjectTable, - HandleTableEntry); - } - else - Status = STATUS_INVALID_HANDLE; - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - KeLeaveCriticalRegion(); - - return Status; -} - -static NTSTATUS -ObpDeleteHandle(HANDLE Handle) -{ - PHANDLE_TABLE_ENTRY HandleEntry; - PVOID Body; - POBJECT_HEADER ObjectHeader; - PHANDLE_TABLE ObjectTable; - - PAGED_CODE(); - - DPRINT("ObpDeleteHandle(Handle %p)\n",Handle); - - ObjectTable = PsGetCurrentProcess()->ObjectTable; - - KeEnterCriticalRegion(); - - HandleEntry = ExMapHandleToPointer(ObjectTable, - Handle); - if(HandleEntry != NULL) - { - if(HandleEntry->ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) - { - ExUnlockHandleTableEntry(ObjectTable, - HandleEntry); - - KeLeaveCriticalRegion(); - - return STATUS_HANDLE_NOT_CLOSABLE; - } - - ObjectHeader = EX_HTE_TO_HDR(HandleEntry); - Body = &ObjectHeader->Body; - - /* destroy and unlock the handle entry */ - ExDestroyHandleByEntry(ObjectTable, - HandleEntry, - Handle); - - ObpDecrementHandleCount(Body); - - KeLeaveCriticalRegion(); - - return STATUS_SUCCESS; - } - KeLeaveCriticalRegion(); - return STATUS_INVALID_HANDLE; -} - -NTSTATUS -NTAPI -ObDuplicateObject(PEPROCESS SourceProcess, - PEPROCESS TargetProcess, - HANDLE SourceHandle, - PHANDLE TargetHandle, - ACCESS_MASK DesiredAccess, - ULONG HandleAttributes, - ULONG Options) -{ - PHANDLE_TABLE_ENTRY SourceHandleEntry; - HANDLE_TABLE_ENTRY NewHandleEntry; - BOOLEAN AttachedToProcess = FALSE; - PVOID ObjectBody; - POBJECT_HEADER ObjectHeader; - ULONG NewHandleCount; - HANDLE NewTargetHandle; - PEPROCESS CurrentProcess; - KAPC_STATE ApcState; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - if(SourceProcess == NULL || - ObIsKernelHandle(SourceHandle, ExGetPreviousMode())) - { - SourceProcess = PsInitialSystemProcess; - SourceHandle = ObKernelHandleToHandle(SourceHandle); - } - - CurrentProcess = PsGetCurrentProcess(); - - KeEnterCriticalRegion(); - - if (SourceProcess != CurrentProcess) - { - KeStackAttachProcess(&SourceProcess->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - SourceHandleEntry = ExMapHandleToPointer(SourceProcess->ObjectTable, - SourceHandle); - if (SourceHandleEntry == NULL) - { - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - KeLeaveCriticalRegion(); - return STATUS_INVALID_HANDLE; - } - - ObjectHeader = EX_HTE_TO_HDR(SourceHandleEntry); - ObjectBody = &ObjectHeader->Body; - - NewHandleEntry.Object = SourceHandleEntry->Object; - if(HandleAttributes & OBJ_INHERIT) - NewHandleEntry.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE; - else - NewHandleEntry.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE; - NewHandleEntry.GrantedAccess = ((Options & DUPLICATE_SAME_ACCESS) ? - SourceHandleEntry->GrantedAccess : - DesiredAccess); - if (Options & DUPLICATE_SAME_ACCESS) - { - NewHandleEntry.GrantedAccess = SourceHandleEntry->GrantedAccess; - } - else - { - if (DesiredAccess & GENERIC_ACCESS) - { - RtlMapGenericMask(&DesiredAccess, - &ObjectHeader->Type->TypeInfo.GenericMapping); - } - NewHandleEntry.GrantedAccess = DesiredAccess; - } - - /* reference the object so it doesn't get deleted after releasing the lock - and before creating a new handle for it */ - ObReferenceObject(ObjectBody); - - /* increment the handle count of the object, it should always be >= 2 because - we're holding a handle lock to this object! if the new handle count was - 1 here, we're in big trouble... it would've been safe to increment and - check the handle count without using interlocked functions because the - entry is locked, which means the handle count can't change. */ - NewHandleCount = InterlockedIncrement(&ObjectHeader->HandleCount); - ASSERT(NewHandleCount >= 2); - - ExUnlockHandleTableEntry(SourceProcess->ObjectTable, - SourceHandleEntry); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - AttachedToProcess = FALSE; - } - - if (TargetProcess != CurrentProcess) - { - KeStackAttachProcess(&TargetProcess->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - - /* attempt to create the new handle */ - NewTargetHandle = ExCreateHandle(TargetProcess->ObjectTable, - &NewHandleEntry); - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - AttachedToProcess = FALSE; - } - - if (NewTargetHandle != NULL) - { - if (Options & DUPLICATE_CLOSE_SOURCE) - { - if (SourceProcess != CurrentProcess) - { - KeStackAttachProcess(&SourceProcess->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - - /* delete the source handle */ - ObpDeleteHandle(SourceHandle); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - } - - ObDereferenceObject(ObjectBody); - - *TargetHandle = NewTargetHandle; - } - else - { - /* decrement the handle count we previously incremented, but don't call the - closing procedure because we're not closing a handle! */ - if(InterlockedDecrement(&ObjectHeader->HandleCount) == 0) - { - ObDereferenceObject(ObjectBody); - } - - ObDereferenceObject(ObjectBody); - Status = STATUS_UNSUCCESSFUL; - } - - KeLeaveCriticalRegion(); - - return Status; -} - -static VOID STDCALL -SweepHandleCallback(PHANDLE_TABLE HandleTable, - PVOID Object, - ULONG GrantedAccess, - PVOID Context) -{ - POBJECT_HEADER ObjectHeader; - PVOID ObjectBody; - - PAGED_CODE(); - - ObjectHeader = EX_OBJ_TO_HDR(Object); - ObjectBody = &ObjectHeader->Body; - - ObpDecrementHandleCount(ObjectBody); -} - -static BOOLEAN STDCALL -DuplicateHandleCallback(PHANDLE_TABLE HandleTable, - PHANDLE_TABLE_ENTRY HandleTableEntry, - PVOID Context) -{ - POBJECT_HEADER ObjectHeader; - BOOLEAN Ret = FALSE; - - PAGED_CODE(); - - Ret = (HandleTableEntry->ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0; - if(Ret) - { - ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry); - if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1) - { - ObReferenceObject(&ObjectHeader->Body); - } - } - - return Ret; -} - -VOID -NTAPI -ObCreateHandleTable(PEPROCESS Parent, - BOOLEAN Inherit, - PEPROCESS Process) - /* - * FUNCTION: Creates a handle table for a process - * ARGUMENTS: - * Parent = Parent process (or NULL if this is the first process) - * Inherit = True if the process should inherit its parent's handles - * Process = Process whose handle table is to be created - */ -{ - PAGED_CODE(); - - DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n", - Parent,Inherit,Process); - if(Parent != NULL) - { - Process->ObjectTable = ExDupHandleTable(Process, - DuplicateHandleCallback, - NULL, - Parent->ObjectTable); - } - else - { - Process->ObjectTable = ExCreateHandleTable(Process); - } -} - - -VOID -STDCALL -ObKillProcess(PEPROCESS Process) -{ - PAGED_CODE(); - - /* FIXME - Temporary hack: sweep and destroy here, needs to be fixed!!! */ - ExSweepHandleTable(Process->ObjectTable, - SweepHandleCallback, - Process); - ExDestroyHandleTable(Process->ObjectTable); - Process->ObjectTable = NULL; -} - - -NTSTATUS -NTAPI -ObpCreateHandle(PVOID ObjectBody, - ACCESS_MASK GrantedAccess, - ULONG HandleAttributes, - PHANDLE HandleReturn) - /* - * FUNCTION: Add a handle referencing an object - * ARGUMENTS: - * obj = Object body that the handle should refer to - * RETURNS: The created handle - * NOTE: The handle is valid only in the context of the current process - */ -{ - HANDLE_TABLE_ENTRY NewEntry; - PEPROCESS Process, CurrentProcess; - POBJECT_HEADER ObjectHeader; - HANDLE Handle; - KAPC_STATE ApcState; - BOOLEAN AttachedToProcess = FALSE; - - PAGED_CODE(); - - DPRINT("ObpCreateHandle(obj %p)\n",ObjectBody); - - ASSERT(ObjectBody); - - CurrentProcess = PsGetCurrentProcess(); - - ObjectHeader = BODY_TO_HEADER(ObjectBody); - - /* check that this is a valid kernel pointer */ - ASSERT((ULONG_PTR)ObjectHeader & EX_HANDLE_ENTRY_LOCKED); - - if (GrantedAccess & MAXIMUM_ALLOWED) - { - GrantedAccess &= ~MAXIMUM_ALLOWED; - GrantedAccess |= GENERIC_ALL; - } - - if (GrantedAccess & GENERIC_ACCESS) - { - RtlMapGenericMask(&GrantedAccess, - &ObjectHeader->Type->TypeInfo.GenericMapping); - } - - NewEntry.Object = ObjectHeader; - if(HandleAttributes & OBJ_INHERIT) - NewEntry.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE; - else - NewEntry.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE; - NewEntry.GrantedAccess = GrantedAccess; - - if ((HandleAttributes & OBJ_KERNEL_HANDLE) && - ExGetPreviousMode == KernelMode) - { - Process = PsInitialSystemProcess; - if (Process != CurrentProcess) - { - KeStackAttachProcess(&Process->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - } - else - { - Process = CurrentProcess; - /* mask out the OBJ_KERNEL_HANDLE attribute */ - HandleAttributes &= ~OBJ_KERNEL_HANDLE; - } - - Handle = ExCreateHandle(Process->ObjectTable, - &NewEntry); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - if(Handle != NULL) - { - if (HandleAttributes & OBJ_KERNEL_HANDLE) - { - /* mark the handle value */ - Handle = ObMarkHandleAsKernelHandle(Handle); - } - - if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1) - { - ObReferenceObject(ObjectBody); - } - - *HandleReturn = Handle; - - return STATUS_SUCCESS; - } - - return STATUS_UNSUCCESSFUL; -} - - -/* -* @implemented -*/ -NTSTATUS STDCALL -ObQueryObjectAuditingByHandle(IN HANDLE Handle, - OUT PBOOLEAN GenerateOnClose) -{ - PHANDLE_TABLE_ENTRY HandleEntry; - PEPROCESS Process, CurrentProcess; - KAPC_STATE ApcState; - BOOLEAN AttachedToProcess = FALSE; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - DPRINT("ObQueryObjectAuditingByHandle(Handle %p)\n", Handle); - - CurrentProcess = PsGetCurrentProcess(); - - KeEnterCriticalRegion(); - - if(ObIsKernelHandle(Handle, ExGetPreviousMode())) - { - Process = PsInitialSystemProcess; - Handle = ObKernelHandleToHandle(Handle); - - if (Process != CurrentProcess) - { - KeStackAttachProcess(&Process->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - } - else - Process = CurrentProcess; - - HandleEntry = ExMapHandleToPointer(Process->ObjectTable, - Handle); - if(HandleEntry != NULL) - { - *GenerateOnClose = (HandleEntry->ObAttributes & EX_HANDLE_ENTRY_AUDITONCLOSE) != 0; - - ExUnlockHandleTableEntry(Process->ObjectTable, - HandleEntry); - } - else - Status = STATUS_INVALID_HANDLE; - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - KeLeaveCriticalRegion(); - - return Status; -} -/* PUBLIC FUNCTIONS *********************************************************/ - -ULONG -NTAPI -ObGetObjectHandleCount(PVOID Object) -{ - POBJECT_HEADER Header; - - PAGED_CODE(); - - ASSERT(Object); - Header = BODY_TO_HEADER(Object); - - return Header->HandleCount; -} - -NTSTATUS STDCALL -ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, - IN POBJECT_TYPE ObjectType, - IN OUT PVOID ParseContext, - IN KPROCESSOR_MODE AccessMode, - IN ACCESS_MASK DesiredAccess, - IN PACCESS_STATE PassedAccessState, - OUT PHANDLE Handle) -{ - UNICODE_STRING RemainingPath; - PVOID Object = NULL; - UNICODE_STRING ObjectName; - OBJECT_CREATE_INFORMATION ObjectCreateInfo; - NTSTATUS Status; - OBP_LOOKUP_CONTEXT Context; - - PAGED_CODE(); - - DPRINT("ObOpenObjectByName(...)\n"); - - /* Capture all the info */ - DPRINT("Capturing Create Info\n"); - Status = ObpCaptureObjectAttributes(ObjectAttributes, - AccessMode, - ObjectType, - &ObjectCreateInfo, - &ObjectName); - if (!NT_SUCCESS(Status)) - { - DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status); - return Status; - } - - Status = ObFindObject(&ObjectCreateInfo, - &ObjectName, - &Object, - &RemainingPath, - ObjectType, - &Context); - if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); - if (!NT_SUCCESS(Status)) - { - DPRINT("ObFindObject() failed (Status %lx)\n", Status); - goto Cleanup; - } - - DPRINT("OBject: %p, Remaining Path: %wZ\n", Object, &RemainingPath); - if (Object == NULL) - { - Status = STATUS_UNSUCCESSFUL; - goto Cleanup; - } - if (RemainingPath.Buffer != NULL) - { - if (wcschr(RemainingPath.Buffer + 1, L'\\') == NULL) - Status = STATUS_OBJECT_NAME_NOT_FOUND; - else - Status =STATUS_OBJECT_PATH_NOT_FOUND; - goto Cleanup; - } - - Status = ObpCreateHandle(Object, - DesiredAccess, - ObjectCreateInfo.Attributes, - Handle); - -Cleanup: - if (Object != NULL) - { - ObDereferenceObject(Object); - } - RtlFreeUnicodeString(&RemainingPath); - ObpReleaseCapturedAttributes(&ObjectCreateInfo); - - return Status; -} - -/* -* @implemented -*/ -NTSTATUS STDCALL -ObOpenObjectByPointer(IN PVOID Object, - IN ULONG HandleAttributes, - IN PACCESS_STATE PassedAccessState, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_TYPE ObjectType, - IN KPROCESSOR_MODE AccessMode, - OUT PHANDLE Handle) -{ - NTSTATUS Status; - - PAGED_CODE(); - - DPRINT("ObOpenObjectByPointer()\n"); - - Status = ObReferenceObjectByPointer(Object, - 0, - ObjectType, - AccessMode); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Status = ObpCreateHandle(Object, - DesiredAccess, - HandleAttributes, - Handle); - - ObDereferenceObject(Object); - - return STATUS_SUCCESS; -} - -NTSTATUS STDCALL -ObFindHandleForObject(IN PEPROCESS Process, - IN PVOID Object, - IN POBJECT_TYPE ObjectType, - IN POBJECT_HANDLE_INFORMATION HandleInformation, - OUT PHANDLE HandleReturn) -{ - DPRINT("ObFindHandleForObject is unimplemented!\n"); - return STATUS_UNSUCCESSFUL; -} - -/*++ -* @name ObMakeTemporaryObject -* @implemented NT4 -* -* The ObMakeTemporaryObject routine -* -* @param ObjectBody -* -* -* @return None. -* -* @remarks None. -* -*--*/ -VOID -NTAPI -ObMakeTemporaryObject(IN PVOID ObjectBody) -{ - ObpSetPermanentObject (ObjectBody, FALSE); -} - -/* -* @implemented -*/ -NTSTATUS -STDCALL -ObInsertObject(IN PVOID Object, - IN PACCESS_STATE PassedAccessState OPTIONAL, - IN ACCESS_MASK DesiredAccess, - IN ULONG AdditionalReferences, - OUT PVOID* ReferencedObject OPTIONAL, - OUT PHANDLE Handle) -{ - POBJECT_CREATE_INFORMATION ObjectCreateInfo; - POBJECT_HEADER Header; - POBJECT_HEADER_NAME_INFO ObjectNameInfo; - PVOID FoundObject = NULL; - POBJECT_HEADER FoundHeader = NULL; - NTSTATUS Status = STATUS_SUCCESS; - UNICODE_STRING RemainingPath; - BOOLEAN ObjectAttached = FALSE; - PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL; - SECURITY_SUBJECT_CONTEXT SubjectContext; - OBP_LOOKUP_CONTEXT Context; - - PAGED_CODE(); - - /* Get the Header and Create Info */ - DPRINT("ObInsertObject: %x\n", Object); - Header = BODY_TO_HEADER(Object); - ObjectCreateInfo = Header->ObjectCreateInfo; - ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header); - - /* First try to find the Object */ - if (ObjectNameInfo && ObjectNameInfo->Name.Buffer) - { - DPRINT("Object has a name. Trying to find it: %wZ.\n", &ObjectNameInfo->Name); - Status = ObFindObject(ObjectCreateInfo, - &ObjectNameInfo->Name, - &FoundObject, - &RemainingPath, - NULL, - &Context); - DPRINT("FoundObject: %x, Path: %wZ\n", FoundObject, &RemainingPath); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ObFindObject() failed! (Status 0x%x)\n", Status); - return Status; - } - - if (FoundObject) - { - DPRINT("Getting header: %x\n", FoundObject); - FoundHeader = BODY_TO_HEADER(FoundObject); - } - - if (FoundHeader && RemainingPath.Buffer == NULL) - { - DPRINT("Object exists\n"); - ObDereferenceObject(FoundObject); - return STATUS_OBJECT_NAME_COLLISION; - } - } - else - { - DPRINT("No name, empty remaining path\n"); - RtlInitUnicodeString(&RemainingPath, NULL); - } - - if (FoundHeader && FoundHeader->Type == ObDirectoryType && - RemainingPath.Buffer) - { - /* The name was changed so let's update it */ - /* FIXME: TEMPORARY HACK This will go in ObFindObject in the next commit */ - PVOID NewName; - PWSTR BufferPos = RemainingPath.Buffer; - ULONG Delta = 0; - - ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header); - - if (BufferPos[0] == L'\\') - { - BufferPos++; - Delta = sizeof(WCHAR); - } - NewName = ExAllocatePool(NonPagedPool, RemainingPath.MaximumLength - Delta); - RtlMoveMemory(NewName, BufferPos, RemainingPath.MaximumLength - Delta); - if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer); - ObjectNameInfo->Name.Buffer = NewName; - ObjectNameInfo->Name.Length = RemainingPath.Length - Delta; - ObjectNameInfo->Name.MaximumLength = RemainingPath.MaximumLength - Delta; - ObpInsertEntryDirectory(FoundObject, &Context, Header); - ObjectAttached = TRUE; - } - - if ((Header->Type == IoFileObjectType) || - (Header->Type == ExDesktopObjectType) || - (Header->Type->TypeInfo.OpenProcedure != NULL)) - { - DPRINT("About to call Open Routine\n"); - if (Header->Type == IoFileObjectType) - { - /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ - DPRINT("Calling IopCreateFile: %x\n", FoundObject); - Status = IopCreateFile(&Header->Body, - FoundObject, - RemainingPath.Buffer, - ObjectCreateInfo); - DPRINT("Called IopCreateFile: %x\n", Status); - - } - else if (Header->Type == ExDesktopObjectType) - { - /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ - DPRINT("Calling ExpDesktopCreate\n"); - Status = ExpDesktopCreate(&Header->Body, - FoundObject, - RemainingPath.Buffer, - ObjectCreateInfo); - } - else if (Header->Type->TypeInfo.OpenProcedure != NULL) - { - DPRINT("Calling %x\n", Header->Type->TypeInfo.OpenProcedure); - Status = Header->Type->TypeInfo.OpenProcedure(ObCreateHandle, - NULL, - &Header->Body, - 0, - 0); - } - - if (!NT_SUCCESS(Status)) - { - DPRINT("Create Failed\n"); - if (ObjectAttached == TRUE) - { - ObpDeleteEntryDirectory(&Context); - } - if (FoundObject) - { - ObDereferenceObject(FoundObject); - } - RtlFreeUnicodeString(&RemainingPath); - return Status; - } - } - - RtlFreeUnicodeString(&RemainingPath); - - DPRINT("Security Assignment in progress\n"); - SeCaptureSubjectContext(&SubjectContext); - - /* Build the new security descriptor */ - Status = SeAssignSecurity((FoundHeader != NULL) ? FoundHeader->SecurityDescriptor : NULL, - (ObjectCreateInfo != NULL) ? ObjectCreateInfo->SecurityDescriptor : NULL, - &NewSecurityDescriptor, - (Header->Type == ObDirectoryType), - &SubjectContext, - &Header->Type->TypeInfo.GenericMapping, - PagedPool); - - if (NT_SUCCESS(Status)) - { - DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor); - - if (Header->Type->TypeInfo.SecurityProcedure != NULL) - { - /* Call the security method */ - Status = Header->Type->TypeInfo.SecurityProcedure(&Header->Body, - AssignSecurityDescriptor, - 0, - NewSecurityDescriptor, - NULL, - NULL, - NonPagedPool, - NULL); - } - else - { - /* Assign the security descriptor to the object header */ - Status = ObpAddSecurityDescriptor(NewSecurityDescriptor, - &Header->SecurityDescriptor); - DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor); - } - - /* Release the new security descriptor */ - SeDeassignSecurity(&NewSecurityDescriptor); - } - - DPRINT("Security Complete\n"); - SeReleaseSubjectContext(&SubjectContext); - - /* Create the Handle */ - /* HACKHACK: Because of ROS's incorrect startup, this can be called - * without a valid Process until I finalize the startup patch, - * so don't create a handle if this is the case. We also don't create - * a handle if Handle is NULL when the Registry Code calls it, because - * the registry code totally bastardizes the Ob and needs to be fixed - */ - DPRINT("Creating handle\n"); - if (Handle != NULL) - { - Status = ObpCreateHandle(&Header->Body, - DesiredAccess, - ObjectCreateInfo->Attributes, - Handle); - DPRINT("handle Created: %d. refcount. handlecount %d %d\n", - *Handle, Header->PointerCount, Header->HandleCount); - } - - /* We can delete the Create Info now */ - Header->ObjectCreateInfo = NULL; - ObpReleaseCapturedAttributes(ObjectCreateInfo); - ExFreePool(ObjectCreateInfo); - - DPRINT("Status %x\n", Status); - return Status; -} - -/* -* @implemented -*/ -NTSTATUS STDCALL -NtDuplicateObject (IN HANDLE SourceProcessHandle, - IN HANDLE SourceHandle, - IN HANDLE TargetProcessHandle, - OUT PHANDLE TargetHandle OPTIONAL, - IN ACCESS_MASK DesiredAccess, - IN ULONG HandleAttributes, - IN ULONG Options) -{ - PEPROCESS SourceProcess; - PEPROCESS TargetProcess; - PEPROCESS CurrentProcess; - HANDLE hTarget; - BOOLEAN AttachedToProcess = FALSE; - KPROCESSOR_MODE PreviousMode; - KAPC_STATE ApcState; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - - if(TargetHandle != NULL && PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForWriteHandle(TargetHandle); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - Status = ObReferenceObjectByHandle(SourceProcessHandle, - PROCESS_DUP_HANDLE, - NULL, - PreviousMode, - (PVOID*)&SourceProcess, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - Status = ObReferenceObjectByHandle(TargetProcessHandle, - PROCESS_DUP_HANDLE, - NULL, - PreviousMode, - (PVOID*)&TargetProcess, - NULL); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(SourceProcess); - return(Status); - } - - CurrentProcess = PsGetCurrentProcess(); - - /* Check for magic handle first */ - if (SourceHandle == NtCurrentThread() || - SourceHandle == NtCurrentProcess()) - { - PVOID ObjectBody; - POBJECT_TYPE ObjectType; - - ObjectType = (SourceHandle == NtCurrentThread()) ? PsThreadType : PsProcessType; - - Status = ObReferenceObjectByHandle(SourceHandle, - 0, - ObjectType, - PreviousMode, - &ObjectBody, - NULL); - if(NT_SUCCESS(Status)) - { - if (Options & DUPLICATE_SAME_ACCESS) - { - /* grant all access rights */ - DesiredAccess = ((ObjectType == PsThreadType) ? THREAD_ALL_ACCESS : PROCESS_ALL_ACCESS); - } - else - { - if (DesiredAccess & GENERIC_ACCESS) - { - RtlMapGenericMask(&DesiredAccess, - &ObjectType->TypeInfo.GenericMapping); - } - } - - if (TargetProcess != CurrentProcess) - { - KeStackAttachProcess(&TargetProcess->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - - Status = ObpCreateHandle(ObjectBody, - DesiredAccess, - HandleAttributes, - &hTarget); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - AttachedToProcess = FALSE; - } - - ObDereferenceObject(ObjectBody); - - if (Options & DUPLICATE_CLOSE_SOURCE) - { - if (SourceProcess != CurrentProcess) - { - KeStackAttachProcess(&SourceProcess->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - - ObpDeleteHandle(SourceHandle); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - } - } - } - else - { - Status = ObDuplicateObject(SourceProcess, - TargetProcess, - SourceHandle, - &hTarget, - DesiredAccess, - HandleAttributes, - Options); - } - - ObDereferenceObject(TargetProcess); - ObDereferenceObject(SourceProcess); - - if(NT_SUCCESS(Status) && TargetHandle != NULL) - { - _SEH_TRY - { - *TargetHandle = hTarget; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - - return Status; -} - -NTSTATUS STDCALL -NtClose(IN HANDLE Handle) -{ - PEPROCESS Process, CurrentProcess; - BOOLEAN AttachedToProcess = FALSE; - KAPC_STATE ApcState; - NTSTATUS Status; - KPROCESSOR_MODE PreviousMode; - - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - CurrentProcess = PsGetCurrentProcess(); - - if(ObIsKernelHandle(Handle, PreviousMode)) - { - Process = PsInitialSystemProcess; - Handle = ObKernelHandleToHandle(Handle); - - if (Process != CurrentProcess) - { - KeStackAttachProcess(&Process->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - } - else - Process = CurrentProcess; - - Status = ObpDeleteHandle(Handle); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - if (!NT_SUCCESS(Status)) - { - if((PreviousMode != KernelMode) && - (CurrentProcess->ExceptionPort)) - { - KeRaiseUserException(Status); - } - return Status; - } - - return(STATUS_SUCCESS); -} - -/*++ -* @name NtMakeTemporaryObject -* @implemented NT4 -* -* The NtMakeTemporaryObject routine -* -* @param ObjectHandle -* -* -* @return STATUS_SUCCESS or appropriate error value. -* -* @remarks None. -* -*--*/ -NTSTATUS -NTAPI -NtMakeTemporaryObject(IN HANDLE ObjectHandle) -{ - PVOID ObjectBody; - NTSTATUS Status; - PAGED_CODE(); - - Status = ObReferenceObjectByHandle(ObjectHandle, - 0, - NULL, - KeGetPreviousMode(), - &ObjectBody, - NULL); - if (Status != STATUS_SUCCESS) return Status; - - ObpSetPermanentObject (ObjectBody, FALSE); - - ObDereferenceObject(ObjectBody); - - return STATUS_SUCCESS; -} - -/*++ -* @name NtMakePermanentObject -* @implemented NT4 -* -* The NtMakePermanentObject routine -* -* @param ObjectHandle -* -* -* @return STATUS_SUCCESS or appropriate error value. -* -* @remarks None. -* -*--*/ -NTSTATUS -NTAPI -NtMakePermanentObject(IN HANDLE ObjectHandle) -{ - PVOID ObjectBody; - NTSTATUS Status; - PAGED_CODE(); - - Status = ObReferenceObjectByHandle(ObjectHandle, - 0, - NULL, - KeGetPreviousMode(), - &ObjectBody, - NULL); - if (Status != STATUS_SUCCESS) return Status; - - ObpSetPermanentObject (ObjectBody, TRUE); - - ObDereferenceObject(ObjectBody); - - return STATUS_SUCCESS; -} -/* EOF */ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ob/obhandle.c + * PURPOSE: Manages all functions related to the Object Manager handle + * implementation, including creating and destroying handles + * and/or handle tables, duplicating objects, and setting the + * permanent or temporary flags. + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl + * Thomas Weidenmueller (w3seek@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +PHANDLE_TABLE ObpKernelHandleTable = NULL; + +/* TEMPORARY HACK. DO NOT REMOVE -- Alex */ +NTSTATUS +STDCALL +ExpDesktopCreate(PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_CREATE_INFORMATION ObjectCreateInformation); + +/* PRIVATE FUNCTIONS *********************************************************/ + +/*++ +* @name ObpSetPermanentObject +* +* The ObpSetPermanentObject routine +* +* @param ObjectBody +* +* +* @param Permanent +* +* +* @return None. +* +* @remarks None. +* +*--*/ +VOID +FASTCALL +ObpSetPermanentObject(IN PVOID ObjectBody, + IN BOOLEAN Permanent) +{ + POBJECT_HEADER ObjectHeader; + OBP_LOOKUP_CONTEXT Context; + + ObjectHeader = BODY_TO_HEADER(ObjectBody); + ASSERT (ObjectHeader->PointerCount > 0); + if (Permanent) + { + ObjectHeader->Flags |= OB_FLAG_PERMANENT; + } + else + { + ObjectHeader->Flags &= ~OB_FLAG_PERMANENT; + if (ObjectHeader->HandleCount == 0 && + HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory) + { + /* Make sure it's still inserted */ + Context.Directory = HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory; + Context.DirectoryLocked = TRUE; + if (ObpLookupEntryDirectory(HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory, + &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name, + 0, + FALSE, + &Context)) + { + ObpDeleteEntryDirectory(&Context); + } + } + } +} + +ULONG +NTAPI +ObpGetHandleCountByHandleTable(PHANDLE_TABLE HandleTable) +{ + return HandleTable->HandleCount; +} + +VOID +ObpGetNextHandleByProcessCount(PSYSTEM_HANDLE_TABLE_ENTRY_INFO pshi, + PEPROCESS Process, + int Count) +{ + ULONG P; + // KIRQL oldIrql; + + // pshi->HandleValue; + + /* + This will never work with ROS! M$, I guess uses 0 -> 65535. + Ros uses 0 -> 4294967295! + */ + + P = (ULONG) Process->UniqueProcessId; + pshi->UniqueProcessId = (USHORT) P; + + // KeAcquireSpinLock( &Process->HandleTable.ListLock, &oldIrql ); + + // pshi->GrantedAccess; + // pshi->Object; + // pshi->TypeIndex; + // pshi->HandleAttributes; + + // KeReleaseSpinLock( &Process->HandleTable.ListLock, oldIrql ); + + return; +} +static VOID +ObpDecrementHandleCount(PVOID ObjectBody) +{ + POBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody); + LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount); + OBP_LOOKUP_CONTEXT Context; + DPRINT("Header: %x\n", ObjectHeader); + DPRINT("NewHandleCount: %x\n", NewHandleCount); + DPRINT("HEADER_TO_OBJECT_NAME: %x\n", HEADER_TO_OBJECT_NAME(ObjectHeader)); + + if ((ObjectHeader->Type != NULL) && + (ObjectHeader->Type->TypeInfo.CloseProcedure != NULL)) + { + /* the handle count should be decremented but we pass the previous value + to the callback */ + ObjectHeader->Type->TypeInfo.CloseProcedure(NULL, ObjectBody, 0, NewHandleCount + 1, NewHandleCount + 1); + } + + if(NewHandleCount == 0) + { + if(HEADER_TO_OBJECT_NAME(ObjectHeader) && + HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory != NULL && + !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) + { + /* delete the object from the namespace when the last handle got closed. + Only do this if it's actually been inserted into the namespace and + if it's not a permanent object. */ + + /* Make sure it's still inserted */ + Context.Directory = HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory; + Context.DirectoryLocked = TRUE; + if (ObpLookupEntryDirectory(HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory, + &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name, + 0, + FALSE, + &Context)) + { + ObpDeleteEntryDirectory(&Context); + } + } + + /* remove the keep-alive reference */ + ObDereferenceObject(ObjectBody); + } +} + +NTSTATUS +NTAPI +ObpQueryHandleAttributes(HANDLE Handle, + POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo) +{ + PHANDLE_TABLE_ENTRY HandleTableEntry; + PEPROCESS Process, CurrentProcess; + KAPC_STATE ApcState; + BOOLEAN AttachedToProcess = FALSE; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + DPRINT("ObpQueryHandleAttributes(Handle %p)\n", Handle); + CurrentProcess = PsGetCurrentProcess(); + + KeEnterCriticalRegion(); + + if(ObIsKernelHandle(Handle, ExGetPreviousMode())) + { + Process = PsInitialSystemProcess; + Handle = ObKernelHandleToHandle(Handle); + + if (Process != CurrentProcess) + { + KeStackAttachProcess(&Process->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + } + else + { + Process = CurrentProcess; + } + + HandleTableEntry = ExMapHandleToPointer(Process->ObjectTable, + Handle); + if (HandleTableEntry != NULL) + { + HandleInfo->Inherit = (HandleTableEntry->ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0; + HandleInfo->ProtectFromClose = (HandleTableEntry->ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) != 0; + + ExUnlockHandleTableEntry(Process->ObjectTable, + HandleTableEntry); + } + else + Status = STATUS_INVALID_HANDLE; + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + KeLeaveCriticalRegion(); + + return Status; +} + +NTSTATUS +NTAPI +ObpSetHandleAttributes(HANDLE Handle, + POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo) +{ + PHANDLE_TABLE_ENTRY HandleTableEntry; + PEPROCESS Process, CurrentProcess; + KAPC_STATE ApcState; + BOOLEAN AttachedToProcess = FALSE; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + DPRINT("ObpSetHandleAttributes(Handle %p)\n", Handle); + CurrentProcess = PsGetCurrentProcess(); + + KeEnterCriticalRegion(); + + if(ObIsKernelHandle(Handle, ExGetPreviousMode())) + { + Process = PsInitialSystemProcess; + Handle = ObKernelHandleToHandle(Handle); + + if (Process != CurrentProcess) + { + KeStackAttachProcess(&Process->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + } + else + { + Process = CurrentProcess; + } + + HandleTableEntry = ExMapHandleToPointer(Process->ObjectTable, + Handle); + if (HandleTableEntry != NULL) + { + if (HandleInfo->Inherit) + HandleTableEntry->ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE; + else + HandleTableEntry->ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE; + + if (HandleInfo->ProtectFromClose) + HandleTableEntry->ObAttributes |= EX_HANDLE_ENTRY_PROTECTFROMCLOSE; + else + HandleTableEntry->ObAttributes &= ~EX_HANDLE_ENTRY_PROTECTFROMCLOSE; + + /* FIXME: Do we need to set anything in the object header??? */ + + ExUnlockHandleTableEntry(Process->ObjectTable, + HandleTableEntry); + } + else + Status = STATUS_INVALID_HANDLE; + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + KeLeaveCriticalRegion(); + + return Status; +} + +static NTSTATUS +ObpDeleteHandle(HANDLE Handle) +{ + PHANDLE_TABLE_ENTRY HandleEntry; + PVOID Body; + POBJECT_HEADER ObjectHeader; + PHANDLE_TABLE ObjectTable; + + PAGED_CODE(); + + DPRINT("ObpDeleteHandle(Handle %p)\n",Handle); + + ObjectTable = PsGetCurrentProcess()->ObjectTable; + + KeEnterCriticalRegion(); + + HandleEntry = ExMapHandleToPointer(ObjectTable, + Handle); + if(HandleEntry != NULL) + { + if(HandleEntry->ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) + { + ExUnlockHandleTableEntry(ObjectTable, + HandleEntry); + + KeLeaveCriticalRegion(); + + return STATUS_HANDLE_NOT_CLOSABLE; + } + + ObjectHeader = EX_HTE_TO_HDR(HandleEntry); + Body = &ObjectHeader->Body; + + /* destroy and unlock the handle entry */ + ExDestroyHandleByEntry(ObjectTable, + HandleEntry, + Handle); + + ObpDecrementHandleCount(Body); + + KeLeaveCriticalRegion(); + + return STATUS_SUCCESS; + } + KeLeaveCriticalRegion(); + return STATUS_INVALID_HANDLE; +} + +NTSTATUS +NTAPI +ObDuplicateObject(PEPROCESS SourceProcess, + PEPROCESS TargetProcess, + HANDLE SourceHandle, + PHANDLE TargetHandle, + ACCESS_MASK DesiredAccess, + ULONG HandleAttributes, + ULONG Options) +{ + PHANDLE_TABLE_ENTRY SourceHandleEntry; + HANDLE_TABLE_ENTRY NewHandleEntry; + BOOLEAN AttachedToProcess = FALSE; + PVOID ObjectBody; + POBJECT_HEADER ObjectHeader; + ULONG NewHandleCount; + HANDLE NewTargetHandle; + PEPROCESS CurrentProcess; + KAPC_STATE ApcState; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + if(SourceProcess == NULL || + ObIsKernelHandle(SourceHandle, ExGetPreviousMode())) + { + SourceProcess = PsInitialSystemProcess; + SourceHandle = ObKernelHandleToHandle(SourceHandle); + } + + CurrentProcess = PsGetCurrentProcess(); + + KeEnterCriticalRegion(); + + if (SourceProcess != CurrentProcess) + { + KeStackAttachProcess(&SourceProcess->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + SourceHandleEntry = ExMapHandleToPointer(SourceProcess->ObjectTable, + SourceHandle); + if (SourceHandleEntry == NULL) + { + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + KeLeaveCriticalRegion(); + return STATUS_INVALID_HANDLE; + } + + ObjectHeader = EX_HTE_TO_HDR(SourceHandleEntry); + ObjectBody = &ObjectHeader->Body; + + NewHandleEntry.Object = SourceHandleEntry->Object; + if(HandleAttributes & OBJ_INHERIT) + NewHandleEntry.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE; + else + NewHandleEntry.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE; + NewHandleEntry.GrantedAccess = ((Options & DUPLICATE_SAME_ACCESS) ? + SourceHandleEntry->GrantedAccess : + DesiredAccess); + if (Options & DUPLICATE_SAME_ACCESS) + { + NewHandleEntry.GrantedAccess = SourceHandleEntry->GrantedAccess; + } + else + { + if (DesiredAccess & GENERIC_ACCESS) + { + RtlMapGenericMask(&DesiredAccess, + &ObjectHeader->Type->TypeInfo.GenericMapping); + } + NewHandleEntry.GrantedAccess = DesiredAccess; + } + + /* reference the object so it doesn't get deleted after releasing the lock + and before creating a new handle for it */ + ObReferenceObject(ObjectBody); + + /* increment the handle count of the object, it should always be >= 2 because + we're holding a handle lock to this object! if the new handle count was + 1 here, we're in big trouble... it would've been safe to increment and + check the handle count without using interlocked functions because the + entry is locked, which means the handle count can't change. */ + NewHandleCount = InterlockedIncrement(&ObjectHeader->HandleCount); + ASSERT(NewHandleCount >= 2); + + ExUnlockHandleTableEntry(SourceProcess->ObjectTable, + SourceHandleEntry); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + AttachedToProcess = FALSE; + } + + if (TargetProcess != CurrentProcess) + { + KeStackAttachProcess(&TargetProcess->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + + /* attempt to create the new handle */ + NewTargetHandle = ExCreateHandle(TargetProcess->ObjectTable, + &NewHandleEntry); + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + AttachedToProcess = FALSE; + } + + if (NewTargetHandle != NULL) + { + if (Options & DUPLICATE_CLOSE_SOURCE) + { + if (SourceProcess != CurrentProcess) + { + KeStackAttachProcess(&SourceProcess->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + + /* delete the source handle */ + ObpDeleteHandle(SourceHandle); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + } + + ObDereferenceObject(ObjectBody); + + *TargetHandle = NewTargetHandle; + } + else + { + /* decrement the handle count we previously incremented, but don't call the + closing procedure because we're not closing a handle! */ + if(InterlockedDecrement(&ObjectHeader->HandleCount) == 0) + { + ObDereferenceObject(ObjectBody); + } + + ObDereferenceObject(ObjectBody); + Status = STATUS_UNSUCCESSFUL; + } + + KeLeaveCriticalRegion(); + + return Status; +} + +static VOID STDCALL +SweepHandleCallback(PHANDLE_TABLE HandleTable, + PVOID Object, + ULONG GrantedAccess, + PVOID Context) +{ + POBJECT_HEADER ObjectHeader; + PVOID ObjectBody; + + PAGED_CODE(); + + ObjectHeader = EX_OBJ_TO_HDR(Object); + ObjectBody = &ObjectHeader->Body; + + ObpDecrementHandleCount(ObjectBody); +} + +static BOOLEAN STDCALL +DuplicateHandleCallback(PHANDLE_TABLE HandleTable, + PHANDLE_TABLE_ENTRY HandleTableEntry, + PVOID Context) +{ + POBJECT_HEADER ObjectHeader; + BOOLEAN Ret = FALSE; + + PAGED_CODE(); + + Ret = (HandleTableEntry->ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0; + if(Ret) + { + ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry); + if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1) + { + ObReferenceObject(&ObjectHeader->Body); + } + } + + return Ret; +} + +VOID +NTAPI +ObCreateHandleTable(PEPROCESS Parent, + BOOLEAN Inherit, + PEPROCESS Process) + /* + * FUNCTION: Creates a handle table for a process + * ARGUMENTS: + * Parent = Parent process (or NULL if this is the first process) + * Inherit = True if the process should inherit its parent's handles + * Process = Process whose handle table is to be created + */ +{ + PAGED_CODE(); + + DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n", + Parent,Inherit,Process); + if(Parent != NULL) + { + Process->ObjectTable = ExDupHandleTable(Process, + DuplicateHandleCallback, + NULL, + Parent->ObjectTable); + } + else + { + Process->ObjectTable = ExCreateHandleTable(Process); + } +} + + +VOID +STDCALL +ObKillProcess(PEPROCESS Process) +{ + PAGED_CODE(); + + /* FIXME - Temporary hack: sweep and destroy here, needs to be fixed!!! */ + ExSweepHandleTable(Process->ObjectTable, + SweepHandleCallback, + Process); + ExDestroyHandleTable(Process->ObjectTable); + Process->ObjectTable = NULL; +} + + +NTSTATUS +NTAPI +ObpCreateHandle(PVOID ObjectBody, + ACCESS_MASK GrantedAccess, + ULONG HandleAttributes, + PHANDLE HandleReturn) + /* + * FUNCTION: Add a handle referencing an object + * ARGUMENTS: + * obj = Object body that the handle should refer to + * RETURNS: The created handle + * NOTE: The handle is valid only in the context of the current process + */ +{ + HANDLE_TABLE_ENTRY NewEntry; + PEPROCESS Process, CurrentProcess; + POBJECT_HEADER ObjectHeader; + HANDLE Handle; + KAPC_STATE ApcState; + BOOLEAN AttachedToProcess = FALSE; + + PAGED_CODE(); + + DPRINT("ObpCreateHandle(obj %p)\n",ObjectBody); + + ASSERT(ObjectBody); + + CurrentProcess = PsGetCurrentProcess(); + + ObjectHeader = BODY_TO_HEADER(ObjectBody); + + /* check that this is a valid kernel pointer */ + ASSERT((ULONG_PTR)ObjectHeader & EX_HANDLE_ENTRY_LOCKED); + + if (GrantedAccess & MAXIMUM_ALLOWED) + { + GrantedAccess &= ~MAXIMUM_ALLOWED; + GrantedAccess |= GENERIC_ALL; + } + + if (GrantedAccess & GENERIC_ACCESS) + { + RtlMapGenericMask(&GrantedAccess, + &ObjectHeader->Type->TypeInfo.GenericMapping); + } + + NewEntry.Object = ObjectHeader; + if(HandleAttributes & OBJ_INHERIT) + NewEntry.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE; + else + NewEntry.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE; + NewEntry.GrantedAccess = GrantedAccess; + + if ((HandleAttributes & OBJ_KERNEL_HANDLE) && + ExGetPreviousMode == KernelMode) + { + Process = PsInitialSystemProcess; + if (Process != CurrentProcess) + { + KeStackAttachProcess(&Process->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + } + else + { + Process = CurrentProcess; + /* mask out the OBJ_KERNEL_HANDLE attribute */ + HandleAttributes &= ~OBJ_KERNEL_HANDLE; + } + + Handle = ExCreateHandle(Process->ObjectTable, + &NewEntry); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + if(Handle != NULL) + { + if (HandleAttributes & OBJ_KERNEL_HANDLE) + { + /* mark the handle value */ + Handle = ObMarkHandleAsKernelHandle(Handle); + } + + if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1) + { + ObReferenceObject(ObjectBody); + } + + *HandleReturn = Handle; + + return STATUS_SUCCESS; + } + + return STATUS_UNSUCCESSFUL; +} + + +/* +* @implemented +*/ +NTSTATUS STDCALL +ObQueryObjectAuditingByHandle(IN HANDLE Handle, + OUT PBOOLEAN GenerateOnClose) +{ + PHANDLE_TABLE_ENTRY HandleEntry; + PEPROCESS Process, CurrentProcess; + KAPC_STATE ApcState; + BOOLEAN AttachedToProcess = FALSE; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + DPRINT("ObQueryObjectAuditingByHandle(Handle %p)\n", Handle); + + CurrentProcess = PsGetCurrentProcess(); + + KeEnterCriticalRegion(); + + if(ObIsKernelHandle(Handle, ExGetPreviousMode())) + { + Process = PsInitialSystemProcess; + Handle = ObKernelHandleToHandle(Handle); + + if (Process != CurrentProcess) + { + KeStackAttachProcess(&Process->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + } + else + Process = CurrentProcess; + + HandleEntry = ExMapHandleToPointer(Process->ObjectTable, + Handle); + if(HandleEntry != NULL) + { + *GenerateOnClose = (HandleEntry->ObAttributes & EX_HANDLE_ENTRY_AUDITONCLOSE) != 0; + + ExUnlockHandleTableEntry(Process->ObjectTable, + HandleEntry); + } + else + Status = STATUS_INVALID_HANDLE; + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + KeLeaveCriticalRegion(); + + return Status; +} +/* PUBLIC FUNCTIONS *********************************************************/ + +ULONG +NTAPI +ObGetObjectHandleCount(PVOID Object) +{ + POBJECT_HEADER Header; + + PAGED_CODE(); + + ASSERT(Object); + Header = BODY_TO_HEADER(Object); + + return Header->HandleCount; +} + +NTSTATUS STDCALL +ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, + IN POBJECT_TYPE ObjectType, + IN OUT PVOID ParseContext, + IN KPROCESSOR_MODE AccessMode, + IN ACCESS_MASK DesiredAccess, + IN PACCESS_STATE PassedAccessState, + OUT PHANDLE Handle) +{ + UNICODE_STRING RemainingPath; + PVOID Object = NULL; + UNICODE_STRING ObjectName; + OBJECT_CREATE_INFORMATION ObjectCreateInfo; + NTSTATUS Status; + OBP_LOOKUP_CONTEXT Context; + + PAGED_CODE(); + + DPRINT("ObOpenObjectByName(...)\n"); + + /* Capture all the info */ + DPRINT("Capturing Create Info\n"); + Status = ObpCaptureObjectAttributes(ObjectAttributes, + AccessMode, + ObjectType, + &ObjectCreateInfo, + &ObjectName); + if (!NT_SUCCESS(Status)) + { + DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status); + return Status; + } + + Status = ObFindObject(&ObjectCreateInfo, + &ObjectName, + &Object, + &RemainingPath, + ObjectType, + &Context); + if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); + if (!NT_SUCCESS(Status)) + { + DPRINT("ObFindObject() failed (Status %lx)\n", Status); + goto Cleanup; + } + + DPRINT("OBject: %p, Remaining Path: %wZ\n", Object, &RemainingPath); + if (Object == NULL) + { + Status = STATUS_UNSUCCESSFUL; + goto Cleanup; + } + if (RemainingPath.Buffer != NULL) + { + if (wcschr(RemainingPath.Buffer + 1, L'\\') == NULL) + Status = STATUS_OBJECT_NAME_NOT_FOUND; + else + Status =STATUS_OBJECT_PATH_NOT_FOUND; + goto Cleanup; + } + + Status = ObpCreateHandle(Object, + DesiredAccess, + ObjectCreateInfo.Attributes, + Handle); + +Cleanup: + if (Object != NULL) + { + ObDereferenceObject(Object); + } + RtlFreeUnicodeString(&RemainingPath); + ObpReleaseCapturedAttributes(&ObjectCreateInfo); + + return Status; +} + +/* +* @implemented +*/ +NTSTATUS STDCALL +ObOpenObjectByPointer(IN PVOID Object, + IN ULONG HandleAttributes, + IN PACCESS_STATE PassedAccessState, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode, + OUT PHANDLE Handle) +{ + NTSTATUS Status; + + PAGED_CODE(); + + DPRINT("ObOpenObjectByPointer()\n"); + + Status = ObReferenceObjectByPointer(Object, + 0, + ObjectType, + AccessMode); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = ObpCreateHandle(Object, + DesiredAccess, + HandleAttributes, + Handle); + + ObDereferenceObject(Object); + + return STATUS_SUCCESS; +} + +NTSTATUS STDCALL +ObFindHandleForObject(IN PEPROCESS Process, + IN PVOID Object, + IN POBJECT_TYPE ObjectType, + IN POBJECT_HANDLE_INFORMATION HandleInformation, + OUT PHANDLE HandleReturn) +{ + DPRINT("ObFindHandleForObject is unimplemented!\n"); + return STATUS_UNSUCCESSFUL; +} + +/*++ +* @name ObMakeTemporaryObject +* @implemented NT4 +* +* The ObMakeTemporaryObject routine +* +* @param ObjectBody +* +* +* @return None. +* +* @remarks None. +* +*--*/ +VOID +NTAPI +ObMakeTemporaryObject(IN PVOID ObjectBody) +{ + ObpSetPermanentObject (ObjectBody, FALSE); +} + +/* +* @implemented +*/ +NTSTATUS +STDCALL +ObInsertObject(IN PVOID Object, + IN PACCESS_STATE PassedAccessState OPTIONAL, + IN ACCESS_MASK DesiredAccess, + IN ULONG AdditionalReferences, + OUT PVOID* ReferencedObject OPTIONAL, + OUT PHANDLE Handle) +{ + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + POBJECT_HEADER Header; + POBJECT_HEADER_NAME_INFO ObjectNameInfo; + PVOID FoundObject = NULL; + POBJECT_HEADER FoundHeader = NULL; + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING RemainingPath; + BOOLEAN ObjectAttached = FALSE; + PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL; + SECURITY_SUBJECT_CONTEXT SubjectContext; + OBP_LOOKUP_CONTEXT Context; + + PAGED_CODE(); + + /* Get the Header and Create Info */ + DPRINT("ObInsertObject: %x\n", Object); + Header = BODY_TO_HEADER(Object); + ObjectCreateInfo = Header->ObjectCreateInfo; + ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header); + + /* First try to find the Object */ + if (ObjectNameInfo && ObjectNameInfo->Name.Buffer) + { + DPRINT("Object has a name. Trying to find it: %wZ.\n", &ObjectNameInfo->Name); + Status = ObFindObject(ObjectCreateInfo, + &ObjectNameInfo->Name, + &FoundObject, + &RemainingPath, + NULL, + &Context); + DPRINT("FoundObject: %x, Path: %wZ\n", FoundObject, &RemainingPath); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ObFindObject() failed! (Status 0x%x)\n", Status); + return Status; + } + + if (FoundObject) + { + DPRINT("Getting header: %x\n", FoundObject); + FoundHeader = BODY_TO_HEADER(FoundObject); + } + + if (FoundHeader && RemainingPath.Buffer == NULL) + { + DPRINT("Object exists\n"); + ObDereferenceObject(FoundObject); + return STATUS_OBJECT_NAME_COLLISION; + } + } + else + { + DPRINT("No name, empty remaining path\n"); + RtlInitUnicodeString(&RemainingPath, NULL); + } + + if (FoundHeader && FoundHeader->Type == ObDirectoryType && + RemainingPath.Buffer) + { + /* The name was changed so let's update it */ + /* FIXME: TEMPORARY HACK This will go in ObFindObject in the next commit */ + PVOID NewName; + PWSTR BufferPos = RemainingPath.Buffer; + ULONG Delta = 0; + + ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header); + + if (BufferPos[0] == L'\\') + { + BufferPos++; + Delta = sizeof(WCHAR); + } + NewName = ExAllocatePool(NonPagedPool, RemainingPath.MaximumLength - Delta); + RtlMoveMemory(NewName, BufferPos, RemainingPath.MaximumLength - Delta); + if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer); + ObjectNameInfo->Name.Buffer = NewName; + ObjectNameInfo->Name.Length = RemainingPath.Length - Delta; + ObjectNameInfo->Name.MaximumLength = RemainingPath.MaximumLength - Delta; + ObpInsertEntryDirectory(FoundObject, &Context, Header); + ObjectAttached = TRUE; + } + + if ((Header->Type == IoFileObjectType) || + (Header->Type == ExDesktopObjectType) || + (Header->Type->TypeInfo.OpenProcedure != NULL)) + { + DPRINT("About to call Open Routine\n"); + if (Header->Type == IoFileObjectType) + { + /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ + DPRINT("Calling IopCreateFile: %x\n", FoundObject); + Status = IopCreateFile(&Header->Body, + FoundObject, + RemainingPath.Buffer, + ObjectCreateInfo); + DPRINT("Called IopCreateFile: %x\n", Status); + + } + else if (Header->Type == ExDesktopObjectType) + { + /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ + DPRINT("Calling ExpDesktopCreate\n"); + Status = ExpDesktopCreate(&Header->Body, + FoundObject, + RemainingPath.Buffer, + ObjectCreateInfo); + } + else if (Header->Type->TypeInfo.OpenProcedure != NULL) + { + DPRINT("Calling %x\n", Header->Type->TypeInfo.OpenProcedure); + Status = Header->Type->TypeInfo.OpenProcedure(ObCreateHandle, + NULL, + &Header->Body, + 0, + 0); + } + + if (!NT_SUCCESS(Status)) + { + DPRINT("Create Failed\n"); + if (ObjectAttached == TRUE) + { + ObpDeleteEntryDirectory(&Context); + } + if (FoundObject) + { + ObDereferenceObject(FoundObject); + } + RtlFreeUnicodeString(&RemainingPath); + return Status; + } + } + + RtlFreeUnicodeString(&RemainingPath); + + DPRINT("Security Assignment in progress\n"); + SeCaptureSubjectContext(&SubjectContext); + + /* Build the new security descriptor */ + Status = SeAssignSecurity((FoundHeader != NULL) ? FoundHeader->SecurityDescriptor : NULL, + (ObjectCreateInfo != NULL) ? ObjectCreateInfo->SecurityDescriptor : NULL, + &NewSecurityDescriptor, + (Header->Type == ObDirectoryType), + &SubjectContext, + &Header->Type->TypeInfo.GenericMapping, + PagedPool); + + if (NT_SUCCESS(Status)) + { + DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor); + + if (Header->Type->TypeInfo.SecurityProcedure != NULL) + { + /* Call the security method */ + Status = Header->Type->TypeInfo.SecurityProcedure(&Header->Body, + AssignSecurityDescriptor, + 0, + NewSecurityDescriptor, + NULL, + NULL, + NonPagedPool, + NULL); + } + else + { + /* Assign the security descriptor to the object header */ + Status = ObpAddSecurityDescriptor(NewSecurityDescriptor, + &Header->SecurityDescriptor); + DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor); + } + + /* Release the new security descriptor */ + SeDeassignSecurity(&NewSecurityDescriptor); + } + + DPRINT("Security Complete\n"); + SeReleaseSubjectContext(&SubjectContext); + + /* Create the Handle */ + /* HACKHACK: Because of ROS's incorrect startup, this can be called + * without a valid Process until I finalize the startup patch, + * so don't create a handle if this is the case. We also don't create + * a handle if Handle is NULL when the Registry Code calls it, because + * the registry code totally bastardizes the Ob and needs to be fixed + */ + DPRINT("Creating handle\n"); + if (Handle != NULL) + { + Status = ObpCreateHandle(&Header->Body, + DesiredAccess, + ObjectCreateInfo->Attributes, + Handle); + DPRINT("handle Created: %d. refcount. handlecount %d %d\n", + *Handle, Header->PointerCount, Header->HandleCount); + } + + /* We can delete the Create Info now */ + Header->ObjectCreateInfo = NULL; + ObpReleaseCapturedAttributes(ObjectCreateInfo); + ExFreePool(ObjectCreateInfo); + + DPRINT("Status %x\n", Status); + return Status; +} + +/* +* @implemented +*/ +NTSTATUS STDCALL +NtDuplicateObject (IN HANDLE SourceProcessHandle, + IN HANDLE SourceHandle, + IN HANDLE TargetProcessHandle, + OUT PHANDLE TargetHandle OPTIONAL, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + IN ULONG Options) +{ + PEPROCESS SourceProcess; + PEPROCESS TargetProcess; + PEPROCESS CurrentProcess; + HANDLE hTarget; + BOOLEAN AttachedToProcess = FALSE; + KPROCESSOR_MODE PreviousMode; + KAPC_STATE ApcState; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + if(TargetHandle != NULL && PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForWriteHandle(TargetHandle); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObReferenceObjectByHandle(SourceProcessHandle, + PROCESS_DUP_HANDLE, + NULL, + PreviousMode, + (PVOID*)&SourceProcess, + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + Status = ObReferenceObjectByHandle(TargetProcessHandle, + PROCESS_DUP_HANDLE, + NULL, + PreviousMode, + (PVOID*)&TargetProcess, + NULL); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(SourceProcess); + return(Status); + } + + CurrentProcess = PsGetCurrentProcess(); + + /* Check for magic handle first */ + if (SourceHandle == NtCurrentThread() || + SourceHandle == NtCurrentProcess()) + { + PVOID ObjectBody; + POBJECT_TYPE ObjectType; + + ObjectType = (SourceHandle == NtCurrentThread()) ? PsThreadType : PsProcessType; + + Status = ObReferenceObjectByHandle(SourceHandle, + 0, + ObjectType, + PreviousMode, + &ObjectBody, + NULL); + if(NT_SUCCESS(Status)) + { + if (Options & DUPLICATE_SAME_ACCESS) + { + /* grant all access rights */ + DesiredAccess = ((ObjectType == PsThreadType) ? THREAD_ALL_ACCESS : PROCESS_ALL_ACCESS); + } + else + { + if (DesiredAccess & GENERIC_ACCESS) + { + RtlMapGenericMask(&DesiredAccess, + &ObjectType->TypeInfo.GenericMapping); + } + } + + if (TargetProcess != CurrentProcess) + { + KeStackAttachProcess(&TargetProcess->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + + Status = ObpCreateHandle(ObjectBody, + DesiredAccess, + HandleAttributes, + &hTarget); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + AttachedToProcess = FALSE; + } + + ObDereferenceObject(ObjectBody); + + if (Options & DUPLICATE_CLOSE_SOURCE) + { + if (SourceProcess != CurrentProcess) + { + KeStackAttachProcess(&SourceProcess->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + + ObpDeleteHandle(SourceHandle); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + } + } + } + else + { + Status = ObDuplicateObject(SourceProcess, + TargetProcess, + SourceHandle, + &hTarget, + DesiredAccess, + HandleAttributes, + Options); + } + + ObDereferenceObject(TargetProcess); + ObDereferenceObject(SourceProcess); + + if(NT_SUCCESS(Status) && TargetHandle != NULL) + { + _SEH_TRY + { + *TargetHandle = hTarget; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + return Status; +} + +NTSTATUS STDCALL +NtClose(IN HANDLE Handle) +{ + PEPROCESS Process, CurrentProcess; + BOOLEAN AttachedToProcess = FALSE; + KAPC_STATE ApcState; + NTSTATUS Status; + KPROCESSOR_MODE PreviousMode; + + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + CurrentProcess = PsGetCurrentProcess(); + + if(ObIsKernelHandle(Handle, PreviousMode)) + { + Process = PsInitialSystemProcess; + Handle = ObKernelHandleToHandle(Handle); + + if (Process != CurrentProcess) + { + KeStackAttachProcess(&Process->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + } + else + Process = CurrentProcess; + + Status = ObpDeleteHandle(Handle); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + if (!NT_SUCCESS(Status)) + { + if((PreviousMode != KernelMode) && + (CurrentProcess->ExceptionPort)) + { + KeRaiseUserException(Status); + } + return Status; + } + + return(STATUS_SUCCESS); +} + +/*++ +* @name NtMakeTemporaryObject +* @implemented NT4 +* +* The NtMakeTemporaryObject routine +* +* @param ObjectHandle +* +* +* @return STATUS_SUCCESS or appropriate error value. +* +* @remarks None. +* +*--*/ +NTSTATUS +NTAPI +NtMakeTemporaryObject(IN HANDLE ObjectHandle) +{ + PVOID ObjectBody; + NTSTATUS Status; + PAGED_CODE(); + + Status = ObReferenceObjectByHandle(ObjectHandle, + 0, + NULL, + KeGetPreviousMode(), + &ObjectBody, + NULL); + if (Status != STATUS_SUCCESS) return Status; + + ObpSetPermanentObject (ObjectBody, FALSE); + + ObDereferenceObject(ObjectBody); + + return STATUS_SUCCESS; +} + +/*++ +* @name NtMakePermanentObject +* @implemented NT4 +* +* The NtMakePermanentObject routine +* +* @param ObjectHandle +* +* +* @return STATUS_SUCCESS or appropriate error value. +* +* @remarks None. +* +*--*/ +NTSTATUS +NTAPI +NtMakePermanentObject(IN HANDLE ObjectHandle) +{ + PVOID ObjectBody; + NTSTATUS Status; + PAGED_CODE(); + + Status = ObReferenceObjectByHandle(ObjectHandle, + 0, + NULL, + KeGetPreviousMode(), + &ObjectBody, + NULL); + if (Status != STATUS_SUCCESS) return Status; + + ObpSetPermanentObject (ObjectBody, TRUE); + + ObDereferenceObject(ObjectBody); + + return STATUS_SUCCESS; +} +/* EOF */ diff --git a/reactos/ntoskrnl/ob/obinit.c b/reactos/ntoskrnl/ob/obinit.c index 523bd0cb1eb..150c3c697ad 100644 --- a/reactos/ntoskrnl/ob/obinit.c +++ b/reactos/ntoskrnl/ob/obinit.c @@ -1,174 +1,174 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/ob/init.c - * PURPOSE: Handles Object Manager Initialization and Shutdown - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - * Eric Kohl - * Thomas Weidenmueller (w3seek@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include - -#if defined (ALLOC_PRAGMA) -#pragma alloc_text(INIT, ObInit) -#endif - -GENERIC_MAPPING ObpTypeMapping = -{ - STANDARD_RIGHTS_READ, - STANDARD_RIGHTS_WRITE, - STANDARD_RIGHTS_EXECUTE, - 0x000F0001 -}; - -GENERIC_MAPPING ObpDirectoryMapping = -{ - STANDARD_RIGHTS_READ | DIRECTORY_QUERY | - DIRECTORY_TRAVERSE, - STANDARD_RIGHTS_WRITE | DIRECTORY_CREATE_SUBDIRECTORY | - DIRECTORY_CREATE_OBJECT, - STANDARD_RIGHTS_EXECUTE | DIRECTORY_QUERY | - DIRECTORY_TRAVERSE, - DIRECTORY_ALL_ACCESS -}; - -PDEVICE_MAP ObSystemDeviceMap = NULL; - -/* PRIVATE FUNCTIONS *********************************************************/ - -VOID -INIT_FUNCTION -ObInit(VOID) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING Name; - SECURITY_DESCRIPTOR SecurityDescriptor; - OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; - OBP_LOOKUP_CONTEXT Context; - - /* Initialize the security descriptor cache */ - ObpInitSdCache(); - - /* Initialize the Default Event */ - KeInitializeEvent(&ObpDefaultObject, NotificationEvent, TRUE ); - - /* Create the Type Type */ - DPRINT("Creating Type Type\n"); - 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); - ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObTypeObjectType); - - /* Create the Directory Type */ - DPRINT("Creating Directory Type\n"); - RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); - RtlInitUnicodeString(&Name, L"Directory"); - ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); - ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS; - ObjectTypeInitializer.UseDefaultObject = FALSE; - ObjectTypeInitializer.ParseProcedure = (OB_PARSE_METHOD)ObpParseDirectory; - ObjectTypeInitializer.MaintainTypeList = FALSE; - ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping; - ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_DIRECTORY); - ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObDirectoryType); - - /* Create security descriptor */ - RtlCreateSecurityDescriptor(&SecurityDescriptor, - SECURITY_DESCRIPTOR_REVISION1); - RtlSetOwnerSecurityDescriptor(&SecurityDescriptor, - SeAliasAdminsSid, - FALSE); - RtlSetGroupSecurityDescriptor(&SecurityDescriptor, - SeLocalSystemSid, - FALSE); - RtlSetDaclSecurityDescriptor(&SecurityDescriptor, - TRUE, - SePublicDefaultDacl, - FALSE); - - /* Create root directory */ - DPRINT("Creating Root Directory\n"); - InitializeObjectAttributes(&ObjectAttributes, - NULL, - OBJ_PERMANENT, - NULL, - &SecurityDescriptor); - ObCreateObject(KernelMode, - ObDirectoryType, - &ObjectAttributes, - KernelMode, - NULL, - sizeof(OBJECT_DIRECTORY), - 0, - 0, - (PVOID*)&NameSpaceRoot); - ObInsertObject((PVOID)NameSpaceRoot, - NULL, - DIRECTORY_ALL_ACCESS, - 0, - NULL, - NULL); - - /* Create '\ObjectTypes' directory */ - RtlInitUnicodeString(&Name, L"\\ObjectTypes"); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_PERMANENT, - NULL, - &SecurityDescriptor); - ObCreateObject(KernelMode, - ObDirectoryType, - &ObjectAttributes, - KernelMode, - NULL, - sizeof(OBJECT_DIRECTORY), - 0, - 0, - (PVOID*)&ObpTypeDirectoryObject); - ObInsertObject((PVOID)ObpTypeDirectoryObject, - NULL, - DIRECTORY_ALL_ACCESS, - 0, - NULL, - NULL); - - /* Insert the two objects we already created but couldn't add */ - /* NOTE: Uses TypeList & Creator Info in OB 2.0 */ - Context.Directory = ObpTypeDirectoryObject; - Context.DirectoryLocked = TRUE; - if (!ObpLookupEntryDirectory(ObpTypeDirectoryObject, - &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObTypeObjectType))->Name, - OBJ_CASE_INSENSITIVE, - FALSE, - &Context)) - { - ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, BODY_TO_HEADER(ObTypeObjectType)); - } - if (!ObpLookupEntryDirectory(ObpTypeDirectoryObject, - &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObDirectoryType))->Name, - OBJ_CASE_INSENSITIVE, - FALSE, - &Context)) - { - ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, BODY_TO_HEADER(ObDirectoryType)); - } - - /* Create 'symbolic link' object type */ - ObInitSymbolicLinkImplementation(); - - /* FIXME: Hack Hack! */ - ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ObSystemDeviceMap), TAG('O', 'b', 'D', 'm')); - RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap)); -} -/* EOF */ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ob/init.c + * PURPOSE: Handles Object Manager Initialization and Shutdown + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl + * Thomas Weidenmueller (w3seek@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +#if defined (ALLOC_PRAGMA) +#pragma alloc_text(INIT, ObInit) +#endif + +GENERIC_MAPPING ObpTypeMapping = +{ + STANDARD_RIGHTS_READ, + STANDARD_RIGHTS_WRITE, + STANDARD_RIGHTS_EXECUTE, + 0x000F0001 +}; + +GENERIC_MAPPING ObpDirectoryMapping = +{ + STANDARD_RIGHTS_READ | DIRECTORY_QUERY | + DIRECTORY_TRAVERSE, + STANDARD_RIGHTS_WRITE | DIRECTORY_CREATE_SUBDIRECTORY | + DIRECTORY_CREATE_OBJECT, + STANDARD_RIGHTS_EXECUTE | DIRECTORY_QUERY | + DIRECTORY_TRAVERSE, + DIRECTORY_ALL_ACCESS +}; + +PDEVICE_MAP ObSystemDeviceMap = NULL; + +/* PRIVATE FUNCTIONS *********************************************************/ + +VOID +INIT_FUNCTION +ObInit(VOID) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING Name; + SECURITY_DESCRIPTOR SecurityDescriptor; + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + OBP_LOOKUP_CONTEXT Context; + + /* Initialize the security descriptor cache */ + ObpInitSdCache(); + + /* Initialize the Default Event */ + KeInitializeEvent(&ObpDefaultObject, NotificationEvent, TRUE ); + + /* Create the Type Type */ + DPRINT("Creating Type Type\n"); + 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); + ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObTypeObjectType); + + /* Create the Directory Type */ + DPRINT("Creating Directory Type\n"); + RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); + RtlInitUnicodeString(&Name, L"Directory"); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = FALSE; + ObjectTypeInitializer.ParseProcedure = (OB_PARSE_METHOD)ObpParseDirectory; + ObjectTypeInitializer.MaintainTypeList = FALSE; + ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping; + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_DIRECTORY); + ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObDirectoryType); + + /* Create security descriptor */ + RtlCreateSecurityDescriptor(&SecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION1); + RtlSetOwnerSecurityDescriptor(&SecurityDescriptor, + SeAliasAdminsSid, + FALSE); + RtlSetGroupSecurityDescriptor(&SecurityDescriptor, + SeLocalSystemSid, + FALSE); + RtlSetDaclSecurityDescriptor(&SecurityDescriptor, + TRUE, + SePublicDefaultDacl, + FALSE); + + /* Create root directory */ + DPRINT("Creating Root Directory\n"); + InitializeObjectAttributes(&ObjectAttributes, + NULL, + OBJ_PERMANENT, + NULL, + &SecurityDescriptor); + ObCreateObject(KernelMode, + ObDirectoryType, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID*)&NameSpaceRoot); + ObInsertObject((PVOID)NameSpaceRoot, + NULL, + DIRECTORY_ALL_ACCESS, + 0, + NULL, + NULL); + + /* Create '\ObjectTypes' directory */ + RtlInitUnicodeString(&Name, L"\\ObjectTypes"); + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_PERMANENT, + NULL, + &SecurityDescriptor); + ObCreateObject(KernelMode, + ObDirectoryType, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID*)&ObpTypeDirectoryObject); + ObInsertObject((PVOID)ObpTypeDirectoryObject, + NULL, + DIRECTORY_ALL_ACCESS, + 0, + NULL, + NULL); + + /* Insert the two objects we already created but couldn't add */ + /* NOTE: Uses TypeList & Creator Info in OB 2.0 */ + Context.Directory = ObpTypeDirectoryObject; + Context.DirectoryLocked = TRUE; + if (!ObpLookupEntryDirectory(ObpTypeDirectoryObject, + &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObTypeObjectType))->Name, + OBJ_CASE_INSENSITIVE, + FALSE, + &Context)) + { + ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, BODY_TO_HEADER(ObTypeObjectType)); + } + if (!ObpLookupEntryDirectory(ObpTypeDirectoryObject, + &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObDirectoryType))->Name, + OBJ_CASE_INSENSITIVE, + FALSE, + &Context)) + { + ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, BODY_TO_HEADER(ObDirectoryType)); + } + + /* Create 'symbolic link' object type */ + ObInitSymbolicLinkImplementation(); + + /* FIXME: Hack Hack! */ + ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ObSystemDeviceMap), TAG('O', 'b', 'D', 'm')); + RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap)); +} +/* EOF */ diff --git a/reactos/ntoskrnl/ob/oblife.c b/reactos/ntoskrnl/ob/oblife.c index d8ee10ad5bc..a3ebadcecc6 100644 --- a/reactos/ntoskrnl/ob/oblife.c +++ b/reactos/ntoskrnl/ob/oblife.c @@ -1,921 +1,921 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/ob/create.c - * PURPOSE: Manages the lifetime of an Object, including its creation, - * and deletion, as well as setting or querying any of its - * information while it is active. Since Object Types are also - * Objects, those are also managed here. - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - * Eric Kohl - * Thomas Weidenmueller (w3seek@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include - -extern ULONG NtGlobalFlag; - -POBJECT_TYPE ObTypeObjectType = NULL; -KEVENT ObpDefaultObject; - -typedef struct _RETENTION_CHECK_PARAMS -{ - WORK_QUEUE_ITEM WorkItem; - POBJECT_HEADER ObjectHeader; -} RETENTION_CHECK_PARAMS, *PRETENTION_CHECK_PARAMS; - -/* PRIVATE FUNCTIONS *********************************************************/ - -static NTSTATUS -ObpDeleteObject(POBJECT_HEADER Header) -{ - PVOID HeaderLocation = Header; - POBJECT_HEADER_HANDLE_INFO HandleInfo; - POBJECT_HEADER_NAME_INFO NameInfo; - POBJECT_HEADER_CREATOR_INFO CreatorInfo; - - DPRINT("ObpDeleteObject(Header %p)\n", Header); - if (KeGetCurrentIrql() != PASSIVE_LEVEL) - { - DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n"); - KEBUGCHECK(0); - } - - if (Header->Type != NULL && - Header->Type->TypeInfo.DeleteProcedure != NULL) - { - Header->Type->TypeInfo.DeleteProcedure(&Header->Body); - } - - if (Header->SecurityDescriptor != NULL) - { - ObpRemoveSecurityDescriptor(Header->SecurityDescriptor); - } - - if (HEADER_TO_OBJECT_NAME(Header)) - { - if(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer) - { - ExFreePool(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer); - } - } - if (Header->ObjectCreateInfo) - { - ObpReleaseCapturedAttributes(Header->ObjectCreateInfo); - ExFreePool(Header->ObjectCreateInfo); - } - - /* To find the header, walk backwards from how we allocated */ - if ((CreatorInfo = HEADER_TO_CREATOR_INFO(Header))) - { - HeaderLocation = CreatorInfo; - } - if ((NameInfo = HEADER_TO_OBJECT_NAME(Header))) - { - HeaderLocation = NameInfo; - } - if ((HandleInfo = HEADER_TO_HANDLE_INFO(Header))) - { - HeaderLocation = HandleInfo; - } - - DPRINT("ObPerformRetentionChecks() = Freeing object\n"); - ExFreePool(HeaderLocation); - - return(STATUS_SUCCESS); -} - - -VOID STDCALL -ObpDeleteObjectWorkRoutine (IN PVOID Parameter) -{ - PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter; - /* ULONG Tag; */ /* See below */ - - ASSERT(Params); - ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */ - - /* Turn this on when we have ExFreePoolWithTag - Tag = Params->ObjectHeader->Type->Tag; */ - ObpDeleteObject(Params->ObjectHeader); - ExFreePool(Params); - /* ExFreePoolWithTag(Params, Tag); */ -} - - -NTSTATUS -ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader, - IN LONG OldPointerCount) -{ -#if 0 - if (ObjectHeader->PointerCount < 0) - { - CPRINT("Object %p/%p has invalid reference count (%d)\n", - ObjectHeader, HEADER_TO_BODY(ObjectHeader), - ObjectHeader->PointerCount); - KEBUGCHECK(0); - } - - if (ObjectHeader->HandleCount < 0) - { - CPRINT("Object %p/%p has invalid handle count (%d)\n", - ObjectHeader, HEADER_TO_BODY(ObjectHeader), - ObjectHeader->HandleCount); - KEBUGCHECK(0); - } -#endif - - - switch (KeGetCurrentIrql ()) - { - case PASSIVE_LEVEL: - return ObpDeleteObject (ObjectHeader); - - case APC_LEVEL: - case DISPATCH_LEVEL: - { - PRETENTION_CHECK_PARAMS Params; - - /* - We use must succeed pool here because if the allocation fails - then we leak memory. - */ - Params = (PRETENTION_CHECK_PARAMS) - ExAllocatePoolWithTag(NonPagedPoolMustSucceed, - sizeof(RETENTION_CHECK_PARAMS), - ObjectHeader->Type->Key); - Params->ObjectHeader = ObjectHeader; - ExInitializeWorkItem(&Params->WorkItem, - ObpDeleteObjectWorkRoutine, - (PVOID)Params); - ExQueueWorkItem(&Params->WorkItem, - CriticalWorkQueue); - } - return STATUS_PENDING; - - default: - DPRINT("ObpDeleteObjectDpcLevel called at unsupported " - "IRQL %u!\n", KeGetCurrentIrql()); - KEBUGCHECK(0); - return STATUS_UNSUCCESSFUL; - } - - return STATUS_SUCCESS; -} - -NTSTATUS -STDCALL -ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName, - IN PUNICODE_STRING ObjectName, - IN KPROCESSOR_MODE AccessMode) -{ - NTSTATUS Status = STATUS_SUCCESS; - ULONG StringLength; - PWCHAR StringBuffer = NULL; - UNICODE_STRING LocalName = {}; /* <= GCC 4.0 + Optimizer */ - - /* Initialize the Input String */ - RtlInitUnicodeString(CapturedName, NULL); - - /* Protect everything */ - _SEH_TRY - { - /* First Probe the String */ - DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName); - if (AccessMode != KernelMode) - { - ProbeForRead(ObjectName, - sizeof(UNICODE_STRING), - sizeof(USHORT)); - LocalName = *ObjectName; - - ProbeForRead(LocalName.Buffer, - LocalName.Length, - sizeof(WCHAR)); - } - else - { - /* No probing needed */ - LocalName = *ObjectName; - } - - /* Make sure there really is a string */ - DPRINT("Probing OK\n"); - if ((StringLength = LocalName.Length)) - { - /* Check that the size is a valid WCHAR multiple */ - if ((StringLength & (sizeof(WCHAR) - 1)) || - /* Check that the NULL-termination below will work */ - (StringLength == (MAXUSHORT - sizeof(WCHAR) + 1))) - { - /* PS: Please keep the checks above expanded for clarity */ - DPRINT1("Invalid String Length\n"); - Status = STATUS_OBJECT_NAME_INVALID; - } - else - { - /* Allocate a non-paged buffer for this string */ - DPRINT("Capturing String\n"); - CapturedName->Length = StringLength; - CapturedName->MaximumLength = StringLength + sizeof(WCHAR); - if ((StringBuffer = ExAllocatePoolWithTag(NonPagedPool, - StringLength + sizeof(WCHAR), - OB_NAME_TAG))) - { - /* Copy the string and null-terminate it */ - RtlMoveMemory(StringBuffer, LocalName.Buffer, StringLength); - StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL; - CapturedName->Buffer = StringBuffer; - DPRINT("String Captured: %wZ\n", CapturedName); - } - else - { - /* Fail */ - DPRINT1("Out of Memory!\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - } - } - _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) - { - Status = _SEH_GetExceptionCode(); - - /* Remember to free the buffer in case of failure */ - DPRINT1("Failed\n"); - if (StringBuffer) ExFreePool(StringBuffer); - } - _SEH_END; - - /* Return */ - DPRINT("Returning: %lx\n", Status); - return Status; -} - -NTSTATUS -STDCALL -ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes, - IN KPROCESSOR_MODE AccessMode, - IN POBJECT_TYPE ObjectType, - IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, - OUT PUNICODE_STRING ObjectName) -{ - NTSTATUS Status = STATUS_SUCCESS; - PSECURITY_DESCRIPTOR SecurityDescriptor; - PSECURITY_QUALITY_OF_SERVICE SecurityQos; - PUNICODE_STRING LocalObjectName = NULL; - - /* Zero out the Capture Data */ - DPRINT("ObpCaptureObjectAttributes\n"); - RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION)); - - /* SEH everything here for protection */ - _SEH_TRY - { - /* Check if we got Oba */ - if (ObjectAttributes) - { - if (AccessMode != KernelMode) - { - DPRINT("Probing OBA\n"); - ProbeForRead(ObjectAttributes, - sizeof(OBJECT_ATTRIBUTES), - sizeof(ULONG)); - } - - /* Validate the Size and Attributes */ - DPRINT("Validating OBA\n"); - if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) || - (ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES)) - { - Status = STATUS_INVALID_PARAMETER; - DPRINT1("Invalid Size: %lx or Attributes: %lx\n", - ObjectAttributes->Length, ObjectAttributes->Attributes); - _SEH_LEAVE; - } - - /* Set some Create Info */ - DPRINT("Creating OBCI\n"); - ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory; - ObjectCreateInfo->Attributes = ObjectAttributes->Attributes; - LocalObjectName = ObjectAttributes->ObjectName; - SecurityDescriptor = ObjectAttributes->SecurityDescriptor; - SecurityQos = ObjectAttributes->SecurityQualityOfService; - - /* Validate the SD */ - if (SecurityDescriptor) - { - DPRINT("Probing SD: %x\n", SecurityDescriptor); - Status = SeCaptureSecurityDescriptor(SecurityDescriptor, - AccessMode, - NonPagedPool, - TRUE, - &ObjectCreateInfo->SecurityDescriptor); - if(!NT_SUCCESS(Status)) - { - DPRINT1("Unable to capture the security descriptor!!!\n"); - ObjectCreateInfo->SecurityDescriptor = NULL; - _SEH_LEAVE; - } - - DPRINT("Probe done\n"); - ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */ - ObjectCreateInfo->ProbeMode = AccessMode; - } - - /* Validate the QoS */ - if (SecurityQos) - { - if (AccessMode != KernelMode) - { - DPRINT("Probing QoS\n"); - ProbeForRead(SecurityQos, - sizeof(SECURITY_QUALITY_OF_SERVICE), - sizeof(ULONG)); - } - - /* Save Info */ - ObjectCreateInfo->SecurityQualityOfService = *SecurityQos; - ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService; - } - } - else - { - LocalObjectName = NULL; - } - } - _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) - { - Status = _SEH_GetExceptionCode(); - DPRINT1("Failed\n"); - } - _SEH_END; - - if (NT_SUCCESS(Status)) - { - /* Now check if the Object Attributes had an Object Name */ - if (LocalObjectName) - { - DPRINT("Name Buffer: %wZ\n", LocalObjectName); - Status = ObpCaptureObjectName(ObjectName, - LocalObjectName, - AccessMode); - } - else - { - /* Clear the string */ - RtlInitUnicodeString(ObjectName, NULL); - - /* He can't have specified a Root Directory */ - if (ObjectCreateInfo->RootDirectory) - { - DPRINT1("Invalid name\n"); - Status = STATUS_OBJECT_NAME_INVALID; - } - } - } - else - { - DPRINT1("Failed to capture, cleaning up\n"); - ObpReleaseCapturedAttributes(ObjectCreateInfo); - } - - DPRINT("Return to caller %x\n", Status); - return Status; -} - - -VOID -STDCALL -ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo) -{ - /* Release the SD, it's the only thing we allocated */ - if (ObjectCreateInfo->SecurityDescriptor) - { - SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor, - ObjectCreateInfo->ProbeMode, - TRUE); - ObjectCreateInfo->SecurityDescriptor = NULL; - } -} - -NTSTATUS -STDCALL -ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, - PUNICODE_STRING ObjectName, - POBJECT_TYPE ObjectType, - ULONG ObjectSize, - POBJECT_HEADER *ObjectHeader) -{ - POBJECT_HEADER Header; - BOOLEAN HasHandleInfo = FALSE; - BOOLEAN HasNameInfo = FALSE; - BOOLEAN HasCreatorInfo = FALSE; - POBJECT_HEADER_HANDLE_INFO HandleInfo; - POBJECT_HEADER_NAME_INFO NameInfo; - POBJECT_HEADER_CREATOR_INFO CreatorInfo; - POOL_TYPE PoolType; - ULONG FinalSize = ObjectSize; - ULONG Tag; - - /* If we don't have an Object Type yet, force NonPaged */ - DPRINT("ObpAllocateObject\n"); - if (!ObjectType) - { - PoolType = NonPagedPool; - Tag = TAG('O', 'b', 'j', 'T'); - } - else - { - PoolType = ObjectType->TypeInfo.PoolType; - Tag = ObjectType->Key; - } - - DPRINT("Checking ObjectName: %x\n", ObjectName); - /* Check if the Object has a name */ - if (ObjectName->Buffer) - { - FinalSize += sizeof(OBJECT_HEADER_NAME_INFO); - HasNameInfo = TRUE; - } - - if (ObjectType) - { - /* Check if the Object maintains handle counts */ - DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType->TypeInfo); - if (ObjectType->TypeInfo.MaintainHandleCount) - { - FinalSize += sizeof(OBJECT_HEADER_HANDLE_INFO); - HasHandleInfo = TRUE; - } - - /* Check if the Object maintains type lists */ - if (ObjectType->TypeInfo.MaintainTypeList) - { - FinalSize += sizeof(OBJECT_HEADER_CREATOR_INFO); - HasCreatorInfo = TRUE; - } - } - - /* Allocate memory for the Object and Header */ - DPRINT("Allocating: %x %x\n", FinalSize, Tag); - Header = ExAllocatePoolWithTag(PoolType, FinalSize, Tag); - if (!Header) { - DPRINT1("Not enough memory!\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Initialize Handle Info */ - if (HasHandleInfo) - { - HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header; - DPRINT("Info: %x\n", HandleInfo); - HandleInfo->SingleEntry.HandleCount = 0; - Header = (POBJECT_HEADER)(HandleInfo + 1); - } - - /* Initialize the Object Name Info */ - if (HasNameInfo) - { - NameInfo = (POBJECT_HEADER_NAME_INFO)Header; - DPRINT("Info: %x %wZ\n", NameInfo, ObjectName); - NameInfo->Name = *ObjectName; - NameInfo->Directory = NULL; - Header = (POBJECT_HEADER)(NameInfo + 1); - } - - /* Initialize Creator Info */ - if (HasCreatorInfo) - { - CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header; - DPRINT("Info: %x\n", CreatorInfo); - /* FIXME: Needs Alex's Init patch - * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId(); - */ - InitializeListHead(&CreatorInfo->TypeList); - Header = (POBJECT_HEADER)(CreatorInfo + 1); - } - - /* Initialize the object header */ - RtlZeroMemory(Header, ObjectSize); - DPRINT("Initalized header %p\n", Header); - Header->HandleCount = 0; - Header->PointerCount = 1; - Header->Type = ObjectType; - Header->Flags = OB_FLAG_CREATE_INFO; - - /* Set the Offsets for the Info */ - if (HasHandleInfo) - { - Header->HandleInfoOffset = HasNameInfo * sizeof(OBJECT_HEADER_NAME_INFO) + - sizeof(OBJECT_HEADER_HANDLE_INFO) + - HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO); - Header->Flags |= OB_FLAG_SINGLE_PROCESS; - } - if (HasNameInfo) - { - Header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) + - HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO); - } - if (HasCreatorInfo) Header->Flags |= OB_FLAG_CREATOR_INFO; - - if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_PERMANENT) - { - Header->Flags |= OB_FLAG_PERMANENT; - } - if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE) - { - Header->Flags |= OB_FLAG_EXCLUSIVE; - } - - /* Link stuff to Object Header */ - Header->ObjectCreateInfo = ObjectCreateInfo; - - /* Return Header */ - *ObjectHeader = Header; - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, - PUNICODE_STRING TypeName, - POBJECT_TYPE *ObjectType) -{ - POBJECT_HEADER Header; - POBJECT_TYPE LocalObjectType; - ULONG HeaderSize; - NTSTATUS Status; - - DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", TypeName); - - /* Allocate the Object */ - Status = ObpAllocateObject(NULL, - TypeName, - ObTypeObjectType, - OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE)), - (POBJECT_HEADER*)&Header); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ObpAllocateObject failed!\n"); - return Status; - } - - LocalObjectType = (POBJECT_TYPE)&Header->Body; - DPRINT("Local ObjectType: %p Header: %p \n", LocalObjectType, Header); - - /* Check if this is the first Object Type */ - if (!ObTypeObjectType) - { - ObTypeObjectType = LocalObjectType; - Header->Type = ObTypeObjectType; - LocalObjectType->Key = TAG('O', 'b', 'j', 'T'); - } - else - { - CHAR Tag[4]; - Tag[0] = TypeName->Buffer[0]; - Tag[1] = TypeName->Buffer[1]; - Tag[2] = TypeName->Buffer[2]; - Tag[3] = TypeName->Buffer[3]; - - /* Set Tag */ - DPRINT("Convert: %s \n", Tag); - LocalObjectType->Key = *(PULONG)Tag; - } - - /* Set it up */ - LocalObjectType->TypeInfo = *ObjectTypeInitializer; - LocalObjectType->Name = *TypeName; - LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType; - - /* These two flags need to be manually set up */ - Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT; - - /* Check if we have to maintain a type list */ - if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST) - { - /* Enable support */ - LocalObjectType->TypeInfo.MaintainTypeList = TRUE; - } - - /* Calculate how much space our header'll take up */ - HeaderSize = sizeof(OBJECT_HEADER) + sizeof(OBJECT_HEADER_NAME_INFO) + - (ObjectTypeInitializer->MaintainHandleCount ? - sizeof(OBJECT_HEADER_HANDLE_INFO) : 0); - - /* Update the Pool Charges */ - if (ObjectTypeInitializer->PoolType == NonPagedPool) - { - LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize; - } - else - { - LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize; - } - - /* All objects types need a security procedure */ - if (!ObjectTypeInitializer->SecurityProcedure) - { - LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod; - } - - /* Select the Wait Object */ - if (LocalObjectType->TypeInfo.UseDefaultObject) - { - /* Add the SYNCHRONIZE access mask since it's waitable */ - LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE; - - /* Use the "Default Object", a simple event */ - LocalObjectType->DefaultObject = &ObpDefaultObject; - } - /* Special system objects get an optimized hack so they can be waited on */ - else if (TypeName->Length == 8 && !wcscmp(TypeName->Buffer, L"File")) - { - LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(FILE_OBJECT, Event); - } - /* FIXME: When LPC stops sucking, add a hack for Waitable Ports */ - else - { - /* No default Object */ - LocalObjectType->DefaultObject = NULL; - } - - /* Initialize Object Type components */ - ExInitializeResourceLite(&LocalObjectType->Mutex); - InitializeListHead(&LocalObjectType->TypeList); - - /* Insert it into the Object Directory */ - if (ObpTypeDirectoryObject) - { - OBP_LOOKUP_CONTEXT Context; - Context.Directory = ObpTypeDirectoryObject; - Context.DirectoryLocked = TRUE; - ObpLookupEntryDirectory(ObpTypeDirectoryObject, - TypeName, - OBJ_CASE_INSENSITIVE, - FALSE, - &Context); - ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header); - ObReferenceObject(ObpTypeDirectoryObject); - } - - *ObjectType = LocalObjectType; - return Status; -} - -/* PUBLIC FUNCTIONS **********************************************************/ - -NTSTATUS -NTAPI -ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL, - IN POBJECT_TYPE Type, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN KPROCESSOR_MODE AccessMode, - IN OUT PVOID ParseContext OPTIONAL, - IN ULONG ObjectSize, - IN ULONG PagedPoolCharge OPTIONAL, - IN ULONG NonPagedPoolCharge OPTIONAL, - OUT PVOID *Object) -{ - NTSTATUS Status; - POBJECT_CREATE_INFORMATION ObjectCreateInfo; - UNICODE_STRING ObjectName; - POBJECT_HEADER Header; - - DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n", - Type, ObjectAttributes, Object); - - /* Allocate a Buffer for the Object Create Info */ - DPRINT("Allocating Create Buffer\n"); - ObjectCreateInfo = ExAllocatePoolWithTag(NonPagedPool, - sizeof(*ObjectCreateInfo), - TAG('O','b','C', 'I')); - - /* Capture all the info */ - DPRINT("Capturing Create Info\n"); - Status = ObpCaptureObjectAttributes(ObjectAttributes, - ObjectAttributesAccessMode, - Type, - ObjectCreateInfo, - &ObjectName); - - if (NT_SUCCESS(Status)) - { - /* Allocate the Object */ - DPRINT("Allocating: %wZ\n", &ObjectName); - Status = ObpAllocateObject(ObjectCreateInfo, - &ObjectName, - Type, - OBJECT_ALLOC_SIZE(ObjectSize), - &Header); - - if (NT_SUCCESS(Status)) - { - /* Return the Object */ - DPRINT("Returning Object\n"); - *Object = &Header->Body; - - /* Return to caller, leave the Capture Info Alive for ObInsert */ - return Status; - } - - /* Release the Capture Info, we don't need it */ - DPRINT1("Allocation failed\n"); - ObpReleaseCapturedAttributes(ObjectCreateInfo); - if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); - } - - /* We failed, so release the Buffer */ - DPRINT1("Capture failed\n"); - ExFreePool(ObjectCreateInfo); - return Status; -} - -/*++ -* @name NtQueryObject -* @implemented NT4 -* -* The NtQueryObject routine -* -* @param ObjectHandle -* -* -* @param ObjectInformationClass -* -* -* @param ObjectInformation -* -* -* @param Length -* -* -* @param ResultLength -* -* -* @return STATUS_SUCCESS or appropriate error value. -* -* @remarks None. -* -*--*/ -NTSTATUS -NTAPI -NtQueryObject(IN HANDLE ObjectHandle, - IN OBJECT_INFORMATION_CLASS ObjectInformationClass, - OUT PVOID ObjectInformation, - IN ULONG Length, - OUT PULONG ResultLength OPTIONAL) -{ - OBJECT_HANDLE_INFORMATION HandleInfo; - POBJECT_HEADER ObjectHeader; - ULONG InfoLength; - PVOID Object; - NTSTATUS Status; - PAGED_CODE(); - - Status = ObReferenceObjectByHandle(ObjectHandle, - 0, - NULL, - KeGetPreviousMode(), - &Object, - &HandleInfo); - if (!NT_SUCCESS (Status)) return Status; - - ObjectHeader = BODY_TO_HEADER(Object); - - switch (ObjectInformationClass) - { - case ObjectBasicInformation: - InfoLength = sizeof(OBJECT_BASIC_INFORMATION); - if (Length != sizeof(OBJECT_BASIC_INFORMATION)) - { - Status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - POBJECT_BASIC_INFORMATION BasicInfo; - - BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation; - BasicInfo->Attributes = HandleInfo.HandleAttributes; - BasicInfo->GrantedAccess = HandleInfo.GrantedAccess; - BasicInfo->HandleCount = ObjectHeader->HandleCount; - BasicInfo->PointerCount = ObjectHeader->PointerCount; - BasicInfo->PagedPoolUsage = 0; /* FIXME*/ - BasicInfo->NonPagedPoolUsage = 0; /* FIXME*/ - BasicInfo->NameInformationLength = 0; /* FIXME*/ - BasicInfo->TypeInformationLength = 0; /* FIXME*/ - BasicInfo->SecurityDescriptorLength = 0; /* FIXME*/ - if (ObjectHeader->Type == ObSymbolicLinkType) - { - BasicInfo->CreateTime.QuadPart = - ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart; - } - else - { - BasicInfo->CreateTime.QuadPart = (ULONGLONG)0; - } - Status = STATUS_SUCCESS; - } - break; - - case ObjectNameInformation: - Status = ObQueryNameString(Object, - (POBJECT_NAME_INFORMATION)ObjectInformation, - Length, - &InfoLength); - break; - - case ObjectTypeInformation: - Status = STATUS_NOT_IMPLEMENTED; - break; - - case ObjectAllTypesInformation: - Status = STATUS_NOT_IMPLEMENTED; - break; - - case ObjectHandleInformation: - InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION); - if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) - { - Status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - Status = ObpQueryHandleAttributes( - ObjectHandle, - (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)ObjectInformation); - } - break; - - default: - Status = STATUS_INVALID_INFO_CLASS; - break; - } - - ObDereferenceObject (Object); - - if (ResultLength != NULL) *ResultLength = InfoLength; - - return Status; -} - -/*++ -* @name NtSetInformationObject -* @implemented NT4 -* -* The NtSetInformationObject routine -* -* @param ObjectHandle -* -* -* @param ObjectInformationClass -* -* -* @param ObjectInformation -* -* -* @param Length -* -* -* @return STATUS_SUCCESS or appropriate error value. -* -* @remarks None. -* -*--*/ -NTSTATUS -NTAPI -NtSetInformationObject(IN HANDLE ObjectHandle, - IN OBJECT_INFORMATION_CLASS ObjectInformationClass, - IN PVOID ObjectInformation, - IN ULONG Length) -{ - PVOID Object; - NTSTATUS Status; - PAGED_CODE(); - - if (ObjectInformationClass != ObjectHandleInformation) - return STATUS_INVALID_INFO_CLASS; - - if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) - return STATUS_INFO_LENGTH_MISMATCH; - - Status = ObReferenceObjectByHandle(ObjectHandle, - 0, - NULL, - KeGetPreviousMode(), - &Object, - NULL); - if (!NT_SUCCESS (Status)) return Status; - - Status = ObpSetHandleAttributes(ObjectHandle, - (POBJECT_HANDLE_ATTRIBUTE_INFORMATION) - ObjectInformation); - - ObDereferenceObject (Object); - return Status; -} -/* EOF */ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ob/create.c + * PURPOSE: Manages the lifetime of an Object, including its creation, + * and deletion, as well as setting or querying any of its + * information while it is active. Since Object Types are also + * Objects, those are also managed here. + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl + * Thomas Weidenmueller (w3seek@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +extern ULONG NtGlobalFlag; + +POBJECT_TYPE ObTypeObjectType = NULL; +KEVENT ObpDefaultObject; + +typedef struct _RETENTION_CHECK_PARAMS +{ + WORK_QUEUE_ITEM WorkItem; + POBJECT_HEADER ObjectHeader; +} RETENTION_CHECK_PARAMS, *PRETENTION_CHECK_PARAMS; + +/* PRIVATE FUNCTIONS *********************************************************/ + +static NTSTATUS +ObpDeleteObject(POBJECT_HEADER Header) +{ + PVOID HeaderLocation = Header; + POBJECT_HEADER_HANDLE_INFO HandleInfo; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER_CREATOR_INFO CreatorInfo; + + DPRINT("ObpDeleteObject(Header %p)\n", Header); + if (KeGetCurrentIrql() != PASSIVE_LEVEL) + { + DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n"); + KEBUGCHECK(0); + } + + if (Header->Type != NULL && + Header->Type->TypeInfo.DeleteProcedure != NULL) + { + Header->Type->TypeInfo.DeleteProcedure(&Header->Body); + } + + if (Header->SecurityDescriptor != NULL) + { + ObpRemoveSecurityDescriptor(Header->SecurityDescriptor); + } + + if (HEADER_TO_OBJECT_NAME(Header)) + { + if(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer) + { + ExFreePool(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer); + } + } + if (Header->ObjectCreateInfo) + { + ObpReleaseCapturedAttributes(Header->ObjectCreateInfo); + ExFreePool(Header->ObjectCreateInfo); + } + + /* To find the header, walk backwards from how we allocated */ + if ((CreatorInfo = HEADER_TO_CREATOR_INFO(Header))) + { + HeaderLocation = CreatorInfo; + } + if ((NameInfo = HEADER_TO_OBJECT_NAME(Header))) + { + HeaderLocation = NameInfo; + } + if ((HandleInfo = HEADER_TO_HANDLE_INFO(Header))) + { + HeaderLocation = HandleInfo; + } + + DPRINT("ObPerformRetentionChecks() = Freeing object\n"); + ExFreePool(HeaderLocation); + + return(STATUS_SUCCESS); +} + + +VOID STDCALL +ObpDeleteObjectWorkRoutine (IN PVOID Parameter) +{ + PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter; + /* ULONG Tag; */ /* See below */ + + ASSERT(Params); + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */ + + /* Turn this on when we have ExFreePoolWithTag + Tag = Params->ObjectHeader->Type->Tag; */ + ObpDeleteObject(Params->ObjectHeader); + ExFreePool(Params); + /* ExFreePoolWithTag(Params, Tag); */ +} + + +NTSTATUS +ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader, + IN LONG OldPointerCount) +{ +#if 0 + if (ObjectHeader->PointerCount < 0) + { + CPRINT("Object %p/%p has invalid reference count (%d)\n", + ObjectHeader, HEADER_TO_BODY(ObjectHeader), + ObjectHeader->PointerCount); + KEBUGCHECK(0); + } + + if (ObjectHeader->HandleCount < 0) + { + CPRINT("Object %p/%p has invalid handle count (%d)\n", + ObjectHeader, HEADER_TO_BODY(ObjectHeader), + ObjectHeader->HandleCount); + KEBUGCHECK(0); + } +#endif + + + switch (KeGetCurrentIrql ()) + { + case PASSIVE_LEVEL: + return ObpDeleteObject (ObjectHeader); + + case APC_LEVEL: + case DISPATCH_LEVEL: + { + PRETENTION_CHECK_PARAMS Params; + + /* + We use must succeed pool here because if the allocation fails + then we leak memory. + */ + Params = (PRETENTION_CHECK_PARAMS) + ExAllocatePoolWithTag(NonPagedPoolMustSucceed, + sizeof(RETENTION_CHECK_PARAMS), + ObjectHeader->Type->Key); + Params->ObjectHeader = ObjectHeader; + ExInitializeWorkItem(&Params->WorkItem, + ObpDeleteObjectWorkRoutine, + (PVOID)Params); + ExQueueWorkItem(&Params->WorkItem, + CriticalWorkQueue); + } + return STATUS_PENDING; + + default: + DPRINT("ObpDeleteObjectDpcLevel called at unsupported " + "IRQL %u!\n", KeGetCurrentIrql()); + KEBUGCHECK(0); + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} + +NTSTATUS +STDCALL +ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName, + IN PUNICODE_STRING ObjectName, + IN KPROCESSOR_MODE AccessMode) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG StringLength; + PWCHAR StringBuffer = NULL; + UNICODE_STRING LocalName = {}; /* <= GCC 4.0 + Optimizer */ + + /* Initialize the Input String */ + RtlInitUnicodeString(CapturedName, NULL); + + /* Protect everything */ + _SEH_TRY + { + /* First Probe the String */ + DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName); + if (AccessMode != KernelMode) + { + ProbeForRead(ObjectName, + sizeof(UNICODE_STRING), + sizeof(USHORT)); + LocalName = *ObjectName; + + ProbeForRead(LocalName.Buffer, + LocalName.Length, + sizeof(WCHAR)); + } + else + { + /* No probing needed */ + LocalName = *ObjectName; + } + + /* Make sure there really is a string */ + DPRINT("Probing OK\n"); + if ((StringLength = LocalName.Length)) + { + /* Check that the size is a valid WCHAR multiple */ + if ((StringLength & (sizeof(WCHAR) - 1)) || + /* Check that the NULL-termination below will work */ + (StringLength == (MAXUSHORT - sizeof(WCHAR) + 1))) + { + /* PS: Please keep the checks above expanded for clarity */ + DPRINT1("Invalid String Length\n"); + Status = STATUS_OBJECT_NAME_INVALID; + } + else + { + /* Allocate a non-paged buffer for this string */ + DPRINT("Capturing String\n"); + CapturedName->Length = StringLength; + CapturedName->MaximumLength = StringLength + sizeof(WCHAR); + if ((StringBuffer = ExAllocatePoolWithTag(NonPagedPool, + StringLength + sizeof(WCHAR), + OB_NAME_TAG))) + { + /* Copy the string and null-terminate it */ + RtlMoveMemory(StringBuffer, LocalName.Buffer, StringLength); + StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL; + CapturedName->Buffer = StringBuffer; + DPRINT("String Captured: %wZ\n", CapturedName); + } + else + { + /* Fail */ + DPRINT1("Out of Memory!\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + } + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { + Status = _SEH_GetExceptionCode(); + + /* Remember to free the buffer in case of failure */ + DPRINT1("Failed\n"); + if (StringBuffer) ExFreePool(StringBuffer); + } + _SEH_END; + + /* Return */ + DPRINT("Returning: %lx\n", Status); + return Status; +} + +NTSTATUS +STDCALL +ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes, + IN KPROCESSOR_MODE AccessMode, + IN POBJECT_TYPE ObjectType, + IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, + OUT PUNICODE_STRING ObjectName) +{ + NTSTATUS Status = STATUS_SUCCESS; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PSECURITY_QUALITY_OF_SERVICE SecurityQos; + PUNICODE_STRING LocalObjectName = NULL; + + /* Zero out the Capture Data */ + DPRINT("ObpCaptureObjectAttributes\n"); + RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION)); + + /* SEH everything here for protection */ + _SEH_TRY + { + /* Check if we got Oba */ + if (ObjectAttributes) + { + if (AccessMode != KernelMode) + { + DPRINT("Probing OBA\n"); + ProbeForRead(ObjectAttributes, + sizeof(OBJECT_ATTRIBUTES), + sizeof(ULONG)); + } + + /* Validate the Size and Attributes */ + DPRINT("Validating OBA\n"); + if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) || + (ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES)) + { + Status = STATUS_INVALID_PARAMETER; + DPRINT1("Invalid Size: %lx or Attributes: %lx\n", + ObjectAttributes->Length, ObjectAttributes->Attributes); + _SEH_LEAVE; + } + + /* Set some Create Info */ + DPRINT("Creating OBCI\n"); + ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory; + ObjectCreateInfo->Attributes = ObjectAttributes->Attributes; + LocalObjectName = ObjectAttributes->ObjectName; + SecurityDescriptor = ObjectAttributes->SecurityDescriptor; + SecurityQos = ObjectAttributes->SecurityQualityOfService; + + /* Validate the SD */ + if (SecurityDescriptor) + { + DPRINT("Probing SD: %x\n", SecurityDescriptor); + Status = SeCaptureSecurityDescriptor(SecurityDescriptor, + AccessMode, + NonPagedPool, + TRUE, + &ObjectCreateInfo->SecurityDescriptor); + if(!NT_SUCCESS(Status)) + { + DPRINT1("Unable to capture the security descriptor!!!\n"); + ObjectCreateInfo->SecurityDescriptor = NULL; + _SEH_LEAVE; + } + + DPRINT("Probe done\n"); + ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */ + ObjectCreateInfo->ProbeMode = AccessMode; + } + + /* Validate the QoS */ + if (SecurityQos) + { + if (AccessMode != KernelMode) + { + DPRINT("Probing QoS\n"); + ProbeForRead(SecurityQos, + sizeof(SECURITY_QUALITY_OF_SERVICE), + sizeof(ULONG)); + } + + /* Save Info */ + ObjectCreateInfo->SecurityQualityOfService = *SecurityQos; + ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService; + } + } + else + { + LocalObjectName = NULL; + } + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { + Status = _SEH_GetExceptionCode(); + DPRINT1("Failed\n"); + } + _SEH_END; + + if (NT_SUCCESS(Status)) + { + /* Now check if the Object Attributes had an Object Name */ + if (LocalObjectName) + { + DPRINT("Name Buffer: %wZ\n", LocalObjectName); + Status = ObpCaptureObjectName(ObjectName, + LocalObjectName, + AccessMode); + } + else + { + /* Clear the string */ + RtlInitUnicodeString(ObjectName, NULL); + + /* He can't have specified a Root Directory */ + if (ObjectCreateInfo->RootDirectory) + { + DPRINT1("Invalid name\n"); + Status = STATUS_OBJECT_NAME_INVALID; + } + } + } + else + { + DPRINT1("Failed to capture, cleaning up\n"); + ObpReleaseCapturedAttributes(ObjectCreateInfo); + } + + DPRINT("Return to caller %x\n", Status); + return Status; +} + + +VOID +STDCALL +ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo) +{ + /* Release the SD, it's the only thing we allocated */ + if (ObjectCreateInfo->SecurityDescriptor) + { + SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor, + ObjectCreateInfo->ProbeMode, + TRUE); + ObjectCreateInfo->SecurityDescriptor = NULL; + } +} + +NTSTATUS +STDCALL +ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, + POBJECT_TYPE ObjectType, + ULONG ObjectSize, + POBJECT_HEADER *ObjectHeader) +{ + POBJECT_HEADER Header; + BOOLEAN HasHandleInfo = FALSE; + BOOLEAN HasNameInfo = FALSE; + BOOLEAN HasCreatorInfo = FALSE; + POBJECT_HEADER_HANDLE_INFO HandleInfo; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER_CREATOR_INFO CreatorInfo; + POOL_TYPE PoolType; + ULONG FinalSize = ObjectSize; + ULONG Tag; + + /* If we don't have an Object Type yet, force NonPaged */ + DPRINT("ObpAllocateObject\n"); + if (!ObjectType) + { + PoolType = NonPagedPool; + Tag = TAG('O', 'b', 'j', 'T'); + } + else + { + PoolType = ObjectType->TypeInfo.PoolType; + Tag = ObjectType->Key; + } + + DPRINT("Checking ObjectName: %x\n", ObjectName); + /* Check if the Object has a name */ + if (ObjectName->Buffer) + { + FinalSize += sizeof(OBJECT_HEADER_NAME_INFO); + HasNameInfo = TRUE; + } + + if (ObjectType) + { + /* Check if the Object maintains handle counts */ + DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType->TypeInfo); + if (ObjectType->TypeInfo.MaintainHandleCount) + { + FinalSize += sizeof(OBJECT_HEADER_HANDLE_INFO); + HasHandleInfo = TRUE; + } + + /* Check if the Object maintains type lists */ + if (ObjectType->TypeInfo.MaintainTypeList) + { + FinalSize += sizeof(OBJECT_HEADER_CREATOR_INFO); + HasCreatorInfo = TRUE; + } + } + + /* Allocate memory for the Object and Header */ + DPRINT("Allocating: %x %x\n", FinalSize, Tag); + Header = ExAllocatePoolWithTag(PoolType, FinalSize, Tag); + if (!Header) { + DPRINT1("Not enough memory!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize Handle Info */ + if (HasHandleInfo) + { + HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header; + DPRINT("Info: %x\n", HandleInfo); + HandleInfo->SingleEntry.HandleCount = 0; + Header = (POBJECT_HEADER)(HandleInfo + 1); + } + + /* Initialize the Object Name Info */ + if (HasNameInfo) + { + NameInfo = (POBJECT_HEADER_NAME_INFO)Header; + DPRINT("Info: %x %wZ\n", NameInfo, ObjectName); + NameInfo->Name = *ObjectName; + NameInfo->Directory = NULL; + Header = (POBJECT_HEADER)(NameInfo + 1); + } + + /* Initialize Creator Info */ + if (HasCreatorInfo) + { + CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header; + DPRINT("Info: %x\n", CreatorInfo); + /* FIXME: Needs Alex's Init patch + * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId(); + */ + InitializeListHead(&CreatorInfo->TypeList); + Header = (POBJECT_HEADER)(CreatorInfo + 1); + } + + /* Initialize the object header */ + RtlZeroMemory(Header, ObjectSize); + DPRINT("Initalized header %p\n", Header); + Header->HandleCount = 0; + Header->PointerCount = 1; + Header->Type = ObjectType; + Header->Flags = OB_FLAG_CREATE_INFO; + + /* Set the Offsets for the Info */ + if (HasHandleInfo) + { + Header->HandleInfoOffset = HasNameInfo * sizeof(OBJECT_HEADER_NAME_INFO) + + sizeof(OBJECT_HEADER_HANDLE_INFO) + + HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO); + Header->Flags |= OB_FLAG_SINGLE_PROCESS; + } + if (HasNameInfo) + { + Header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) + + HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO); + } + if (HasCreatorInfo) Header->Flags |= OB_FLAG_CREATOR_INFO; + + if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_PERMANENT) + { + Header->Flags |= OB_FLAG_PERMANENT; + } + if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE) + { + Header->Flags |= OB_FLAG_EXCLUSIVE; + } + + /* Link stuff to Object Header */ + Header->ObjectCreateInfo = ObjectCreateInfo; + + /* Return Header */ + *ObjectHeader = Header; + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, + PUNICODE_STRING TypeName, + POBJECT_TYPE *ObjectType) +{ + POBJECT_HEADER Header; + POBJECT_TYPE LocalObjectType; + ULONG HeaderSize; + NTSTATUS Status; + + DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", TypeName); + + /* Allocate the Object */ + Status = ObpAllocateObject(NULL, + TypeName, + ObTypeObjectType, + OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE)), + (POBJECT_HEADER*)&Header); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ObpAllocateObject failed!\n"); + return Status; + } + + LocalObjectType = (POBJECT_TYPE)&Header->Body; + DPRINT("Local ObjectType: %p Header: %p \n", LocalObjectType, Header); + + /* Check if this is the first Object Type */ + if (!ObTypeObjectType) + { + ObTypeObjectType = LocalObjectType; + Header->Type = ObTypeObjectType; + LocalObjectType->Key = TAG('O', 'b', 'j', 'T'); + } + else + { + CHAR Tag[4]; + Tag[0] = TypeName->Buffer[0]; + Tag[1] = TypeName->Buffer[1]; + Tag[2] = TypeName->Buffer[2]; + Tag[3] = TypeName->Buffer[3]; + + /* Set Tag */ + DPRINT("Convert: %s \n", Tag); + LocalObjectType->Key = *(PULONG)Tag; + } + + /* Set it up */ + LocalObjectType->TypeInfo = *ObjectTypeInitializer; + LocalObjectType->Name = *TypeName; + LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType; + + /* These two flags need to be manually set up */ + Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT; + + /* Check if we have to maintain a type list */ + if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST) + { + /* Enable support */ + LocalObjectType->TypeInfo.MaintainTypeList = TRUE; + } + + /* Calculate how much space our header'll take up */ + HeaderSize = sizeof(OBJECT_HEADER) + sizeof(OBJECT_HEADER_NAME_INFO) + + (ObjectTypeInitializer->MaintainHandleCount ? + sizeof(OBJECT_HEADER_HANDLE_INFO) : 0); + + /* Update the Pool Charges */ + if (ObjectTypeInitializer->PoolType == NonPagedPool) + { + LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize; + } + else + { + LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize; + } + + /* All objects types need a security procedure */ + if (!ObjectTypeInitializer->SecurityProcedure) + { + LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod; + } + + /* Select the Wait Object */ + if (LocalObjectType->TypeInfo.UseDefaultObject) + { + /* Add the SYNCHRONIZE access mask since it's waitable */ + LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE; + + /* Use the "Default Object", a simple event */ + LocalObjectType->DefaultObject = &ObpDefaultObject; + } + /* Special system objects get an optimized hack so they can be waited on */ + else if (TypeName->Length == 8 && !wcscmp(TypeName->Buffer, L"File")) + { + LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(FILE_OBJECT, Event); + } + /* FIXME: When LPC stops sucking, add a hack for Waitable Ports */ + else + { + /* No default Object */ + LocalObjectType->DefaultObject = NULL; + } + + /* Initialize Object Type components */ + ExInitializeResourceLite(&LocalObjectType->Mutex); + InitializeListHead(&LocalObjectType->TypeList); + + /* Insert it into the Object Directory */ + if (ObpTypeDirectoryObject) + { + OBP_LOOKUP_CONTEXT Context; + Context.Directory = ObpTypeDirectoryObject; + Context.DirectoryLocked = TRUE; + ObpLookupEntryDirectory(ObpTypeDirectoryObject, + TypeName, + OBJ_CASE_INSENSITIVE, + FALSE, + &Context); + ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header); + ObReferenceObject(ObpTypeDirectoryObject); + } + + *ObjectType = LocalObjectType; + return Status; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +NTSTATUS +NTAPI +ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL, + IN POBJECT_TYPE Type, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN KPROCESSOR_MODE AccessMode, + IN OUT PVOID ParseContext OPTIONAL, + IN ULONG ObjectSize, + IN ULONG PagedPoolCharge OPTIONAL, + IN ULONG NonPagedPoolCharge OPTIONAL, + OUT PVOID *Object) +{ + NTSTATUS Status; + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + UNICODE_STRING ObjectName; + POBJECT_HEADER Header; + + DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n", + Type, ObjectAttributes, Object); + + /* Allocate a Buffer for the Object Create Info */ + DPRINT("Allocating Create Buffer\n"); + ObjectCreateInfo = ExAllocatePoolWithTag(NonPagedPool, + sizeof(*ObjectCreateInfo), + TAG('O','b','C', 'I')); + + /* Capture all the info */ + DPRINT("Capturing Create Info\n"); + Status = ObpCaptureObjectAttributes(ObjectAttributes, + ObjectAttributesAccessMode, + Type, + ObjectCreateInfo, + &ObjectName); + + if (NT_SUCCESS(Status)) + { + /* Allocate the Object */ + DPRINT("Allocating: %wZ\n", &ObjectName); + Status = ObpAllocateObject(ObjectCreateInfo, + &ObjectName, + Type, + OBJECT_ALLOC_SIZE(ObjectSize), + &Header); + + if (NT_SUCCESS(Status)) + { + /* Return the Object */ + DPRINT("Returning Object\n"); + *Object = &Header->Body; + + /* Return to caller, leave the Capture Info Alive for ObInsert */ + return Status; + } + + /* Release the Capture Info, we don't need it */ + DPRINT1("Allocation failed\n"); + ObpReleaseCapturedAttributes(ObjectCreateInfo); + if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); + } + + /* We failed, so release the Buffer */ + DPRINT1("Capture failed\n"); + ExFreePool(ObjectCreateInfo); + return Status; +} + +/*++ +* @name NtQueryObject +* @implemented NT4 +* +* The NtQueryObject routine +* +* @param ObjectHandle +* +* +* @param ObjectInformationClass +* +* +* @param ObjectInformation +* +* +* @param Length +* +* +* @param ResultLength +* +* +* @return STATUS_SUCCESS or appropriate error value. +* +* @remarks None. +* +*--*/ +NTSTATUS +NTAPI +NtQueryObject(IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL) +{ + OBJECT_HANDLE_INFORMATION HandleInfo; + POBJECT_HEADER ObjectHeader; + ULONG InfoLength; + PVOID Object; + NTSTATUS Status; + PAGED_CODE(); + + Status = ObReferenceObjectByHandle(ObjectHandle, + 0, + NULL, + KeGetPreviousMode(), + &Object, + &HandleInfo); + if (!NT_SUCCESS (Status)) return Status; + + ObjectHeader = BODY_TO_HEADER(Object); + + switch (ObjectInformationClass) + { + case ObjectBasicInformation: + InfoLength = sizeof(OBJECT_BASIC_INFORMATION); + if (Length != sizeof(OBJECT_BASIC_INFORMATION)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + POBJECT_BASIC_INFORMATION BasicInfo; + + BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation; + BasicInfo->Attributes = HandleInfo.HandleAttributes; + BasicInfo->GrantedAccess = HandleInfo.GrantedAccess; + BasicInfo->HandleCount = ObjectHeader->HandleCount; + BasicInfo->PointerCount = ObjectHeader->PointerCount; + BasicInfo->PagedPoolUsage = 0; /* FIXME*/ + BasicInfo->NonPagedPoolUsage = 0; /* FIXME*/ + BasicInfo->NameInformationLength = 0; /* FIXME*/ + BasicInfo->TypeInformationLength = 0; /* FIXME*/ + BasicInfo->SecurityDescriptorLength = 0; /* FIXME*/ + if (ObjectHeader->Type == ObSymbolicLinkType) + { + BasicInfo->CreateTime.QuadPart = + ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart; + } + else + { + BasicInfo->CreateTime.QuadPart = (ULONGLONG)0; + } + Status = STATUS_SUCCESS; + } + break; + + case ObjectNameInformation: + Status = ObQueryNameString(Object, + (POBJECT_NAME_INFORMATION)ObjectInformation, + Length, + &InfoLength); + break; + + case ObjectTypeInformation: + Status = STATUS_NOT_IMPLEMENTED; + break; + + case ObjectAllTypesInformation: + Status = STATUS_NOT_IMPLEMENTED; + break; + + case ObjectHandleInformation: + InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION); + if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + Status = ObpQueryHandleAttributes( + ObjectHandle, + (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)ObjectInformation); + } + break; + + default: + Status = STATUS_INVALID_INFO_CLASS; + break; + } + + ObDereferenceObject (Object); + + if (ResultLength != NULL) *ResultLength = InfoLength; + + return Status; +} + +/*++ +* @name NtSetInformationObject +* @implemented NT4 +* +* The NtSetInformationObject routine +* +* @param ObjectHandle +* +* +* @param ObjectInformationClass +* +* +* @param ObjectInformation +* +* +* @param Length +* +* +* @return STATUS_SUCCESS or appropriate error value. +* +* @remarks None. +* +*--*/ +NTSTATUS +NTAPI +NtSetInformationObject(IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + IN PVOID ObjectInformation, + IN ULONG Length) +{ + PVOID Object; + NTSTATUS Status; + PAGED_CODE(); + + if (ObjectInformationClass != ObjectHandleInformation) + return STATUS_INVALID_INFO_CLASS; + + if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) + return STATUS_INFO_LENGTH_MISMATCH; + + Status = ObReferenceObjectByHandle(ObjectHandle, + 0, + NULL, + KeGetPreviousMode(), + &Object, + NULL); + if (!NT_SUCCESS (Status)) return Status; + + Status = ObpSetHandleAttributes(ObjectHandle, + (POBJECT_HANDLE_ATTRIBUTE_INFORMATION) + ObjectInformation); + + ObDereferenceObject (Object); + return Status; +} +/* EOF */ diff --git a/reactos/ntoskrnl/ob/obname.c b/reactos/ntoskrnl/ob/obname.c index 13ca304923c..d524399c1da 100644 --- a/reactos/ntoskrnl/ob/obname.c +++ b/reactos/ntoskrnl/ob/obname.c @@ -1,365 +1,365 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/ob/namespce.c - * PURPOSE: Manages all functions related to the Object Manager name- - * space, such as finding objects or querying their names. - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - * Eric Kohl - * Thomas Weidenmueller (w3seek@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include - -POBJECT_DIRECTORY NameSpaceRoot = NULL; -POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL; - -/* PRIVATE FUNCTIONS *********************************************************/ - -NTSTATUS -NTAPI -ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, - PUNICODE_STRING ObjectName, - PVOID* ReturnedObject, - PUNICODE_STRING RemainingPath, - POBJECT_TYPE ObjectType, - POBP_LOOKUP_CONTEXT Context) -{ - PVOID NextObject; - PVOID CurrentObject; - PVOID RootObject; - POBJECT_HEADER CurrentHeader; - NTSTATUS Status; - PWSTR current; - UNICODE_STRING PathString; - ULONG Attributes; - - PAGED_CODE(); - - DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, " - "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath); - - RtlInitUnicodeString (RemainingPath, NULL); - - if (ObjectCreateInfo->RootDirectory == NULL) - { - ObReferenceObjectByPointer(NameSpaceRoot, - DIRECTORY_TRAVERSE, - NULL, - ObjectCreateInfo->ProbeMode); - CurrentObject = NameSpaceRoot; - } - else - { - Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory, - 0, - NULL, - ObjectCreateInfo->ProbeMode, - &CurrentObject, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - } - - if (ObjectName->Length == 0 || - ObjectName->Buffer[0] == UNICODE_NULL) - { - *ReturnedObject = CurrentObject; - return STATUS_SUCCESS; - } - - if (ObjectCreateInfo->RootDirectory == NULL && - ObjectName->Buffer[0] != L'\\') - { - ObDereferenceObject (CurrentObject); - DPRINT1("failed\n"); - return STATUS_UNSUCCESSFUL; - } - - /* Create a zero-terminated copy of the object name */ - PathString.Length = ObjectName->Length; - PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR); - PathString.Buffer = ExAllocatePool (NonPagedPool, - PathString.MaximumLength); - if (PathString.Buffer == NULL) - { - ObDereferenceObject (CurrentObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlCopyMemory (PathString.Buffer, - ObjectName->Buffer, - ObjectName->Length); - PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL; - - current = PathString.Buffer; - - RootObject = CurrentObject; - Attributes = ObjectCreateInfo->Attributes; - if (ObjectType == ObSymbolicLinkType) - Attributes |= OBJ_OPENLINK; - - while (TRUE) - { - DPRINT("current %S\n",current); - CurrentHeader = BODY_TO_HEADER(CurrentObject); - - DPRINT("Current ObjectType %wZ\n", - &CurrentHeader->Type->Name); - - if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL) - { - DPRINT("Current object can't parse\n"); - break; - } - Status = ((OB_ROS_PARSE_METHOD)CurrentHeader->Type->TypeInfo.ParseProcedure)(CurrentObject, - &NextObject, - &PathString, - ¤t, - Attributes, - Context); - if (Status == STATUS_REPARSE) - { - /* reparse the object path */ - NextObject = NameSpaceRoot; - current = PathString.Buffer; - - ObReferenceObjectByPointer(NextObject, - DIRECTORY_TRAVERSE, - NULL, - ObjectCreateInfo->ProbeMode); - } - - if (NextObject == NULL) - { - break; - } - ObDereferenceObject(CurrentObject); - CurrentObject = NextObject; - } - - if (current) - { - RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool); - } - - RtlFreeUnicodeString (&PathString); - *ReturnedObject = CurrentObject; - - return STATUS_SUCCESS; -} - -/* PUBLIC FUNCTIONS *********************************************************/ - -NTSTATUS -STDCALL -ObQueryNameString(IN PVOID Object, - OUT POBJECT_NAME_INFORMATION ObjectNameInfo, - IN ULONG Length, - OUT PULONG ReturnLength) -{ - POBJECT_HEADER_NAME_INFO LocalInfo; - POBJECT_HEADER ObjectHeader; - POBJECT_DIRECTORY ParentDirectory; - ULONG NameSize; - PWCH ObjectName; - NTSTATUS Status; - - DPRINT("ObQueryNameString: %x, %x\n", Object, ObjectNameInfo); - - /* Get the Kernel Meta-Structures */ - ObjectHeader = BODY_TO_HEADER(Object); - LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); - - /* Check if a Query Name Procedure is available */ - if (ObjectHeader->Type->TypeInfo.QueryNameProcedure) - { - /* Call the procedure */ - DPRINT("Calling Object's Procedure\n"); - Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object, - TRUE, //fixme - ObjectNameInfo, - Length, - ReturnLength); - - /* Return the status */ - return Status; - } - - /* Check if the object doesn't even have a name */ - if (!LocalInfo || !LocalInfo->Name.Buffer) - { - /* We're returning the name structure */ - DPRINT("Nameless Object\n"); - *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); - - /* Check if we were given enough space */ - if (*ReturnLength > Length) - { - DPRINT1("Not enough buffer space\n"); - return STATUS_INFO_LENGTH_MISMATCH; - } - - /* Return an empty buffer */ - ObjectNameInfo->Name.Length = 0; - ObjectNameInfo->Name.MaximumLength = 0; - ObjectNameInfo->Name.Buffer = NULL; - - return STATUS_SUCCESS; - } - - /* - * Find the size needed for the name. We won't do - * this during the Name Creation loop because we want - * to let the caller know that the buffer isn't big - * enough right at the beginning, not work our way through - * and find out at the end - */ - if (Object == NameSpaceRoot) - { - /* Size of the '\' string */ - DPRINT("Object is Root\n"); - NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR); - } - else - { - /* Get the Object Directory and add name of Object */ - ParentDirectory = LocalInfo->Directory; - NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; - - /* Loop inside the directory to get the top-most one (meaning root) */ - while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory)) - { - /* Get the Name Information */ - LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory)); - - /* Add the size of the Directory Name */ - if (LocalInfo && LocalInfo->Directory) - { - /* Size of the '\' string + Directory Name */ - NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; - - /* Move to next parent Directory */ - ParentDirectory = LocalInfo->Directory; - } - else - { - /* Directory with no name. We append "...\" */ - DPRINT("Nameless Directory\n"); - NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR); - break; - } - } - } - - /* Finally, add the name of the structure and the null char */ - *ReturnLength = NameSize + sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL); - DPRINT("Final Length: %x\n", *ReturnLength); - - /* Check if we were given enough space */ - if (*ReturnLength > Length) - { - DPRINT1("Not enough buffer space\n"); - return STATUS_INFO_LENGTH_MISMATCH; - } - - /* - * Now we will actually create the name. We work backwards because - * it's easier to start off from the Name we have and walk up the - * parent directories. We use the same logic as Name Length calculation. - */ - LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); - ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength); - *--ObjectName = UNICODE_NULL; - - if (Object == NameSpaceRoot) - { - /* This is already the Root Directory, return "\\" */ - DPRINT("Returning Root Dir\n"); - *--ObjectName = OBJ_NAME_PATH_SEPARATOR; - ObjectNameInfo->Name.Length = (USHORT)NameSize; - ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL)); - ObjectNameInfo->Name.Buffer = ObjectName; - - return STATUS_SUCCESS; - } - else - { - /* Start by adding the Object's Name */ - ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length); - RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length); - - /* Now parse the Parent directories until we reach the top */ - ParentDirectory = LocalInfo->Directory; - while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory)) - { - /* Get the name information */ - LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory)); - - /* Add the "\" */ - *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; - - /* Add the Parent Directory's Name */ - if (LocalInfo && LocalInfo->Name.Buffer) - { - /* Add the name */ - ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length); - RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length); - - /* Move to next parent */ - ParentDirectory = LocalInfo->Directory; - } - else - { - /* Directory without a name, we add "..." */ - DPRINT("Nameless Directory\n"); - ObjectName -= sizeof(L"..."); - ObjectName = L"..."; - break; - } - } - - /* Add Root Directory Name */ - *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; - DPRINT("Current Buffer: %S\n", ObjectName); - ObjectNameInfo->Name.Length = (USHORT)NameSize; - ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL)); - ObjectNameInfo->Name.Buffer = ObjectName; - DPRINT("Complete: %wZ\n", ObjectNameInfo); - } - - return STATUS_SUCCESS; -} - -VOID -NTAPI -ObQueryDeviceMapInformation(IN PEPROCESS Process, - IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo) -{ - //KIRQL OldIrql ; - - /* - * FIXME: This is an ugly hack for now, to always return the System Device Map - * instead of returning the Process Device Map. Not important yet since we don't use it - */ - - /* FIXME: Acquire the DeviceMap Spinlock */ - // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql); - - /* Make a copy */ - DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap; - RtlMoveMemory(DeviceMapInfo->Query.DriveType, - ObSystemDeviceMap->DriveType, - sizeof(ObSystemDeviceMap->DriveType)); - - /* FIXME: Release the DeviceMap Spinlock */ - // KeReleasepinLock(DeviceMap->Lock, OldIrql); -} - -/* EOF */ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ob/namespce.c + * PURPOSE: Manages all functions related to the Object Manager name- + * space, such as finding objects or querying their names. + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl + * Thomas Weidenmueller (w3seek@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +POBJECT_DIRECTORY NameSpaceRoot = NULL; +POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL; + +/* PRIVATE FUNCTIONS *********************************************************/ + +NTSTATUS +NTAPI +ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, + PVOID* ReturnedObject, + PUNICODE_STRING RemainingPath, + POBJECT_TYPE ObjectType, + POBP_LOOKUP_CONTEXT Context) +{ + PVOID NextObject; + PVOID CurrentObject; + PVOID RootObject; + POBJECT_HEADER CurrentHeader; + NTSTATUS Status; + PWSTR current; + UNICODE_STRING PathString; + ULONG Attributes; + + PAGED_CODE(); + + DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, " + "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath); + + RtlInitUnicodeString (RemainingPath, NULL); + + if (ObjectCreateInfo->RootDirectory == NULL) + { + ObReferenceObjectByPointer(NameSpaceRoot, + DIRECTORY_TRAVERSE, + NULL, + ObjectCreateInfo->ProbeMode); + CurrentObject = NameSpaceRoot; + } + else + { + Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory, + 0, + NULL, + ObjectCreateInfo->ProbeMode, + &CurrentObject, + NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + + if (ObjectName->Length == 0 || + ObjectName->Buffer[0] == UNICODE_NULL) + { + *ReturnedObject = CurrentObject; + return STATUS_SUCCESS; + } + + if (ObjectCreateInfo->RootDirectory == NULL && + ObjectName->Buffer[0] != L'\\') + { + ObDereferenceObject (CurrentObject); + DPRINT1("failed\n"); + return STATUS_UNSUCCESSFUL; + } + + /* Create a zero-terminated copy of the object name */ + PathString.Length = ObjectName->Length; + PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR); + PathString.Buffer = ExAllocatePool (NonPagedPool, + PathString.MaximumLength); + if (PathString.Buffer == NULL) + { + ObDereferenceObject (CurrentObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory (PathString.Buffer, + ObjectName->Buffer, + ObjectName->Length); + PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL; + + current = PathString.Buffer; + + RootObject = CurrentObject; + Attributes = ObjectCreateInfo->Attributes; + if (ObjectType == ObSymbolicLinkType) + Attributes |= OBJ_OPENLINK; + + while (TRUE) + { + DPRINT("current %S\n",current); + CurrentHeader = BODY_TO_HEADER(CurrentObject); + + DPRINT("Current ObjectType %wZ\n", + &CurrentHeader->Type->Name); + + if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL) + { + DPRINT("Current object can't parse\n"); + break; + } + Status = ((OB_ROS_PARSE_METHOD)CurrentHeader->Type->TypeInfo.ParseProcedure)(CurrentObject, + &NextObject, + &PathString, + ¤t, + Attributes, + Context); + if (Status == STATUS_REPARSE) + { + /* reparse the object path */ + NextObject = NameSpaceRoot; + current = PathString.Buffer; + + ObReferenceObjectByPointer(NextObject, + DIRECTORY_TRAVERSE, + NULL, + ObjectCreateInfo->ProbeMode); + } + + if (NextObject == NULL) + { + break; + } + ObDereferenceObject(CurrentObject); + CurrentObject = NextObject; + } + + if (current) + { + RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool); + } + + RtlFreeUnicodeString (&PathString); + *ReturnedObject = CurrentObject; + + return STATUS_SUCCESS; +} + +/* PUBLIC FUNCTIONS *********************************************************/ + +NTSTATUS +STDCALL +ObQueryNameString(IN PVOID Object, + OUT POBJECT_NAME_INFORMATION ObjectNameInfo, + IN ULONG Length, + OUT PULONG ReturnLength) +{ + POBJECT_HEADER_NAME_INFO LocalInfo; + POBJECT_HEADER ObjectHeader; + POBJECT_DIRECTORY ParentDirectory; + ULONG NameSize; + PWCH ObjectName; + NTSTATUS Status; + + DPRINT("ObQueryNameString: %x, %x\n", Object, ObjectNameInfo); + + /* Get the Kernel Meta-Structures */ + ObjectHeader = BODY_TO_HEADER(Object); + LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + + /* Check if a Query Name Procedure is available */ + if (ObjectHeader->Type->TypeInfo.QueryNameProcedure) + { + /* Call the procedure */ + DPRINT("Calling Object's Procedure\n"); + Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object, + TRUE, //fixme + ObjectNameInfo, + Length, + ReturnLength); + + /* Return the status */ + return Status; + } + + /* Check if the object doesn't even have a name */ + if (!LocalInfo || !LocalInfo->Name.Buffer) + { + /* We're returning the name structure */ + DPRINT("Nameless Object\n"); + *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); + + /* Check if we were given enough space */ + if (*ReturnLength > Length) + { + DPRINT1("Not enough buffer space\n"); + return STATUS_INFO_LENGTH_MISMATCH; + } + + /* Return an empty buffer */ + ObjectNameInfo->Name.Length = 0; + ObjectNameInfo->Name.MaximumLength = 0; + ObjectNameInfo->Name.Buffer = NULL; + + return STATUS_SUCCESS; + } + + /* + * Find the size needed for the name. We won't do + * this during the Name Creation loop because we want + * to let the caller know that the buffer isn't big + * enough right at the beginning, not work our way through + * and find out at the end + */ + if (Object == NameSpaceRoot) + { + /* Size of the '\' string */ + DPRINT("Object is Root\n"); + NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR); + } + else + { + /* Get the Object Directory and add name of Object */ + ParentDirectory = LocalInfo->Directory; + NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; + + /* Loop inside the directory to get the top-most one (meaning root) */ + while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory)) + { + /* Get the Name Information */ + LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory)); + + /* Add the size of the Directory Name */ + if (LocalInfo && LocalInfo->Directory) + { + /* Size of the '\' string + Directory Name */ + NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; + + /* Move to next parent Directory */ + ParentDirectory = LocalInfo->Directory; + } + else + { + /* Directory with no name. We append "...\" */ + DPRINT("Nameless Directory\n"); + NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR); + break; + } + } + } + + /* Finally, add the name of the structure and the null char */ + *ReturnLength = NameSize + sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL); + DPRINT("Final Length: %x\n", *ReturnLength); + + /* Check if we were given enough space */ + if (*ReturnLength > Length) + { + DPRINT1("Not enough buffer space\n"); + return STATUS_INFO_LENGTH_MISMATCH; + } + + /* + * Now we will actually create the name. We work backwards because + * it's easier to start off from the Name we have and walk up the + * parent directories. We use the same logic as Name Length calculation. + */ + LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength); + *--ObjectName = UNICODE_NULL; + + if (Object == NameSpaceRoot) + { + /* This is already the Root Directory, return "\\" */ + DPRINT("Returning Root Dir\n"); + *--ObjectName = OBJ_NAME_PATH_SEPARATOR; + ObjectNameInfo->Name.Length = (USHORT)NameSize; + ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL)); + ObjectNameInfo->Name.Buffer = ObjectName; + + return STATUS_SUCCESS; + } + else + { + /* Start by adding the Object's Name */ + ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length); + RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length); + + /* Now parse the Parent directories until we reach the top */ + ParentDirectory = LocalInfo->Directory; + while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory)) + { + /* Get the name information */ + LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory)); + + /* Add the "\" */ + *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; + + /* Add the Parent Directory's Name */ + if (LocalInfo && LocalInfo->Name.Buffer) + { + /* Add the name */ + ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length); + RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length); + + /* Move to next parent */ + ParentDirectory = LocalInfo->Directory; + } + else + { + /* Directory without a name, we add "..." */ + DPRINT("Nameless Directory\n"); + ObjectName -= sizeof(L"..."); + ObjectName = L"..."; + break; + } + } + + /* Add Root Directory Name */ + *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; + DPRINT("Current Buffer: %S\n", ObjectName); + ObjectNameInfo->Name.Length = (USHORT)NameSize; + ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL)); + ObjectNameInfo->Name.Buffer = ObjectName; + DPRINT("Complete: %wZ\n", ObjectNameInfo); + } + + return STATUS_SUCCESS; +} + +VOID +NTAPI +ObQueryDeviceMapInformation(IN PEPROCESS Process, + IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo) +{ + //KIRQL OldIrql ; + + /* + * FIXME: This is an ugly hack for now, to always return the System Device Map + * instead of returning the Process Device Map. Not important yet since we don't use it + */ + + /* FIXME: Acquire the DeviceMap Spinlock */ + // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql); + + /* Make a copy */ + DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap; + RtlMoveMemory(DeviceMapInfo->Query.DriveType, + ObSystemDeviceMap->DriveType, + sizeof(ObSystemDeviceMap->DriveType)); + + /* FIXME: Release the DeviceMap Spinlock */ + // KeReleasepinLock(DeviceMap->Lock, OldIrql); +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ob/obref.c b/reactos/ntoskrnl/ob/obref.c index cd29e5a5df0..79c2b968fca 100644 --- a/reactos/ntoskrnl/ob/obref.c +++ b/reactos/ntoskrnl/ob/obref.c @@ -1,455 +1,455 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/ob/refderef.c - * PURPOSE: Manages the referencing and de-referencing of all Objects, - * as well as the Object Fast Reference implementation. - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - * Eric Kohl - * Thomas Weidenmueller (w3seek@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include - -/* PRIVATE FUNCTIONS *********************************************************/ - -VOID -FASTCALL -ObInitializeFastReference(IN PEX_FAST_REF FastRef, - PVOID Object) -{ - /* FIXME: Fast Referencing is Unimplemented */ - FastRef->Object = Object; -} - -PVOID -FASTCALL -ObFastReferenceObject(IN PEX_FAST_REF FastRef) -{ - /* FIXME: Fast Referencing is Unimplemented */ - - /* Do a normal Reference */ - ObReferenceObject(FastRef->Object); - - /* Return the Object */ - return FastRef->Object; -} - -VOID -FASTCALL -ObFastDereferenceObject(IN PEX_FAST_REF FastRef, - PVOID Object) -{ - /* FIXME: Fast Referencing is Unimplemented */ - - /* Do a normal Dereference */ - ObDereferenceObject(FastRef->Object); -} - -PVOID -FASTCALL -ObFastReplaceObject(IN PEX_FAST_REF FastRef, - PVOID Object) -{ - PVOID OldObject = FastRef->Object; - - /* FIXME: Fast Referencing is Unimplemented */ - FastRef->Object = Object; - - /* Do a normal Dereference */ - ObDereferenceObject(OldObject); - - /* Return old Object*/ - return OldObject; -} - -/* PUBLIC FUNCTIONS *********************************************************/ - -ULONG STDCALL -ObGetObjectPointerCount(PVOID Object) -{ - POBJECT_HEADER Header; - - PAGED_CODE(); - - ASSERT(Object); - Header = BODY_TO_HEADER(Object); - - return Header->PointerCount; -} - -VOID FASTCALL -ObfReferenceObject(IN PVOID Object) -{ - POBJECT_HEADER Header; - - ASSERT(Object); - - Header = BODY_TO_HEADER(Object); - - /* No one should be referencing an object once we are deleting it. */ - if (InterlockedIncrement(&Header->PointerCount) == 1 && !(Header->Flags & OB_FLAG_PERMANENT)) - { - KEBUGCHECK(0); - } - -} - -VOID -FASTCALL -ObfDereferenceObject(IN PVOID Object) -{ - POBJECT_HEADER Header; - LONG NewPointerCount; - BOOL Permanent; - - ASSERT(Object); - - /* Extract the object header. */ - Header = BODY_TO_HEADER(Object); - Permanent = Header->Flags & OB_FLAG_PERMANENT; - - /* - Drop our reference and get the new count so we can tell if this was the - last reference. - */ - NewPointerCount = InterlockedDecrement(&Header->PointerCount); - DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object, NewPointerCount); - ASSERT(NewPointerCount >= 0); - - /* Check whether the object can now be deleted. */ - if (NewPointerCount == 0 && - !Permanent) - { - ObpDeleteObjectDpcLevel(Header, NewPointerCount); - } -} - -NTSTATUS STDCALL -ObReferenceObjectByPointer(IN PVOID Object, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_TYPE ObjectType, - IN KPROCESSOR_MODE AccessMode) -{ - POBJECT_HEADER Header; - - /* NOTE: should be possible to reference an object above APC_LEVEL! */ - - DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n", - Object,ObjectType); - - Header = BODY_TO_HEADER(Object); - - if (ObjectType != NULL && Header->Type != ObjectType) - { - DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n", - Header, - Header->Type, - &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header->Type))->Name, - ObjectType, - &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType))->Name); - return(STATUS_UNSUCCESSFUL); - } - if (Header->Type == PsProcessType) - { - DPRINT("Ref p 0x%x PointerCount %d type %x ", - Object, Header->PointerCount, PsProcessType); - DPRINT("eip %x\n", ((PULONG)&Object)[-1]); - } - if (Header->Type == PsThreadType) - { - DPRINT("Deref t 0x%x with PointerCount %d type %x ", - Object, Header->PointerCount, PsThreadType); - DPRINT("eip %x\n", ((PULONG)&Object)[-1]); - } - - if (Header->PointerCount == 0 && !(Header->Flags & OB_FLAG_PERMANENT)) - { - if (Header->Type == PsProcessType) - { - return STATUS_PROCESS_IS_TERMINATING; - } - if (Header->Type == PsThreadType) - { - return STATUS_THREAD_IS_TERMINATING; - } - return(STATUS_UNSUCCESSFUL); - } - - if (1 == InterlockedIncrement(&Header->PointerCount) && !(Header->Flags & OB_FLAG_PERMANENT)) - { - KEBUGCHECK(0); - } - - return(STATUS_SUCCESS); -} - -NTSTATUS STDCALL -ObReferenceObjectByName(PUNICODE_STRING ObjectPath, - ULONG Attributes, - PACCESS_STATE PassedAccessState, - ACCESS_MASK DesiredAccess, - POBJECT_TYPE ObjectType, - KPROCESSOR_MODE AccessMode, - PVOID ParseContext, - PVOID* ObjectPtr) -{ - PVOID Object = NULL; - UNICODE_STRING RemainingPath; - UNICODE_STRING ObjectName; - OBJECT_CREATE_INFORMATION ObjectCreateInfo; - NTSTATUS Status; - OBP_LOOKUP_CONTEXT Context; - - PAGED_CODE(); - - /* Capture the name */ - DPRINT("Capturing Name\n"); - Status = ObpCaptureObjectName(&ObjectName, ObjectPath, AccessMode); - if (!NT_SUCCESS(Status)) - { - DPRINT("ObpCaptureObjectName() failed (Status %lx)\n", Status); - return Status; - } - - /* - * Create a fake ObjectCreateInfo structure. Note that my upcoming - * ObFindObject refactoring will remove the need for this hack. - */ - ObjectCreateInfo.RootDirectory = NULL; - ObjectCreateInfo.Attributes = Attributes; - - Status = ObFindObject(&ObjectCreateInfo, - &ObjectName, - &Object, - &RemainingPath, - ObjectType, - &Context); - - if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); - - if (!NT_SUCCESS(Status)) - { - return(Status); - } - DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object); - - if (RemainingPath.Buffer != NULL || Object == NULL) - { - DPRINT("Object %p\n", Object); - *ObjectPtr = NULL; - RtlFreeUnicodeString (&RemainingPath); - return(STATUS_OBJECT_NAME_NOT_FOUND); - } - *ObjectPtr = Object; - RtlFreeUnicodeString (&RemainingPath); - return(STATUS_SUCCESS); -} - -NTSTATUS STDCALL -ObReferenceObjectByHandle(HANDLE Handle, - ACCESS_MASK DesiredAccess, - POBJECT_TYPE ObjectType, - KPROCESSOR_MODE AccessMode, - PVOID* Object, - POBJECT_HANDLE_INFORMATION HandleInformation) -{ - PHANDLE_TABLE_ENTRY HandleEntry; - POBJECT_HEADER ObjectHeader; - PVOID ObjectBody; - ACCESS_MASK GrantedAccess; - ULONG Attributes; - PEPROCESS CurrentProcess, Process; - BOOLEAN AttachedToProcess = FALSE; - KAPC_STATE ApcState; - - PAGED_CODE(); - - DPRINT("ObReferenceObjectByHandle(Handle %p, DesiredAccess %x, " - "ObjectType %p, AccessMode %d, Object %p)\n",Handle,DesiredAccess, - ObjectType,AccessMode,Object); - - if (Handle == NULL) - { - return STATUS_INVALID_HANDLE; - } - - CurrentProcess = PsGetCurrentProcess(); - - /* - * Handle special handle names - */ - if (Handle == NtCurrentProcess() && - (ObjectType == PsProcessType || ObjectType == NULL)) - { - ObReferenceObject(CurrentProcess); - - if (HandleInformation != NULL) - { - HandleInformation->HandleAttributes = 0; - HandleInformation->GrantedAccess = PROCESS_ALL_ACCESS; - } - - *Object = CurrentProcess; - DPRINT("Referencing current process %p\n", CurrentProcess); - return STATUS_SUCCESS; - } - else if (Handle == NtCurrentProcess()) - { - CHECKPOINT; - return(STATUS_OBJECT_TYPE_MISMATCH); - } - - if (Handle == NtCurrentThread() && - (ObjectType == PsThreadType || ObjectType == NULL)) - { - PETHREAD CurrentThread = PsGetCurrentThread(); - - ObReferenceObject(CurrentThread); - - if (HandleInformation != NULL) - { - HandleInformation->HandleAttributes = 0; - HandleInformation->GrantedAccess = THREAD_ALL_ACCESS; - } - - *Object = CurrentThread; - CHECKPOINT; - return STATUS_SUCCESS; - } - else if (Handle == NtCurrentThread()) - { - CHECKPOINT; - return(STATUS_OBJECT_TYPE_MISMATCH); - } - - /* desire as much access rights as possible */ - if (DesiredAccess & MAXIMUM_ALLOWED) - { - DesiredAccess &= ~MAXIMUM_ALLOWED; - DesiredAccess |= GENERIC_ALL; - } - - if(ObIsKernelHandle(Handle, AccessMode)) - { - Process = PsInitialSystemProcess; - Handle = ObKernelHandleToHandle(Handle); - } - else - { - Process = CurrentProcess; - } - - KeEnterCriticalRegion(); - - if (Process != CurrentProcess) - { - KeStackAttachProcess(&Process->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - - HandleEntry = ExMapHandleToPointer(Process->ObjectTable, - Handle); - if (HandleEntry == NULL) - { - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - KeLeaveCriticalRegion(); - DPRINT("ExMapHandleToPointer() failed for handle 0x%p\n", Handle); - return(STATUS_INVALID_HANDLE); - } - - ObjectHeader = EX_HTE_TO_HDR(HandleEntry); - ObjectBody = &ObjectHeader->Body; - - DPRINT("locked1: ObjectHeader: 0x%p [HT:0x%p]\n", ObjectHeader, Process->ObjectTable); - - if (ObjectType != NULL && ObjectType != ObjectHeader->Type) - { - DPRINT("ObjectType mismatch: %wZ vs %wZ (handle 0x%p)\n", &ObjectType->Name, ObjectHeader->Type ? &ObjectHeader->Type->Name : NULL, Handle); - - ExUnlockHandleTableEntry(Process->ObjectTable, - HandleEntry); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - KeLeaveCriticalRegion(); - - return(STATUS_OBJECT_TYPE_MISMATCH); - } - - /* map the generic access masks if the caller asks for generic access */ - if (DesiredAccess & GENERIC_ACCESS) - { - RtlMapGenericMask(&DesiredAccess, - &BODY_TO_HEADER(ObjectBody)->Type->TypeInfo.GenericMapping); - } - - GrantedAccess = HandleEntry->GrantedAccess; - - /* Unless running as KernelMode, deny access if caller desires more access - rights than the handle can grant */ - if(AccessMode != KernelMode && (~GrantedAccess & DesiredAccess)) - { - ExUnlockHandleTableEntry(Process->ObjectTable, - HandleEntry); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - KeLeaveCriticalRegion(); - - DPRINT1("GrantedAccess: 0x%x, ~GrantedAccess: 0x%x, DesiredAccess: 0x%x, denied: 0x%x\n", GrantedAccess, ~GrantedAccess, DesiredAccess, ~GrantedAccess & DesiredAccess); - - return(STATUS_ACCESS_DENIED); - } - - ObReferenceObject(ObjectBody); - - Attributes = HandleEntry->ObAttributes & (EX_HANDLE_ENTRY_PROTECTFROMCLOSE | - EX_HANDLE_ENTRY_INHERITABLE | - EX_HANDLE_ENTRY_AUDITONCLOSE); - - ExUnlockHandleTableEntry(Process->ObjectTable, - HandleEntry); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - KeLeaveCriticalRegion(); - - if (HandleInformation != NULL) - { - HandleInformation->HandleAttributes = Attributes; - HandleInformation->GrantedAccess = GrantedAccess; - } - - *Object = ObjectBody; - - return(STATUS_SUCCESS); -} - -#ifdef ObDereferenceObject -#undef ObDereferenceObject -#endif - -VOID STDCALL -ObDereferenceObject(IN PVOID Object) -{ - ObfDereferenceObject(Object); -} -/* EOF */ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ob/refderef.c + * PURPOSE: Manages the referencing and de-referencing of all Objects, + * as well as the Object Fast Reference implementation. + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl + * Thomas Weidenmueller (w3seek@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* PRIVATE FUNCTIONS *********************************************************/ + +VOID +FASTCALL +ObInitializeFastReference(IN PEX_FAST_REF FastRef, + PVOID Object) +{ + /* FIXME: Fast Referencing is Unimplemented */ + FastRef->Object = Object; +} + +PVOID +FASTCALL +ObFastReferenceObject(IN PEX_FAST_REF FastRef) +{ + /* FIXME: Fast Referencing is Unimplemented */ + + /* Do a normal Reference */ + ObReferenceObject(FastRef->Object); + + /* Return the Object */ + return FastRef->Object; +} + +VOID +FASTCALL +ObFastDereferenceObject(IN PEX_FAST_REF FastRef, + PVOID Object) +{ + /* FIXME: Fast Referencing is Unimplemented */ + + /* Do a normal Dereference */ + ObDereferenceObject(FastRef->Object); +} + +PVOID +FASTCALL +ObFastReplaceObject(IN PEX_FAST_REF FastRef, + PVOID Object) +{ + PVOID OldObject = FastRef->Object; + + /* FIXME: Fast Referencing is Unimplemented */ + FastRef->Object = Object; + + /* Do a normal Dereference */ + ObDereferenceObject(OldObject); + + /* Return old Object*/ + return OldObject; +} + +/* PUBLIC FUNCTIONS *********************************************************/ + +ULONG STDCALL +ObGetObjectPointerCount(PVOID Object) +{ + POBJECT_HEADER Header; + + PAGED_CODE(); + + ASSERT(Object); + Header = BODY_TO_HEADER(Object); + + return Header->PointerCount; +} + +VOID FASTCALL +ObfReferenceObject(IN PVOID Object) +{ + POBJECT_HEADER Header; + + ASSERT(Object); + + Header = BODY_TO_HEADER(Object); + + /* No one should be referencing an object once we are deleting it. */ + if (InterlockedIncrement(&Header->PointerCount) == 1 && !(Header->Flags & OB_FLAG_PERMANENT)) + { + KEBUGCHECK(0); + } + +} + +VOID +FASTCALL +ObfDereferenceObject(IN PVOID Object) +{ + POBJECT_HEADER Header; + LONG NewPointerCount; + BOOL Permanent; + + ASSERT(Object); + + /* Extract the object header. */ + Header = BODY_TO_HEADER(Object); + Permanent = Header->Flags & OB_FLAG_PERMANENT; + + /* + Drop our reference and get the new count so we can tell if this was the + last reference. + */ + NewPointerCount = InterlockedDecrement(&Header->PointerCount); + DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object, NewPointerCount); + ASSERT(NewPointerCount >= 0); + + /* Check whether the object can now be deleted. */ + if (NewPointerCount == 0 && + !Permanent) + { + ObpDeleteObjectDpcLevel(Header, NewPointerCount); + } +} + +NTSTATUS STDCALL +ObReferenceObjectByPointer(IN PVOID Object, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode) +{ + POBJECT_HEADER Header; + + /* NOTE: should be possible to reference an object above APC_LEVEL! */ + + DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n", + Object,ObjectType); + + Header = BODY_TO_HEADER(Object); + + if (ObjectType != NULL && Header->Type != ObjectType) + { + DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n", + Header, + Header->Type, + &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header->Type))->Name, + ObjectType, + &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType))->Name); + return(STATUS_UNSUCCESSFUL); + } + if (Header->Type == PsProcessType) + { + DPRINT("Ref p 0x%x PointerCount %d type %x ", + Object, Header->PointerCount, PsProcessType); + DPRINT("eip %x\n", ((PULONG)&Object)[-1]); + } + if (Header->Type == PsThreadType) + { + DPRINT("Deref t 0x%x with PointerCount %d type %x ", + Object, Header->PointerCount, PsThreadType); + DPRINT("eip %x\n", ((PULONG)&Object)[-1]); + } + + if (Header->PointerCount == 0 && !(Header->Flags & OB_FLAG_PERMANENT)) + { + if (Header->Type == PsProcessType) + { + return STATUS_PROCESS_IS_TERMINATING; + } + if (Header->Type == PsThreadType) + { + return STATUS_THREAD_IS_TERMINATING; + } + return(STATUS_UNSUCCESSFUL); + } + + if (1 == InterlockedIncrement(&Header->PointerCount) && !(Header->Flags & OB_FLAG_PERMANENT)) + { + KEBUGCHECK(0); + } + + return(STATUS_SUCCESS); +} + +NTSTATUS STDCALL +ObReferenceObjectByName(PUNICODE_STRING ObjectPath, + ULONG Attributes, + PACCESS_STATE PassedAccessState, + ACCESS_MASK DesiredAccess, + POBJECT_TYPE ObjectType, + KPROCESSOR_MODE AccessMode, + PVOID ParseContext, + PVOID* ObjectPtr) +{ + PVOID Object = NULL; + UNICODE_STRING RemainingPath; + UNICODE_STRING ObjectName; + OBJECT_CREATE_INFORMATION ObjectCreateInfo; + NTSTATUS Status; + OBP_LOOKUP_CONTEXT Context; + + PAGED_CODE(); + + /* Capture the name */ + DPRINT("Capturing Name\n"); + Status = ObpCaptureObjectName(&ObjectName, ObjectPath, AccessMode); + if (!NT_SUCCESS(Status)) + { + DPRINT("ObpCaptureObjectName() failed (Status %lx)\n", Status); + return Status; + } + + /* + * Create a fake ObjectCreateInfo structure. Note that my upcoming + * ObFindObject refactoring will remove the need for this hack. + */ + ObjectCreateInfo.RootDirectory = NULL; + ObjectCreateInfo.Attributes = Attributes; + + Status = ObFindObject(&ObjectCreateInfo, + &ObjectName, + &Object, + &RemainingPath, + ObjectType, + &Context); + + if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); + + if (!NT_SUCCESS(Status)) + { + return(Status); + } + DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object); + + if (RemainingPath.Buffer != NULL || Object == NULL) + { + DPRINT("Object %p\n", Object); + *ObjectPtr = NULL; + RtlFreeUnicodeString (&RemainingPath); + return(STATUS_OBJECT_NAME_NOT_FOUND); + } + *ObjectPtr = Object; + RtlFreeUnicodeString (&RemainingPath); + return(STATUS_SUCCESS); +} + +NTSTATUS STDCALL +ObReferenceObjectByHandle(HANDLE Handle, + ACCESS_MASK DesiredAccess, + POBJECT_TYPE ObjectType, + KPROCESSOR_MODE AccessMode, + PVOID* Object, + POBJECT_HANDLE_INFORMATION HandleInformation) +{ + PHANDLE_TABLE_ENTRY HandleEntry; + POBJECT_HEADER ObjectHeader; + PVOID ObjectBody; + ACCESS_MASK GrantedAccess; + ULONG Attributes; + PEPROCESS CurrentProcess, Process; + BOOLEAN AttachedToProcess = FALSE; + KAPC_STATE ApcState; + + PAGED_CODE(); + + DPRINT("ObReferenceObjectByHandle(Handle %p, DesiredAccess %x, " + "ObjectType %p, AccessMode %d, Object %p)\n",Handle,DesiredAccess, + ObjectType,AccessMode,Object); + + if (Handle == NULL) + { + return STATUS_INVALID_HANDLE; + } + + CurrentProcess = PsGetCurrentProcess(); + + /* + * Handle special handle names + */ + if (Handle == NtCurrentProcess() && + (ObjectType == PsProcessType || ObjectType == NULL)) + { + ObReferenceObject(CurrentProcess); + + if (HandleInformation != NULL) + { + HandleInformation->HandleAttributes = 0; + HandleInformation->GrantedAccess = PROCESS_ALL_ACCESS; + } + + *Object = CurrentProcess; + DPRINT("Referencing current process %p\n", CurrentProcess); + return STATUS_SUCCESS; + } + else if (Handle == NtCurrentProcess()) + { + CHECKPOINT; + return(STATUS_OBJECT_TYPE_MISMATCH); + } + + if (Handle == NtCurrentThread() && + (ObjectType == PsThreadType || ObjectType == NULL)) + { + PETHREAD CurrentThread = PsGetCurrentThread(); + + ObReferenceObject(CurrentThread); + + if (HandleInformation != NULL) + { + HandleInformation->HandleAttributes = 0; + HandleInformation->GrantedAccess = THREAD_ALL_ACCESS; + } + + *Object = CurrentThread; + CHECKPOINT; + return STATUS_SUCCESS; + } + else if (Handle == NtCurrentThread()) + { + CHECKPOINT; + return(STATUS_OBJECT_TYPE_MISMATCH); + } + + /* desire as much access rights as possible */ + if (DesiredAccess & MAXIMUM_ALLOWED) + { + DesiredAccess &= ~MAXIMUM_ALLOWED; + DesiredAccess |= GENERIC_ALL; + } + + if(ObIsKernelHandle(Handle, AccessMode)) + { + Process = PsInitialSystemProcess; + Handle = ObKernelHandleToHandle(Handle); + } + else + { + Process = CurrentProcess; + } + + KeEnterCriticalRegion(); + + if (Process != CurrentProcess) + { + KeStackAttachProcess(&Process->Pcb, + &ApcState); + AttachedToProcess = TRUE; + } + + HandleEntry = ExMapHandleToPointer(Process->ObjectTable, + Handle); + if (HandleEntry == NULL) + { + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + KeLeaveCriticalRegion(); + DPRINT("ExMapHandleToPointer() failed for handle 0x%p\n", Handle); + return(STATUS_INVALID_HANDLE); + } + + ObjectHeader = EX_HTE_TO_HDR(HandleEntry); + ObjectBody = &ObjectHeader->Body; + + DPRINT("locked1: ObjectHeader: 0x%p [HT:0x%p]\n", ObjectHeader, Process->ObjectTable); + + if (ObjectType != NULL && ObjectType != ObjectHeader->Type) + { + DPRINT("ObjectType mismatch: %wZ vs %wZ (handle 0x%p)\n", &ObjectType->Name, ObjectHeader->Type ? &ObjectHeader->Type->Name : NULL, Handle); + + ExUnlockHandleTableEntry(Process->ObjectTable, + HandleEntry); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + KeLeaveCriticalRegion(); + + return(STATUS_OBJECT_TYPE_MISMATCH); + } + + /* map the generic access masks if the caller asks for generic access */ + if (DesiredAccess & GENERIC_ACCESS) + { + RtlMapGenericMask(&DesiredAccess, + &BODY_TO_HEADER(ObjectBody)->Type->TypeInfo.GenericMapping); + } + + GrantedAccess = HandleEntry->GrantedAccess; + + /* Unless running as KernelMode, deny access if caller desires more access + rights than the handle can grant */ + if(AccessMode != KernelMode && (~GrantedAccess & DesiredAccess)) + { + ExUnlockHandleTableEntry(Process->ObjectTable, + HandleEntry); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + KeLeaveCriticalRegion(); + + DPRINT1("GrantedAccess: 0x%x, ~GrantedAccess: 0x%x, DesiredAccess: 0x%x, denied: 0x%x\n", GrantedAccess, ~GrantedAccess, DesiredAccess, ~GrantedAccess & DesiredAccess); + + return(STATUS_ACCESS_DENIED); + } + + ObReferenceObject(ObjectBody); + + Attributes = HandleEntry->ObAttributes & (EX_HANDLE_ENTRY_PROTECTFROMCLOSE | + EX_HANDLE_ENTRY_INHERITABLE | + EX_HANDLE_ENTRY_AUDITONCLOSE); + + ExUnlockHandleTableEntry(Process->ObjectTable, + HandleEntry); + + if (AttachedToProcess) + { + KeUnstackDetachProcess(&ApcState); + } + + KeLeaveCriticalRegion(); + + if (HandleInformation != NULL) + { + HandleInformation->HandleAttributes = Attributes; + HandleInformation->GrantedAccess = GrantedAccess; + } + + *Object = ObjectBody; + + return(STATUS_SUCCESS); +} + +#ifdef ObDereferenceObject +#undef ObDereferenceObject +#endif + +VOID STDCALL +ObDereferenceObject(IN PVOID Object) +{ + ObfDereferenceObject(Object); +} +/* EOF */