Author: ion Date: Tue Jan 23 01:16:13 2007 New Revision: 25602
URL: http://svn.reactos.org/svn/reactos?rev=25602&view=rev Log: - Fix MSVC breakage caused by recent modifications of cctypes.h. - Remove structures from ntifs.h that shouldn't be there. - Add support for optimized detection of a DOS device path ?? or ??\ and implement it into ObpLookupObjectName. - Add support for proper re-parsing up to a maximum of 30 times to avoid reparse DOS attacks on the kernel. - Set WIN32_WINNT version to Windows 2003 SP1.
Modified: trunk/reactos/include/ddk/ntifs.h trunk/reactos/include/ndk/cctypes.h trunk/reactos/ntoskrnl/ex/pushlock.c trunk/reactos/ntoskrnl/include/internal/ex.h trunk/reactos/ntoskrnl/include/internal/ob.h trunk/reactos/ntoskrnl/include/ntoskrnl.h trunk/reactos/ntoskrnl/ob/obname.c
Modified: trunk/reactos/include/ddk/ntifs.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ddk/ntifs.h?rev=256... ============================================================================== --- trunk/reactos/include/ddk/ntifs.h (original) +++ trunk/reactos/include/ddk/ntifs.h Tue Jan 23 01:16:13 2007 @@ -49,6 +49,9 @@ #ifndef NTSYSAPI #define NTSYSAPI #endif + +#define EX_PUSH_LOCK ULONG_PTR +#define PEX_PUSH_LOCK PULONG_PTR
#include "csq.h"
@@ -1402,35 +1405,6 @@ WCHAR Name[1]; } PATHNAME_BUFFER, *PPATHNAME_BUFFER;
-#if (VER_PRODUCTBUILD >= 2600) - -typedef struct _PRIVATE_CACHE_MAP_FLAGS { - ULONG DontUse : 16; - ULONG ReadAheadActive : 1; - ULONG ReadAheadEnabled : 1; - ULONG Available : 14; -} PRIVATE_CACHE_MAP_FLAGS, *PPRIVATE_CACHE_MAP_FLAGS; - -typedef struct _PRIVATE_CACHE_MAP { - _ANONYMOUS_UNION union { - CSHORT NodeTypeCode; - PRIVATE_CACHE_MAP_FLAGS Flags; - ULONG UlongFlags; - } DUMMYUNIONNAME; - ULONG ReadAheadMask; - PFILE_OBJECT FileObject; - LARGE_INTEGER FileOffset1; - LARGE_INTEGER BeyondLastByte1; - LARGE_INTEGER FileOffset2; - LARGE_INTEGER BeyondLastByte2; - LARGE_INTEGER ReadAheadOffset[2]; - ULONG ReadAheadLength[2]; - KSPIN_LOCK ReadAheadSpinLock; - LIST_ENTRY PrivateLinks; -} PRIVATE_CACHE_MAP, *PPRIVATE_CACHE_MAP; - -#endif - typedef enum _RTL_GENERIC_COMPARE_RESULTS { GenericLessThan, @@ -1715,16 +1689,6 @@ USHORT NumEntries; } TUNNEL, *PTUNNEL;
-typedef struct _VACB { - PVOID BaseAddress; - PSHARED_CACHE_MAP SharedCacheMap; - union { - LARGE_INTEGER FileOffset; - USHORT ActiveCount; - } Overlay; - LIST_ENTRY LruList; -} VACB, *PVACB; - typedef struct _VAD_HEADER { PVOID StartVPN; PVOID EndVPN;
Modified: trunk/reactos/include/ndk/cctypes.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/cctypes.h?rev=2... ============================================================================== --- trunk/reactos/include/ndk/cctypes.h (original) +++ trunk/reactos/include/ndk/cctypes.h Tue Jan 23 01:16:13 2007 @@ -35,54 +35,101 @@ extern ULONG NTSYSAPI CcFastReadNoWait; extern ULONG NTSYSAPI CcFastMdlReadNotPossible;
+// +// Virtual Address Control BLock +// +typedef struct _VACB +{ + PVOID BaseAddress; + struct _SHARED_CACHE_MAP *SharedCacheMap; + union + { + LARGE_INTEGER FileOffset; + USHORT ActiveCount; + } Overlay; + LIST_ENTRY LruList; +} VACB, *PVACB; + +// +// Private Cache Map Structure and Flags +// +typedef struct _PRIVATE_CACHE_MAP_FLAGS +{ + ULONG DontUse:16; + ULONG ReadAheadActive:1; + ULONG ReadAheadEnabled:1; + ULONG Available:14; +} PRIVATE_CACHE_MAP_FLAGS; + +typedef struct _PRIVATE_CACHE_MAP +{ + union + { + CSHORT NodeTypeCode; + PRIVATE_CACHE_MAP_FLAGS Flags; + ULONG UlongFlags; + }; + ULONG ReadAheadMask; + PFILE_OBJECT FileObject; + LARGE_INTEGER FileOffset1; + LARGE_INTEGER BeyondLastByte1; + LARGE_INTEGER FileOffset2; + LARGE_INTEGER BeyondLastByte2; + LARGE_INTEGER ReadAheadOffset[2]; + ULONG ReadAheadLength[2]; + KSPIN_LOCK ReadAheadSpinLock; + LIST_ENTRY PrivateLinks; +} PRIVATE_CACHE_MAP, *PPRIVATE_CACHE_MAP;
#ifdef _NTIFS_INCLUDED_
-typedef struct _SHARED_CACHE_MAP { - SHORT NodeTypeCode; - SHORT NodeByteSize; - ULONG OpenCount; - LARGE_INTEGER FileSize; - LIST_ENTRY BcbList; - LARGE_INTEGER SectionSize; - LARGE_INTEGER ValidDataLength; - LARGE_INTEGER ValidDataGoal; - PVACB InitialVacbs[4]; - PVACB Vacbs; - PFILE_OBJECT FileObject; - PVACB ActiveVacb; - PVOID NeedToZero; - ULONG ActivePage; - ULONG NeedToZeroPage; - ULONG ActiveVacbSpinLock; - ULONG VacbActiveCount; - ULONG DirtyPages; - LIST_ENTRY SharedCacheMapLinks; - ULONG Flags; - ULONG Status; - PMCB Mbcb; - PVOID Section; - PKEVENT CreateEvent; - PKEVENT WaitOnActiveCount; - ULONG PagesToWrite; - LONGLONG BeyondLastFlush; - PCACHE_MANAGER_CALLBACKS Callbacks; - PVOID LazyWriteContext; - PLIST_ENTRY PrivateList; - PVOID LogHandle; - PVOID FlushToLsnRoutine; - ULONG DirtyPageThreshold; - ULONG LazyWritePassCount; - PCACHE_UNINITIALIZE_EVENT UninitializeEvent; - PVACB NeedToZeroVacb; - ULONG BcbSpinLock; - PVOID Reserved; - KEVENT Event; - /* FIX ME: This should be PEX_PUSH_LOCK */ - PVOID VacbPushLock; - PPRIVATE_CACHE_MAP PrivateCacheMap; - } SHARED_CACHE_MAP; - +// +// Shared Cache Map +// +typedef struct _SHARED_CACHE_MAP +{ + SHORT NodeTypeCode; + SHORT NodeByteSize; + ULONG OpenCount; + LARGE_INTEGER FileSize; + LIST_ENTRY BcbList; + LARGE_INTEGER SectionSize; + LARGE_INTEGER ValidDataLength; + LARGE_INTEGER ValidDataGoal; + PVACB InitialVacbs[4]; + PVACB Vacbs; + PFILE_OBJECT FileObject; + PVACB ActiveVacb; + PVOID NeedToZero; + ULONG ActivePage; + ULONG NeedToZeroPage; + ULONG ActiveVacbSpinLock; + ULONG VacbActiveCount; + ULONG DirtyPages; + LIST_ENTRY SharedCacheMapLinks; + ULONG Flags; + ULONG Status; + PMCB Mbcb; + PVOID Section; + PKEVENT CreateEvent; + PKEVENT WaitOnActiveCount; + ULONG PagesToWrite; + LONGLONG BeyondLastFlush; + PCACHE_MANAGER_CALLBACKS Callbacks; + PVOID LazyWriteContext; + PLIST_ENTRY PrivateList; + PVOID LogHandle; + PVOID FlushToLsnRoutine; + ULONG DirtyPageThreshold; + ULONG LazyWritePassCount; + PCACHE_UNINITIALIZE_EVENT UninitializeEvent; + PVACB NeedToZeroVacb; + ULONG BcbSpinLock; + PVOID Reserved; + KEVENT Event; + PEX_PUSH_LOCK VacbPushLock; + PPRIVATE_CACHE_MAP PrivateCacheMap; +} SHARED_CACHE_MAP;
#endif /* _NTIFS_INCLUDED_ */ #endif /* NTOS_MODE_USER */
Modified: trunk/reactos/ntoskrnl/ex/pushlock.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/pushlock.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/ex/pushlock.c (original) +++ trunk/reactos/ntoskrnl/ex/pushlock.c Tue Jan 23 01:16:13 2007 @@ -362,7 +362,7 @@ VOID FASTCALL ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock, - IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock) + IN PVOID WaitBlock) { /* Call the timed function with no timeout */ ExTimedWaitForUnblockPushLock(PushLock, WaitBlock, NULL);
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/e... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ex.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ex.h Tue Jan 23 01:16:13 2007 @@ -652,18 +652,24 @@
VOID FASTCALL -ExBlockPushLock(PEX_PUSH_LOCK PushLock, - PVOID WaitBlock); - -VOID -FASTCALL -ExfUnblockPushLock(PEX_PUSH_LOCK PushLock, - PVOID CurrentWaitBlock); - -VOID -FASTCALL -ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock, - IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock); +ExBlockPushLock( + IN PEX_PUSH_LOCK PushLock, + IN PVOID WaitBlock +); + +VOID +FASTCALL +ExfUnblockPushLock( + IN PEX_PUSH_LOCK PushLock, + IN PVOID CurrentWaitBlock +); + +VOID +FASTCALL +ExWaitForUnblockPushLock( + IN PEX_PUSH_LOCK PushLock, + IN PVOID WaitBlock +);
/*++ * @name ExInitializePushLock
Modified: trunk/reactos/ntoskrnl/include/internal/ob.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/o... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ob.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ob.h Tue Jan 23 01:16:13 2007 @@ -103,6 +103,15 @@ } OBP_FIND_HANDLE_DATA, *POBP_FIND_HANDLE_DATA;
// +// Structure for quick-compare of a DOS Device path +// +typedef union +{ + WCHAR Name[sizeof(ULARGE_INTEGER) / sizeof(WCHAR)]; + ULARGE_INTEGER Alignment; +} ALIGNEDNAME; + +// // Private Temporary Buffer for Lookup Routines // #define TAG_OB_TEMP_STORAGE TAG('O', 'b', 'S', 't') @@ -502,6 +511,9 @@ extern volatile PVOID ObpReaperList; extern NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList; extern BOOLEAN IoCountOperations; +extern ALIGNEDNAME ObpDosDevicesShortNamePrefix; +extern ALIGNEDNAME ObpDosDevicesShortNameRoot; +extern UNICODE_STRING ObpDosDevicesShortName;
// // Inlined Functions
Modified: trunk/reactos/ntoskrnl/include/ntoskrnl.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/ntoskrnl.h... ============================================================================== --- trunk/reactos/ntoskrnl/include/ntoskrnl.h (original) +++ trunk/reactos/ntoskrnl/include/ntoskrnl.h Tue Jan 23 01:16:13 2007 @@ -9,7 +9,7 @@ /* INCLUDES ******************************************************************/
/* Always target Windows 2003 Service Pack 1 */ -#undef NTDDI_VERSION +#define _WIN32_WINNT _WIN32_WINNT_WS03 #define NTDDI_VERSION NTDDI_WS03SP1 #define NTKERNELAPI
Modified: trunk/reactos/ntoskrnl/ob/obname.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ob/obname.c?rev=25... ============================================================================== --- trunk/reactos/ntoskrnl/ob/obname.c (original) +++ trunk/reactos/ntoskrnl/ob/obname.c Tue Jan 23 01:16:13 2007 @@ -16,8 +16,18 @@ #include <debug.h>
BOOLEAN ObpCaseInsensitive = TRUE; -POBJECT_DIRECTORY NameSpaceRoot = NULL; -POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL; +POBJECT_DIRECTORY NameSpaceRoot; +POBJECT_DIRECTORY ObpTypeDirectoryObject; + +/* DOS Device Prefix ??\ and ?? */ +ALIGNEDNAME ObpDosDevicesShortNamePrefix = {{L'\',L'?',L'?',L'\'}}; +ALIGNEDNAME ObpDosDevicesShortNameRoot = {{L'\',L'?',L'?',L'\0'}}; +UNICODE_STRING ObpDosDevicesShortName = +{ + sizeof(ObpDosDevicesShortNamePrefix), + sizeof(ObpDosDevicesShortNamePrefix), + (PWSTR)&ObpDosDevicesShortNamePrefix +};
/* PRIVATE FUNCTIONS *********************************************************/
@@ -256,22 +266,22 @@
NTSTATUS NTAPI -ObpLookupObjectName(IN HANDLE RootHandle, +ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL, IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext, - IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, - IN PVOID InsertObject, - IN PACCESS_STATE AccessState, - IN POBP_LOOKUP_CONTEXT LookupContext, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + IN PVOID InsertObject OPTIONAL, + IN OUT PACCESS_STATE AccessState, + OUT POBP_LOOKUP_CONTEXT LookupContext, OUT PVOID *FoundObject) { PVOID Object; POBJECT_HEADER ObjectHeader; UNICODE_STRING ComponentName, RemainingName; - BOOLEAN InsideRoot = FALSE; + BOOLEAN Reparse = FALSE, SymLink = FALSE; PDEVICE_MAP DeviceMap = NULL; POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory; POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL; @@ -281,6 +291,7 @@ KPROCESSOR_MODE AccessCheckMode; PWCHAR NewName; POBJECT_HEADER_NAME_INFO ObjectNameInfo; + ULONG MaxReparse = 30; PAGED_CODE(); OBTRACE(OB_NAMESPACE_DEBUG, "%s - Finding Object: %wZ. Expecting: %p\n", @@ -345,6 +356,9 @@ ObDereferenceObject(RootDirectory); return STATUS_INVALID_HANDLE; } + + /* Set default parse count */ + MaxReparse = 30;
/* Now parse */ while (TRUE) @@ -397,7 +411,22 @@
/* Don't use this anymore, since we're starting at root */ RootHandle = NULL; - break; + goto ParseFromRoot; + } + else if (--MaxReparse) + { + /* Try reparsing again */ + continue; + } + else + { + /* Reparsed too many times */ + ObDereferenceObject(RootDirectory); + + /* Return the object and normalized status */ + *FoundObject = Object; + if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND; + return Status; } } } @@ -465,373 +494,434 @@ return Status; } } - } - - /* Save the name */ -ReparseNewDir: - RemainingName = *ObjectName; + else + { +ParseFromRoot: + /* Check if we have a device map */ + if (DeviceMap) + { + /* Dereference it */ + ObfDereferenceDeviceMap(DeviceMap); + DeviceMap = NULL; + } + + /* Check if this is a possible DOS name */ + if (!((ULONG_PTR)(ObjectName->Buffer) & 7)) + { + /* + * This could be one. Does it match the prefix? + * Note that as an optimization, the match is done as 64-bit + * compare since the prefix is "??" which is exactly 8 bytes. + * + * In the second branch, we test for "??" which is also valid. + * This time, we use a 32-bit compare followed by a Unicode + * character compare (16-bit), since the sum is 6 bytes. + */ + if ((ObjectName->Length >= ObpDosDevicesShortName.Length) && + (*(PULONGLONG)(ObjectName->Buffer) == + ObpDosDevicesShortNamePrefix.Alignment.QuadPart)) + { + /* FIXME! */ + } + else if ((ObjectName->Length == ObpDosDevicesShortName.Length - + sizeof(WCHAR)) && + (*(PULONG)(ObjectName->Buffer) == + ObpDosDevicesShortNameRoot.Alignment.LowPart) && + (*((PWCHAR)(ObjectName->Buffer) + 2) == + (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart))) + { + /* FIXME! */ + } + } + } + } + + /* Check if we were reparsing a symbolic link */ + if (!SymLink) + { + /* Allow reparse */ + Reparse = TRUE; + MaxReparse = 30; + }
/* Reparse */ - while (TRUE) - { - /* Check if we should use the Root Directory */ - if (!InsideRoot) - { - /* Yes, use the root directory and remember that */ - Directory = RootDirectory; - InsideRoot = TRUE; - } - - /* Check if the name starts with a path separator */ - if ((RemainingName.Length) && - (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) - { - /* Skip the path separator */ - RemainingName.Buffer++; - RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); - } - - /* Find the next Part Name */ - ComponentName = RemainingName; - while (RemainingName.Length) - { - /* Break if we found the \ ending */ - if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break; - - /* Move on */ - RemainingName.Buffer++; - RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); - } - - /* Get its size and make sure it's valid */ - ComponentName.Length -= RemainingName.Length; - if (!ComponentName.Length) - { - /* Invalid size, fail */ - Status = STATUS_OBJECT_NAME_INVALID; - break; - } - - /* Check if this is a user-mode call that needs to traverse */ - if ((AccessCheckMode != KernelMode) && - !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) - { - /* We shouldn't have referenced a directory yet */ - ASSERT(ReferencedDirectory == NULL); - - /* Reference the directory */ - ObReferenceObject(Directory); - ReferencedDirectory = Directory; - - /* Check if we have a parent directory */ - if (ParentDirectory) - { - /* Check for traverse access */ - if (!ObpCheckTraverseAccess(ParentDirectory, - DIRECTORY_TRAVERSE, - AccessState, - FALSE, - AccessCheckMode, - &Status)) - { - /* We don't have it, fail */ - break; - } - } - } - - /* Check if we don't have a remaining name yet */ - if (!RemainingName.Length) - { - /* Check if we don't have a referenced directory yet */ - if (!ReferencedDirectory) - { - /* Reference it */ + while (Reparse) + { + /* Get the name */ + RemainingName = *ObjectName; + + /* Disable reparsing again */ + Reparse = FALSE; + + /* Start parse loop */ + while (TRUE) + { + /* Clear object */ + Object = NULL; + + /* Check if the name starts with a path separator */ + if ((RemainingName.Length) && + (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) + { + /* Skip the path separator */ + RemainingName.Buffer++; + RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); + } + + /* Find the next Part Name */ + ComponentName = RemainingName; + while (RemainingName.Length) + { + /* Break if we found the \ ending */ + if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break; + + /* Move on */ + RemainingName.Buffer++; + RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); + } + + /* Get its size and make sure it's valid */ + ComponentName.Length -= RemainingName.Length; + if (!ComponentName.Length) + { + /* Invalid size, fail */ + Status = STATUS_OBJECT_NAME_INVALID; + break; + } + + /* Check if we're in the root */ + if (!Directory) Directory = RootDirectory; + + /* Check if this is a user-mode call that needs to traverse */ + if ((AccessCheckMode != KernelMode) && + !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) + { + /* We shouldn't have referenced a directory yet */ + ASSERT(ReferencedDirectory == NULL); + + /* Reference the directory */ ObReferenceObject(Directory); ReferencedDirectory = Directory; - } - - /* Check if we are inserting an object */ - if (InsertObject) - { - /* Lock the directory */ - ObpAcquireDirectoryLockExclusive(Directory, LookupContext); - } - } - - /* Do the lookup */ - Object = ObpLookupEntryDirectory(Directory, - &ComponentName, - Attributes, - InsertObject ? FALSE : TRUE, - LookupContext); - if (!Object) - { - /* We didn't find it... do we still have a path? */ - if (RemainingName.Length) - { - /* Then tell the caller the path wasn't found */ - Status = STATUS_OBJECT_PATH_NOT_FOUND; + + /* Check if we have a parent directory */ + if (ParentDirectory) + { + /* Check for traverse access */ + if (!ObpCheckTraverseAccess(ParentDirectory, + DIRECTORY_TRAVERSE, + AccessState, + FALSE, + AccessCheckMode, + &Status)) + { + /* We don't have it, fail */ + break; + } + } + } + + /* Check if we don't have a remaining name yet */ + if (!RemainingName.Length) + { + /* Check if we don't have a referenced directory yet */ + if (!ReferencedDirectory) + { + /* Reference it */ + ObReferenceObject(Directory); + ReferencedDirectory = Directory; + } + + /* Check if we are inserting an object */ + if (InsertObject) + { + /* Lock the directory */ + ObpAcquireDirectoryLockExclusive(Directory, LookupContext); + } + } + + /* Do the lookup */ + Object = ObpLookupEntryDirectory(Directory, + &ComponentName, + Attributes, + InsertObject ? FALSE : TRUE, + LookupContext); + if (!Object) + { + /* We didn't find it... do we still have a path? */ + if (RemainingName.Length) + { + /* Then tell the caller the path wasn't found */ + Status = STATUS_OBJECT_PATH_NOT_FOUND; + break; + } + else if (!InsertObject) + { + /* Otherwise, we have a path, but the name isn't valid */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + break; + } + + /* Check create access for the object */ + if (!ObCheckCreateObjectAccess(Directory, + ObjectType == ObDirectoryType ? + DIRECTORY_CREATE_SUBDIRECTORY : + DIRECTORY_CREATE_OBJECT, + AccessState, + &ComponentName, + FALSE, + AccessCheckMode, + &Status)) + { + /* We don't have create access, fail */ + break; + } + + /* Get the object header */ + ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject); + + /* FIXME: Check if this is a Section Object or Sym Link */ + /* FIXME: If it is, then check if this isn't session 0 */ + /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */ + /* FIXME: If privilege isn't there, check for unsecure name */ + /* FIXME: If it isn't a known unsecure name, then fail */ + + /* Create Object Name */ + NewName = ExAllocatePoolWithTag(PagedPool, + ComponentName.Length, + OB_NAME_TAG); + if (!(NewName) || + !(ObpInsertEntryDirectory(Directory, + LookupContext, + ObjectHeader))) + { + /* Either couldn't allocate the name, or insert failed */ + if (NewName) ExFreePool(NewName); + + /* Fail due to memory reasons */ + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + /* Reference newly to be inserted object */ + ObReferenceObject(InsertObject); + + /* Get the name information */ + ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); + + /* Reference the directory */ + ObReferenceObject(Directory); + + /* Copy the Name */ + RtlCopyMemory(NewName, + ComponentName.Buffer, + ComponentName.Length); + + /* Check if we had an old name */ + if (ObjectNameInfo->Name.Buffer) + { + /* Free it */ + ExFreePool(ObjectNameInfo->Name.Buffer); + } + + /* Write new one */ + ObjectNameInfo->Name.Buffer = NewName; + ObjectNameInfo->Name.Length = ComponentName.Length; + ObjectNameInfo->Name.MaximumLength = ComponentName.Length; + + /* Return Status and the Expected Object */ + Status = STATUS_SUCCESS; + Object = InsertObject; + + /* Get out of here */ break; } - else if (!InsertObject) - { - /* Otherwise, we have a path, but the name isn't valid */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - break; - } - - /* Check create access for the object */ - if (!ObCheckCreateObjectAccess(Directory, - ObjectType == ObDirectoryType ? - DIRECTORY_CREATE_SUBDIRECTORY : - DIRECTORY_CREATE_OBJECT, - AccessState, - &ComponentName, - FALSE, - AccessCheckMode, - &Status)) - { - /* We don't have create access, fail */ - break; - } - - /* Get the object header */ - ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject); - - /* FIXME: Check if this is a Section Object or Sym Link */ - /* FIXME: If it is, then check if this isn't session 0 */ - /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */ - /* FIXME: If privilege isn't there, check for unsecure name */ - /* FIXME: If it isn't a known unsecure name, then fail */ - - /* Create Object Name */ - NewName = ExAllocatePoolWithTag(PagedPool, - ComponentName.Length, - OB_NAME_TAG); - if (!(NewName) || - !(ObpInsertEntryDirectory(Directory, - LookupContext, - ObjectHeader))) - { - /* Either couldn't allocate the name, or insert failed */ - if (NewName) ExFreePool(NewName); - - /* Fail due to memory reasons */ - Status = STATUS_INSUFFICIENT_RESOURCES; - break; - } - - /* Reference newly to be inserted object */ - ObReferenceObject(InsertObject); - - /* Get the name information */ - ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); - - /* Reference the directory */ - ObReferenceObject(Directory); - - /* Copy the Name */ - RtlCopyMemory(NewName, - ComponentName.Buffer, - ComponentName.Length); - - /* Check if we had an old name */ - if (ObjectNameInfo->Name.Buffer) - { - /* Free it */ - ExFreePool(ObjectNameInfo->Name.Buffer); - } - - /* Write new one */ - ObjectNameInfo->Name.Buffer = NewName; - ObjectNameInfo->Name.Length = ComponentName.Length; - ObjectNameInfo->Name.MaximumLength = ComponentName.Length; - - /* Return Status and the Expected Object */ - Status = STATUS_SUCCESS; - Object = InsertObject; - - /* Get out of here */ - break; - } - -Reparse: - /* We found it, so now get its header */ - ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); - - /* - * Check for a parse Procedure, but don't bother to parse for an insert - * unless it's a Symbolic Link, in which case we MUST parse - */ - ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; - if ((ParseRoutine) && - (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink))) - { - /* Use the Root Directory next time */ - InsideRoot = FALSE; - - /* Increment the pointer count */ - InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1); - - /* Cleanup from the first lookup */ - ObpCleanupDirectoryLookup(LookupContext); - - /* Check if we have a referenced directory */ - if (ReferencedDirectory) - { - /* We do, dereference it */ - ObDereferenceObject(ReferencedDirectory); - ReferencedDirectory = NULL; - } - - /* Check if we have a referenced parent directory */ - if (ReferencedParentDirectory) - { - /* We do, dereference it */ - ObDereferenceObject(ReferencedParentDirectory); - ReferencedParentDirectory = NULL; - } - - /* Call the Parse Procedure */ - ObpCalloutStart(&CalloutIrql); - Status = ParseRoutine(Object, - ObjectType, - AccessState, - AccessCheckMode, - Attributes, - ObjectName, - &RemainingName, - ParseContext, - SecurityQos, - &Object); - ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); - - /* Remove our extra reference */ - ObDereferenceObject(&ObjectHeader->Body); - - /* Check if we have to reparse */ - if ((Status == STATUS_REPARSE) || - (Status == STATUS_REPARSE_OBJECT)) - { - /* Start over from root if we got sent back there */ - if ((Status == STATUS_REPARSE_OBJECT) || - (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) - { - /* Check if we got a root directory */ - if (RootHandle) + +ReparseObject: + /* We found it, so now get its header */ + ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); + + /* + * Check for a parse Procedure, but don't bother to parse for an insert + * unless it's a Symbolic Link, in which case we MUST parse + */ + ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; + if ((ParseRoutine) && + (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink))) + { + /* Use the Root Directory next time */ + Directory = NULL; + + /* Increment the pointer count */ + InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1); + + /* Cleanup from the first lookup */ + ObpCleanupDirectoryLookup(LookupContext); + + /* Check if we have a referenced directory */ + if (ReferencedDirectory) + { + /* We do, dereference it */ + ObDereferenceObject(ReferencedDirectory); + ReferencedDirectory = NULL; + } + + /* Check if we have a referenced parent directory */ + if (ReferencedParentDirectory) + { + /* We do, dereference it */ + ObDereferenceObject(ReferencedParentDirectory); + ReferencedParentDirectory = NULL; + } + + /* Call the Parse Procedure */ + ObpCalloutStart(&CalloutIrql); + Status = ParseRoutine(Object, + ObjectType, + AccessState, + AccessCheckMode, + Attributes, + ObjectName, + &RemainingName, + ParseContext, + SecurityQos, + &Object); + ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); + + /* Remove our extra reference */ + ObDereferenceObject(&ObjectHeader->Body); + + /* Check if we have to reparse */ + if ((Status == STATUS_REPARSE) || + (Status == STATUS_REPARSE_OBJECT)) + { + /* Reparse again */ + Reparse = TRUE; + + /* Start over from root if we got sent back there */ + if ((Status == STATUS_REPARSE_OBJECT) || + (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) { - /* Stop using it, because we have a new directory now */ - ObDereferenceObject(RootDirectory); - RootHandle = NULL; - } - - /* Start at Root */ - ParentDirectory = NULL; - RootDirectory = NameSpaceRoot; - - /* Check for reparse status */ - if (Status == STATUS_REPARSE_OBJECT) - { - /* Did we actually get an object to which to reparse? */ - if (!Object) + /* Check if we got a root directory */ + if (RootHandle) { - /* We didn't, so set a failure status */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; + /* Stop using it, because we have a new directory now */ + ObDereferenceObject(RootDirectory); + RootHandle = NULL; + } + + /* Start at Root */ + ParentDirectory = NULL; + RootDirectory = NameSpaceRoot; + + /* Check for reparse status */ + if (Status == STATUS_REPARSE_OBJECT) + { + /* Don't reparse again */ + Reparse = FALSE; + + /* Did we actually get an object to which to reparse? */ + if (!Object) + { + /* We didn't, so set a failure status */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else + { + /* We did, so we're free to parse the new object */ + goto ReparseObject; + } } else { - /* We did, so we're free to parse the new object */ - InsideRoot = TRUE; - goto Reparse; + /* This is a symbolic link */ + SymLink = TRUE; + goto ParseFromRoot; } } - - /* Restart the search */ - goto ReparseNewDir; - } - else if (RootDirectory == NameSpaceRoot) - { - /* We got STATUS_REPARSE but are at the Root Directory */ + else if (RootDirectory == NameSpaceRoot) + { + /* We got STATUS_REPARSE but are at the Root Directory */ + Object = NULL; + Status = STATUS_OBJECT_NAME_NOT_FOUND; + Reparse = FALSE; + } + } + else if (!NT_SUCCESS(Status)) + { + /* Total failure */ Object = NULL; + } + else if (!Object) + { + /* We didn't reparse but we didn't find the Object Either */ Status = STATUS_OBJECT_NAME_NOT_FOUND; } - } - else if (!NT_SUCCESS(Status)) - { - /* Total failure */ - Object = NULL; - } - else if (!Object) - { - /* We didn't reparse but we didn't find the Object Either */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* Break out of the loop */ - break; - } - else - { - /* No parse routine...do we still have a remaining name? */ - if (!RemainingName.Length) - { - /* Are we creating an object? */ - if (!InsertObject) - { - /* Check if this is a user-mode call that needs to traverse */ - if ((AccessCheckMode != KernelMode) && - !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) + + /* Break out of the loop */ + break; + } + else + { + /* No parse routine...do we still have a remaining name? */ + if (!RemainingName.Length) + { + /* Are we creating an object? */ + if (!InsertObject) { - /* Check if we can get it */ - if (!ObpCheckTraverseAccess(Directory, - DIRECTORY_TRAVERSE, - AccessState, - FALSE, - AccessCheckMode, - &Status)) + /* Check if this is a user-mode call that needs to traverse */ + if ((AccessCheckMode != KernelMode) && + !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) { - /* We don't have access, fail */ - Object = NULL; - break; + /* Check if we can get it */ + if (!ObpCheckTraverseAccess(Directory, + DIRECTORY_TRAVERSE, + AccessState, + FALSE, + AccessCheckMode, + &Status)) + { + /* We don't have access, fail */ + Object = NULL; + break; + } } + + /* Reference the Object */ + Status = ObReferenceObjectByPointer(Object, + 0, + ObjectType, + AccessMode); + if (!NT_SUCCESS(Status)) Object = NULL; }
- /* Reference the Object */ - Status = ObReferenceObjectByPointer(Object, - 0, - ObjectType, - AccessMode); - if (!NT_SUCCESS(Status)) Object = NULL; - } - - /* And get out of the reparse loop */ - break; - } - else - { - /* We still have a name; check if this is a directory object */ - if (ObjectHeader->Type == ObDirectoryType) - { - /* Check if we have a referenced parent directory */ - if (ReferencedParentDirectory) + /* And get out of the reparse loop */ + break; + } + else + { + /* We still have a name; check if this is a directory object */ + if (ObjectHeader->Type == ObDirectoryType) { - /* Dereference it */ - ObDereferenceObject(ReferencedParentDirectory); + /* Check if we have a referenced parent directory */ + if (ReferencedParentDirectory) + { + /* Dereference it */ + ObDereferenceObject(ReferencedParentDirectory); + } + + /* Restart the lookup from this directory */ + ReferencedParentDirectory = ReferencedDirectory; + ParentDirectory = Directory; + Directory = Object; + ReferencedDirectory = NULL; } - - /* Restart the lookup from this directory */ - ReferencedParentDirectory = ReferencedDirectory; - ParentDirectory = Directory; - Directory = Object; - ReferencedDirectory = NULL; - } - else - { - /* We still have a name, but no parse routine for it */ - Status = STATUS_OBJECT_TYPE_MISMATCH; - Object = NULL; - break; + else + { + /* We still have a name, but no parse routine for it */ + Status = STATUS_OBJECT_TYPE_MISMATCH; + Object = NULL; + break; + } } } }