Selaa lähdekoodia

Add PathHasInvalidCharacters function

Jordan Russell 9 kuukautta sitten
vanhempi
commit
0adec08c98
1 muutettua tiedostoa jossa 65 lisäystä ja 0 poistoa
  1. 65 0
      Projects/Src/Setup.InstFunc.pas

+ 65 - 0
Projects/Src/Setup.InstFunc.pas

@@ -83,6 +83,8 @@ function IsProtectedSystemFile(const DisableFsRedir: Boolean;
   const Filename: String): Boolean;
 function MakePendingFileRenameOperationsChecksum: TSHA256Digest;
 function ModifyPifFile(const Filename: String; const CloseOnExit: Boolean): Boolean;
+function PathHasInvalidCharacters(const S: String;
+  const AllowDriveLetterColon: Boolean): Boolean;
 procedure RaiseFunctionFailedError(const FunctionName: String);
 procedure RaiseOleError(const FunctionName: String; const ResultCode: HRESULT);
 procedure RefreshEnvironment;
@@ -1063,6 +1065,69 @@ begin
       CreateDirectoryRedir(DisableFsRedir, Dir);
 end;
 
+function PathHasInvalidCharacters(const S: String;
+  const AllowDriveLetterColon: Boolean): Boolean;
+{ Checks the specified path for characters that are never allowed in paths,
+  or characters and path components that are accepted by the system but might
+  present a security problem (such as '..' and sometimes ':').
+  Specifically, True is returned if S includes any of the following:
+  - Control characters (0-31)
+  - One of these characters: /*?"<>|
+    (This means forward slashes and the prefixes '\\?\' and '\??\' are never
+    allowed.)
+  - Colons (':'), except when AllowDriveLetterColon=True and the string's
+    first character is a letter and the second character is the only colon.
+    (This blocks NTFS alternate data stream names.)
+  - A component with a trailing dot or space
+
+  Due to the last rule above, '.' and '..' components are never allowed, nor
+  are components like these:
+    'file '
+    'file.'
+    'file. . .'
+    'file . . '
+  When expanding paths (with no '\\?\' prefix used), Windows 11 23H2 silently
+  removes all trailing dots and spaces from the end of the string. Therefore,
+  if used at the end of a path, all of the above cases yield just 'file'.
+  On preceding components of the path, nothing is done with spaces; if there
+  is exactly one dot at the end, it is removed (e.g., 'dir.\file' becomes
+  'dir\file'), while multiple dots are left untouched ('dir..\file' doesn't
+  change).
+  By rejecting trailing dots and spaces up front, we avoid all that weirdness
+  and the problems that could arise from it.
+
+  Since ':' is considered invalid (except in the one case noted above), it's
+  not possible to sneak in disallowed dots/spaces by including an NTFS
+  alternate data stream name. The function will return True in these cases:
+    '..:streamname'
+    'file :streamname'
+}
+begin
+  Result := True;
+  for var I := Low(S) to High(S) do begin
+    var C := S[I];
+    if Ord(C) < 32 then
+      Exit;
+    case C of
+      #32, '.':
+        begin
+          if (I = High(S)) or PathCharIsSlash(S[I+1]) then
+            Exit;
+        end;
+      ':':
+        begin
+          { The A-Z check ensures that '.:streamname', ' :streamname', and
+            '\:streamname' are disallowed. }
+          if not AllowDriveLetterColon or (I <> Low(S)+1) or
+             not CharInSet(S[Low(S)], ['A'..'Z', 'a'..'z']) then
+            Exit;
+        end;
+      '/', '*', '?', '"', '<', '>', '|': Exit;
+    end;
+  end;
+  Result := False;
+end;
+
 { TSimpleStringList }
 
 procedure TSimpleStringList.Add(const S: String);