2014-11-19 1 views
6

Я пытаюсь управлять системами ssh-agent, добавляя к нему новые ключи, используя ssh-add. Для этого я использую компонент Symfony Process.Управление интерактивным процессом с помощью PHP с использованием Symfony Process

Когда я запускаю этот код с веб-сайта он отлично работает нормально, но когда я запускаю тот же код в оболочке/утешать процесс SSH-добавить висит на Enter passphrase for <path to key>:

Упрощенная версия кода выглядит примерно так это

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(); 

Как вы можете видеть в коде выше я сделать вызов ssh-add, устанавливает SSH_AUTH_SOCK в среде так ssh-add может говорить с агентом, а затем отправляет пароль в поле ввода. Как я уже говорил ранее, когда я запускаю это в веб-контексте, он работает, но он зависает в контексте оболочки/консоли.

Я сделал strace о том, когда работает в консоли, и соответствующие части выглядит следующим образом

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) 
... 

Как вы можете увидеть запись, кажется, игнорируется и программа ssh-add начинает блокировать ожидание ввода.

+0

ARE YOU гнездования команды? этот вопрос ожидает ввода от пользователя, но он заблокирован за вашим процессом упаковки. Вам нужно будет найти способ выполнить базовую команду не интерактивно. – Flosculus

+0

Я не думаю, что процесс ssh_add заблокирован, так как я могу ввести пароль вручную. Более того, скрипт PHP не может вводить пароль для пользователя, так как ssh_add переместился на передний план, и скрипт PHP просто сидит, ожидая завершения процесса. – codeaken

+0

Что такое fd's 5 и 7 для этого процесса? Где открывается fd 4? Выполняет ли запуск скрипта из оболочки с помощью '

ответ

7

Наконец-то нашел решение этой проблемы после прочтения источника для ssh-add и чтения this very old article from Wez Furlong, где он говорит о добавлении поддержки PTY для PHP.

Цитирую статью:

Что это делает похоже на создание трубы к процессу, но вместо этого создает мастер (для вашего сценария) и ведомого (для процесса вы работаете) ручки PTY используя интерфейс/dev/ptmx вашей ОС. Это позволяет вам отправлять и извлекать данные из приложений, открывающих/dev/tty явно, - и это обычно делается при интерактивном запросе пароля.

Оказалось, что Symfony Process также поддерживает PTY, поэтому исходный код потребовал всего пару изменений. Сначала мне нужно указать, что я хочу использовать PTY вместо труб, вызывая setPty(true). Затем мне нужно смоделировать, что пользователь нажал ENTER после ввода пароля, просто добавив фид строки к входу.

Окончательный код будет выглядеть примерно так (с комментариями на измененных строк)

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();