8

I am trying to control the systems ssh-agent by adding new keys to it using ssh-add. For this I'm using the Symfony Process component.

When I run this code from a web site it works perfectly fine but when I run the same code in a shell/console the ssh-add process hangs on Enter passphrase for <path to key>:

A simplified version of the code looks something like this

use Symfony\Component\Process\Process;

$keyPath = '<path to key>';
$keyPassword = '<password for unlocking the key>';
$socketPath = '<path to ssh-agent socket>';

$sshAdd = new Process(
    "ssh-add {$keyPath}",
    null,
    [
        'SSH_AUTH_SOCK' => $socketPath
    ],
    $keyPassword
);
$sshAdd->run();

As you can see in the code above I make a call to ssh-add, sets the SSH_AUTH_SOCK in the environment so ssh-add can talk to the agent and then sends the password in the input. As I said previously, when I run this in a web context it works but it hangs in a shell/console context.

I did an strace of when running in the console and the relevant parts looks like this

open("<path to key>", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
write(4, "<key password>", <length of password>)      = 20
close(4)                                              = 0
wait4(9650, 0x7fff00ab3554, WNOHANG|WSTOPPED, NULL)   = 0
select(8, [5 7], [], [], {0, 0})                      = 0 (Timeout)
wait4(9650, 0x7fff00ab3554, WNOHANG|WSTOPPED, NULL)   = 0
select(8, [5 7], [], [], {0, 0})                      = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000}Enter passphrase for <path to key>:) = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
select(8, [5 7], [], [], {0, 200000})                 = 0 (Timeout)
...

As you can see the write seems to be ignored and the ssh-add program starts to block waiting for input.

3
  • Are you nesting commands? that question is expecting input from the user, but it is blocked behind your wrapping process. You will need to find a way to perform the underlying command non-interactively. Commented Nov 19, 2014 at 17:06
  • I dont think the ssh_add process is blocked since I can enter the password manually. It is more that the PHP script cannot enter the password for the user since ssh_add has moved to the foreground and the PHP script just sits around waiting for the process to finish. Commented Nov 19, 2014 at 19:01
  • What are fd's 5 and 7 to that process? Where does fd 4 get opened? Does running the script from the shell with < /dev/null (and possibly 2</dev/null) help it to work? Commented Nov 23, 2014 at 17:44

1 Answer 1

9

Finally found a solution to this problem after reading the source for ssh-add and by reading this very old article from Wez Furlong where he talks about adding PTY support to PHP.

To quote the article:

What this does is similar to creating a pipe to the process, but instead creates master (for your script) and slave (for the process you're running) pty handles using the /dev/ptmx interface of your OS. This allows you to send to, and capture data from, applications that open /dev/tty explicitly--and this is generally done when interactively prompting for a password.

Turns out Symfony Process also supports PTY so the original code only needed a couple of changes. First I need to specify I want to use PTY instead of pipes by calling setPty(true). Then I need to simulate that the user has pressed ENTER after inputting the password simply by appending a line feed to the input.

The final code would look something like this (with comments on the changed lines)

use Symfony\Component\Process\Process;

$keyPath = '<path to key>';
$keyPassword = '<password for unlocking the key>';
$socketPath = '<path to ssh-agent socket>';

$sshAdd = new Process(
    "ssh-add {$keyPath}",
    null,
    [
        'SSH_AUTH_SOCK' => $socketPath
    ],
    $keyPassword . "\n"   // Append a line feed to simulate pressing ENTER
);
$sshAdd->setPty(true);   // Use PTY instead of the default pipes
$sshAdd->run();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.