Ssh uzak komut satırı bağımsız değişkenleri nasıl ayrıştırılır


11

Uzak ssh komutlarına yapılan argümanlardan iki kez kaçmak gerektiğine dair soru ve cevapları gördüm. Sorum şu: İkinci ayrıştırma nerede ve ne zaman yapılıyor?

Aşağıdakileri çalıştırırsam:

$ ssh otherhost pstree -a -p

Çıktıda aşağıdakileri görüyorum:

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

Remote command ( pstree) için üst işlem sshd, komut satırı bağımsız değişkenlerini uzak komutla ayrıştıracak herhangi bir kabuk görünmüyor, bu nedenle çift tırnak veya kaçış gerekli gibi görünmüyor ( ama kesinlikle öyle). Bunun yerine önce orada ssh ve bir oturum açma kabuğu almak ve daha sonra çalıştırmak pstree -a -pçıktı aşağıdaki görüyorum:

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

Yani açıkça bashbu durumda komut satırı ayrıştırma yapacak bir kabuk var. Ama doğrudan uzaktan komut kullandığımda, bir kabuk görünmüyor, neden çift tırnak gerekli?

Yanıtlar:


22

Her zaman uzak bir kabuk vardır. SSH protokolünde, istemci sunucuya yürütülecek bir dize gönderir. SSH komut satırı istemcisi komut satırı bağımsız değişkenlerini alır ve bunları bağımsız değişkenler arasındaki boşlukla birleştirir. Sunucu bu dizeyi alır, kullanıcının oturum açma kabuğunu çalıştırır ve bu dizeyi iletir.

Uzak kabuğu atlamak imkansızdır. Protokolün sunucuda argv dizisi olarak ayrıştırılabilecek bir dizi dizi göndermesi gibi bir şey yoktur. SSH sunucusu uzak kabuğu atlamaz, çünkü bu bir güvenlik kısıtlaması olabilir: kullanıcının kabuğu olarak kısıtlı bir program kullanmak, yalnızca belirli komutları çalıştırmasına izin verilen kısıtlı bir hesap sağlamanın bir yoludur (örn. salt git hesabı).

Kabuğu göremeyebilirsiniz pstreeçünkü zaten gitmiş olabilir. Birçok mermi, "bu harici komutu çalıştırmak, tamamlanmasını bekleyin ve komutun durumuyla çıkmak" üzere olduğunu tespit ederse, kabuğun execveyerine "bu harici komutun" çalıştığı bir optimizasyona sahiptir . İlk örneğinizde olan budur. Aşağıdaki üç komutu karşılaştırın:

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

İlk ikisi aynıdır: istemci sunucuya tamamen aynı verileri gönderir. Üçüncüsü, kabuğun exec optimizasyonunu yenen bir shell komutu gönderir.


2
Ha! kendi soruma cevap vermem için beni dövdüğüne inanamıyorum. Soruyu göndererek yarısını anladım ve sadece kendim sorup cevaplayarak geçmem gerektiğini düşündüm.
onlynone

10

Bence anladım:

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

Yapılacak argümanlar pstree: komut satırı argümanlarını göster, pids göster ve verilen pid'in sadece üst süreçlerini göster. Bu '$$', bash komut satırı bağımsız değişkenlerini değerlendirdiğinde bash'ın kendi pid'i ile değiştireceği özel bir kabuk değişkenidir. Yerel kabuğum tarafından yorumlanmasını durdurmak için bir kez alıntı yapıldı. Ancak, uzak kabuk tarafından yorumlanmasına izin vermek için iki kez alıntılanmaz veya kaçmaz.

Gördüğümüz gibi, yerini 12001kabuğun pid'i alıyor. Çıktıdan da görebiliriz: pstree,1200112001'lik bir pid ile işlem pstree'nin kendisidir. Yani pstreekabuk?

Ne oluyor orada toplamak olduğunu bashçağrılan ediliyor ve komut satırı argümanları ayrıştırma, ancak o zaman çağıran execkomut olmak vadede kendini değiştirmeyi.

Görünüşe göre bunu sadece tek bir uzaktan kumanda durumunda yapar:

$ 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

Bu durumda, iki komutun çalıştırılmasını istiyorum: pstreearkasından echo. Burada bashaslında süreç ağacında bir ebeveyni olarak ortaya çıkan bir şey görüyoruz pstree.


Evet ! + 1. Gilles'in önce daha resmi ve ikinci olarak ne koyduğunu örneklendirir. Belki de erken cevabı için ona kredi vermek uygun mudur?
Cbhihe

0

Diğer cevapların söylediklerini destekleyerek, uzaktan kumandadaki komutları çağıran kodu aradım, 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);

... görebileceğiniz gibi, shellilk argüman -cve ikinci argüman ile koşulsuz olarak çağrılıyor command. Daha önce shelldeğişken, kullanıcının giriş kabuğuna kaydedildiği şekilde ayarlanmıştı /etc/passwd. command, bu işleve ilişkin bir bağımsız değişkendir ve sonuçta kablodan kelimesi kelimesine okunan bir dizeye ayarlanır ( session_exec_reqaynı dosyaya bakın ). Bu nedenle, sunucu komutu hiç yorumlamaz, ancak uzaktan kumandada her zaman bir kabuk çağrılır.

Ancak, SSH protokolü şartnamenin ilgili kısmı yok olmayan bu davranışı gerektirecek şekilde görünür; sadece diyor

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

Bu ileti, sunucunun verilen komutun yürütülmesini başlatmasını ister. 'Command' dizesi bir yol içerebilir. Yetkisiz komutların yürütülmesini önlemek için normal önlemler alınmalıdır * ZORUNLU *.

Bunun nedeni, muhtemelen tüm işletim sistemlerinin bir komut satırı kabuğu kavramına sahip olmamasıdır. Örneğin, Klasik MacOS ssh sunucusunun "exec" komut dizelerini AppleScript yorumlayıcısına beslemesi çılgınca olmazdı .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.