mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 19:12:57 +00:00
- 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. svn path=/trunk/; revision=25602
This commit is contained in:
parent
b5edfb619c
commit
89056c2f7a
7 changed files with 546 additions and 427 deletions
|
@ -50,6 +50,9 @@ extern "C" {
|
||||||
#define NTSYSAPI
|
#define NTSYSAPI
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define EX_PUSH_LOCK ULONG_PTR
|
||||||
|
#define PEX_PUSH_LOCK PULONG_PTR
|
||||||
|
|
||||||
#include "csq.h"
|
#include "csq.h"
|
||||||
|
|
||||||
typedef struct _SE_EXPORTS *PSE_EXPORTS;
|
typedef struct _SE_EXPORTS *PSE_EXPORTS;
|
||||||
|
@ -1402,35 +1405,6 @@ typedef struct _PATHNAME_BUFFER {
|
||||||
WCHAR Name[1];
|
WCHAR Name[1];
|
||||||
} PATHNAME_BUFFER, *PPATHNAME_BUFFER;
|
} 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
|
typedef enum _RTL_GENERIC_COMPARE_RESULTS
|
||||||
{
|
{
|
||||||
GenericLessThan,
|
GenericLessThan,
|
||||||
|
@ -1715,16 +1689,6 @@ typedef struct _TUNNEL {
|
||||||
USHORT NumEntries;
|
USHORT NumEntries;
|
||||||
} TUNNEL, *PTUNNEL;
|
} 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 {
|
typedef struct _VAD_HEADER {
|
||||||
PVOID StartVPN;
|
PVOID StartVPN;
|
||||||
PVOID EndVPN;
|
PVOID EndVPN;
|
||||||
|
|
|
@ -35,54 +35,101 @@ extern ULONG NTSYSAPI CcFastReadResourceMiss;
|
||||||
extern ULONG NTSYSAPI CcFastReadNoWait;
|
extern ULONG NTSYSAPI CcFastReadNoWait;
|
||||||
extern ULONG NTSYSAPI CcFastMdlReadNotPossible;
|
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_
|
#ifdef _NTIFS_INCLUDED_
|
||||||
|
|
||||||
typedef struct _SHARED_CACHE_MAP {
|
//
|
||||||
SHORT NodeTypeCode;
|
// Shared Cache Map
|
||||||
SHORT NodeByteSize;
|
//
|
||||||
ULONG OpenCount;
|
typedef struct _SHARED_CACHE_MAP
|
||||||
LARGE_INTEGER FileSize;
|
{
|
||||||
LIST_ENTRY BcbList;
|
SHORT NodeTypeCode;
|
||||||
LARGE_INTEGER SectionSize;
|
SHORT NodeByteSize;
|
||||||
LARGE_INTEGER ValidDataLength;
|
ULONG OpenCount;
|
||||||
LARGE_INTEGER ValidDataGoal;
|
LARGE_INTEGER FileSize;
|
||||||
PVACB InitialVacbs[4];
|
LIST_ENTRY BcbList;
|
||||||
PVACB Vacbs;
|
LARGE_INTEGER SectionSize;
|
||||||
PFILE_OBJECT FileObject;
|
LARGE_INTEGER ValidDataLength;
|
||||||
PVACB ActiveVacb;
|
LARGE_INTEGER ValidDataGoal;
|
||||||
PVOID NeedToZero;
|
PVACB InitialVacbs[4];
|
||||||
ULONG ActivePage;
|
PVACB Vacbs;
|
||||||
ULONG NeedToZeroPage;
|
PFILE_OBJECT FileObject;
|
||||||
ULONG ActiveVacbSpinLock;
|
PVACB ActiveVacb;
|
||||||
ULONG VacbActiveCount;
|
PVOID NeedToZero;
|
||||||
ULONG DirtyPages;
|
ULONG ActivePage;
|
||||||
LIST_ENTRY SharedCacheMapLinks;
|
ULONG NeedToZeroPage;
|
||||||
ULONG Flags;
|
ULONG ActiveVacbSpinLock;
|
||||||
ULONG Status;
|
ULONG VacbActiveCount;
|
||||||
PMCB Mbcb;
|
ULONG DirtyPages;
|
||||||
PVOID Section;
|
LIST_ENTRY SharedCacheMapLinks;
|
||||||
PKEVENT CreateEvent;
|
ULONG Flags;
|
||||||
PKEVENT WaitOnActiveCount;
|
ULONG Status;
|
||||||
ULONG PagesToWrite;
|
PMCB Mbcb;
|
||||||
LONGLONG BeyondLastFlush;
|
PVOID Section;
|
||||||
PCACHE_MANAGER_CALLBACKS Callbacks;
|
PKEVENT CreateEvent;
|
||||||
PVOID LazyWriteContext;
|
PKEVENT WaitOnActiveCount;
|
||||||
PLIST_ENTRY PrivateList;
|
ULONG PagesToWrite;
|
||||||
PVOID LogHandle;
|
LONGLONG BeyondLastFlush;
|
||||||
PVOID FlushToLsnRoutine;
|
PCACHE_MANAGER_CALLBACKS Callbacks;
|
||||||
ULONG DirtyPageThreshold;
|
PVOID LazyWriteContext;
|
||||||
ULONG LazyWritePassCount;
|
PLIST_ENTRY PrivateList;
|
||||||
PCACHE_UNINITIALIZE_EVENT UninitializeEvent;
|
PVOID LogHandle;
|
||||||
PVACB NeedToZeroVacb;
|
PVOID FlushToLsnRoutine;
|
||||||
ULONG BcbSpinLock;
|
ULONG DirtyPageThreshold;
|
||||||
PVOID Reserved;
|
ULONG LazyWritePassCount;
|
||||||
KEVENT Event;
|
PCACHE_UNINITIALIZE_EVENT UninitializeEvent;
|
||||||
/* FIX ME: This should be PEX_PUSH_LOCK */
|
PVACB NeedToZeroVacb;
|
||||||
PVOID VacbPushLock;
|
ULONG BcbSpinLock;
|
||||||
PPRIVATE_CACHE_MAP PrivateCacheMap;
|
PVOID Reserved;
|
||||||
} SHARED_CACHE_MAP;
|
KEVENT Event;
|
||||||
|
PEX_PUSH_LOCK VacbPushLock;
|
||||||
|
PPRIVATE_CACHE_MAP PrivateCacheMap;
|
||||||
|
} SHARED_CACHE_MAP;
|
||||||
|
|
||||||
#endif /* _NTIFS_INCLUDED_ */
|
#endif /* _NTIFS_INCLUDED_ */
|
||||||
#endif /* NTOS_MODE_USER */
|
#endif /* NTOS_MODE_USER */
|
||||||
|
|
|
@ -362,7 +362,7 @@ ExTimedWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock,
|
||||||
VOID
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock,
|
ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock,
|
||||||
IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock)
|
IN PVOID WaitBlock)
|
||||||
{
|
{
|
||||||
/* Call the timed function with no timeout */
|
/* Call the timed function with no timeout */
|
||||||
ExTimedWaitForUnblockPushLock(PushLock, WaitBlock, NULL);
|
ExTimedWaitForUnblockPushLock(PushLock, WaitBlock, NULL);
|
||||||
|
|
|
@ -652,18 +652,24 @@ _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
ExBlockPushLock(PEX_PUSH_LOCK PushLock,
|
ExBlockPushLock(
|
||||||
PVOID WaitBlock);
|
IN PEX_PUSH_LOCK PushLock,
|
||||||
|
IN PVOID WaitBlock
|
||||||
|
);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
ExfUnblockPushLock(PEX_PUSH_LOCK PushLock,
|
ExfUnblockPushLock(
|
||||||
PVOID CurrentWaitBlock);
|
IN PEX_PUSH_LOCK PushLock,
|
||||||
|
IN PVOID CurrentWaitBlock
|
||||||
|
);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock,
|
ExWaitForUnblockPushLock(
|
||||||
IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock);
|
IN PEX_PUSH_LOCK PushLock,
|
||||||
|
IN PVOID WaitBlock
|
||||||
|
);
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
* @name ExInitializePushLock
|
* @name ExInitializePushLock
|
||||||
|
|
|
@ -102,6 +102,15 @@ typedef struct _OBP_FIND_HANDLE_DATA
|
||||||
POBJECT_HANDLE_INFORMATION HandleInformation;
|
POBJECT_HANDLE_INFORMATION HandleInformation;
|
||||||
} OBP_FIND_HANDLE_DATA, *POBP_FIND_HANDLE_DATA;
|
} 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
|
// Private Temporary Buffer for Lookup Routines
|
||||||
//
|
//
|
||||||
|
@ -502,6 +511,9 @@ extern WORK_QUEUE_ITEM ObpReaperWorkItem;
|
||||||
extern volatile PVOID ObpReaperList;
|
extern volatile PVOID ObpReaperList;
|
||||||
extern NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
|
extern NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
|
||||||
extern BOOLEAN IoCountOperations;
|
extern BOOLEAN IoCountOperations;
|
||||||
|
extern ALIGNEDNAME ObpDosDevicesShortNamePrefix;
|
||||||
|
extern ALIGNEDNAME ObpDosDevicesShortNameRoot;
|
||||||
|
extern UNICODE_STRING ObpDosDevicesShortName;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Inlined Functions
|
// Inlined Functions
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
/* INCLUDES ******************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
/* Always target Windows 2003 Service Pack 1 */
|
/* Always target Windows 2003 Service Pack 1 */
|
||||||
#undef NTDDI_VERSION
|
#define _WIN32_WINNT _WIN32_WINNT_WS03
|
||||||
#define NTDDI_VERSION NTDDI_WS03SP1
|
#define NTDDI_VERSION NTDDI_WS03SP1
|
||||||
#define NTKERNELAPI
|
#define NTKERNELAPI
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,18 @@
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
BOOLEAN ObpCaseInsensitive = TRUE;
|
BOOLEAN ObpCaseInsensitive = TRUE;
|
||||||
POBJECT_DIRECTORY NameSpaceRoot = NULL;
|
POBJECT_DIRECTORY NameSpaceRoot;
|
||||||
POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL;
|
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 *********************************************************/
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
|
@ -256,22 +266,22 @@ ObpDeleteNameCheck(IN PVOID Object)
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
ObpLookupObjectName(IN HANDLE RootHandle,
|
ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL,
|
||||||
IN PUNICODE_STRING ObjectName,
|
IN PUNICODE_STRING ObjectName,
|
||||||
IN ULONG Attributes,
|
IN ULONG Attributes,
|
||||||
IN POBJECT_TYPE ObjectType,
|
IN POBJECT_TYPE ObjectType,
|
||||||
IN KPROCESSOR_MODE AccessMode,
|
IN KPROCESSOR_MODE AccessMode,
|
||||||
IN OUT PVOID ParseContext,
|
IN OUT PVOID ParseContext,
|
||||||
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
|
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
|
||||||
IN PVOID InsertObject,
|
IN PVOID InsertObject OPTIONAL,
|
||||||
IN PACCESS_STATE AccessState,
|
IN OUT PACCESS_STATE AccessState,
|
||||||
IN POBP_LOOKUP_CONTEXT LookupContext,
|
OUT POBP_LOOKUP_CONTEXT LookupContext,
|
||||||
OUT PVOID *FoundObject)
|
OUT PVOID *FoundObject)
|
||||||
{
|
{
|
||||||
PVOID Object;
|
PVOID Object;
|
||||||
POBJECT_HEADER ObjectHeader;
|
POBJECT_HEADER ObjectHeader;
|
||||||
UNICODE_STRING ComponentName, RemainingName;
|
UNICODE_STRING ComponentName, RemainingName;
|
||||||
BOOLEAN InsideRoot = FALSE;
|
BOOLEAN Reparse = FALSE, SymLink = FALSE;
|
||||||
PDEVICE_MAP DeviceMap = NULL;
|
PDEVICE_MAP DeviceMap = NULL;
|
||||||
POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory;
|
POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory;
|
||||||
POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL;
|
POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL;
|
||||||
|
@ -281,6 +291,7 @@ ObpLookupObjectName(IN HANDLE RootHandle,
|
||||||
KPROCESSOR_MODE AccessCheckMode;
|
KPROCESSOR_MODE AccessCheckMode;
|
||||||
PWCHAR NewName;
|
PWCHAR NewName;
|
||||||
POBJECT_HEADER_NAME_INFO ObjectNameInfo;
|
POBJECT_HEADER_NAME_INFO ObjectNameInfo;
|
||||||
|
ULONG MaxReparse = 30;
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
OBTRACE(OB_NAMESPACE_DEBUG,
|
OBTRACE(OB_NAMESPACE_DEBUG,
|
||||||
"%s - Finding Object: %wZ. Expecting: %p\n",
|
"%s - Finding Object: %wZ. Expecting: %p\n",
|
||||||
|
@ -346,6 +357,9 @@ ObpLookupObjectName(IN HANDLE RootHandle,
|
||||||
return STATUS_INVALID_HANDLE;
|
return STATUS_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set default parse count */
|
||||||
|
MaxReparse = 30;
|
||||||
|
|
||||||
/* Now parse */
|
/* Now parse */
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
|
@ -397,7 +411,22 @@ ObpLookupObjectName(IN HANDLE RootHandle,
|
||||||
|
|
||||||
/* Don't use this anymore, since we're starting at root */
|
/* Don't use this anymore, since we're starting at root */
|
||||||
RootHandle = NULL;
|
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 @@ ObpLookupObjectName(IN HANDLE RootHandle,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
/* Save the name */
|
|
||||||
ReparseNewDir:
|
|
||||||
RemainingName = *ObjectName;
|
|
||||||
|
|
||||||
/* Reparse */
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
/* Check if we should use the Root Directory */
|
|
||||||
if (!InsideRoot)
|
|
||||||
{
|
{
|
||||||
/* Yes, use the root directory and remember that */
|
ParseFromRoot:
|
||||||
Directory = RootDirectory;
|
/* Check if we have a device map */
|
||||||
InsideRoot = TRUE;
|
if (DeviceMap)
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 */
|
/* Dereference it */
|
||||||
if (!ObpCheckTraverseAccess(ParentDirectory,
|
ObfDereferenceDeviceMap(DeviceMap);
|
||||||
DIRECTORY_TRAVERSE,
|
DeviceMap = NULL;
|
||||||
AccessState,
|
}
|
||||||
FALSE,
|
|
||||||
AccessCheckMode,
|
/* Check if this is a possible DOS name */
|
||||||
&Status))
|
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))
|
||||||
{
|
{
|
||||||
/* We don't have it, fail */
|
/* FIXME! */
|
||||||
break;
|
}
|
||||||
|
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 don't have a remaining name yet */
|
/* Check if we were reparsing a symbolic link */
|
||||||
if (!RemainingName.Length)
|
if (!SymLink)
|
||||||
|
{
|
||||||
|
/* Allow reparse */
|
||||||
|
Reparse = TRUE;
|
||||||
|
MaxReparse = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reparse */
|
||||||
|
while (Reparse)
|
||||||
|
{
|
||||||
|
/* Get the name */
|
||||||
|
RemainingName = *ObjectName;
|
||||||
|
|
||||||
|
/* Disable reparsing again */
|
||||||
|
Reparse = FALSE;
|
||||||
|
|
||||||
|
/* Start parse loop */
|
||||||
|
while (TRUE)
|
||||||
{
|
{
|
||||||
/* Check if we don't have a referenced directory yet */
|
/* Clear object */
|
||||||
if (!ReferencedDirectory)
|
Object = NULL;
|
||||||
|
|
||||||
|
/* Check if the name starts with a path separator */
|
||||||
|
if ((RemainingName.Length) &&
|
||||||
|
(RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
|
||||||
{
|
{
|
||||||
/* Reference it */
|
/* 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);
|
ObReferenceObject(Directory);
|
||||||
ReferencedDirectory = Directory;
|
ReferencedDirectory = Directory;
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if we are inserting an object */
|
/* Check if we have a parent directory */
|
||||||
if (InsertObject)
|
if (ParentDirectory)
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
/* Check for traverse access */
|
||||||
if (RootHandle)
|
if (!ObpCheckTraverseAccess(ParentDirectory,
|
||||||
|
DIRECTORY_TRAVERSE,
|
||||||
|
AccessState,
|
||||||
|
FALSE,
|
||||||
|
AccessCheckMode,
|
||||||
|
&Status))
|
||||||
{
|
{
|
||||||
/* Stop using it, because we have a new directory now */
|
/* We don't have it, fail */
|
||||||
ObDereferenceObject(RootDirectory);
|
break;
|
||||||
RootHandle = NULL;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Start at Root */
|
/* Check if we don't have a remaining name yet */
|
||||||
ParentDirectory = NULL;
|
if (!RemainingName.Length)
|
||||||
RootDirectory = NameSpaceRoot;
|
{
|
||||||
|
/* Check if we don't have a referenced directory yet */
|
||||||
|
if (!ReferencedDirectory)
|
||||||
|
{
|
||||||
|
/* Reference it */
|
||||||
|
ObReferenceObject(Directory);
|
||||||
|
ReferencedDirectory = Directory;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for reparse status */
|
/* Check if we are inserting an object */
|
||||||
if (Status == STATUS_REPARSE_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
{
|
{
|
||||||
/* Did we actually get an object to which to reparse? */
|
/* Check if we got a root directory */
|
||||||
if (!Object)
|
if (RootHandle)
|
||||||
{
|
{
|
||||||
/* We didn't, so set a failure status */
|
/* Stop using it, because we have a new directory now */
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
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
|
else
|
||||||
{
|
{
|
||||||
/* We did, so we're free to parse the new object */
|
/* This is a symbolic link */
|
||||||
InsideRoot = TRUE;
|
SymLink = TRUE;
|
||||||
goto Reparse;
|
goto ParseFromRoot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (RootDirectory == NameSpaceRoot)
|
||||||
/* Restart the search */
|
{
|
||||||
goto ReparseNewDir;
|
/* We got STATUS_REPARSE but are at the Root Directory */
|
||||||
|
Object = NULL;
|
||||||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
Reparse = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (RootDirectory == NameSpaceRoot)
|
else if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* We got STATUS_REPARSE but are at the Root Directory */
|
/* Total failure */
|
||||||
Object = NULL;
|
Object = NULL;
|
||||||
|
}
|
||||||
|
else if (!Object)
|
||||||
|
{
|
||||||
|
/* We didn't reparse but we didn't find the Object Either */
|
||||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
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 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))
|
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And get out of the reparse loop */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We still have a name; check if this is a directory object */
|
/* No parse routine...do we still have a remaining name? */
|
||||||
if (ObjectHeader->Type == ObDirectoryType)
|
if (!RemainingName.Length)
|
||||||
{
|
{
|
||||||
/* Check if we have a referenced parent directory */
|
/* Are we creating an object? */
|
||||||
if (ReferencedParentDirectory)
|
if (!InsertObject)
|
||||||
{
|
{
|
||||||
/* Dereference it */
|
/* Check if this is a user-mode call that needs to traverse */
|
||||||
ObDereferenceObject(ReferencedParentDirectory);
|
if ((AccessCheckMode != KernelMode) &&
|
||||||
|
!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restart the lookup from this directory */
|
/* And get out of the reparse loop */
|
||||||
ReferencedParentDirectory = ReferencedDirectory;
|
break;
|
||||||
ParentDirectory = Directory;
|
|
||||||
Directory = Object;
|
|
||||||
ReferencedDirectory = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We still have a name, but no parse routine for it */
|
/* We still have a name; check if this is a directory object */
|
||||||
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
if (ObjectHeader->Type == ObDirectoryType)
|
||||||
Object = NULL;
|
{
|
||||||
break;
|
/* 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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We still have a name, but no parse routine for it */
|
||||||
|
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||||
|
Object = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue