W jaki sposób parsowane są argumenty zdalnego wiersza poleceń ssh

11

Widziałem pytania i odpowiedzi dotyczące konieczności podwójnego ucieczki argumentów do zdalnych poleceń ssh. Moje pytanie brzmi: dokładnie gdzie i kiedy wykonuje się drugie parsowanie?

Jeśli uruchomię następujące:

$ ssh otherhost pstree -a -p

W danych wyjściowych widzę następujące:

  |-sshd,3736
  |   `-sshd,1102
  |       `-sshd,1109
  |           `-pstree,1112 -a -p

Proces nadrzędny dla polecenia zdalnego ( pstree) polega na tym sshd, że nie wydaje się, aby istniała tam jakaś powłoka, która analizowałaby argumenty wiersza poleceń dla polecenia zdalnego, więc nie wydaje się, że konieczne byłoby podwójne cytowanie lub zmiana znaczenia ( ale na pewno jest). Jeśli zamiast tego najpierw ssh tam i uzyskać powłokę logowania, a następnie uruchomić pstree -a -pwidzę następujące dane wyjściowe:

  ├─sshd,3736
     └─sshd,3733
         └─sshd,3735
             └─bash,3737
                 └─pstree,4130 -a -p

Widać więc, że istnieje tam bashpowłoka, która w takim przypadku przeprowadzałaby analizę wiersza poleceń. Ale w przypadku, gdy używam polecenia zdalnego bezpośrednio, wydaje się, że nie ma powłoki, więc dlaczego podwójne cytowanie jest konieczne?

tylko nikt
źródło

Odpowiedzi:

22

Zawsze istnieje zdalna powłoka. W protokole SSH klient wysyła do serwera ciąg znaków do wykonania. Klient wiersza polecenia SSH pobiera argumenty wiersza polecenia i łączy je ze spacją między argumentami. Serwer pobiera ten ciąg, uruchamia powłokę logowania użytkownika i przekazuje ten ciąg.

Nie można ominąć zdalnej powłoki. Protokół nie ma nic takiego jak wysyłanie tablicy ciągów, które mogłyby zostać przeanalizowane jako tablica argv na serwerze. A serwer SSH nie obejdzie zdalnej powłoki, ponieważ może to stanowić ograniczenie bezpieczeństwa: użycie ograniczonego programu jako powłoki użytkownika jest sposobem na zapewnienie ograniczonego konta, które może uruchamiać tylko niektóre polecenia (np. Konto tylko rsync lub konto tylko dla git).

Możesz nie widzieć powłoki, pstreeponieważ mogła już zniknąć. Wiele powłok ma optymalizację, w której jeśli wykryją, że zamierzają „uruchomić to polecenie zewnętrzne, poczekać na jego zakończenie i wyjść ze statusem polecenia”, wówczas powłoka uruchomi się „ execvetego polecenia zewnętrznego”. Tak dzieje się w twoim pierwszym przykładzie. Porównaj trzy następujące polecenia:

ssh otherhost pstree -a -p
ssh otherhost 'pstree -a -p'
ssh otherhost 'pstree -a -p; true'

Pierwsze dwa są identyczne: klient wysyła dokładnie te same dane do serwera. Trzeci wysyła polecenie powłoki, które pokonuje optymalizację wykonania powłoki.

Gilles „SO- przestań być zły”
źródło
2
ha! nie mogę uwierzyć, że pobiłeś mnie, odpowiadając na moje własne pytanie. Zrozumiałem to w połowie pisania pytania i pomyślałem, że powinienem sam zadać pytanie i odpowiedzieć.
tylko
10

Myślę, że wymyśliłem to:

$ ssh otherhost pstree -a -p -s '$$'
init,1         
  `-sshd,3736
      `-sshd,11998
          `-sshd,12000
              `-pstree,12001 -a -p -s 12001

Argumenty, które pstreenależy wykonać: pokazać argumenty wiersza poleceń, pokazać pidy i pokazać tylko procesy nadrzędne danego pid. '$$'Jest specjalną zmienną powłoki bash, które zastąpi z własnym PID kiedy bash ocenia argumenty wiersza poleceń. Jest cytowany raz, aby powstrzymać go przed interpretacją przez moją lokalną powłokę. Ale nie jest podwójnie cytowany ani nie ma znaczenia, aby umożliwić interpretację go przez zdalną powłokę.

Jak widzimy, jest on zastąpiony przez, 12001więc jest to pid powłoki. Na podstawie danych wyjściowych widzimy również, pstree,12001że sam proces z pid 12001 jest pstree. Więc pstreejest skorupa?

To, co zbieram, dzieje się tam, że bashjest wywoływane i analizuje argumenty wiersza poleceń, ale następnie wywołuje się w execcelu zastąpienia się uruchamianym poleceniem.

Wygląda na to, że robi to tylko w przypadku pojedynczego polecenia zdalnego:

$ ssh otherhost pstree -a -p -s '$$' \; echo hi
init,1         
  `-sshd,3736
      `-sshd,17687
          `-sshd,17690
              `-bash,17691 -c pstree -a -p -s $$ ; echo hi
                  `-pstree,17692 -a -p -s 17691
hi

W takim przypadku żądam uruchomienia dwóch poleceń: pstreenastępnie echo. Widzimy tutaj, że bashtak naprawdę pojawia się w drzewie procesów jako rodzic pstree.

tylko nikt
źródło
Tak ! + 1. Jest przykładem tego, co Gilles bardziej formalnie umieścił na pierwszym miejscu, a przykładem drugiego. Być może uznanie go za wczesną odpowiedź jest w porządku?
Cbhihe
0

Wspierając to, co powiedziały inne odpowiedzi, poszukałem kodu wywołującego polecenia na pilocie, https://github.com/openssh/openssh-portable/blob/4f29309c4cb19bcb1774931db84cacc414f17d29/session.c#L1660 ...

1660    /*
1661     * Execute the command using the user's shell.  This uses the -c
1662     * option to execute the command.
1663     */
1664    argv[0] = (char *) shell0;
1665    argv[1] = "-c";
1666    argv[2] = (char *) command;
1667    argv[3] = NULL;
1668    execve(shell, argv, env);
1669    perror(shell);
1670    exit(1);

... które, jak widać, bezwarunkowo przywołuje shellpierwszy argument -ci drugi argument command. Wcześniej shellzmienna była ustawiona na powłokę logowania użytkownika, jak zapisano w /etc/passwd. commandjest argumentem tej funkcji i ostatecznie jest ustawiony na ciąg odczytywany dosłownie z drutu (patrz session_exec_reqw tym samym pliku ). Tak więc serwer w ogóle nie interpretuje polecenia, ale na pilocie zawsze wywoływana jest powłoka.

Jednak odpowiednia część specyfikacji protokołu SSH czy nie wydaje się wymagać tego zachowania; mówi tylko

 byte      SSH_MSG_CHANNEL_REQUEST
 uint32    recipient channel
 string    "exec"
 boolean   want reply
 string    command

Ten komunikat zażąda, aby serwer rozpoczął wykonywanie podanego polecenia. Ciąg „polecenia” może zawierać ścieżkę. NALEŻY podjąć zwykłe środki ostrożności, aby zapobiec wykonywaniu nieautoryzowanych poleceń.

Jest to prawdopodobnie spowodowane tym, że nie wszystkie systemy operacyjne mają koncepcję powłoki wiersza poleceń. Na przykład nie byłoby szaleństwem, gdyby serwer ssh Classic MacOS podawał ciągi poleceń „exec” do interpretera AppleScript .

zwol
źródło