2014-11-19 13 views
6

Próbuję kontrolować systemy ssh-agent, dodając do nich nowe klucze, używając ssh-add. Do tego używam komponentu Symfony Process.Sterowanie procesem interaktywnym za pomocą PHP za pomocą procesu Symfony

Kiedy uruchomić ten kod ze strony internetowej działa idealnie w porządku, ale po uruchomieniu tego samego kodu w powłoce/console proces ssh-add wisi na Enter passphrase for <path to key>:

Uproszczona wersja kodu wygląda mniej więcej tak to

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

Jak widać w powyższym kodzie nawiązywać połączenia do ssh-add, ustawia SSH_AUTH_SOCK w środowisku tak ssh-add może mówić do środka, a następnie wysyła hasło na wejściu. Jak już wcześniej wspomniałem, kiedy uruchamiam to w kontekście sieciowym, działa, ale zawiesza się w kontekście powłoki/konsoli.

Zrobiłem strace, kiedy działa w konsoli i odpowiednie części wygląda następująco

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

Jak można zobaczyć zapis wydaje się być ignorowane i program ssh-add zaczyna blokować czekając na wejście.

+0

Czy jesteś gniazdowania polecenia? to pytanie oczekuje wkładu od użytkownika, ale jest zablokowane za procesem owijania. Będziesz musiał znaleźć sposób na wykonywanie podstawowych poleceń w sposób nieinteraktywny. – Flosculus

+0

Nie sądzę, aby proces ssh_add został zablokowany, ponieważ mogę ręcznie wprowadzić hasło. Chodzi raczej o to, że skrypt PHP nie może wprowadzić hasła dla użytkownika, ponieważ ssh_add został przeniesiony na pierwszy plan, a skrypt PHP po prostu czeka, aż proces się zakończy. – codeaken

+0

Co to są 5 i 7 FDA dla tego procesu? Gdzie otwiera się fd 4? Czy uruchomienie skryptu z powłoki '

Odpowiedz

7

W końcu znalazłem rozwiązanie tego problemu po przeczytaniu źródła dla ssh-add i przeczytaniu this very old article from Wez Furlong gdzie mówi o dodaniu wsparcia PTY do PHP.

Cytując artykuł:

Co to jest podobne do tworzenia rury do procesu, ale zamiast tego tworzy mistrza (dla skryptu) i slave (dla procesu używasz) uchwyty PTY za pomocą interfejsu/dev/ptmx twojego systemu operacyjnego. Pozwala to na wysyłanie i przechwytywanie danych z aplikacji jawnie otwieranych/dev/tty - zwykle odbywa się to w przypadku interaktywnego monitowania o hasło.

Okazało się, że proces Symfony obsługuje również PTY, więc oryginalny kod wymagał tylko kilku zmian. Najpierw muszę określić, że chcę używać PTY zamiast rur, dzwoniąc pod numer setPty(true). Następnie muszę zasymulować, że użytkownik po przyciśnięciu hasła wprowadził do wejścia znak wejściowy ENTER.

Ostateczny kod będzie wyglądać następująco (z uwagi na zmienionych wierszy)

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(); 
Powiązane problemy