|
|
bf087c |
From 6e823f2fcb904efccd8ae16d6aab8c1b34a09d5c Mon Sep 17 00:00:00 2001
|
|
|
bf087c |
From: Kristian Rosenvold <krosenvold@apache.org>
|
|
|
bf087c |
Date: Tue, 8 Oct 2013 18:21:04 +0200
|
|
|
bf087c |
Subject: [PATCH] [PLXUTILS-161] Commandline shell injection problems
|
|
|
bf087c |
|
|
|
bf087c |
Patch by Charles Duffy, applied unmodified
|
|
|
bf087c |
---
|
|
|
bf087c |
.../org/codehaus/plexus/util/cli/Commandline.java | 38 +++++++++++---
|
|
|
bf087c |
.../plexus/util/cli/shell/BourneShell.java | 60 +++++++---------------
|
|
|
bf087c |
.../org/codehaus/plexus/util/cli/shell/Shell.java | 35 ++++++++++---
|
|
|
bf087c |
.../codehaus/plexus/util/cli/CommandlineTest.java | 37 +++++++------
|
|
|
bf087c |
.../plexus/util/cli/shell/BourneShellTest.java | 19 ++++---
|
|
|
bf087c |
5 files changed, 107 insertions(+), 82 deletions(-)
|
|
|
bf087c |
|
|
|
bf087c |
diff --git a/src/main/java/org/codehaus/plexus/util/cli/Commandline.java b/src/main/java/org/codehaus/plexus/util/cli/Commandline.java
|
|
|
bf087c |
index 5e0d5af..7346c7e 100644
|
|
|
bf087c |
--- a/src/main/java/org/codehaus/plexus/util/cli/Commandline.java
|
|
|
bf087c |
+++ b/src/main/java/org/codehaus/plexus/util/cli/Commandline.java
|
|
|
bf087c |
@@ -139,6 +139,8 @@ public class Commandline
|
|
|
bf087c |
* Create a new command line object.
|
|
|
bf087c |
* Shell is autodetected from operating system
|
|
|
bf087c |
*
|
|
|
bf087c |
+ * Shell usage is only desirable when generating code for remote execution.
|
|
|
bf087c |
+ *
|
|
|
bf087c |
* @param toProcess
|
|
|
bf087c |
*/
|
|
|
bf087c |
public Commandline( String toProcess, Shell shell )
|
|
|
bf087c |
@@ -167,6 +169,8 @@ public class Commandline
|
|
|
bf087c |
/**
|
|
|
bf087c |
* Create a new command line object.
|
|
|
bf087c |
* Shell is autodetected from operating system
|
|
|
bf087c |
+ *
|
|
|
bf087c |
+ * Shell usage is only desirable when generating code for remote execution.
|
|
|
bf087c |
*/
|
|
|
bf087c |
public Commandline( Shell shell )
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -174,8 +178,7 @@ public class Commandline
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
/**
|
|
|
bf087c |
- * Create a new command line object.
|
|
|
bf087c |
- * Shell is autodetected from operating system
|
|
|
bf087c |
+ * Create a new command line object, given a command following POSIX sh quoting rules
|
|
|
bf087c |
*
|
|
|
bf087c |
* @param toProcess
|
|
|
bf087c |
*/
|
|
|
bf087c |
@@ -203,7 +206,6 @@ public class Commandline
|
|
|
bf087c |
|
|
|
bf087c |
/**
|
|
|
bf087c |
* Create a new command line object.
|
|
|
bf087c |
- * Shell is autodetected from operating system
|
|
|
bf087c |
*/
|
|
|
bf087c |
public Commandline()
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -253,7 +255,7 @@ public class Commandline
|
|
|
bf087c |
{
|
|
|
bf087c |
if ( realPos == -1 )
|
|
|
bf087c |
{
|
|
|
bf087c |
- realPos = ( getExecutable() == null ? 0 : 1 );
|
|
|
bf087c |
+ realPos = ( getLiteralExecutable() == null ? 0 : 1 );
|
|
|
bf087c |
for ( int i = 0; i < position; i++ )
|
|
|
bf087c |
{
|
|
|
bf087c |
Arg arg = (Arg) arguments.elementAt( i );
|
|
|
bf087c |
@@ -404,6 +406,21 @@ public class Commandline
|
|
|
bf087c |
this.executable = executable;
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
+ /**
|
|
|
bf087c |
+ * @return Executable to be run, as a literal string (no shell quoting/munging)
|
|
|
bf087c |
+ */
|
|
|
bf087c |
+ public String getLiteralExecutable()
|
|
|
bf087c |
+ {
|
|
|
bf087c |
+ return executable;
|
|
|
bf087c |
+ }
|
|
|
bf087c |
+
|
|
|
bf087c |
+ /**
|
|
|
bf087c |
+ * Return an executable name, quoted for shell use.
|
|
|
bf087c |
+ *
|
|
|
bf087c |
+ * Shell usage is only desirable when generating code for remote execution.
|
|
|
bf087c |
+ *
|
|
|
bf087c |
+ * @return Executable to be run, quoted for shell interpretation
|
|
|
bf087c |
+ */
|
|
|
bf087c |
public String getExecutable()
|
|
|
bf087c |
{
|
|
|
bf087c |
String exec = shell.getExecutable();
|
|
|
bf087c |
@@ -483,7 +500,7 @@ public class Commandline
|
|
|
bf087c |
public String[] getCommandline()
|
|
|
bf087c |
{
|
|
|
bf087c |
final String[] args = getArguments();
|
|
|
bf087c |
- String executable = getExecutable();
|
|
|
bf087c |
+ String executable = getLiteralExecutable();
|
|
|
bf087c |
|
|
|
bf087c |
if ( executable == null )
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -497,6 +514,8 @@ public class Commandline
|
|
|
bf087c |
|
|
|
bf087c |
/**
|
|
|
bf087c |
* Returns the shell, executable and all defined arguments.
|
|
|
bf087c |
+ *
|
|
|
bf087c |
+ * Shell usage is only desirable when generating code for remote execution.
|
|
|
bf087c |
*/
|
|
|
bf087c |
public String[] getShellCommandline()
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -633,7 +652,7 @@ public class Commandline
|
|
|
bf087c |
{
|
|
|
bf087c |
if ( workingDir == null )
|
|
|
bf087c |
{
|
|
|
bf087c |
- process = Runtime.getRuntime().exec( getShellCommandline(), environment );
|
|
|
bf087c |
+ process = Runtime.getRuntime().exec( getCommandline(), environment, workingDir );
|
|
|
bf087c |
}
|
|
|
bf087c |
else
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -648,7 +667,7 @@ public class Commandline
|
|
|
bf087c |
+ "\" does not specify a directory." );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
- process = Runtime.getRuntime().exec( getShellCommandline(), environment, workingDir );
|
|
|
bf087c |
+ process = Runtime.getRuntime().exec( getCommandline(), environment, workingDir );
|
|
|
bf087c |
}
|
|
|
bf087c |
}
|
|
|
bf087c |
catch ( IOException ex )
|
|
|
bf087c |
@@ -669,7 +688,7 @@ public class Commandline
|
|
|
bf087c |
shell.setWorkingDirectory( workingDir );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
- if ( shell.getExecutable() == null )
|
|
|
bf087c |
+ if ( shell.getOriginalExecutable() == null )
|
|
|
bf087c |
{
|
|
|
bf087c |
shell.setExecutable( executable );
|
|
|
bf087c |
}
|
|
|
bf087c |
@@ -684,6 +703,8 @@ public class Commandline
|
|
|
bf087c |
/**
|
|
|
bf087c |
* Allows to set the shell to be used in this command line.
|
|
|
bf087c |
*
|
|
|
bf087c |
+ * Shell usage is only desirable when generating code for remote execution.
|
|
|
bf087c |
+ *
|
|
|
bf087c |
* @param shell
|
|
|
bf087c |
* @since 1.2
|
|
|
bf087c |
*/
|
|
|
bf087c |
@@ -695,6 +716,7 @@ public class Commandline
|
|
|
bf087c |
/**
|
|
|
bf087c |
* Get the shell to be used in this command line.
|
|
|
bf087c |
*
|
|
|
bf087c |
+ * Shell usage is only desirable when generating code for remote execution.
|
|
|
bf087c |
* @since 1.2
|
|
|
bf087c |
*/
|
|
|
bf087c |
public Shell getShell()
|
|
|
bf087c |
diff --git a/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java b/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java
|
|
|
bf087c |
index e4b4cde..3c07fb6 100644
|
|
|
bf087c |
--- a/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java
|
|
|
bf087c |
+++ b/src/main/java/org/codehaus/plexus/util/cli/shell/BourneShell.java
|
|
|
bf087c |
@@ -17,7 +17,6 @@ package org.codehaus.plexus.util.cli.shell;
|
|
|
bf087c |
*/
|
|
|
bf087c |
|
|
|
bf087c |
import org.codehaus.plexus.util.Os;
|
|
|
bf087c |
-import org.codehaus.plexus.util.StringUtils;
|
|
|
bf087c |
|
|
|
bf087c |
import java.util.ArrayList;
|
|
|
bf087c |
import java.util.List;
|
|
|
bf087c |
@@ -29,34 +28,18 @@ import java.util.List;
|
|
|
bf087c |
public class BourneShell
|
|
|
bf087c |
extends Shell
|
|
|
bf087c |
{
|
|
|
bf087c |
- private static final char[] BASH_QUOTING_TRIGGER_CHARS = {
|
|
|
bf087c |
- ' ',
|
|
|
bf087c |
- '$',
|
|
|
bf087c |
- ';',
|
|
|
bf087c |
- '&',
|
|
|
bf087c |
- '|',
|
|
|
bf087c |
- '<',
|
|
|
bf087c |
- '>',
|
|
|
bf087c |
- '*',
|
|
|
bf087c |
- '?',
|
|
|
bf087c |
- '(',
|
|
|
bf087c |
- ')',
|
|
|
bf087c |
- '[',
|
|
|
bf087c |
- ']',
|
|
|
bf087c |
- '{',
|
|
|
bf087c |
- '}',
|
|
|
bf087c |
- '`' };
|
|
|
bf087c |
|
|
|
bf087c |
public BourneShell()
|
|
|
bf087c |
{
|
|
|
bf087c |
- this( false );
|
|
|
bf087c |
+ this(false);
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
public BourneShell( boolean isLoginShell )
|
|
|
bf087c |
{
|
|
|
bf087c |
+ setUnconditionalQuoting( true );
|
|
|
bf087c |
setShellCommand( "/bin/sh" );
|
|
|
bf087c |
setArgumentQuoteDelimiter( '\'' );
|
|
|
bf087c |
- setExecutableQuoteDelimiter( '\"' );
|
|
|
bf087c |
+ setExecutableQuoteDelimiter( '\'' );
|
|
|
bf087c |
setSingleQuotedArgumentEscaped( true );
|
|
|
bf087c |
setSingleQuotedExecutableEscaped( false );
|
|
|
bf087c |
setQuotedExecutableEnabled( true );
|
|
|
bf087c |
@@ -76,7 +59,7 @@ public class BourneShell
|
|
|
bf087c |
return super.getExecutable();
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
- return unifyQuotes( super.getExecutable());
|
|
|
bf087c |
+ return quoteOneItem( super.getOriginalExecutable(), true );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
public List<String> getShellArgsList()
|
|
|
bf087c |
@@ -126,46 +109,41 @@ public class BourneShell
|
|
|
bf087c |
StringBuffer sb = new StringBuffer();
|
|
|
bf087c |
sb.append( "cd " );
|
|
|
bf087c |
|
|
|
bf087c |
- sb.append( unifyQuotes( dir ) );
|
|
|
bf087c |
+ sb.append( quoteOneItem( dir, false ) );
|
|
|
bf087c |
sb.append( " && " );
|
|
|
bf087c |
|
|
|
bf087c |
return sb.toString();
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
- protected char[] getQuotingTriggerChars()
|
|
|
bf087c |
- {
|
|
|
bf087c |
- return BASH_QUOTING_TRIGGER_CHARS;
|
|
|
bf087c |
- }
|
|
|
bf087c |
-
|
|
|
bf087c |
/**
|
|
|
bf087c |
* Unify quotes in a path for the Bourne Shell.
|
|
|
bf087c |
*
|
|
|
bf087c |
*
|
|
|
bf087c |
- * BourneShell.unifyQuotes(null) = null
|
|
|
bf087c |
- * BourneShell.unifyQuotes("") = (empty)
|
|
|
bf087c |
- * BourneShell.unifyQuotes("/test/quotedpath'abc") = /test/quotedpath\'abc
|
|
|
bf087c |
- * BourneShell.unifyQuotes("/test/quoted path'abc") = "/test/quoted path'abc"
|
|
|
bf087c |
- * BourneShell.unifyQuotes("/test/quotedpath\"abc") = "/test/quotedpath\"abc"
|
|
|
bf087c |
- * BourneShell.unifyQuotes("/test/quoted path\"abc") = "/test/quoted path\"abc"
|
|
|
bf087c |
- * BourneShell.unifyQuotes("/test/quotedpath\"'abc") = "/test/quotedpath\"'abc"
|
|
|
bf087c |
- * BourneShell.unifyQuotes("/test/quoted path\"'abc") = "/test/quoted path\"'abc"
|
|
|
bf087c |
+ * BourneShell.quoteOneItem(null) = null
|
|
|
bf087c |
+ * BourneShell.quoteOneItem("") = ''
|
|
|
bf087c |
+ * BourneShell.quoteOneItem("/test/quotedpath'abc") = '/test/quotedpath'"'"'abc'
|
|
|
bf087c |
+ * BourneShell.quoteOneItem("/test/quoted path'abc") = '/test/quoted pat'"'"'habc'
|
|
|
bf087c |
+ * BourneShell.quoteOneItem("/test/quotedpath\"abc") = '/test/quotedpath"abc'
|
|
|
bf087c |
+ * BourneShell.quoteOneItem("/test/quoted path\"abc") = '/test/quoted path"abc'
|
|
|
bf087c |
+ * BourneShell.quoteOneItem("/test/quotedpath\"'abc") = '/test/quotedpath"'"'"'abc'
|
|
|
bf087c |
+ * BourneShell.quoteOneItem("/test/quoted path\"'abc") = '/test/quoted path"'"'"'abc'
|
|
|
bf087c |
*
|
|
|
bf087c |
*
|
|
|
bf087c |
* @param path not null path.
|
|
|
bf087c |
* @return the path unified correctly for the Bourne shell.
|
|
|
bf087c |
*/
|
|
|
bf087c |
- protected static String unifyQuotes( String path )
|
|
|
bf087c |
+ protected String quoteOneItem( String path, boolean isExecutable )
|
|
|
bf087c |
{
|
|
|
bf087c |
if ( path == null )
|
|
|
bf087c |
{
|
|
|
bf087c |
return null;
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
- if ( path.indexOf( " " ) == -1 && path.indexOf( "'" ) != -1 && path.indexOf( "\"" ) == -1 )
|
|
|
bf087c |
- {
|
|
|
bf087c |
- return StringUtils.escape( path );
|
|
|
bf087c |
- }
|
|
|
bf087c |
+ StringBuilder sb = new StringBuilder();
|
|
|
bf087c |
+ sb.append( "'" );
|
|
|
bf087c |
+ sb.append( path.replace( "'", "'\"'\"'" ) );
|
|
|
bf087c |
+ sb.append( "'" );
|
|
|
bf087c |
|
|
|
bf087c |
- return StringUtils.quoteAndEscape( path, '\"', BASH_QUOTING_TRIGGER_CHARS );
|
|
|
bf087c |
+ return sb.toString();
|
|
|
bf087c |
}
|
|
|
bf087c |
}
|
|
|
bf087c |
diff --git a/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java b/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java
|
|
|
bf087c |
index 571b249..a42eae8 100644
|
|
|
bf087c |
--- a/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java
|
|
|
bf087c |
+++ b/src/main/java/org/codehaus/plexus/util/cli/shell/Shell.java
|
|
|
bf087c |
@@ -48,6 +48,8 @@ public class Shell
|
|
|
bf087c |
|
|
|
bf087c |
private boolean quotedArgumentsEnabled = true;
|
|
|
bf087c |
|
|
|
bf087c |
+ private boolean unconditionallyQuote = false;
|
|
|
bf087c |
+
|
|
|
bf087c |
private String executable;
|
|
|
bf087c |
|
|
|
bf087c |
private String workingDir;
|
|
|
bf087c |
@@ -69,6 +71,16 @@ public class Shell
|
|
|
bf087c |
private String argumentEscapePattern = "\\%s";
|
|
|
bf087c |
|
|
|
bf087c |
/**
|
|
|
bf087c |
+ * Toggle unconditional quoting
|
|
|
bf087c |
+ *
|
|
|
bf087c |
+ * @param unconditionallyQuote
|
|
|
bf087c |
+ */
|
|
|
bf087c |
+ public void setUnconditionalQuoting(boolean unconditionallyQuote)
|
|
|
bf087c |
+ {
|
|
|
bf087c |
+ this.unconditionallyQuote = unconditionallyQuote;
|
|
|
bf087c |
+ }
|
|
|
bf087c |
+
|
|
|
bf087c |
+ /**
|
|
|
bf087c |
* Set the command to execute the shell (eg. COMMAND.COM, /bin/bash,...)
|
|
|
bf087c |
*
|
|
|
bf087c |
* @param shellCommand
|
|
|
bf087c |
@@ -129,6 +141,19 @@ public class Shell
|
|
|
bf087c |
return getRawCommandLine( executable, arguments );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
+ protected String quoteOneItem(String inputString, boolean isExecutable)
|
|
|
bf087c |
+ {
|
|
|
bf087c |
+ char[] escapeChars = getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
|
|
|
bf087c |
+ return StringUtils.quoteAndEscape(
|
|
|
bf087c |
+ inputString,
|
|
|
bf087c |
+ isExecutable ? getExecutableQuoteDelimiter() : getArgumentQuoteDelimiter(),
|
|
|
bf087c |
+ escapeChars,
|
|
|
bf087c |
+ getQuotingTriggerChars(),
|
|
|
bf087c |
+ '\\',
|
|
|
bf087c |
+ unconditionallyQuote
|
|
|
bf087c |
+ );
|
|
|
bf087c |
+ }
|
|
|
bf087c |
+
|
|
|
bf087c |
protected List<String> getRawCommandLine( String executable, String[] arguments )
|
|
|
bf087c |
{
|
|
|
bf087c |
List<String> commandLine = new ArrayList<String>();
|
|
|
bf087c |
@@ -144,9 +169,7 @@ public class Shell
|
|
|
bf087c |
|
|
|
bf087c |
if ( isQuotedExecutableEnabled() )
|
|
|
bf087c |
{
|
|
|
bf087c |
- char[] escapeChars = getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
|
|
|
bf087c |
-
|
|
|
bf087c |
- sb.append( StringUtils.quoteAndEscape( getExecutable(), getExecutableQuoteDelimiter(), escapeChars, getQuotingTriggerChars(), '\\', false ) );
|
|
|
bf087c |
+ sb.append( quoteOneItem( getOriginalExecutable(), true ) );
|
|
|
bf087c |
}
|
|
|
bf087c |
else
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -162,9 +185,7 @@ public class Shell
|
|
|
bf087c |
|
|
|
bf087c |
if ( isQuotedArgumentsEnabled() )
|
|
|
bf087c |
{
|
|
|
bf087c |
- char[] escapeChars = getEscapeChars( isSingleQuotedArgumentEscaped(), isDoubleQuotedArgumentEscaped() );
|
|
|
bf087c |
-
|
|
|
bf087c |
- sb.append( StringUtils.quoteAndEscape( arguments[i], getArgumentQuoteDelimiter(), escapeChars, getQuotingTriggerChars(), getArgumentEscapePattern(), false ) );
|
|
|
bf087c |
+ sb.append( quoteOneItem( arguments[i], false ) );
|
|
|
bf087c |
}
|
|
|
bf087c |
else
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -278,7 +299,7 @@ public class Shell
|
|
|
bf087c |
commandLine.addAll( getShellArgsList() );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
- commandLine.addAll( getCommandLine( getExecutable(), arguments ) );
|
|
|
bf087c |
+ commandLine.addAll( getCommandLine( getOriginalExecutable(), arguments ) );
|
|
|
bf087c |
|
|
|
bf087c |
return commandLine;
|
|
|
bf087c |
|
|
|
bf087c |
diff --git a/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java b/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java
|
|
|
bf087c |
index b22814b..42bbb7f 100644
|
|
|
bf087c |
--- a/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java
|
|
|
bf087c |
+++ b/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java
|
|
|
bf087c |
@@ -16,6 +16,7 @@ package org.codehaus.plexus.util.cli;
|
|
|
bf087c |
* limitations under the License.
|
|
|
bf087c |
*/
|
|
|
bf087c |
|
|
|
bf087c |
+import junit.framework.TestCase;
|
|
|
bf087c |
import org.codehaus.plexus.util.IOUtil;
|
|
|
bf087c |
import org.codehaus.plexus.util.Os;
|
|
|
bf087c |
import org.codehaus.plexus.util.StringUtils;
|
|
|
bf087c |
@@ -23,15 +24,7 @@ import org.codehaus.plexus.util.cli.shell.BourneShell;
|
|
|
bf087c |
import org.codehaus.plexus.util.cli.shell.CmdShell;
|
|
|
bf087c |
import org.codehaus.plexus.util.cli.shell.Shell;
|
|
|
bf087c |
|
|
|
bf087c |
-import java.io.File;
|
|
|
bf087c |
-import java.io.FileWriter;
|
|
|
bf087c |
-import java.io.IOException;
|
|
|
bf087c |
-import java.io.InputStreamReader;
|
|
|
bf087c |
-import java.io.Reader;
|
|
|
bf087c |
-import java.io.StringWriter;
|
|
|
bf087c |
-import java.io.Writer;
|
|
|
bf087c |
-
|
|
|
bf087c |
-import junit.framework.TestCase;
|
|
|
bf087c |
+import java.io.*;
|
|
|
bf087c |
|
|
|
bf087c |
public class CommandlineTest
|
|
|
bf087c |
extends TestCase
|
|
|
bf087c |
@@ -252,7 +245,7 @@ public class CommandlineTest
|
|
|
bf087c |
|
|
|
bf087c |
assertEquals( "/bin/sh", shellCommandline[0] );
|
|
|
bf087c |
assertEquals( "-c", shellCommandline[1] );
|
|
|
bf087c |
- String expectedShellCmd = "/bin/echo \'hello world\'";
|
|
|
bf087c |
+ String expectedShellCmd = "'/bin/echo' 'hello world'";
|
|
|
bf087c |
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
|
|
|
bf087c |
{
|
|
|
bf087c |
expectedShellCmd = "\\bin\\echo \'hello world\'";
|
|
|
bf087c |
@@ -282,12 +275,12 @@ public class CommandlineTest
|
|
|
bf087c |
|
|
|
bf087c |
assertEquals( "/bin/sh", shellCommandline[0] );
|
|
|
bf087c |
assertEquals( "-c", shellCommandline[1] );
|
|
|
bf087c |
- String expectedShellCmd = "cd \"" + root.getAbsolutePath()
|
|
|
bf087c |
- + "path with spaces\" && /bin/echo \'hello world\'";
|
|
|
bf087c |
+ String expectedShellCmd = "cd '" + root.getAbsolutePath()
|
|
|
bf087c |
+ + "path with spaces' && '/bin/echo' 'hello world'";
|
|
|
bf087c |
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
|
|
|
bf087c |
{
|
|
|
bf087c |
- expectedShellCmd = "cd \"" + root.getAbsolutePath()
|
|
|
bf087c |
- + "path with spaces\" && \\bin\\echo \'hello world\'";
|
|
|
bf087c |
+ expectedShellCmd = "cd '" + root.getAbsolutePath()
|
|
|
bf087c |
+ + "path with spaces' && '\\bin\\echo' 'hello world'";
|
|
|
bf087c |
}
|
|
|
bf087c |
assertEquals( expectedShellCmd, shellCommandline[2] );
|
|
|
bf087c |
}
|
|
|
bf087c |
@@ -311,7 +304,7 @@ public class CommandlineTest
|
|
|
bf087c |
|
|
|
bf087c |
assertEquals( "/bin/sh", shellCommandline[0] );
|
|
|
bf087c |
assertEquals( "-c", shellCommandline[1] );
|
|
|
bf087c |
- String expectedShellCmd = "/bin/echo \'hello world\'";
|
|
|
bf087c |
+ String expectedShellCmd = "'/bin/echo' ''\"'\"'hello world'\"'\"''";
|
|
|
bf087c |
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
|
|
|
bf087c |
{
|
|
|
bf087c |
expectedShellCmd = "\\bin\\echo \'hello world\'";
|
|
|
bf087c |
@@ -341,7 +334,7 @@ public class CommandlineTest
|
|
|
bf087c |
}
|
|
|
bf087c |
else
|
|
|
bf087c |
{
|
|
|
bf087c |
- assertEquals( "/usr/bin a b", shellCommandline[2] );
|
|
|
bf087c |
+ assertEquals( "'/usr/bin' 'a' 'b'", shellCommandline[2] );
|
|
|
bf087c |
}
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
@@ -388,6 +381,18 @@ public class CommandlineTest
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
/**
|
|
|
bf087c |
+ * Test an executable with shell-expandable content in its path.
|
|
|
bf087c |
+ *
|
|
|
bf087c |
+ * @throws Exception
|
|
|
bf087c |
+ */
|
|
|
bf087c |
+ public void testPathWithShellExpansionStrings()
|
|
|
bf087c |
+ throws Exception
|
|
|
bf087c |
+ {
|
|
|
bf087c |
+ File dir = new File( System.getProperty( "basedir" ), "target/test/dollar$test" );
|
|
|
bf087c |
+ createAndCallScript( dir, "echo Quoted" );
|
|
|
bf087c |
+ }
|
|
|
bf087c |
+
|
|
|
bf087c |
+ /**
|
|
|
bf087c |
* Test an executable with a single quotation mark \" in its path only for non Windows box.
|
|
|
bf087c |
*
|
|
|
bf087c |
* @throws Exception
|
|
|
bf087c |
diff --git a/src/test/java/org/codehaus/plexus/util/cli/shell/BourneShellTest.java b/src/test/java/org/codehaus/plexus/util/cli/shell/BourneShellTest.java
|
|
|
bf087c |
index 2a987ed..0e06c63 100644
|
|
|
bf087c |
--- a/src/test/java/org/codehaus/plexus/util/cli/shell/BourneShellTest.java
|
|
|
bf087c |
+++ b/src/test/java/org/codehaus/plexus/util/cli/shell/BourneShellTest.java
|
|
|
bf087c |
@@ -16,14 +16,13 @@ package org.codehaus.plexus.util.cli.shell;
|
|
|
bf087c |
* limitations under the License.
|
|
|
bf087c |
*/
|
|
|
bf087c |
|
|
|
bf087c |
+import junit.framework.TestCase;
|
|
|
bf087c |
import org.codehaus.plexus.util.StringUtils;
|
|
|
bf087c |
import org.codehaus.plexus.util.cli.Commandline;
|
|
|
bf087c |
|
|
|
bf087c |
import java.util.Arrays;
|
|
|
bf087c |
import java.util.List;
|
|
|
bf087c |
|
|
|
bf087c |
-import junit.framework.TestCase;
|
|
|
bf087c |
-
|
|
|
bf087c |
public class BourneShellTest
|
|
|
bf087c |
extends TestCase
|
|
|
bf087c |
{
|
|
|
bf087c |
@@ -42,7 +41,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );
|
|
|
bf087c |
|
|
|
bf087c |
- assertEquals( "/bin/sh -c cd /usr/local/bin && chmod", executable );
|
|
|
bf087c |
+ assertEquals( "/bin/sh -c cd '/usr/local/bin' && 'chmod'", executable );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
public void testQuoteWorkingDirectoryAndExecutable_WDPathWithSingleQuotes()
|
|
|
bf087c |
@@ -54,7 +53,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );
|
|
|
bf087c |
|
|
|
bf087c |
- assertEquals( "/bin/sh -c cd \"/usr/local/\'something else\'\" && chmod", executable );
|
|
|
bf087c |
+ assertEquals( "/bin/sh -c cd '/usr/local/'\"'\"'something else'\"'\"'' && 'chmod'", executable );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
public void testQuoteWorkingDirectoryAndExecutable_WDPathWithSingleQuotes_BackslashFileSep()
|
|
|
bf087c |
@@ -66,7 +65,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
String executable = StringUtils.join( sh.getShellCommandLine( new String[]{} ).iterator(), " " );
|
|
|
bf087c |
|
|
|
bf087c |
- assertEquals( "/bin/sh -c cd \"\\usr\\local\\\'something else\'\" && chmod", executable );
|
|
|
bf087c |
+ assertEquals( "/bin/sh -c cd '\\usr\\local\\\'\"'\"'something else'\"'\"'' && 'chmod'", executable );
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
public void testPreserveSingleQuotesOnArgument()
|
|
|
bf087c |
@@ -82,7 +81,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
String cli = StringUtils.join( shellCommandLine.iterator(), " " );
|
|
|
bf087c |
System.out.println( cli );
|
|
|
bf087c |
- assertTrue( cli.endsWith( args[0] ) );
|
|
|
bf087c |
+ assertTrue( cli.endsWith("''\"'\"'some arg with spaces'\"'\"''"));
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
public void testAddSingleQuotesOnArgumentWithSpaces()
|
|
|
bf087c |
@@ -114,7 +113,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
String cli = StringUtils.join( shellCommandLine.iterator(), " " );
|
|
|
bf087c |
System.out.println( cli );
|
|
|
bf087c |
- assertEquals("cd /usr/bin && chmod 'arg'\\''withquote'", shellCommandLine.get(shellCommandLine.size() - 1));
|
|
|
bf087c |
+ assertEquals("cd '/usr/bin' && 'chmod' 'arg'\"'\"'withquote'", shellCommandLine.get(shellCommandLine.size() - 1));
|
|
|
bf087c |
}
|
|
|
bf087c |
|
|
|
bf087c |
public void testArgumentsWithsemicolon()
|
|
|
bf087c |
@@ -146,7 +145,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
assertEquals( "/bin/sh", lines[0] );
|
|
|
bf087c |
assertEquals( "-c", lines[1] );
|
|
|
bf087c |
- assertEquals( "chmod --password ';password'", lines[2] );
|
|
|
bf087c |
+ assertEquals( "'chmod' '--password' ';password'", lines[2] );
|
|
|
bf087c |
|
|
|
bf087c |
commandline = new Commandline( newShell() );
|
|
|
bf087c |
commandline.setExecutable( "chmod" );
|
|
|
bf087c |
@@ -158,7 +157,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
assertEquals( "/bin/sh", lines[0] );
|
|
|
bf087c |
assertEquals( "-c", lines[1] );
|
|
|
bf087c |
- assertEquals( "chmod --password ';password'", lines[2] );
|
|
|
bf087c |
+ assertEquals( "'chmod' '--password' ';password'", lines[2] );
|
|
|
bf087c |
|
|
|
bf087c |
commandline = new Commandline( new CmdShell() );
|
|
|
bf087c |
commandline.getShell().setQuotedArgumentsEnabled( true );
|
|
|
bf087c |
@@ -206,7 +205,7 @@ public class BourneShellTest
|
|
|
bf087c |
|
|
|
bf087c |
assertEquals( "/bin/sh", lines[0] );
|
|
|
bf087c |
assertEquals( "-c", lines[1] );
|
|
|
bf087c |
- assertEquals( "chmod ' ' '|' '&&' '||' ';' ';;' '&' '()' '<' '<<' '>' '>>' '*' '?' '[' ']' '{' '}' '`'",
|
|
|
bf087c |
+ assertEquals( "'chmod' ' ' '|' '&&' '||' ';' ';;' '&' '()' '<' '<<' '>' '>>' '*' '?' '[' ']' '{' '}' '`'",
|
|
|
bf087c |
lines[2] );
|
|
|
bf087c |
|
|
|
bf087c |
}
|
|
|
bf087c |
--
|
|
|
bf087c |
1.8.4.2
|
|
|
bf087c |
|