0

I'm creating a process in Java that runs ssh-keygen in Linux. This utility normally takes user input from the terminal, so I need to send responses from within my Java program. Here's the relevant code, created with some help from this question:

// Create a process to run ssh-keygen.
ProcessBuilder procBuilder = new ProcessBuilder("ssh-keygen", "-t", "rsa");
// Redirect errors to the process' standard output.
procBuilder.redirectErrorStream(true);
Process proc = procBuilder.start();

Scanner fromProc = new Scanner(new InputStreamReader(proc.getInputStream()));
OutputStream toProc = proc.getOutputStream();

// While there is another line of output from the process. GETS STUCK HERE.
while (fromProc.hasNextLine()) {
    String message = fromProc.nextLine();
    // If the process asks to overwrite existing keys.
    if (message.startsWith("Overwrite (y/n)?") == true) {
        // Send response to overwrite RSA keys.
        toProc.write("y\n".getBytes());
        toProc.flush();
    }
    // If the message asks to enter a passphrase or specify a file.
    else if (message.startsWith("Enter")) {
        // Send response to use the default.
        toProc.write("\n".getBytes());
        toProc.flush();
    }
}

Now for the problem, and why the question I linked to earlier falls short. This seems to get stuck on fromProc.hasNextLine() when ssh-keygen is asking for user input. I suspect this is because the line asking for user input doesn't end with a newline character (since a response typed into the terminal directly would appear on the same line as the prompt).

So here's my question. How can I read prompt lines if they don't end in a newline character? I'm thinking I might be able to use fromProc.useDelimiter() with some alternative to the newline character, but I'm not entirely sure what, since prompts tend to just end with a space.

Alternatively, could this be done more easily with a bash script? Unfortunately I have little experience with bash and I'm not sure if it's possible to simulate user input when the prompts from ssh-keygen may differ each time. The Java code I have here is intended to be flexible in that it only responds to certain prompts if they appear.

Disclaimer: this will only be run on known machines with very specific system details. It is effectively embedded code, so I don't need to worry about portability.

Community
  • 1
  • 1
Graph Theory
  • 699
  • 1
  • 7
  • 18

1 Answers1

2

To scan for a phrase without an end-of-line you should probably use Scanner.findInLine.

However, I don't think your troubles will end there. The ssh-keygen outputs some of the prompts to its associated tty (and expects the answers from there) rather than standard output and standard input. In fact, I've just tested it out of curiosity, and it gives one prompt on standard error and one on standard output, and then the next one on tty.

Why don't you avoid all that and pass the name of the file, the passphrase and all that as parameters to the ssh-keygen command?

You can see how in this answer.

Community
  • 1
  • 1
RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
  • That was effective, thank you, though I did need to pipe "y\n".getBytes() to the process to handle the ask-for-overwrite prompt. – Graph Theory Dec 31 '14 at 01:28