[SETUPLIB][USETUP] Improve IsValidInstallDirectory() behaviour (#7187)

CORE-6149, CORE-6179, CORE-9529

See also commits d329fbebf (r66995), 7c3f4c94a (r68307), and 16daf6700.

The function verifies that each path component of the directory is
a valid 8.3 name, not . or .. nor empty. This behaviour is compatible
with what can be observed from Windows XP/2003 installer.
(To reliably test this with the Windows installer, you need to modify
the TXTSETUP.SIF DefaultPath value in the [SetupData] section.)
This commit is contained in:
Hermès Bélusca-Maïto 2024-07-25 18:57:23 +02:00
parent 6289183dcd
commit 71197535a1
No known key found for this signature in database
GPG Key ID: 3B2539C65E7B93D0

View File

@ -712,51 +712,99 @@ InitSystemPartition(
return TRUE; return TRUE;
} }
#define IS_PATH_SEPARATOR(c) ((c) == L'\\' || (c) == L'/')
/**
* @brief
* Verify whether the given directory is suitable for ReactOS installation.
* Each path component must be a valid 8.3 name.
**/
BOOLEAN BOOLEAN
IsValidInstallDirectory( IsValidInstallDirectory(
_In_ PCWSTR InstallDir) _In_ PCWSTR InstallDir)
{ {
UINT i, Length; PCWCH p;
Length = wcslen(InstallDir); /* As with the NT installer, fail if the path is empty or "\\" */
p = InstallDir;
// TODO: Add check for 8.3 too. if (!*p || (IS_PATH_SEPARATOR(*p) && !*(p + 1)))
/* Path must be at least 2 characters long */
// if (Length < 2)
// return FALSE;
/* Path must start with a backslash */
// if (InstallDir[0] != L'\\')
// return FALSE;
/* Path must not end with a backslash */
if (InstallDir[Length - 1] == L'\\')
return FALSE; return FALSE;
/* Path must not contain whitespace characters */ /* The path must contain only valid characters (alpha-numeric,
for (i = 0; i < Length; i++) * '.', '\\', '-' and '_'). Spaces are not accepted. */
for (p = InstallDir; *p; ++p)
{ {
if (iswspace(InstallDir[i])) if (!IS_VALID_INSTALL_PATH_CHAR(*p))
return FALSE; return FALSE;
} }
/* Path component must not end with a dot */ /*
for (i = 0; i < Length; i++) * Loop over each path component and verify that each is a valid 8.3 name.
*/
for (p = InstallDir; *p;)
{ {
if (InstallDir[i] == L'\\' && i > 0) PCWSTR Path;
{ SIZE_T Length;
if (InstallDir[i - 1] == L'.') UNICODE_STRING Name;
return FALSE; BOOLEAN IsNameLegal, SpacesInName;
}
}
if (InstallDir[Length - 1] == L'.') /* Skip any first separator */
return FALSE; if (IS_PATH_SEPARATOR(*p))
++p;
/* Now skip past the path component until we reach the next separator */
Path = p;
while (*p && !IS_PATH_SEPARATOR(*p))
++p;
if (p == Path)
{
/* Succeed if nothing else follows this separator; otherwise
* it's a separator and consecutive ones are not supported */
return (!*p);
}
/* Calculate the path component length */
Length = p - Path;
/* As with the NT installer, fail for '.' and '..';
* RtlIsNameLegalDOS8Dot3() would succeed otherwise */
if ((Length == 1 && *Path == '.') || (Length == 2 && *Path == '.' && *(Path + 1) == '.'))
return FALSE;
/* As with the NT installer, allow _only ONE trailing_ dot in
* the path component (but not 2 or more), by reducing Length
* in that case; RtlIsNameLegalDOS8Dot3() would fail otherwise */
if (Length > 1 && *(p - 2) != L'.' && *(p - 1) == L'.')
--Length;
if (Length == 0)
return FALSE;
/* Verify that the path component is a valid 8.3 name */
// if (Length > 8+1+3)
// return FALSE;
Name.Length = Name.MaximumLength = (USHORT)(Length * sizeof(WCHAR));
Name.Buffer = (PWCHAR)Path;
SpacesInName = FALSE;
IsNameLegal = RtlIsNameLegalDOS8Dot3(&Name, NULL, &SpacesInName);
/* If it isn't legal or contain spaces, fail */
if (!IsNameLegal || SpacesInName)
{
DPRINT("'%wZ' is %s 8.3 filename %s spaces\n",
&Name,
(IsNameLegal ? "a valid" : "an invalid"),
(SpacesInName ? "with" : "without"));
return FALSE;
}
/* Go to the next path component */
}
return TRUE; return TRUE;
} }
NTSTATUS NTSTATUS
InitDestinationPaths( InitDestinationPaths(
IN OUT PUSETUP_DATA pSetupData, IN OUT PUSETUP_DATA pSetupData,