ssh를 통해 환경 변수를 명령에 전달할 생각이었습니다.
$ ssh HOST A=1 set | grep ^A
$ ssh HOST A=1 sh -c set | grep ^A
A='1'
$ ssh HOST A=1 echo '$A'
$ ssh HOST A=1 sh -c 'echo $A'
따라서 set
환경 변수는 보이지 않지만 별도의 프로세스에서 수행됩니다. 같은 일이 echo
.
정확히 무엇이 전송되고 정확히 어떻게 실행되는지 (어떤 명령이 실행되는지) 알 수있는 방법이 sshd
있습니까?
를 실행하면 ssh user@host command
의 확장으로 인한 토큰 이 사이에 공백으로 command
연결되어 ssh
원격 호스트에 문자열로 전송됩니다. 그런 다음 원격 호스트는 원격 사용자의 기본 셸 (에서 지정된 것 /etc/passwd
) 의 인스턴스를 실행 하여 클라이언트로부터받은 문자열을 셸의 -c
옵션에 대한 인수로 전달합니다 (아래에서 자세히 설명).
예를 들어
$ foo="bar baz"
$ ssh user@host echo "$foo"
bar baz
로컬 ssh
은 두 개의 인수 echo
와 bar baz
. 그것들을 연결하여 문자열을 형성 echo bar baz
하고 서버로 보냅니다. 서버는 라인을 따라 무언가를 실행 /bin/sh -c 'echo bar baz'
하고이 명령의 출력은 로컬 ssh
의 표준 출력 에 인쇄됩니다 .
클라이언트가 실제로 서버에 보내는 내용을 어떻게 알 수 있습니까?
으로 카밀 Maciorowski 지적 질문에 대한 코멘트에, ssh -v
디버그 메시지 명령 문자열로 출력은 서버에 전송되는 :
$ ssh -v host A=1 sh -c set | grep ^A
...
debug1: Sending command: A=1 sh -c set
...
sshd
실제로 무엇이 실행 되는지 어떻게 알 수 있습니까?
클라이언트에게 자체 작업의 흔적을 보여달라고 서버에 요청하는 방법을 알지 못합니다. 그러나 테스트 목적으로 strace
데몬의 인스턴스 를 사용할 수 있습니다 .
$ sudo strace -e execve -f /usr/bin/sshd -p 2222
원격 실행을 위해 명령 줄을 작성할 때 인용을 제대로하지 않기가 쉽기 때문에 특히 유용합니다. 예를 들어 (귀하의 질문에 제공된 예제의 변형) :
$ ssh -p 2222 host bash -c 'A=1 set'
# Prints nothing
strace
는 명령 문자열로 볼 수있는 것이 실제로 원격 호스트에서 분할되어 사용자의 기본 셸에서 전체 명령 줄을 먼저 실행 함을 보여줍니다 (에 대한 인수 목록을 만들 때 로컬 셸에서 작은 따옴표가 제거되었습니다 ssh
).
... execve("/bin/bash", ["bash", "-c", "bash -c A=1 set"] ...
그리고:
... execve("/usr/bin/bash", ["bash", "-c", "A=1", "set"] ...
명령 문자열 (에 대한 인수 -c
)이 어떻게되는지 주목하십시오 A=1
. 0 번째 인수로 set
전달됩니다 bash
( $0
명령 이름으로 사용 가능 하고 사용됨).
원격 쉘이 실제로 무엇을 실행하는지 확인하는 방법은 무엇입니까?
다시 말하지만, 나는 쉬운 방법을 알지 못합니다. 간단한 경우에는 쉘 xtrace
옵션을 사용하는 것이 간단합니다. 예를 들어 다음과 같이 ssh host A=1 set
될 수 있습니다.
$ command=$(printf '%s ' A=1 set); printf '%s\n' "${command% }" |
ssh host sh -x
sh
원격 사용자의 기본 셸로 바꿔야합니다.
ssh
이 형식은 변경되지 않은 입력을 허용하기 때문에 명령은 의 표준 입력으로 파이프됩니다 ( ssh host sh -xc A=1 set
위에 표시된 이유로 작동하지 않으며 인용을 추가하면이 연습의 목적 자체가 어느 정도 실패합니다).
단순하지 않은 경우, 특히 ssh
탐색중인 호출이 이미 표준 입력을 사용하는 경우 원격 호스트가 xtrace
켜진 상태에서 쉘을 실행하도록 강제 할 수 있습니다 . 실험 목적으로 오류로 인해 원격 시스템에 로그인 할 수 없다는 점을 분명히 알고 있는 경우 (대략적인) 방법은에서 원격 사용자의 기본 셸을 대체하는 것입니다 /etc/passwd
. 라고 가정하고로 /bin/sh
변경 /home/your_user/bin/sh
하고 후자를 실행 가능한 스크립트로 만듭니다.
#!/bin/sh
exec /bin/sh -x "$@"
그러면 쉘이 실행중인 내용을 추적 할 수 있습니다.
$ ssh host A=1 echo foo
foo
+ A=1
+ echo foo
마지막으로 샘플 명령에 대해 :
ssh HOST A=1 set
인쇄되지 않는 이유 는 A=1
사용자의 기본 셸이 Bash (으로 호출 될 수 있음 sh
) 이기 때문일 수 있습니다 . 에서 일어나는 것과는 달리 dash
, ksh
, yash
, zsh
, set
강타 (적어도 버전 내가 가지고있는 5.0.17
) 설정되지 않은 출력 변수 않습니다 에 대한 set
명령 자체를 . 반면에 다음을 확인할 수 있습니다.
$ ssh host 'A=1
> set' | grep ^A
A=1
Ie A
가 호출 set
되기 전에 선언 된 경우의 출력에 표시 set
됩니다.
이어 A=1 sh -c set
, A
의 환경에 첨가 sh
되므로 당연히 의해 인쇄된다 set
.
A=1 echo '$A'
의 확장 후 (내장되어 있다고 가정) 실행을 위해 환경에만 추가 A
되기 때문에 의 값을 인쇄하지 않습니다 . 그것을 인쇄 하는과 비교하십시오 .A
echo
$A
ssh host 'A=1; echo $A'
1
A=1 sh -c 'echo $A'
위에 표시된대로 원격 호스트는 -c
옵션과 A=1 sh -c echo $A
인수로 원격 사용자의 기본 쉘을 실행 한 다음 해당 쉘이 실행 되기 때문에 아무것도 인쇄하지 않습니다 sh -c echo $A
. 명령 문자열은 echo
인수없이.
당신이 있는지 주위에 따옴표를 만들 필요가 작동하게하려면 echo $A
원격 호스트로 전송을 하고 $A
예를 들면 : (로컬 쉘에 의해 또는 "외부"원격 하나) 너무 일찍 확장되는 보호 ssh host A=1 sh -c '"echo \$A"'
나 ssh host A=1 sh -c "'echo \$A'"
.
원격 셸을 명시 적으로 호출 할 때 표준 입력에서 명령을 읽는 것이 더 쉬울 것입니다.
$ echo 'echo $A' | ssh host A=1 sh -s
1
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다