Ssh दूरस्थ कमांड लाइन तर्क कैसे पार्स किया जाता है


11

मैंने दूरस्थ ssh कमांडों के तर्कों से बचने के लिए प्रश्नों और उत्तरों को देखा है। मेरा प्रश्न है: वास्तव में दूसरा पार्सिंग कहाँ और कब होता है?

यदि मैं निम्नलिखित चलाता हूं:

$ ssh otherhost pstree -a -p

मैं आउटपुट में निम्नलिखित देखता हूं:

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

दूरस्थ कमांड ( pstree) के लिए मूल प्रक्रिया है sshd, वहाँ कोई भी ऐसा प्रतीत नहीं होता है जो कमांड लाइन के तर्कों को दूरस्थ कमांड पर पार्स कर रहा हो, इसलिए ऐसा प्रतीत नहीं होता है कि डबल क्विटिंग या बचना आवश्यक होगा () लेकिन यह निश्चित रूप से है)। अगर इसके बजाय मैं पहले वहां बैठता हूं और एक लॉगिन शेल प्राप्त करता pstree -a -pहूं , और फिर रन करता हूं तो मुझे आउटपुट में निम्नलिखित मिलते हैं:

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

तो स्पष्ट रूप से वहां एक bashशेल है जो उस मामले में कमांड लाइन पार्सिंग करेगा। लेकिन जिस मामले में मैं सीधे रिमोट कमांड का उपयोग करता हूं, वहां कोई शेल नहीं लगता है, इसलिए दोहरा उद्धरण आवश्यक क्यों है?

जवाबों:


22

हमेशा एक दूरस्थ शेल होता है। SSH प्रोटोकॉल में, क्लाइंट सर्वर को निष्पादित करने के लिए एक स्ट्रिंग भेजता है। SSH कमांड लाइन क्लाइंट अपने कमांड लाइन के तर्कों को लेता है और उन्हें तर्कों के बीच एक स्थान के साथ समेटता है। सर्वर उस स्ट्रिंग को लेता है, उपयोगकर्ता के लॉगिन शेल को चलाता है और इसे उस स्ट्रिंग को पास करता है।

दूरस्थ शेल को बायपास करना असंभव है। प्रोटोकॉल के पास कुछ भी नहीं है जैसे कि स्ट्रिंग की एक सरणी भेजना जिसे सर्वर पर एक argv सरणी के रूप में पार्स किया जा सकता है। और SSH सर्वर दूरस्थ शेल को बायपास नहीं करेगा क्योंकि यह एक सुरक्षा प्रतिबंध हो सकता है: एक प्रतिबंधित प्रोग्राम का उपयोग करना क्योंकि उपयोगकर्ता का शेल एक प्रतिबंधित खाता प्रदान करने का एक तरीका है जिसे केवल कुछ कमांड चलाने की अनुमति है (जैसे कि rsync-only खाता या git-only खाता)।

आप शेल नहीं देख सकते pstreeक्योंकि यह पहले से ही चला गया हो सकता है। कई गोले का एक अनुकूलन होता है जहां अगर वे पता लगाते हैं कि वे "इस बाहरी कमांड को चलाने वाले हैं, तो इसे पूरा करने के लिए प्रतीक्षा करें और कमांड की स्थिति से बाहर निकलें", फिर शेल execveइसके बजाय "बाहरी कमांड" चलाता है । यह आपके पहले उदाहरण में हो रहा है। निम्नलिखित तीन आदेशों का विरोध करें:

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

पहले दो समान हैं: क्लाइंट सर्वर पर ठीक उसी डेटा को भेजता है। तीसरा एक शेल कमांड भेजता है जो शेल के एग्जिट ऑप्टिमाइजेशन को हरा देता है।


2
हा! विश्वास नहीं हो रहा है कि आप मुझे मेरे ही सवाल का जवाब देने के लिए पीटेंगे। मैं यह सवाल पोस्ट करने के माध्यम से आधे रास्ते में लगा और मुझे लगा कि मुझे इसे स्वयं पूछना और उत्तर देना चाहिए।
केवल

10

