src/windows/classes/java/lang/ProcessImpl.java
Print this page
*** 35,44 ****
--- 35,45 ----
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.lang.ProcessBuilder.Redirect;
import java.security.AccessController;
import java.security.PrivilegedAction;
+ import java.util.StringTokenizer;
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
*
* @author Martin Buchholz
*** 153,162 ****
--- 154,166 ----
final String path,
final long[] stdHandles,
final boolean redirectErrorStream)
throws IOException
{
+ String prog = "";
+
+ try {
// Win32 CreateProcess requires cmd[0] to be normalized
cmd[0] = new File(cmd[0]).getPath();
StringBuilder cmdbuf = new StringBuilder(80);
for (int i = 0; i < cmd.length; i++) {
*** 183,192 ****
--- 187,227 ----
cmdbuf.append(s);
}
}
String cmdstr = cmdbuf.toString();
+ if (cmdstr.length() > 0 && cmdstr.charAt(0) == '"') {
+ // quoted string must contain the prog name
+ int end = cmdstr.indexOf('"', 1);
+ if (end == -1 || cmdstr.indexOf('"', end+1) != -1) {
+ // either unterminated string or has embedded string
+ throw new IllegalArgumentException("Invalid string");
+ }
+ prog = cmdstr.substring(1, end);
+ } else {
+ prog = getProgramPath(cmdstr);
+ }
+
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ security.checkExec(prog);
+ } catch (SecurityException e) {
+ // We support invocation of "foo" or "foo.exe" assuming "foo.exe" exists.
+ // So, the security check should allow the same latitude.
+ String lprog = prog.toLowerCase();
+ if (lprog.endsWith(".exe")) {
+ // check without the .exe extension
+ int len = lprog.length();
+ String mprog = prog.substring(0, len-4);
+ security.checkExec(mprog);
+ } else {
+ throw e;
+ }
+ }
+ }
+
handle = create(cmdstr, envblock, path,
stdHandles, redirectErrorStream);
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
*** 215,227 ****
FileDescriptor stderr_fd = new FileDescriptor();
fdAccess.setHandle(stderr_fd, stdHandles[2]);
stderr_stream = new FileInputStream(stderr_fd);
}
! return null; }});
}
public OutputStream getOutputStream() {
return stdin_stream;
}
public InputStream getInputStream() {
--- 250,331 ----
FileDescriptor stderr_fd = new FileDescriptor();
fdAccess.setHandle(stderr_fd, stdHandles[2]);
stderr_stream = new FileInputStream(stderr_fd);
}
! return null; }
! });
! } catch (IOException e) {
! throw new IOException (
! "Cannot run program \"" + prog + "\""
! + (path == null ? "" : " (in directory \"" + path + "\")")
! + ": " + e.getMessage(), e);
}
+ }
+ /**
+ * Use the same algorithm as Windows CreateProcess to determine the pathname to
+ * the given command. Is complicated by the presence of whitespace in the pathname,
+ * which makes it hard(er) to distinguish between command line parameters and
+ * whitespace in the command path. We have to check for the existence of files
+ * to disambiguate. Note, this means when the target does *not* exist, the path
+ * remains ambiguous, and security checks in particular, will probably fail
+ * because the whole command string (including args) will be passed to the security
+ * check.
+ *
+ * C:\A B\C D\E F G
+ *
+ * We check in the following order (for files existing)
+ * 1. C:\A.exe
+ * 2. C:\A
+ * 3. C:\A B\C.exe
+ * 4. C:\A B\C
+ * 5. C:\A B\C D\E.exe
+ * 6. C:\A B\C D\E (and so on)
+ * Any token ending in '\\' can't be a valid filename. So it isn't checked.
+ * If no file is found, then the entire original string is returned.
+ */
+ static String getProgramPath(final String command) {
+ return java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<String>() {
+ public String run() {
+ StringBuilder sb = new StringBuilder();
+ StringTokenizer tokenizer = new StringTokenizer(command, " \t", true);
+ while (tokenizer.hasMoreTokens()) {
+ String t = tokenizer.nextToken();
+ sb.append(t);
+ if (t.equals(" ") || t.equals("\t") || t.endsWith("\\")) {
+ continue;
+ }
+ t = sb.toString();
+ if (fileHasNoDot(t)) {
+ // try appending .exe
+ String t1 = t + ".exe";
+ if (exists(t1)) {
+ return t1;
+ }
+ }
+ if (exists(t)) {
+ return t;
+ }
+ }
+ return command;
+ }
+ });
+ }
+
+ // final component of path has no '.' in it
+ private static boolean fileHasNoDot(String name) {
+ int n = name.lastIndexOf('\\') + 1;
+ return name.length() > n ? name.indexOf('.', n) == -1 : false;
+ }
+
+ private static boolean exists(String name) {
+ File f = new File (name);
+ return f.exists();
+ }
+
public OutputStream getOutputStream() {
return stdin_stream;
}
public InputStream getInputStream() {