Я пытаюсь контролировать системы SSH-агент добавив новые ключи к нему с помощью SSH-добавить. Для этого я использую Процесс Symfony составная часть.
Когда я запускаю этот код с веб-сайта, он работает отлично, но когда я запускаю тот же код в оболочке / консоли, процесс ssh-add зависает 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
Программа начинает блокировать ожидание ввода.
Наконец-то нашел решение этой проблемы после прочтения исходного кода для ssh-add и чтения это очень старая статья от Wez Furlong где он говорит о добавлении поддержки PTY в PHP.
Цитировать статью:
Это похоже на создание канала для процесса, но вместо этого создает основные (для вашего сценария) и подчиненные (для процесса, который вы запускаете) pty с помощью интерфейса / dev / ptmx вашей ОС. Это позволяет отправлять и захватывать данные из приложений, которые явно открывают / dev / tty — и это обычно делается при интерактивном запросе пароля.
Оказывается, Symfony Process также поддерживает PTY, поэтому исходному коду потребовалось всего несколько изменений. Сначала мне нужно указать, что я хочу использовать PTY вместо каналов, вызвав setPty(true)
, Тогда мне нужно смоделировать, что пользователь нажал ВОЙТИ после ввода пароля просто добавив к входу перевод строки.
Конечный код будет выглядеть примерно так (с комментариями к измененным строкам)
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();
Других решений пока нет …