ssh 원격 명령 행 인수를 구문 분석하는 방법


11

원격 ssh 명령에 대한 인수를 두 번 이스케이프 해야하는 것에 대한 질문과 답변을 보았습니다. 내 질문은 : 정확히 어디에서 언제 두 번째 파싱을 수행합니까?

내가 다음을 실행하면 :

$ ssh otherhost pstree -a -p

출력에 다음이 표시됩니다.

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

원격 명령 ( pstree) 의 부모 프로세스는입니다. sshd명령 행 인수를 원격 명령으로 구문 분석하는 쉘이 없으므로 이중 인용 또는 이스케이프가 필요한 것처럼 보이지 않습니다 ( 그러나 그것은 확실히입니다). 대신 먼저 ssh하고 로그인 셸을 얻은 다음 실행 pstree -a -p하면 출력에 다음이 표시됩니다.

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

따라서 분명히이 경우 bash명령 줄 구문 분석을 수행 하는 쉘이 있습니다. 그러나 원격 명령을 직접 사용하는 경우 쉘이없는 것처럼 보이므로 왜 큰 따옴표가 필요합니까?

답변:


22

항상 원격 쉘이 있습니다. SSH 프로토콜에서 클라이언트는 실행할 문자열을 서버에 보냅니다. SSH 명령 행 클라이언트는 명령 행 인수를 사용하여 인수 사이에 공백으로 연결합니다. 서버는 해당 문자열을 가져와 사용자의 로그인 셸을 실행하여 해당 문자열을 전달합니다.

원격 쉘을 우회하는 것은 불가능합니다. 프로토콜에는 서버에서 argv 배열로 구문 분석 할 수있는 문자열 배열을 보내는 것과 같은 것이 없습니다. SSH 서버는 보안상의 제한이 있기 때문에 원격 쉘을 우회하지 않습니다. 사용자의 쉘로 제한된 프로그램을 사용하는 것은 특정 명령 (예 : rsync-only 계정 또는 자식 전용 계정).

pstree이 이미 사라 졌을 수 있습니다. 많은 쉘은“이 외부 명령을 실행하고 완료 될 때까지 기다렸다가 명령 상태로 종료”하려고 할 경우, 쉘 execve이 대신이 외부 명령의“를 실행합니다” 를 최적화 합니다. 이것이 첫 번째 예에서 일어나는 일입니다. 다음 세 가지 명령을 대조하십시오.

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

처음 두 개는 동일합니다. 클라이언트는 서버에 정확히 동일한 데이터를 보냅니다. 세 번째는 쉘의 exec 최적화를 무효화하는 쉘 명령을 보냅니다.


2
하아! 내 질문에 대답하는 걸 믿어 줄 수 없어 나는 질문을 게시하면서 반쯤 알아 냈고 스스로 질문하고 대답해야합니다.
only

10

나는 그것을 이해했다고 생각한다.

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

인수 pstree는 show command line arguments, show pids 및 주어진 pid의 부모 프로세스 만 표시합니다. 이것은 '$$'bash가 명령 행 인수를 평가할 때 bash가 자체 pid로 대체하는 특수 쉘 변수입니다. 로컬 셸에서 해석되지 않도록 한 번 인용했습니다. 그러나 원격 쉘에서 해석 할 수 있도록 이중 인용이나 이스케이프 처리되지 않았습니다.

보시다시피, 그것은 12001쉘의 pid 인 것으로 대체됩니다 . 우리는 또한 출력에서 ​​볼 수 있습니다 : pstree,12001pid가 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. 그것은 Gilles가 공식적으로 더 우선적으로 두는 것을 예시합니다. 아마도 그에게 초기 답변에 대한 신용을주는 것은 순서대로입니까?
Cbhihe

0

다른 답변이 말한 지원, 내가 코드를보고 그 리모컨의 발동 명령 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);

... 보시다시피 shell, 첫 번째 인수 -c와 두 번째 인수로 무조건 호출합니다 command. 이전에는에 shell기록 된대로 변수가 사용자의 로그인 쉘로 설정되었습니다 /etc/passwd. command는이 함수에 대한 인수이며 궁극적으로 와이어에서 직접 읽은 문자열로 설정됩니다 ( session_exec_req동일한 파일 참조 ). 따라서 서버는 명령을 전혀 해석하지 않지만 항상 원격에서 쉘이 호출됩니다.

그러나 SSH 프로토콜 사양관련 부분 에는이 동작이 필요 하지 않습니다 . 그것은 단지 말한다

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

이 메시지는 서버가 주어진 명령의 실행을 시작하도록 요청합니다. 'command'문자열은 경로를 포함 할 수 있습니다. 무단 명령의 실행을 방지하기 위해 일반적인 예방 조치를 취해야합니다.

모든 운영 체제에 명령 줄 셸 개념이있는 것은 아닙니다. 예를 들어 Classic MacOS ssh 서버가 대신 "exec"명령 문자열을 AppleScript 인터프리터 에 공급하는 것은 그리 놀라운 일이 아닙니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.