command-line-api icon indicating copy to clipboard operation
command-line-api copied to clipboard

Parameter starting with @ is interpreted as a response file path

Open robsonj opened this issue 5 years ago • 6 comments

My app accepts a password as a command line argument, an example...

MyApp.exe --password @123#456

Unfortunately, the @ results in failure, as the dragonfruit subsystem thinks it is a response file and tries (and fails) to locate it as a file on the filesystem.

Would it be possible to allow for the @ character to either be escaped, or handle the exception of failing to open a response file and allow the arguments to pass through to the app unaltered?

Currently the behaviors is to throw an unhandled exception and crash...

System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks

Found in System.CommandLine.DragonFruit v0.3.0-alpha.20158.1

Cheers Jonathan

robsonj avatar Mar 11 '20 15:03 robsonj

Command line parameters should typically be treated as plain strings, but no further parsing, if you enclose them in quotes. Does the following work?

MyApp.exe --password "@123#456"

jonsequitur avatar Mar 11 '20 15:03 jonsequitur

No it does not, I tried both...

MyApp.exe --password "@123#456"

and also

MyApp.exe --password @@123#456

robsonj avatar Mar 11 '20 15:03 robsonj

Full exception details...

System.ArgumentException
  HResult=0x80070057
  Message=Illegal characters in path.
  Source=mscorlib
  StackTrace:
   at System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks(String fullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize, Boolean checkHost)
   at System.IO.StreamReader..ctor(String path, Encoding encoding)
   at System.IO.File.InternalReadAllLines(String path, Encoding encoding)
   at System.CommandLine.Parsing.StringExtensions.<ExpandResponseFile>d__15.MoveNext()
   at System.CommandLine.Parsing.StringExtensions.<Tokenize>g__ReadResponseFile|4_2(String filePath, Int32 i, <>c__DisplayClass4_0& )
   at System.CommandLine.Parsing.StringExtensions.Tokenize(IReadOnlyList`1 args, CommandLineConfiguration configuration)
   at System.CommandLine.Parsing.Parser.Parse(IReadOnlyList`1 arguments, String rawInput)
   at System.CommandLine.Parsing.ParserExtensions.<InvokeAsync>d__3.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.DragonFruit.CommandLine.<InvokeMethodAsync>d__2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.DragonFruit.CommandLine.<ExecuteAssemblyAsync>d__0.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at AutoGeneratedProgram.<Main>d__0.MoveNext() in C:\Source\coredev\applications\Deploy\Deploy\obj\Debug\net472\Deploy.Program.g.cs:line 10
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at AutoGeneratedProgram.<Main>(String[] args)

  This exception was originally thrown at this call stack:
	System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks(string)
	System.IO.FileStream.Init(string, System.IO.FileMode, System.IO.FileAccess, int, bool, System.IO.FileShare, int, System.IO.FileOptions, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES, string, bool, bool, bool)
	System.IO.FileStream.FileStream(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, int, System.IO.FileOptions, string, bool, bool, bool)
	System.IO.StreamReader.StreamReader(string, System.Text.Encoding, bool, int, bool)
	System.IO.StreamReader.StreamReader(string, System.Text.Encoding)
	System.IO.File.InternalReadAllLines(string, System.Text.Encoding)
	System.CommandLine.Parsing.StringExtensions.ExpandResponseFile(string, System.CommandLine.Parsing.ResponseFileHandling)
	System.CommandLine.Parsing.StringExtensions.Tokenize.__ReadResponseFile|4_2(string, int, ref System.CommandLine.Parsing.StringExtensions.<>c__DisplayClass4_0)
	System.CommandLine.Parsing.StringExtensions.Tokenize(System.Collections.Generic.IReadOnlyList<string>, System.CommandLine.CommandLineConfiguration)
	System.CommandLine.Parsing.Parser.Parse(System.Collections.Generic.IReadOnlyList<string>, string)
    ...
    [Call Stack Truncated]

robsonj avatar Mar 16 '20 14:03 robsonj

Escaping the @ with a \ at least stops the subsystem regarding it as a response file.

However, this is not a fix but a workaround, you'll need to remove the \ from the argument in your code.

sandord avatar Mar 23 '21 12:03 sandord

FYI many common tools use libiberty's expandargv or a compatible implementation. They check for the leading @ after all escaping/quoting is resolved and don't provide any way to prevent an argument starting with @ from being treated as a response file. They do however silently leave the original argument alone if the response file does not exist or cannot be read.

If you are passing paths and not arbitrary strings like passwords, you can "escape" them by prepending ./ when the first character is @ as such paths are always relative.

billybednar avatar Aug 04 '23 01:08 billybednar