Я пытаюсь управлять системным ssh-агентом , добавляя к нему новые ключи, используя ssh-add . Для этого я использую компонент Symfony Process .
Когда я запускаю этот код с веб-сайта, он отлично работает, но когда я запускаю тот же код в оболочке / консоли, процесс 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
может разговаривать с агентом, а затем отправляет пароль на вход. Как я уже говорил ранее, когда я запускаю это в веб-контексте, он работает, но он зависает в контексте оболочки / консоли.
Я работал с консолью, и соответствующие части выглядят так:
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.
Процитировать статью:
То, что это делает, похоже на создание канала для процесса, но вместо этого создает master (для вашего скрипта) и slave (для выполняемого процесса) 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();