This commit is contained in:
DavidXanatos 2023-08-18 19:03:29 +02:00
parent 9df59f2e13
commit 161bc06148
3 changed files with 607 additions and 425 deletions

View File

@ -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;
@ -384,6 +404,467 @@ _FX ULONG File_FindBoxPrefixLength(const WCHAR* CopyPath)
}
//---------------------------------------------------------------------------
// File_GetCopyPathImpl
//---------------------------------------------------------------------------
_FX NTSTATUS File_GetCopyPathImpl(WCHAR* TruePath, WCHAR **OutCopyPath, ULONG *OutFlags, WCHAR* snapshot_id, BOOLEAN have_trailing_backslash, BOOLEAN* p_add_trailing_backslash)
{
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
ULONG length;
WCHAR* name;
const FILE_DRIVE *drive;
ULONG PrefixLength;
length = wcslen(TruePath);
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 && *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 (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 (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 (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
//
if (p_add_trailing_backslash) *p_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';
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// File_GetCopyPath
//---------------------------------------------------------------------------
_FX NTSTATUS File_GetCopyPath(WCHAR* TruePath, WCHAR **OutCopyPath)
{
return File_GetCopyPathImpl(TruePath, OutCopyPath, NULL, NULL, FALSE, NULL);
}
//---------------------------------------------------------------------------
// File_GetTruePathImpl
//---------------------------------------------------------------------------
_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);
WCHAR* name;
const FILE_DRIVE *drive;
check_sandbox_prefix:
if (*p_length >= Dll_BoxFilePathLen &&
0 == Dll_NlsStrCmp(
*OutTruePath, Dll_BoxFilePath, Dll_BoxFilePathLen))
{
*OutTruePath += Dll_BoxFilePathLen;
*p_length -= Dll_BoxFilePathLen;
if (! *p_length) {
//
// caller specified just the sandbox prefix
//
*OutTruePath = NULL;
return STATUS_BAD_INITIAL_PC;
}
if (OutFlags)
*OutFlags |= FGN_IS_BOXED_PATH;
*p_is_boxed_path = TRUE;
}
if (File_AltBoxPath &&
*p_length >= File_AltBoxPathLen &&
0 == Dll_NlsStrCmp(
*OutTruePath, File_AltBoxPath, File_AltBoxPathLen))
{
*OutTruePath += File_AltBoxPathLen;
*p_length -= File_AltBoxPathLen;
if (! *p_length) {
//
// caller specified just the sandbox prefix
//
*OutTruePath = NULL;
return STATUS_BAD_INITIAL_PC;
}
if (OutFlags)
*OutFlags |= FGN_IS_BOXED_PATH;
*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 (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 = NULL;
return STATUS_BAD_INITIAL_PC;
}
if (no_relocation) {
ULONG len = (ULONG)(path - (*OutTruePath + 1 + File_Snapshot_PrefixLen));
if (len < FILE_MAX_SNAPSHOT_ID) {
wmemcpy(snapshot_id, *OutTruePath + 1 + File_Snapshot_PrefixLen, len);
snapshot_id[len] = L'\0';
}
}
*p_length -= (ULONG)(path - *OutTruePath);
*OutTruePath = path;
}
}
//
// the true path may now begin with "\drive\x", for instance,
// if the process specified a RootDirectory handle that leads
// inside the box. we have to change this box convention to
// full NT path of the drive letter. a later section of code
// will change it back to \drive\x for the copy path.
//
// note that we temporarily use the COPY_NAME_BUFFER here, but
// that's ok because it hasn't been initialized yet
//
if (*p_length >= (_DriveLen - 1) &&
_wcsnicmp(*OutTruePath, _Drive, _DriveLen - 1) == 0)
{
name = (*OutTruePath);
if (name[_DriveLen - 1] == L'\\')
drive = File_GetDriveForLetter(name[_DriveLen]);
else
drive = NULL;
if (! drive) {
//
// caller specified invalid path for \sandbox\drive\x
//
*OutTruePath = NULL;
return STATUS_BAD_INITIAL_PC;
}
ULONG len = _DriveLen + 1; /* drive letter */
// skip any suffix after the drive letter
if (File_DriveAddSN) {
WCHAR* ptr = wcschr(*OutTruePath + _DriveLen + 1, L'\\');
if (!ptr) ptr = wcschr(*OutTruePath + _DriveLen + 1, L'\0');
len = (ULONG)(ptr - *OutTruePath);
}
File_GetName_FixTruePrefix(TlsData,
OutTruePath, p_length, len,
drive->path, drive->len);
if (p_convert_links_again) *p_convert_links_again = TRUE;
LeaveCriticalSection(File_DrivesAndLinks_CritSec);
goto check_sandbox_prefix;
}
//
// alternatively, the true path may begin with "\user\all" which,
// is a box convention for the AllUsers home folder. or, with
// "\user\current", which is a box convention for the home folder
// of the current user. both cases must be translated similarly
// to the "\drive\x" case above.
//
// note that we temporarily use the COPY_NAME_BUFFER here, but
// that's ok because it hasn't been initialized yet
//
else if (*p_length >= _UserLen &&
_wcsnicmp(*OutTruePath, _User, _UserLen) == 0) {
if (File_AllUsersLen && *p_length >= _UserAllLen &&
_wcsnicmp(*OutTruePath, _UserAll, _UserAllLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, p_length, _UserAllLen,
File_AllUsers, File_AllUsersLen);
} else if (File_CurrentUserLen &&
*p_length >= _UserCurrentLen && _wcsnicmp(
*OutTruePath, _UserCurrent, _UserCurrentLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, p_length, _UserCurrentLen,
File_CurrentUser, File_CurrentUserLen);
} else if (File_PublicUserLen &&
*p_length >= _UserPublicLen && _wcsnicmp(
*OutTruePath, _UserPublic, _UserPublicLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, p_length, _UserPublicLen,
File_PublicUser, File_PublicUserLen);
} else {
//
// the path is "...\box\user..." but not for user\current or
// user\all, so restore the sandbox prefix and return special
// status for read-only access
//
name = Dll_GetTlsNameBuffer(
TlsData, TRUE_NAME_BUFFER,
(Dll_BoxFilePathLen + *p_length + 1) * sizeof(WCHAR));
wmemmove(name + Dll_BoxFilePathLen, *OutTruePath, *p_length + 1);
wmemcpy(name, Dll_BoxFilePath, Dll_BoxFilePathLen);
*OutTruePath = name;
return STATUS_BAD_INITIAL_PC;
}
if (p_convert_links_again) *p_convert_links_again = TRUE;
}
//
// alternatively, the true path may begin with "\share\..." which,
// is a box convention for remote shares. in this case it has to
// be translated similarly to the "\drive\x" case above.
//
else if (*p_length >= _ShareLen &&
_wcsnicmp(*OutTruePath, _Share, _ShareLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, p_length, _ShareLen,
File_Mup, File_MupLen);
if (p_convert_links_again) *p_convert_links_again = TRUE;
}
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// File_GetTruePath
//---------------------------------------------------------------------------
_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;
}
//---------------------------------------------------------------------------
// File_GetName
//---------------------------------------------------------------------------
@ -392,22 +873,7 @@ _FX ULONG File_FindBoxPrefixLength(const WCHAR* CopyPath)
_FX NTSTATUS File_GetName(
HANDLE RootDirectory, UNICODE_STRING *ObjectName,
WCHAR **OutTruePath, WCHAR **OutCopyPath, ULONG *OutFlags)
{
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;
@ -421,7 +887,6 @@ _FX NTSTATUS File_GetName(
BOOLEAN convert_links_again;
BOOLEAN is_boxed_path;
BOOLEAN free_true_path;
ULONG PrefixLength;
#ifdef WOW64_FS_REDIR
BOOLEAN convert_wow64_link = (File_Wow64FileLink) ? TRUE : FALSE;
@ -767,202 +1232,11 @@ _FX NTSTATUS File_GetName(
check_sandbox_prefix:
if (length >= Dll_BoxFilePathLen &&
0 == Dll_NlsStrCmp(
*OutTruePath, Dll_BoxFilePath, Dll_BoxFilePathLen))
{
*OutTruePath += Dll_BoxFilePathLen;
length -= Dll_BoxFilePathLen;
if (! length) {
//
// caller specified just the 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_BAD_INITIAL_PC;
}
if (OutFlags)
*OutFlags |= FGN_IS_BOXED_PATH;
is_boxed_path = TRUE;
}
if (File_AltBoxPath &&
length >= File_AltBoxPathLen &&
0 == Dll_NlsStrCmp(
*OutTruePath, File_AltBoxPath, File_AltBoxPathLen))
{
*OutTruePath += File_AltBoxPathLen;
length -= File_AltBoxPathLen;
if (! length) {
//
// caller specified just the sandbox prefix
//
*OutTruePath = TruePath;
return STATUS_BAD_INITIAL_PC;
}
if (OutFlags)
*OutFlags |= FGN_IS_BOXED_PATH;
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))
{
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;
return STATUS_BAD_INITIAL_PC;
}
if (no_relocation) {
ULONG len = (ULONG)(path - (*OutTruePath + 1 + File_Snapshot_PrefixLen));
if (len < FILE_MAX_SNAPSHOT_ID) {
wmemcpy(snapshot_id, *OutTruePath + 1 + File_Snapshot_PrefixLen, len);
snapshot_id[len] = L'\0';
}
}
length -= (ULONG)(path - *OutTruePath);
*OutTruePath = path;
}
}
//
// the true path may now begin with "\drive\x", for instance,
// if the process specified a RootDirectory handle that leads
// inside the box. we have to change this box convention to
// full NT path of the drive letter. a later section of code
// will change it back to \drive\x for the copy path.
//
// note that we temporarily use the COPY_NAME_BUFFER here, but
// that's ok because it hasn't been initialized yet
//
if (length >= (_DriveLen - 1) &&
_wcsnicmp(*OutTruePath, _Drive, _DriveLen - 1) == 0)
{
name = (*OutTruePath);
if (name[_DriveLen - 1] == L'\\')
drive = File_GetDriveForLetter(name[_DriveLen]);
else
drive = NULL;
if (! drive) {
//
// caller specified invalid path for \sandbox\drive\x
//
*OutTruePath = TruePath;
return STATUS_BAD_INITIAL_PC;
}
ULONG len = _DriveLen + 1; /* drive letter */
// skip any suffix after the drive letter
if (File_DriveAddSN) {
WCHAR* ptr = wcschr(*OutTruePath + _DriveLen + 1, L'\\');
if (!ptr) ptr = wcschr(*OutTruePath + _DriveLen + 1, L'\0');
len = (ULONG)(ptr - *OutTruePath);
}
File_GetName_FixTruePrefix(TlsData,
OutTruePath, &length, len,
drive->path, drive->len);
convert_links_again = TRUE;
LeaveCriticalSection(File_DrivesAndLinks_CritSec);
goto check_sandbox_prefix;
}
//
// alternatively, the true path may begin with "\user\all" which,
// is a box convention for the AllUsers home folder. or, with
// "\user\current", which is a box convention for the home folder
// of the current user. both cases must be translated similarly
// to the "\drive\x" case above.
//
// note that we temporarily use the COPY_NAME_BUFFER here, but
// 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 &&
_wcsnicmp(*OutTruePath, _User, _UserLen) == 0) {
if (File_AllUsersLen && length >= _UserAllLen &&
_wcsnicmp(*OutTruePath, _UserAll, _UserAllLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, &length, _UserAllLen,
File_AllUsers, File_AllUsersLen);
} else if (File_CurrentUserLen &&
length >= _UserCurrentLen && _wcsnicmp(
*OutTruePath, _UserCurrent, _UserCurrentLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, &length, _UserCurrentLen,
File_CurrentUser, File_CurrentUserLen);
} else if (File_PublicUserLen &&
length >= _UserPublicLen && _wcsnicmp(
*OutTruePath, _UserPublic, _UserPublicLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, &length, _UserPublicLen,
File_PublicUser, File_PublicUserLen);
} else {
//
// the path is "...\box\user..." but not for user\current or
// user\all, so restore the sandbox prefix and return special
// status for read-only access
//
name = Dll_GetTlsNameBuffer(
TlsData, TRUE_NAME_BUFFER,
(Dll_BoxFilePathLen + length + 1) * sizeof(WCHAR));
wmemmove(name + Dll_BoxFilePathLen, *OutTruePath, length + 1);
wmemcpy(name, Dll_BoxFilePath, Dll_BoxFilePathLen);
*OutTruePath = name;
return STATUS_BAD_INITIAL_PC;
}
convert_links_again = TRUE;
}
//
// alternatively, the true path may begin with "\share\..." which,
// is a box convention for remote shares. in this case it has to
// be translated similarly to the "\drive\x" case above.
//
else if (length >= _ShareLen &&
_wcsnicmp(*OutTruePath, _Share, _ShareLen) == 0) {
File_GetName_FixTruePrefix(TlsData,
OutTruePath, &length, _ShareLen,
File_Mup, File_MupLen);
convert_links_again = TRUE;
return status;
}
//
@ -1109,209 +1383,9 @@ check_sandbox_prefix:
// 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;

View File

@ -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,

View File

@ -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);
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 (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_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)) {
//