https://git.reactos.org/?p=reactos.git;a=commitdiff;h=71197535a1031eb137700…
commit 71197535a1031eb137700d9ba0821210edeb51be
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Thu Jul 25 18:57:23 2024 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Jul 31 11:41:24 2024 +0200
[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.)
---
base/setup/lib/setuplib.c | 100 ++++++++++++++++++++++++++++++++++------------
1 file changed, 74 insertions(+), 26 deletions(-)
diff --git a/base/setup/lib/setuplib.c b/base/setup/lib/setuplib.c
index 22ec4afc3fe..9fb91b24f80 100644
--- a/base/setup/lib/setuplib.c
+++ b/base/setup/lib/setuplib.c
@@ -712,51 +712,99 @@ InitSystemPartition(
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
IsValidInstallDirectory(
_In_ PCWSTR InstallDir)
{
- UINT i, Length;
+ PCWCH p;
+
+ /* As with the NT installer, fail if the path is empty or "\\" */
+ p = InstallDir;
+ if (!*p || (IS_PATH_SEPARATOR(*p) && !*(p + 1)))
+ return FALSE;
- Length = wcslen(InstallDir);
+ /* The path must contain only valid characters (alpha-numeric,
+ * '.', '\\', '-' and '_'). Spaces are not accepted.
*/
+ for (p = InstallDir; *p; ++p)
+ {
+ if (!IS_VALID_INSTALL_PATH_CHAR(*p))
+ return FALSE;
+ }
- // TODO: Add check for 8.3 too.
+ /*
+ * Loop over each path component and verify that each is a valid 8.3 name.
+ */
+ for (p = InstallDir; *p;)
+ {
+ PCWSTR Path;
+ SIZE_T Length;
+ UNICODE_STRING Name;
+ BOOLEAN IsNameLegal, SpacesInName;
+
+ /* Skip any first separator */
+ 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);
+ }
- /* Path must be at least 2 characters long */
-// if (Length < 2)
-// return FALSE;
+ /* Calculate the path component length */
+ Length = p - Path;
- /* Path must start with a backslash */
-// if (InstallDir[0] != L'\\')
-// return FALSE;
+ /* As with the NT installer, fail for '.' and '..';
+ * RtlIsNameLegalDOS8Dot3() would succeed otherwise */
+ if ((Length == 1 && *Path == '.') || (Length == 2 &&
*Path == '.' && *(Path + 1) == '.'))
+ return FALSE;
- /* Path must not end with a backslash */
- if (InstallDir[Length - 1] == L'\\')
- 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;
- /* Path must not contain whitespace characters */
- for (i = 0; i < Length; i++)
- {
- if (iswspace(InstallDir[i]))
+ if (Length == 0)
return FALSE;
- }
- /* Path component must not end with a dot */
- for (i = 0; i < Length; i++)
- {
- if (InstallDir[i] == L'\\' && i > 0)
+ /* 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)
{
- if (InstallDir[i - 1] == L'.')
- return FALSE;
+ 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 */
}
- if (InstallDir[Length - 1] == L'.')
- return FALSE;
-
return TRUE;
}
+
NTSTATUS
InitDestinationPaths(
IN OUT PUSETUP_DATA pSetupData,