मुझे लगता है कि मैंने हल निकाल लिया:

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

pstreeनिम्न तर्क ये हैं: कमांड लाइन आर्ग्युमेंट्स दिखाएं, पाइड्स दिखाएं, और दिए गए पीड की सिर्फ पैरेंट प्रक्रियाएं दिखाएं। '$$'एक विशेष खोल चर जब बैश आदेश पंक्ति तर्क का मूल्यांकन करता है कि पार्टी का अपना पीआईडी के साथ बदल देगा है। इसे मेरे स्थानीय शेल द्वारा व्याख्या किए जाने से रोकने के लिए एक बार उद्धृत किया गया है। लेकिन इसे दूरस्थ शेल द्वारा व्याख्या करने की अनुमति देने के लिए दोगुना या बच नहीं गया है।

जैसा कि हम देख सकते हैं, इसे इस तरह से बदल दिया गया है 12001ताकि शेल का ढक्कन बंद हो जाए। हम आउटपुट से भी देख सकते हैं: pstree,12001यह कि 12001 की पाइड के साथ प्रक्रिया स्वयं ही pstree है। तो pstreeखोल है क्या?

मैं जो इकट्ठा कर रहा हूं, वह है कि bashइसे लागू किया जा रहा है और यह कमांड लाइन के तर्कों को पार्स कर रहा है, लेकिन फिर यह execकमांड को चलाने के साथ खुद को बदलने के लिए आमंत्रित करता है।

ऐसा लगता है कि यह केवल एक ही दूरस्थ कमांड के मामले में ऐसा करता है:

$ 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

इस मामले में, मैं दो कमांड चलाने का अनुरोध कर रहा हूं: pstreeइसके बाद echo। और हम यहां देख सकते हैं कि bashवास्तव में प्रक्रिया पेड़ में माता-पिता के रूप में दिखाई देती है pstree


हाँ ! + 1. यह उदाहरण देता है कि गिल्स ने औपचारिक रूप से पहला और अनुकरणीय दूसरा क्या रखा। शायद अपने प्रारंभिक उत्तर के लिए उसे श्रेय देना क्रम में है?
Cbhihe

0

अन्य उत्तरों ने जो कहा है, उसका समर्थन करते हुए, मैंने रिमोट पर कमांड को इनवॉइस करने वाले कोड को देखा, https://github.com/openssh/openssh-portable/blob/4f29309c4cb19bcb17174931db84cacc1414c17d29/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);

... जो, जैसा कि आप देख सकते हैं, बिना शर्त shellपहले तर्क -cऔर दूसरे तर्क के साथ आह्वान करते हैं command। इससे पहले, shellवैरिएबल उपयोगकर्ता के लॉगिन शेल में सेट किया गया था जैसा कि रिकॉर्ड किया गया था /etc/passwdcommandइस फ़ंक्शन का एक तर्क है, और अंततः तार से एक स्ट्रिंग रीड वर्बेटिम पर सेट होता है ( session_exec_reqउसी फ़ाइल में देखें )। इसलिए, सर्वर कमांड की व्याख्या बिल्कुल नहीं करता है, लेकिन रिमोट पर एक शेल हमेशा लगाया जाता है।

हालांकि, SSH प्रोटोकॉल विनिर्देश के प्रासंगिक हिस्सा है नहीं इस व्यवहार की आवश्यकता के लिए दिखाई देते हैं; यह केवल कहता है

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

यह संदेश अनुरोध करेगा कि सर्वर दिए गए कमांड का निष्पादन शुरू करें। 'कमांड' स्ट्रिंग में एक पथ हो सकता है। अनधिकृत आदेशों के निष्पादन को रोकने के लिए सामान्य सावधानी बरती जानी चाहिए।

यह शायद इसलिए है क्योंकि सभी ऑपरेटिंग सिस्टम में कमांड-लाइन शेल की अवधारणा नहीं है। उदाहरण के लिए, यह क्लासिक MacOS ssh सर्वर के बजाय AppleScript दुभाषिया को "निष्पादन" कमांड स्ट्रिंग्स को खिलाने के लिए पागल नहीं हुआ होगा ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.