https://git.reactos.org/?p=reactos.git;a=commitdiff;h=71197535a1031eb137700d9ba0821210edeb51be
commit 71197535a1031eb137700d9ba0821210edeb51be Author: Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org> AuthorDate: Thu Jul 25 18:57:23 2024 +0200 Commit: Hermès Bélusca-Maïto <hermes.belusca-ma...@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,