admin管理员组

文章数量:1321416

I have a config file secrets.properties file with USER_PW=xxx and I wold like to pass the password to a process that executes a command that requires root privileges.

In tried to pass the password in two different ways. In the first code snippet my password is printed to the terminal, instead of passed to the pipe.

 // Process Builder
ProcessBuilder pb = new ProcessBuilder();
String cmd = "cp";
String tableName = "password_entries.ibd";
String source = properties.getProperty("DB_PATH");
String target = ".";
String userPassword = secrets.getProperty("USER_PW");

try {
      pb.inheritIO();

      // elevate privileges to root
      pbmand("echo", userPassword, "|", "sudo", "-S", "echo", "test");
      pb.start().waitFor();
      

      // cp to host
      pbmand("sudo", "-S", cmd, source + tableName, target);
      pb.start().waitFor();
      
} catch (IOException | InterruptedException e) {
      throw new RuntimeException(e);
}

In the second one something else does not work. I think it is because the password is provided via <<< without the "" around it.

The correct call on the terminal is: sudo -S <<< "password" echo Test but I don't know how to provide the "" around the password.

I also tried pbmand("sudo", "-S", "<<<", "\"" + userPassword + "\"", "echo", "test"); but the sudo still prompts for the password.

 // Process Builder
ProcessBuilder pb = new ProcessBuilder();
String cmd = "cp";
String tableName = "password_entries.ibd";
String source = properties.getProperty("DB_PATH");
String target = ".";
String userPassword = secrets.getProperty("USER_PW");

try {
      pb.inheritIO();

      // elevate privileges to root
      pbmand("sudo", "-S", "<<<", userPassword, "echo", "test");
      pb.start().waitFor();

      // cp to host
      pbmand("sudo", "-S", cmd, source + tableName, target);
      pb.start().waitFor();
      
} catch (IOException | InterruptedException e) {
      throw new RuntimeException(e);
}

I have a config file secrets.properties file with USER_PW=xxx and I wold like to pass the password to a process that executes a command that requires root privileges.

In tried to pass the password in two different ways. In the first code snippet my password is printed to the terminal, instead of passed to the pipe.

 // Process Builder
ProcessBuilder pb = new ProcessBuilder();
String cmd = "cp";
String tableName = "password_entries.ibd";
String source = properties.getProperty("DB_PATH");
String target = ".";
String userPassword = secrets.getProperty("USER_PW");

try {
      pb.inheritIO();

      // elevate privileges to root
      pbmand("echo", userPassword, "|", "sudo", "-S", "echo", "test");
      pb.start().waitFor();
      

      // cp to host
      pbmand("sudo", "-S", cmd, source + tableName, target);
      pb.start().waitFor();
      
} catch (IOException | InterruptedException e) {
      throw new RuntimeException(e);
}

In the second one something else does not work. I think it is because the password is provided via <<< without the "" around it.

The correct call on the terminal is: sudo -S <<< "password" echo Test but I don't know how to provide the "" around the password.

I also tried pbmand("sudo", "-S", "<<<", "\"" + userPassword + "\"", "echo", "test"); but the sudo still prompts for the password.

 // Process Builder
ProcessBuilder pb = new ProcessBuilder();
String cmd = "cp";
String tableName = "password_entries.ibd";
String source = properties.getProperty("DB_PATH");
String target = ".";
String userPassword = secrets.getProperty("USER_PW");

