From 161bc06148858afe7d18b9f384644d1419a2c07e Mon Sep 17 00:00:00 2001 From: DavidXanatos <3890945+DavidXanatos@users.noreply.github.com> Date: Fri, 18 Aug 2023 19:03:29 +0200 Subject: [PATCH] 1.11.0 --- Sandboxie/core/dll/file.c | 1228 +++++++++++++++++--------------- Sandboxie/core/dll/file_init.c | 2 +- Sandboxie/core/dll/file_link.c | 126 +++- 3 files changed, 769 insertions(+), 587 deletions(-) diff --git a/Sandboxie/core/dll/file.c b/Sandboxie/core/dll/file.c index 5fb3a2d454..8028b8993b 100644 --- a/Sandboxie/core/dll/file.c +++ b/Sandboxie/core/dll/file.c @@ -106,6 +106,11 @@ typedef struct _FILE_DRIVE FILE_DRIVE; static ULONG File_FindBoxPrefixLength(const WCHAR* CopyPath); +NTSTATUS File_GetCopyPath(WCHAR *TruePath, WCHAR **OutCopyPath); + +NTSTATUS File_GetTruePath(WCHAR *CopyPath, WCHAR **OutTruePath); + +WCHAR* File_FindSnapshotPath(WCHAR* CopyPath); SBIEDLL_EXPORT NTSTATUS File_GetName( HANDLE RootDirectory, UNICODE_STRING *ObjectName, @@ -318,6 +323,21 @@ static const ULONG File_MupLen = 12; const WCHAR *File_BQQB = L"\\??\\"; +static const ULONG _DeviceLen = 8; +static const WCHAR *_Share = L"\\share\\"; +static const ULONG _ShareLen = 7; +static const WCHAR *_Drive = L"\\drive\\"; +static const ULONG _DriveLen = 7; + +static const WCHAR *_User = L"\\user"; +static const ULONG _UserLen = 5; +static const WCHAR *_UserAll = L"\\user\\all"; +static const ULONG _UserAllLen = 9; +static const WCHAR *_UserCurrent = L"\\user\\current"; +static const ULONG _UserCurrentLen = 13; +static const WCHAR *_UserPublic = L"\\user\\public"; +static const ULONG _UserPublicLen = 12; + #ifdef WOW64_FS_REDIR static WCHAR *File_Wow64System32 = NULL; static ULONG File_Wow64System32Len = 0; @@ -385,445 +405,305 @@ _FX ULONG File_FindBoxPrefixLength(const WCHAR* CopyPath) //--------------------------------------------------------------------------- -// File_GetName +// File_GetCopyPathImpl //--------------------------------------------------------------------------- -_FX NTSTATUS File_GetName( - HANDLE RootDirectory, UNICODE_STRING *ObjectName, - WCHAR **OutTruePath, WCHAR **OutCopyPath, ULONG *OutFlags) +_FX NTSTATUS File_GetCopyPathImpl(WCHAR* TruePath, WCHAR **OutCopyPath, ULONG *OutFlags, WCHAR* snapshot_id, BOOLEAN have_trailing_backslash, BOOLEAN* p_add_trailing_backslash) { - static const ULONG _DeviceLen = 8; - static const WCHAR *_Share = L"\\share\\"; - static const ULONG _ShareLen = 7; - static const WCHAR *_Drive = L"\\drive\\"; - static const ULONG _DriveLen = 7; - - static const WCHAR *_User = L"\\user"; - static const ULONG _UserLen = 5; - static const WCHAR *_UserAll = L"\\user\\all"; - static const ULONG _UserAllLen = 9; - static const WCHAR *_UserCurrent = L"\\user\\current"; - static const ULONG _UserCurrentLen = 13; - static const WCHAR *_UserPublic = L"\\user\\public"; - static const ULONG _UserPublicLen = 12; - THREAD_DATA *TlsData = Dll_GetTlsData(NULL); - NTSTATUS status; ULONG length; - WCHAR *name, *TruePath; - ULONG objname_len; - WCHAR *objname_buf; + WCHAR* name; const FILE_DRIVE *drive; - BOOLEAN have_trailing_backslash, add_trailing_backslash; - BOOLEAN have_tilde; - BOOLEAN convert_links_again; - BOOLEAN is_boxed_path; - BOOLEAN free_true_path; ULONG PrefixLength; + + length = wcslen(TruePath); + name = Dll_GetTlsNameBuffer( + TlsData, COPY_NAME_BUFFER, Dll_BoxFilePathLen + length); -#ifdef WOW64_FS_REDIR - BOOLEAN convert_wow64_link = (File_Wow64FileLink) ? TRUE : FALSE; -#else - const BOOLEAN convert_wow64_link = FALSE; -#endif WOW64_FS_REDIR - BOOLEAN no_relocation = FALSE; - WCHAR snapshot_id[FILE_MAX_SNAPSHOT_ID]; - snapshot_id[0] = L'\0'; + *OutCopyPath = name; - *OutTruePath = NULL; - *OutCopyPath = NULL; - if (OutFlags) - *OutFlags = 0; + wmemcpy(name, Dll_BoxFilePath, Dll_BoxFilePathLen); + name += Dll_BoxFilePathLen; - if (ObjectName == NO_RELOCATION) { - no_relocation = TRUE; - ObjectName = NULL; - } + // + // if we requested real paths, re add the snapshot prefix + // - if (ObjectName) { - objname_len = ObjectName->Length & ~1; - objname_buf = ObjectName->Buffer; - } else { - objname_len = 0; - objname_buf = NULL; - } + if (snapshot_id && *snapshot_id) { - drive = NULL; + *name++ = L'\\'; + wmemcpy(name, File_Snapshot_Prefix, File_Snapshot_PrefixLen); + name += File_Snapshot_PrefixLen; + ULONG len = wcslen(snapshot_id); + wmemcpy(name, snapshot_id, len); + name += len; + } - free_true_path = FALSE; // - // if a root handle is specified, we query the full name of the - // root file, and append the ObjectName + // if the true path points to a remote share or mapped drive, + // convert that to box the portable form "\share\computer\folder" // - if (RootDirectory) { + PrefixLength = 0; + if (length >= File_RedirectorLen && _wcsnicmp(TruePath, File_Redirector, File_RedirectorLen) == 0) + PrefixLength = File_RedirectorLen; + else if (length >= File_DfsClientRedirLen && _wcsnicmp(TruePath, File_DfsClientRedir, File_DfsClientRedirLen) == 0) + PrefixLength = File_DfsClientRedirLen; + else if (length >= File_HgfsRedirLen && _wcsnicmp(TruePath, File_HgfsRedir, File_HgfsRedirLen) == 0) + PrefixLength = File_HgfsRedirLen; + else if (length >= File_MupRedirLen && _wcsnicmp(TruePath, File_MupRedir, File_MupRedirLen) == 0) + PrefixLength = File_MupRedirLen; - UNICODE_STRING *uni = NULL; + if (PrefixLength) { - length = 256; - name = Dll_GetTlsNameBuffer( - TlsData, TRUE_NAME_BUFFER, length + objname_len); + WCHAR *ptr = TruePath + PrefixLength; + if (*ptr == L';') { + ptr = wcschr(ptr, L'\\'); + if (! ptr) + return STATUS_BAD_INITIAL_PC; + ++ptr; + } - status = Obj_GetObjectName(RootDirectory, name, &length); + wmemcpy(name, _Share, _ShareLen); + name += _ShareLen; - if (status == STATUS_OBJECT_PATH_INVALID && objname_len == 0) { + length = wcslen(ptr); + wmemcpy(name, ptr, length); - // - // special case: if STATUS_OBJECT_PATH_INVALID is returned, - // and the root directory turns out to be a File object, - // and there is no object name, then: - // this is most likely an anonynymous pipe, so return special - // status STATUS_BAD_INITIAL_PC - // + if (OutFlags) + *OutFlags |= FGN_NETWORK_SHARE; - if (Obj_GetObjectType(RootDirectory) == OBJ_TYPE_FILE) { + // does this next section really need to be different than above? + } else if (length >= File_MupLen && + _wcsnicmp(TruePath, File_Mup, File_MupLen) == 0) { - name[0] = L'\0'; - name[1] = L'\0'; - *OutTruePath = name; - return STATUS_BAD_INITIAL_PC; - } - } + WCHAR *ptr = TruePath + File_MupLen; + if (*ptr == L';') // like \Device\Mup\;RdpDr;:2\... + return STATUS_BAD_INITIAL_PC; + ptr = wcschr(ptr, L'\\'); + if (File_IsPipeSuffix(ptr)) + return STATUS_BAD_INITIAL_PC; - if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) { + wmemcpy(name, _Share, _ShareLen); + name += _ShareLen; - name = Dll_GetTlsNameBuffer( - TlsData, TRUE_NAME_BUFFER, length + objname_len); + length -= File_MupLen; + wmemcpy(name, TruePath + File_MupLen, length); - status = Obj_GetObjectName(RootDirectory, name, &length); - } + if (OutFlags) + *OutFlags |= FGN_NETWORK_SHARE; + } - if (! NT_SUCCESS(status)) - return status; + // + // if the true path begins with the full path to the home folder + // for the AllUsers or for the current user, then we translate + // the copy path to the box portable form "\user\all" or + // "\user\current", respectively + // - uni = &((OBJECT_NAME_INFORMATION *)name)->Name; + else if (File_AllUsersLen && length >= File_AllUsersLen && + 0 == Dll_NlsStrCmp( + TruePath, File_AllUsers, File_AllUsersLen)) + { + wmemcpy(name, _UserAll, _UserAllLen); + name += _UserAllLen; -#ifdef WOW64_FS_REDIR - // - // if the root directory handle references System32 in a WOW64 - // process, for example as a result of opening SysNative, then - // we should not convert that System32 back to SysWow64 - // + length -= File_AllUsersLen; + wmemcpy(name, TruePath + File_AllUsersLen, length); - if (uni->Buffer && convert_wow64_link) { + } - const ULONG sys32len = File_Wow64FileLink->src_len; + else if (File_CurrentUserLen && length >= File_CurrentUserLen && + 0 == Dll_NlsStrCmp( + TruePath, File_CurrentUser, File_CurrentUserLen)) + { + wmemcpy(name, _UserCurrent, _UserCurrentLen); + name += _UserCurrentLen; - name = uni->Buffer; - length = uni->Length & ~1; - name[length] = L'\0'; + length -= File_CurrentUserLen; + wmemcpy(name, TruePath + File_CurrentUserLen, length); - if (length >= sys32len - && _wcsnicmp(name, File_Wow64FileLink->src, sys32len) == 0 - && (name[sys32len] == L'\\' || name[sys32len] == L'\0')) { + } - convert_wow64_link = FALSE; - } + else if (File_PublicUserLen && length >= File_PublicUserLen && + 0 == Dll_NlsStrCmp( + TruePath, File_PublicUser, File_PublicUserLen)) + { + wmemcpy(name, _UserPublic, _UserPublicLen); + name += _UserPublicLen; - else { + length -= File_PublicUserLen; + wmemcpy(name, TruePath + File_PublicUserLen, length); + } - // - // if the file/directory is located in the sandbox, we still need to check the path - // + // + // otherwise, if the true path begins with the NT path for one of + // the known DosDevices drives, then translate to the box portable + // form "\drive\x" + // - ULONG prefixLen = File_FindBoxPrefixLength(name); - if (prefixLen != 0) { + else { - name += prefixLen; - length -= prefixLen; + ULONG drive_len; - if (length >= 10 && 0 == Dll_NlsStrCmp(name + 1, File_Snapshot_Prefix, File_Snapshot_PrefixLen)) { - WCHAR* ptr = wcschr(name + 1 + File_Snapshot_PrefixLen, L'\\'); - if (ptr) { - length -= (ULONG)(ptr - name); - name = ptr; - } - } + drive = File_GetDriveForPath(TruePath, length); + if (drive) + drive_len = drive->len; + else + drive = File_GetDriveForUncPath(TruePath, length, &drive_len); - if(length >= File_Wow64System32Len - && _wcsnicmp(name, File_Wow64System32, File_Wow64System32Len) == 0 - && (name[File_Wow64System32Len] == L'\\' || name[File_Wow64System32Len] == L'\0')) { + if (drive) { - convert_wow64_link = FALSE; - } - } - } - } -#endif WOW64_FS_REDIR + WCHAR drive_letter = drive->letter; - if (uni->Buffer) { - *OutTruePath = uni->Buffer; - name = uni->Buffer + uni->Length / sizeof(WCHAR); - } else - *OutTruePath = name; + LeaveCriticalSection(File_DrivesAndLinks_CritSec); - if (objname_len) { + wmemcpy(name, _Drive, _DriveLen); + name += _DriveLen; + *name = drive_letter; + ++name; - if (*objname_buf != L':') { - *name = L'\\'; + if (File_DriveAddSN && *drive->sn) { + + *name = L'~'; ++name; + wcscpy(name, drive->sn); + name += 9; } - memcpy(name, objname_buf, objname_len); - name += objname_len / sizeof(WCHAR); - } + *name = L'\0'; - *name = L'\0'; + if (length == drive_len) { - File_GetName_ConvertLinks(TlsData, OutTruePath, convert_wow64_link); + // + // in the special case of a request to open the + // volume device itself, rather than any file within + // the device, we return a special status code + // - // - // if no root handle, then we only have the object name to - // work with. it may begin with a DosDevices name "\??\x:" - // which we have to convert to a full path to the device - // + if (! have_trailing_backslash) + return STATUS_BAD_INITIAL_PC; - } else if (objname_len) { + // + // otherwise, caller must want to open the root + // directory of the device, so remember to add the + // trailing backslash before we're done + // - if (objname_len >= 6 * sizeof(WCHAR)) { - if (objname_buf[0] == L'\\' && objname_buf[1] == L'?' && - objname_buf[2] == L'?' && objname_buf[3] == L'\\' && - objname_buf[5] == L':') - { - drive = File_GetDriveForLetter(objname_buf[4]); - if (! drive) - return STATUS_OBJECT_PATH_NOT_FOUND; - objname_buf += 6; - objname_len -= 6 * sizeof(WCHAR); + if (p_add_trailing_backslash) *p_add_trailing_backslash = TRUE; } - } - - if (drive) { - - // - // convert a DosDevices name into a full NT path to - // the device represented by the drive letter - // - - name = Dll_GetTlsNameBuffer( - TlsData, TRUE_NAME_BUFFER, - objname_len + (drive->len + 1) * sizeof(WCHAR)); - - *OutTruePath = name; - wmemcpy(name, drive->path, drive->len); - name += drive->len; - - memcpy(name, objname_buf, objname_len); - name += objname_len / sizeof(WCHAR); - *name = L'\0'; + length -= drive_len; + wmemcpy(name, TruePath + drive_len, length); } else { // - // otherwise check if we were already given a full NT path - // to a disk device. if we find a drive here, it also prevents - // the next section of code from trying to translate symlinks + // if we couldn't find any matching logical drive, then + // we return STATUS_BAD_INITIAL_PC so this DLL does not + // try any further sandboxing. (But the driver will still + // block any attempt to access disk devices.) // - drive = File_GetDriveForPath( - objname_buf, objname_len / sizeof(WCHAR)); - if (drive) { - - name = Dll_GetTlsNameBuffer( - TlsData, TRUE_NAME_BUFFER, - objname_len + sizeof(WCHAR)); - - *OutTruePath = name; - - memcpy(name, objname_buf, objname_len); - name += objname_len / sizeof(WCHAR); - *name = L'\0'; - } - } - - if (drive) { - - File_GetName_ConvertLinks( - TlsData, OutTruePath, convert_wow64_link); - - LeaveCriticalSection(File_DrivesAndLinks_CritSec); - - } else { - - BOOLEAN translated = FALSE; - - *OutTruePath = File_GetName_TranslateSymlinks( - TlsData, objname_buf, objname_len, &translated); - - if (! *OutTruePath) - return STATUS_OBJECT_PATH_SYNTAX_BAD; - - translated |= File_GetName_ConvertLinks( - TlsData, OutTruePath, convert_wow64_link); - - if (! translated) { - // remote shares prefixed by \Device\Mup are ok even - // if they were not translated. anything else means - // a device that probably isn't a filesystem, although - // it may also be a volume that is not mounted to a drive - // letter, so check for a reparse point before failing - if (_wcsnicmp(*OutTruePath, File_Mup, File_MupLen) != 0) { - if (! translated) - return STATUS_BAD_INITIAL_PC; - } - } + return STATUS_BAD_INITIAL_PC; } - - // - // if no root handle, and no object name, then abort - // - - } else - return STATUS_OBJECT_PATH_SYNTAX_BAD; - - // - // remove duplicate backslashes - // - - name = *OutTruePath; - length = wcslen(name); - - while (name[0]) { - if (name[0] == L'\\' && name[1] == L'\\') { - - ULONG move_len = length - (ULONG)(name - *OutTruePath) + 1; - wmemmove(name, name + 1, move_len); - --length; - - } else - ++name; } // - // remove the trailing backslash. only if the caller is trying to - // open the root directory, we will be putting that backslash - // back onto the true path, before returning - // - - name = *OutTruePath; - if (length && name[length - 1] == L'\\') { - - --length; - name[length] = L'\0'; - have_trailing_backslash = TRUE; - - if (OutFlags) - *OutFlags |= FGN_TRAILING_BACKSLASH; - - } else - have_trailing_backslash = FALSE; - - add_trailing_backslash = FALSE; - - // - // make sure the true path begins with the "\device\" prefix. - // note that Windows returns more informative status codes here, - // like STATUS_OBJECT_NAME_NOT_FOUND, STATUS_OBJECT_PATH_NOT_FOUND - // and STATUS_OBJECT_TYPE_MISMATCH. but we take the easy way out + // null-terminate the copy path, and add the missing trailing + // backslash to the true path, if there was one // - if (length < _DeviceLen || - _wcsnicmp(*OutTruePath, File_Mup, _DeviceLen) != 0) { - - return STATUS_OBJECT_PATH_SYNTAX_BAD; - } - - // - // if this is a named pipe or mail slot, return special status - // + name += length; + *name = L'\0'; - if ((! drive) && File_IsNamedPipe(*OutTruePath, NULL)) { + return STATUS_SUCCESS; +} - return STATUS_BAD_INITIAL_PC; - } - // - // expand short names in the true path, but only if contains a tilde - // +//--------------------------------------------------------------------------- +// File_GetCopyPath +//--------------------------------------------------------------------------- - if (wcschr(*OutTruePath, L'~')) { - have_tilde = TRUE; +_FX NTSTATUS File_GetCopyPath(WCHAR* TruePath, WCHAR **OutCopyPath) +{ + return File_GetCopyPathImpl(TruePath, OutCopyPath, NULL, NULL, FALSE, NULL); +} - name = File_GetName_ExpandShortNames(TlsData, *OutTruePath); - length = wcslen(name); - *OutTruePath = name; - } else - have_tilde = FALSE; +//--------------------------------------------------------------------------- +// File_GetTruePathImpl +//--------------------------------------------------------------------------- - // - // if the path leads inside the sandbox, we advance the pointer. - // - convert_links_again = FALSE; - is_boxed_path = FALSE; +_FX NTSTATUS File_GetTruePathImpl(ULONG* p_length, WCHAR **OutTruePath, ULONG *OutFlags, BOOLEAN* p_is_boxed_path, BOOLEAN no_relocation, WCHAR* snapshot_id, BOOLEAN* p_convert_links_again) +{ + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); - TruePath = *OutTruePath; // save pointer in case we need to restore + WCHAR* name; + const FILE_DRIVE *drive; check_sandbox_prefix: - if (length >= Dll_BoxFilePathLen && + if (*p_length >= Dll_BoxFilePathLen && 0 == Dll_NlsStrCmp( *OutTruePath, Dll_BoxFilePath, Dll_BoxFilePathLen)) { *OutTruePath += Dll_BoxFilePathLen; - length -= Dll_BoxFilePathLen; + *p_length -= Dll_BoxFilePathLen; - if (! length) { + if (! *p_length) { // // caller specified just the sandbox prefix // - *OutTruePath = TruePath; + *OutTruePath = NULL; return STATUS_BAD_INITIAL_PC; } if (OutFlags) *OutFlags |= FGN_IS_BOXED_PATH; - is_boxed_path = TRUE; + *p_is_boxed_path = TRUE; } if (File_AltBoxPath && - length >= File_AltBoxPathLen && + *p_length >= File_AltBoxPathLen && 0 == Dll_NlsStrCmp( *OutTruePath, File_AltBoxPath, File_AltBoxPathLen)) { *OutTruePath += File_AltBoxPathLen; - length -= File_AltBoxPathLen; + *p_length -= File_AltBoxPathLen; - if (! length) { + if (! *p_length) { // // caller specified just the sandbox prefix // - *OutTruePath = TruePath; + *OutTruePath = NULL; return STATUS_BAD_INITIAL_PC; } if (OutFlags) *OutFlags |= FGN_IS_BOXED_PATH; - is_boxed_path = TRUE; + *p_is_boxed_path = TRUE; } - + // // If its a sandboxed file, check if its in the current image or in a snapshot // If its in a snapshot remove the snapshot prefix // - if (is_boxed_path) { - if (length >= 10 && 0 == Dll_NlsStrCmp(*OutTruePath + 1, File_Snapshot_Prefix, File_Snapshot_PrefixLen)) + if (p_is_boxed_path) { + if (*p_length >= 10 && 0 == Dll_NlsStrCmp(*OutTruePath + 1, File_Snapshot_Prefix, File_Snapshot_PrefixLen)) { WCHAR* path = wcschr(*OutTruePath + 1 + File_Snapshot_PrefixLen, L'\\'); if (path == NULL) { - // // caller specified just the sandbox snapshot prefix, or the path is to long // - - *OutTruePath = TruePath; + *OutTruePath = NULL; return STATUS_BAD_INITIAL_PC; } @@ -835,7 +715,7 @@ _FX NTSTATUS File_GetName( } } - length -= (ULONG)(path - *OutTruePath); + *p_length -= (ULONG)(path - *OutTruePath); *OutTruePath = path; } } @@ -851,7 +731,7 @@ _FX NTSTATUS File_GetName( // that's ok because it hasn't been initialized yet // - if (length >= (_DriveLen - 1) && + if (*p_length >= (_DriveLen - 1) && _wcsnicmp(*OutTruePath, _Drive, _DriveLen - 1) == 0) { name = (*OutTruePath); @@ -864,7 +744,7 @@ _FX NTSTATUS File_GetName( // // caller specified invalid path for \sandbox\drive\x // - *OutTruePath = TruePath; + *OutTruePath = NULL; return STATUS_BAD_INITIAL_PC; } @@ -878,10 +758,10 @@ _FX NTSTATUS File_GetName( } File_GetName_FixTruePrefix(TlsData, - OutTruePath, &length, len, + OutTruePath, p_length, len, drive->path, drive->len); - convert_links_again = TRUE; + if (p_convert_links_again) *p_convert_links_again = TRUE; LeaveCriticalSection(File_DrivesAndLinks_CritSec); @@ -899,31 +779,30 @@ _FX NTSTATUS File_GetName( // that's ok because it hasn't been initialized yet // - else if (//SbieApi_QueryConfBool(NULL, L"SeparateUserFolders", TRUE) && // if we disable File_InitUsers we don't need to do it here and below - length >= _UserLen && + else if (*p_length >= _UserLen && _wcsnicmp(*OutTruePath, _User, _UserLen) == 0) { - if (File_AllUsersLen && length >= _UserAllLen && + if (File_AllUsersLen && *p_length >= _UserAllLen && _wcsnicmp(*OutTruePath, _UserAll, _UserAllLen) == 0) { File_GetName_FixTruePrefix(TlsData, - OutTruePath, &length, _UserAllLen, + OutTruePath, p_length, _UserAllLen, File_AllUsers, File_AllUsersLen); } else if (File_CurrentUserLen && - length >= _UserCurrentLen && _wcsnicmp( + *p_length >= _UserCurrentLen && _wcsnicmp( *OutTruePath, _UserCurrent, _UserCurrentLen) == 0) { File_GetName_FixTruePrefix(TlsData, - OutTruePath, &length, _UserCurrentLen, + OutTruePath, p_length, _UserCurrentLen, File_CurrentUser, File_CurrentUserLen); } else if (File_PublicUserLen && - length >= _UserPublicLen && _wcsnicmp( + *p_length >= _UserPublicLen && _wcsnicmp( *OutTruePath, _UserPublic, _UserPublicLen) == 0) { File_GetName_FixTruePrefix(TlsData, - OutTruePath, &length, _UserPublicLen, + OutTruePath, p_length, _UserPublicLen, File_PublicUser, File_PublicUserLen); } else { @@ -936,9 +815,9 @@ _FX NTSTATUS File_GetName( name = Dll_GetTlsNameBuffer( TlsData, TRUE_NAME_BUFFER, - (Dll_BoxFilePathLen + length + 1) * sizeof(WCHAR)); + (Dll_BoxFilePathLen + *p_length + 1) * sizeof(WCHAR)); - wmemmove(name + Dll_BoxFilePathLen, *OutTruePath, length + 1); + wmemmove(name + Dll_BoxFilePathLen, *OutTruePath, *p_length + 1); wmemcpy(name, Dll_BoxFilePath, Dll_BoxFilePathLen); *OutTruePath = name; @@ -946,7 +825,7 @@ _FX NTSTATUS File_GetName( return STATUS_BAD_INITIAL_PC; } - convert_links_again = TRUE; + if (p_convert_links_again) *p_convert_links_again = TRUE; } // @@ -955,65 +834,460 @@ _FX NTSTATUS File_GetName( // be translated similarly to the "\drive\x" case above. // - else if (length >= _ShareLen && + else if (*p_length >= _ShareLen && _wcsnicmp(*OutTruePath, _Share, _ShareLen) == 0) { File_GetName_FixTruePrefix(TlsData, - OutTruePath, &length, _ShareLen, + OutTruePath, p_length, _ShareLen, File_Mup, File_MupLen); - convert_links_again = TRUE; + if (p_convert_links_again) *p_convert_links_again = TRUE; } - // - // if we had a tilde, try short name expansion again, now that we - // have translated prefixes like \user\current back into their - // real path names - // + return STATUS_SUCCESS; +} - if (have_tilde) { - name = File_GetName_ExpandShortNames(TlsData, *OutTruePath); - *OutTruePath = name; - length = wcslen(name); - } - // - // final conversion of any links (volume reparse points), but only - // in case TruePath was inside the sandbox and we adjusted it - // +//--------------------------------------------------------------------------- +// File_GetTruePath +//--------------------------------------------------------------------------- - if (convert_links_again) { - File_GetName_ConvertLinks(TlsData, OutTruePath, convert_wow64_link); - length = wcslen(*OutTruePath); - } - // - // convert \Windows\SysNative to \Windows\System32 - // +_FX NTSTATUS File_GetTruePath(WCHAR *CopyPath, WCHAR **OutTruePath) +{ + ULONG length = wcslen(CopyPath); + BOOLEAN is_boxed_path = FALSE; + *OutTruePath = CopyPath; + NTSTATUS status = File_GetTruePathImpl(&length, OutTruePath, NULL, &is_boxed_path, FALSE, NULL, NULL); + if (NT_SUCCESS(status) && !is_boxed_path) + return STATUS_BAD_INITIAL_STACK; // indicate with this error code that the path provided was already the true path + return status; +} -#ifdef WOW64_FS_REDIR - if (convert_wow64_link) { - name = *OutTruePath; - length = wcslen(name); +//--------------------------------------------------------------------------- +// File_GetName +//--------------------------------------------------------------------------- - if (length >= File_Wow64SysNativeLen - && 0 == _wcsnicmp( - name, File_Wow64SysNative, File_Wow64SysNativeLen) - && (name[File_Wow64SysNativeLen] == L'\\' || - name[File_Wow64SysNativeLen] == L'\0') - && (! File_GetName_SkipWow64Link(L""))) { - name = *OutTruePath; +_FX NTSTATUS File_GetName( + HANDLE RootDirectory, UNICODE_STRING *ObjectName, + WCHAR **OutTruePath, WCHAR **OutCopyPath, ULONG *OutFlags) +{ + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); - File_GetName_FixTruePrefix( - TlsData, &name, &length, - File_Wow64SysNativeLen, - File_Wow64FileLink->src, File_Wow64FileLink->src_len); + NTSTATUS status; + ULONG length; + WCHAR *name, *TruePath; + ULONG objname_len; + WCHAR *objname_buf; + const FILE_DRIVE *drive; + BOOLEAN have_trailing_backslash, add_trailing_backslash; + BOOLEAN have_tilde; + BOOLEAN convert_links_again; + BOOLEAN is_boxed_path; + BOOLEAN free_true_path; - *OutTruePath = name; - } - } +#ifdef WOW64_FS_REDIR + BOOLEAN convert_wow64_link = (File_Wow64FileLink) ? TRUE : FALSE; +#else + const BOOLEAN convert_wow64_link = FALSE; +#endif WOW64_FS_REDIR + BOOLEAN no_relocation = FALSE; + WCHAR snapshot_id[FILE_MAX_SNAPSHOT_ID]; + snapshot_id[0] = L'\0'; + + *OutTruePath = NULL; + *OutCopyPath = NULL; + if (OutFlags) + *OutFlags = 0; + + if (ObjectName == NO_RELOCATION) { + no_relocation = TRUE; + ObjectName = NULL; + } + + if (ObjectName) { + objname_len = ObjectName->Length & ~1; + objname_buf = ObjectName->Buffer; + } else { + objname_len = 0; + objname_buf = NULL; + } + + drive = NULL; + + free_true_path = FALSE; + + // + // if a root handle is specified, we query the full name of the + // root file, and append the ObjectName + // + + if (RootDirectory) { + + UNICODE_STRING *uni = NULL; + + length = 256; + name = Dll_GetTlsNameBuffer( + TlsData, TRUE_NAME_BUFFER, length + objname_len); + + status = Obj_GetObjectName(RootDirectory, name, &length); + + if (status == STATUS_OBJECT_PATH_INVALID && objname_len == 0) { + + // + // special case: if STATUS_OBJECT_PATH_INVALID is returned, + // and the root directory turns out to be a File object, + // and there is no object name, then: + // this is most likely an anonynymous pipe, so return special + // status STATUS_BAD_INITIAL_PC + // + + if (Obj_GetObjectType(RootDirectory) == OBJ_TYPE_FILE) { + + name[0] = L'\0'; + name[1] = L'\0'; + *OutTruePath = name; + return STATUS_BAD_INITIAL_PC; + } + } + + if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) { + + name = Dll_GetTlsNameBuffer( + TlsData, TRUE_NAME_BUFFER, length + objname_len); + + status = Obj_GetObjectName(RootDirectory, name, &length); + } + + if (! NT_SUCCESS(status)) + return status; + + uni = &((OBJECT_NAME_INFORMATION *)name)->Name; + +#ifdef WOW64_FS_REDIR + // + // if the root directory handle references System32 in a WOW64 + // process, for example as a result of opening SysNative, then + // we should not convert that System32 back to SysWow64 + // + + if (uni->Buffer && convert_wow64_link) { + + const ULONG sys32len = File_Wow64FileLink->src_len; + + name = uni->Buffer; + length = uni->Length & ~1; + name[length] = L'\0'; + + if (length >= sys32len + && _wcsnicmp(name, File_Wow64FileLink->src, sys32len) == 0 + && (name[sys32len] == L'\\' || name[sys32len] == L'\0')) { + + convert_wow64_link = FALSE; + } + + else { + + // + // if the file/directory is located in the sandbox, we still need to check the path + // + + ULONG prefixLen = File_FindBoxPrefixLength(name); + if (prefixLen != 0) { + + name += prefixLen; + length -= prefixLen; + + if (length >= 10 && 0 == Dll_NlsStrCmp(name + 1, File_Snapshot_Prefix, File_Snapshot_PrefixLen)) { + WCHAR* ptr = wcschr(name + 1 + File_Snapshot_PrefixLen, L'\\'); + if (ptr) { + length -= (ULONG)(ptr - name); + name = ptr; + } + } + + if(length >= File_Wow64System32Len + && _wcsnicmp(name, File_Wow64System32, File_Wow64System32Len) == 0 + && (name[File_Wow64System32Len] == L'\\' || name[File_Wow64System32Len] == L'\0')) { + + convert_wow64_link = FALSE; + } + } + } + } +#endif WOW64_FS_REDIR + + if (uni->Buffer) { + *OutTruePath = uni->Buffer; + name = uni->Buffer + uni->Length / sizeof(WCHAR); + } else + *OutTruePath = name; + + if (objname_len) { + + if (*objname_buf != L':') { + *name = L'\\'; + ++name; + } + + memcpy(name, objname_buf, objname_len); + name += objname_len / sizeof(WCHAR); + } + + *name = L'\0'; + + File_GetName_ConvertLinks(TlsData, OutTruePath, convert_wow64_link); + + // + // if no root handle, then we only have the object name to + // work with. it may begin with a DosDevices name "\??\x:" + // which we have to convert to a full path to the device + // + + } else if (objname_len) { + + if (objname_len >= 6 * sizeof(WCHAR)) { + if (objname_buf[0] == L'\\' && objname_buf[1] == L'?' && + objname_buf[2] == L'?' && objname_buf[3] == L'\\' && + objname_buf[5] == L':') + { + drive = File_GetDriveForLetter(objname_buf[4]); + if (! drive) + return STATUS_OBJECT_PATH_NOT_FOUND; + objname_buf += 6; + objname_len -= 6 * sizeof(WCHAR); + } + } + + if (drive) { + + // + // convert a DosDevices name into a full NT path to + // the device represented by the drive letter + // + + name = Dll_GetTlsNameBuffer( + TlsData, TRUE_NAME_BUFFER, + objname_len + (drive->len + 1) * sizeof(WCHAR)); + + *OutTruePath = name; + + wmemcpy(name, drive->path, drive->len); + name += drive->len; + + memcpy(name, objname_buf, objname_len); + name += objname_len / sizeof(WCHAR); + *name = L'\0'; + + } else { + + // + // otherwise check if we were already given a full NT path + // to a disk device. if we find a drive here, it also prevents + // the next section of code from trying to translate symlinks + // + + drive = File_GetDriveForPath( + objname_buf, objname_len / sizeof(WCHAR)); + if (drive) { + + name = Dll_GetTlsNameBuffer( + TlsData, TRUE_NAME_BUFFER, + objname_len + sizeof(WCHAR)); + + *OutTruePath = name; + + memcpy(name, objname_buf, objname_len); + name += objname_len / sizeof(WCHAR); + *name = L'\0'; + } + } + + if (drive) { + + File_GetName_ConvertLinks( + TlsData, OutTruePath, convert_wow64_link); + + LeaveCriticalSection(File_DrivesAndLinks_CritSec); + + } else { + + BOOLEAN translated = FALSE; + + *OutTruePath = File_GetName_TranslateSymlinks( + TlsData, objname_buf, objname_len, &translated); + + if (! *OutTruePath) + return STATUS_OBJECT_PATH_SYNTAX_BAD; + + translated |= File_GetName_ConvertLinks( + TlsData, OutTruePath, convert_wow64_link); + + if (! translated) { + // remote shares prefixed by \Device\Mup are ok even + // if they were not translated. anything else means + // a device that probably isn't a filesystem, although + // it may also be a volume that is not mounted to a drive + // letter, so check for a reparse point before failing + if (_wcsnicmp(*OutTruePath, File_Mup, File_MupLen) != 0) { + if (! translated) + return STATUS_BAD_INITIAL_PC; + } + } + } + + // + // if no root handle, and no object name, then abort + // + + } else + return STATUS_OBJECT_PATH_SYNTAX_BAD; + + // + // remove duplicate backslashes + // + + name = *OutTruePath; + length = wcslen(name); + + while (name[0]) { + if (name[0] == L'\\' && name[1] == L'\\') { + + ULONG move_len = length - (ULONG)(name - *OutTruePath) + 1; + wmemmove(name, name + 1, move_len); + --length; + + } else + ++name; + } + + // + // remove the trailing backslash. only if the caller is trying to + // open the root directory, we will be putting that backslash + // back onto the true path, before returning + // + + name = *OutTruePath; + if (length && name[length - 1] == L'\\') { + + --length; + name[length] = L'\0'; + have_trailing_backslash = TRUE; + + if (OutFlags) + *OutFlags |= FGN_TRAILING_BACKSLASH; + + } else + have_trailing_backslash = FALSE; + + add_trailing_backslash = FALSE; + + // + // make sure the true path begins with the "\device\" prefix. + // note that Windows returns more informative status codes here, + // like STATUS_OBJECT_NAME_NOT_FOUND, STATUS_OBJECT_PATH_NOT_FOUND + // and STATUS_OBJECT_TYPE_MISMATCH. but we take the easy way out + // + + if (length < _DeviceLen || + _wcsnicmp(*OutTruePath, File_Mup, _DeviceLen) != 0) { + + return STATUS_OBJECT_PATH_SYNTAX_BAD; + } + + // + // if this is a named pipe or mail slot, return special status + // + + if ((! drive) && File_IsNamedPipe(*OutTruePath, NULL)) { + + return STATUS_BAD_INITIAL_PC; + } + + // + // expand short names in the true path, but only if contains a tilde + // + + if (wcschr(*OutTruePath, L'~')) { + + have_tilde = TRUE; + + name = File_GetName_ExpandShortNames(TlsData, *OutTruePath); + length = wcslen(name); + *OutTruePath = name; + + } else + have_tilde = FALSE; + + // + // if the path leads inside the sandbox, we advance the pointer. + // + + convert_links_again = FALSE; + is_boxed_path = FALSE; + + TruePath = *OutTruePath; // save pointer in case we need to restore + +check_sandbox_prefix: + + status = File_GetTruePathImpl(&length, OutTruePath, OutFlags, &is_boxed_path, no_relocation, snapshot_id, &convert_links_again); + if (!NT_SUCCESS(status)) { + if(*OutTruePath == NULL) + *OutTruePath = TruePath; + return status; + } + + // + // if we had a tilde, try short name expansion again, now that we + // have translated prefixes like \user\current back into their + // real path names + // + + if (have_tilde) { + name = File_GetName_ExpandShortNames(TlsData, *OutTruePath); + *OutTruePath = name; + length = wcslen(name); + } + + // + // final conversion of any links (volume reparse points), but only + // in case TruePath was inside the sandbox and we adjusted it + // + + if (convert_links_again) { + File_GetName_ConvertLinks(TlsData, OutTruePath, convert_wow64_link); + length = wcslen(*OutTruePath); + } + + // + // convert \Windows\SysNative to \Windows\System32 + // + +#ifdef WOW64_FS_REDIR + if (convert_wow64_link) { + + name = *OutTruePath; + length = wcslen(name); + + if (length >= File_Wow64SysNativeLen + && 0 == _wcsnicmp( + name, File_Wow64SysNative, File_Wow64SysNativeLen) + && (name[File_Wow64SysNativeLen] == L'\\' || + name[File_Wow64SysNativeLen] == L'\0') + && (! File_GetName_SkipWow64Link(L""))) { + + name = *OutTruePath; + + File_GetName_FixTruePrefix( + TlsData, &name, &length, + File_Wow64SysNativeLen, + File_Wow64FileLink->src, File_Wow64FileLink->src_len); + + *OutTruePath = name; + } + } #endif WOW64_FS_REDIR // @@ -1109,209 +1383,9 @@ _FX NTSTATUS File_GetName( // still be missing its null terminator. // - name = Dll_GetTlsNameBuffer( - TlsData, COPY_NAME_BUFFER, Dll_BoxFilePathLen + length); - - *OutCopyPath = name; - - wmemcpy(name, Dll_BoxFilePath, Dll_BoxFilePathLen); - name += Dll_BoxFilePathLen; - - // - // if we requested real paths, re add the snapshot prefix - // - - if (*snapshot_id) { - - *name++ = L'\\'; - wmemcpy(name, File_Snapshot_Prefix, File_Snapshot_PrefixLen); - name += File_Snapshot_PrefixLen; - ULONG len = wcslen(snapshot_id); - wmemcpy(name, snapshot_id, len); - name += len; - } - - - // - // if the true path points to a remote share or mapped drive, - // convert that to box the portable form "\share\computer\folder" - // - - PrefixLength = 0; - if (length >= File_RedirectorLen && _wcsnicmp(TruePath, File_Redirector, File_RedirectorLen) == 0) - PrefixLength = File_RedirectorLen; - else if (length >= File_DfsClientRedirLen && _wcsnicmp(TruePath, File_DfsClientRedir, File_DfsClientRedirLen) == 0) - PrefixLength = File_DfsClientRedirLen; - else if (length >= File_HgfsRedirLen && _wcsnicmp(TruePath, File_HgfsRedir, File_HgfsRedirLen) == 0) - PrefixLength = File_HgfsRedirLen; - else if (length >= File_MupRedirLen && _wcsnicmp(TruePath, File_MupRedir, File_MupRedirLen) == 0) - PrefixLength = File_MupRedirLen; - - if (PrefixLength) { - - WCHAR *ptr = TruePath + PrefixLength; - if (*ptr == L';') { - ptr = wcschr(ptr, L'\\'); - if (! ptr) - return STATUS_BAD_INITIAL_PC; - ++ptr; - } - - wmemcpy(name, _Share, _ShareLen); - name += _ShareLen; - - length = wcslen(ptr); - wmemcpy(name, ptr, length); - - if (OutFlags) - *OutFlags |= FGN_NETWORK_SHARE; - - // does this next section really need to be different than above? - } else if (length >= File_MupLen && - _wcsnicmp(TruePath, File_Mup, File_MupLen) == 0) { - - WCHAR *ptr = TruePath + File_MupLen; - if (*ptr == L';') // like \Device\Mup\;RdpDr;:2\... - return STATUS_BAD_INITIAL_PC; - ptr = wcschr(ptr, L'\\'); - if (File_IsPipeSuffix(ptr)) - return STATUS_BAD_INITIAL_PC; - - wmemcpy(name, _Share, _ShareLen); - name += _ShareLen; - - length -= File_MupLen; - wmemcpy(name, TruePath + File_MupLen, length); - - if (OutFlags) - *OutFlags |= FGN_NETWORK_SHARE; - } - - // - // if the true path begins with the full path to the home folder - // for the AllUsers or for the current user, then we translate - // the copy path to the box portable form "\user\all" or - // "\user\current", respectively - // - - else if (//SbieApi_QueryConfBool(NULL, L"SeparateUserFolders", TRUE) && - File_AllUsersLen && length >= File_AllUsersLen && - 0 == Dll_NlsStrCmp( - TruePath, File_AllUsers, File_AllUsersLen)) - { - wmemcpy(name, _UserAll, _UserAllLen); - name += _UserAllLen; - - length -= File_AllUsersLen; - wmemcpy(name, TruePath + File_AllUsersLen, length); - - } - - else if (//SbieApi_QueryConfBool(NULL, L"SeparateUserFolders", TRUE) && - File_CurrentUserLen && length >= File_CurrentUserLen && - 0 == Dll_NlsStrCmp( - TruePath, File_CurrentUser, File_CurrentUserLen)) - { - wmemcpy(name, _UserCurrent, _UserCurrentLen); - name += _UserCurrentLen; - - length -= File_CurrentUserLen; - wmemcpy(name, TruePath + File_CurrentUserLen, length); - - } - - else if (//SbieApi_QueryConfBool(NULL, L"SeparateUserFolders", TRUE) && - File_PublicUserLen && length >= File_PublicUserLen && - 0 == Dll_NlsStrCmp( - TruePath, File_PublicUser, File_PublicUserLen)) - { - wmemcpy(name, _UserPublic, _UserPublicLen); - name += _UserPublicLen; - - length -= File_PublicUserLen; - wmemcpy(name, TruePath + File_PublicUserLen, length); - } - - // - // otherwise, if the true path begins with the NT path for one of - // the known DosDevices drives, then translate to the box portable - // form "\drive\x" - // - - else { - - ULONG drive_len; - - drive = File_GetDriveForPath(TruePath, length); - if (drive) - drive_len = drive->len; - else - drive = File_GetDriveForUncPath(TruePath, length, &drive_len); - - if (drive) { - - WCHAR drive_letter = drive->letter; - - LeaveCriticalSection(File_DrivesAndLinks_CritSec); - - wmemcpy(name, _Drive, _DriveLen); - name += _DriveLen; - *name = drive_letter; - ++name; - - if (File_DriveAddSN && *drive->sn) { - - *name = L'~'; - ++name; - wcscpy(name, drive->sn); - name += 9; - } - - *name = L'\0'; - - if (length == drive_len) { - - // - // in the special case of a request to open the - // volume device itself, rather than any file within - // the device, we return a special status code - // - - if (! have_trailing_backslash) - return STATUS_BAD_INITIAL_PC; - - // - // otherwise, caller must want to open the root - // directory of the device, so remember to add the - // trailing backslash before we're done - // - - add_trailing_backslash = TRUE; - } - - length -= drive_len; - wmemcpy(name, TruePath + drive_len, length); - - } else { - - // - // if we couldn't find any matching logical drive, then - // we return STATUS_BAD_INITIAL_PC so this DLL does not - // try any further sandboxing. (But the driver will still - // block any attempt to access disk devices.) - // - - return STATUS_BAD_INITIAL_PC; - } - } - - // - // null-terminate the copy path, and add the missing trailing - // backslash to the true path, if there was one - // - - name += length; - *name = L'\0'; + status = File_GetCopyPathImpl(TruePath, OutCopyPath, OutFlags, snapshot_id, have_trailing_backslash, &add_trailing_backslash); + if (!NT_SUCCESS(status)) + return status; if (add_trailing_backslash) { name = *OutTruePath; diff --git a/Sandboxie/core/dll/file_init.c b/Sandboxie/core/dll/file_init.c index 9d27edd11f..1732bc0ef8 100644 --- a/Sandboxie/core/dll/file_init.c +++ b/Sandboxie/core/dll/file_init.c @@ -166,7 +166,7 @@ _FX BOOLEAN File_Init(void) return FALSE; } - if (Dll_OsBuild >= 6000) { // needed for File_GetFileName used indirectly by File_InitRecoverFolders + if (Dll_OsBuild >= 6000) { void *GetFinalPathNameByHandleW = GetProcAddress(Dll_KernelBase ? Dll_KernelBase : Dll_Kernel32, diff --git a/Sandboxie/core/dll/file_link.c b/Sandboxie/core/dll/file_link.c index 21f3793b54..b7c5d7773c 100644 --- a/Sandboxie/core/dll/file_link.c +++ b/Sandboxie/core/dll/file_link.c @@ -831,34 +831,142 @@ _FX FILE_LINK *File_AddTempLink(WCHAR *path) P_NtCreateFile pNtCreateFile = __sys_NtCreateFile; P_NtClose pNtClose = __sys_NtClose; - if (! pNtCreateFile) + P_NtFsControlFile pNtFsControlFile = __sys_NtFsControlFile; + if (!pNtCreateFile) { + SbieApi_Log(2325, L"File_AddTempLink !pNtCreateFile"); pNtCreateFile = NtCreateFile; + } if (! pNtClose) pNtClose = NtClose; + if (! pNtFsControlFile) + pNtFsControlFile = NtFsControlFile; stop = TRUE; InitializeObjectAttributes( &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); - RtlInitUnicodeString(&objname, path); + BOOLEAN UserReparse = SbieApi_QueryConfBool(NULL, L"UseNewSymlinkResolver", FALSE); + + if (UserReparse) { + + // + // first try the copy path + // + + if (_wcsnicmp(path, Dll_BoxFilePath, Dll_BoxFilePathLen) != 0) + { + THREAD_DATA* TlsData = Dll_GetTlsData(NULL); + + WCHAR* CopyPath = NULL; + + + Dll_PushTlsNameBuffer(TlsData); + + File_GetCopyPath(path, &CopyPath); + + // + // get tempalte file if present, and reparese the path + // + + WCHAR* TmplName = File_FindSnapshotPath(CopyPath); + if (TmplName != NULL) + RtlInitUnicodeString(&objname, TmplName); + else + RtlInitUnicodeString(&objname, CopyPath); + + status = pNtCreateFile( + &handle, FILE_GENERIC_READ | SYNCHRONIZE, &objattrs, + &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT, + NULL, 0); + + Dll_PopTlsNameBuffer(TlsData); + } + else + status = STATUS_BAD_INITIAL_PC; + + // + // then try the true path + // + + if (!NT_SUCCESS(status)) { + + RtlInitUnicodeString(&objname, path); - status = pNtCreateFile( - &handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &objattrs, - &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, - FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, - NULL, 0); + status = pNtCreateFile( + &handle, FILE_GENERIC_READ | SYNCHRONIZE, &objattrs, + &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT, + NULL, 0); + } + } + else { + + RtlInitUnicodeString(&objname, path); + + status = pNtCreateFile( + &handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &objattrs, + &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, 0); + } if (NT_SUCCESS(status)) { + if (UserReparse) { + + REPARSE_DATA_BUFFER* reparseDataBuffer = Dll_AllocTemp(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + status = pNtFsControlFile(handle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseDataBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + + if (NT_SUCCESS(status)) { + + WCHAR* input_str = reparseDataBuffer->MountPointReparseBuffer.PathBuffer; + if (_wcsnicmp(input_str, File_BQQB, 4) == 0) + input_str = File_TranslateDosToNtPath(reparseDataBuffer->MountPointReparseBuffer.PathBuffer + 4); + + newpath = File_TranslateTempLinks_2(input_str, wcslen(input_str)); + + if (input_str != reparseDataBuffer->MountPointReparseBuffer.PathBuffer) + Dll_Free(input_str); + + /*THREAD_DATA* TlsData = Dll_GetTlsData(NULL); + + Dll_PushTlsNameBuffer(TlsData); + + WCHAR* TruePath = NULL; + if (NT_SUCCESS(File_GetTruePath(newpath, &TruePath))) { + + Dll_Free(newpath); + newpath = Dll_AllocTemp((wcslen(TruePath) + 1) * sizeof(WCHAR)); + wcscpy(newpath, TruePath); + } + + Dll_PopTlsNameBuffer(TlsData);*/ + } + else //if (status == STATUS_NOT_A_REPARSE_POINT) + { + newpath = Dll_AllocTemp((wcslen(path) + 1) * sizeof(WCHAR)); + wcscpy(newpath, path); + status = STATUS_SUCCESS; + } + + Dll_Free(reparseDataBuffer); + } + // // get the reparsed absolute path // const ULONG PATH_BUF_LEN = 1024; - newpath = Dll_AllocTemp(PATH_BUF_LEN); - status = File_GetFileName(handle, PATH_BUF_LEN - 4, newpath); + if (!UserReparse) { + + newpath = Dll_AllocTemp(PATH_BUF_LEN); + + status = File_GetFileName(handle, PATH_BUF_LEN - 4, newpath); + } + if (NT_SUCCESS(status)) { //