try {
      pb.inheritIO();

      // elevate privileges to root
      pbmand("sudo", "-S", "<<<", userPassword, "echo", "test");
      pb.start().waitFor();

      // cp to host
      pbmand("sudo", "-S", cmd, source + tableName, target);
      pb.start().waitFor();
      
} catch (IOException | InterruptedException e) {
      throw new RuntimeException(e);
}
Share Improve this question asked Jan 22 at 16:29 max23max23 491 silver badge7 bronze badges 4
  • In the first code snippet my password is printed to the terminal, instead of passed to the pipe. You can't use a pipe without a shell, so your command would have to start something like bash -c echo foo | bar The same goes for redirections – g00se Commented Jan 22 at 16:37
  • This woked for me: pbmand("/bin/bash", "-c", "echo '%s' | sudo -S whoami".formatted(password)); – Turing85 Commented Jan 22 at 16:42
  • 1 It is your use of pb.inheritIO(); that means the terminal shows information. Also ps will see the password (albeit briefly in some cases) – DuncG Commented Jan 22 at 17:02
  • Similarly this should work too: new ProcessBuilder("bash", "-c", "sudo -S < /tmp/password-file cat /etc/sudoers").inheritIO().start(); It might be an idea to make more use of the file that's the subject of cat in the above – g00se Commented Jan 22 at 17:21
Add a comment  | 

2 Answers 2

Reset to default 2

The underlying problem appears to be that you don't understand how terminal apps work.

When you type echo somePass | sudo whatever that's not 'a command your computer runs'. No, that's a string you type, and bash.exe picks that up, tears it into pieces, and treats it as a little programming script.

Bash is bash. ProcessBuilder is not.

Putting:

ProcessBuildermand("echo", "somePass", "|", "sudo", "whatever");

in a java file is thus obviously not going to work; trying it means you don't understand this part of how it works. Which is somewhat sensible; this stuff is complicated!

ProcessBuilder interprets the first argument as a 'command' and does its own, extremely lightweight, 'smart processing', i.e. apply looking up the executable via PATH. You should probably opt out of that and always specify as first argument an absolute path (so, not 'echo', but /bin/echo).

The rest of the args are passed verbatim to that process. "password" is something that instructs bash, when tearing apart the command line, to not attempt to parse out spaces as 'separators'. ProcessBuilder is not bash! - so, PB just sends "password", quotes and all, straight to sudo or echo or whatever the first arg to pbmand() is. It will dutifully interpret "password" as the password. I don't think your password actually starts with a quote, so, it would be an incorrect password.

This command in bash:

echo "Hello World"

Is, in PB terms:

pbmand("/bin/echo", "Hello World");

there is no need for quotes. Because pb doesn't treat a command as a 'script' that needs to be executed. The quotes are for bash to tell it: Do not attempt to chop this up.

Similarly, < and > and such are bashisms - in pb terms you use getOutputStream, getInputStream and getErrorStream and read or write as needed.

TL;DR: If you put ", ', >, <, |, & or $ in any string you pass to pbmand, that's not going to do what you think it will; those are programming constructs that the bash programming language understands, it's not something the OS execution system understands, and that's what both bash and pb use to actually 'run' your command.

NB: If you know how to do something 'in bash' and can't figure out how to do it 'in pb', then you can ask pb to run bash and pass your bashisms to it: pbmand("/bin/bash", "-c", "the whole bashism thing here, quotes, dollars, pipes, you name it") usually works fine. You are now of course relying on /bin/bash existing.

NB: There are many shells; bash is just one. In that sense 'bashism' isn't exactly fair and oversimplifies a bit, but the answer is trying to cater to those quite new to the concept of shells, and trying to disentangle the mess that is '"the shell" is not necessarily "bash"' is not something I wanted to mess with in this answer.

I found a solution:

// Process Builder
ProcessBuilder pb = new ProcessBuilder();
String cmd = "cp";
String tableName = "password_entries.ibd";
String source = properties.getProperty("DB_PATH");
String target = ".";
String userPassword = secrets.getProperty("USER_PW");

try {
      // elevate privileges to root
      pbmand("sudo", "-S", "echo", "test");
      Process p = pb.start();
      p.getOutputStream().write((userPassword + "\n").getBytes());
      p.getOutputStream().flush();
      p.waitFor();

      // cp to host
      pbmand("sudo", "-S", cmd, source + tableName, target);
      pb.start().waitFor();
      
} catch (IOException | InterruptedException e) {
      throw new RuntimeException(e);
}

本文标签: Java how to pass password from file to processStack Overflow