에 따르면 man sshd
:
LOGIN PROCESS
When a user successfully logs in, sshd does the following:
<...>
9. Runs user's shell or command. All commands are run under the
user's login shell as specified in the system password data‐
base.
그러나 "사용자의 로그인 셸에서 실행"이 문자 그대로 bash -l
"? 에서와 같이 로그인 셸을 의미하는지 확실하지 않습니다. 내 실험에 따르면 그렇지 않습니다.
$ ssh u@h shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'
Not login shell
왜 이런 일이 일어나는지 이해가 안 되나요? 이로 인해 실행 중인 명령이 셸에 로그인하는 것과 같은 일반적인 환경을 얻지 못하게 됩니다. 이것은 번거로운 일입니다.
답변1
로그인 쉘이 경우 두 가지 다른 의미를 가질 수 있습니다.
계정 데이터베이스에서 사용자의 로그인 셸로 정의된 셸입니다.
예를 들어:
$ getent passwd stephane stephane:*:1000:1000:Stephane Chazelas:/home/stephane:/bin/zsh
/bin/zsh
내 로그인 쉘이며 계정 데이터베이스 에 입력한 7번째 필드입니다 . 일부 다른 사용자는/bin/tcsh
,,,,...을 (를) 가질 수 있습니다./bin/fish
/bin/bash
/sbin/nologin
/bin/false
일반적으로 로그인/sshd에 의해 수행되는 로그인 세션을 초기화하는 데 사용되는 쉘 호출입니다. 접두사를 붙이고
argv[0]
(-
일부 쉘은-l
또는--login
옵션도 허용함) 쉘이 , 등과 같은 일부 세션 초기화 파일을 해석하도록 지시.profile
합니다 ..login
.zlogin
어쨌든 sh
in ssh
은껍데기이전 sshd
과 마찬가지로 rshd
클라이언트가 보낸 코드(있는 경우)를 해석하기 위해 항상 쉘이 호출됩니다.
실행하는 경우:
ssh user@host foo bar
여기서 foo
및 bar
인수는 에 전달되고 ssh
공백 ssh
으로 연결되어 foo bar
쉘 코드를 서버로 보냅니다.
서버가 host
실행됩니다로그인 쉘3가지 매개변수 가 있습니다 user
:
- 로그인 쉘의 기본 이름입니다. 나로서는
zsh
-c
- 고객이 제공한 코드:
foo bar
이 예에서는
쉘은 이를 자체 구문의 코드로 해석하며 실행되지 않습니다.~처럼로그인 쉘 argv[0]
이 아닌 -
.
만약에아니요매개변수는 클라이언트를 호출할 때와 마찬가지로 클라이언트에 전달됩니다.
ssh user@host
그런 다음 해당 모드로 들어가고( rlogin
명령이 전달되지 않을 때 rsh
실행하는 모드와 마찬가지로) rlogin
의사 tty와 단 하나의 인수( )를 사용하여 sshd
사용자의 로그인 셸을 실행합니다 .argv[0]
-
제 경우에는 로그인 셸의 기본 이름 앞에-zsh
.
이는 로그인 쉘로 실행 중이며 .zprofile
// 를 읽을 것임을 쉘에 알려줍니다 .profile
..login
결론적으로:
ssh host shell-code
rsh host shell-code
원격 사용자의 로그인 쉘이 일부 코드를 구문 분석하도록 하여 원격으로 명령을 실행하는 것과 같습니다 .ssh host
와 유사하며rlogin host
, 가상 터미널에서 로그인 쉘 모드로 로그인 쉘을 시작하여 원격으로 로그인합니다.
1 이 매우 간단한 경우 모든 쉘은 로그인 쉘 사용을 선호하는 사용자를 제외 /bin/false
하고는 코드를 동일하게 해석 하지만 더 복잡한 쉘의 경우 몇 가지 변경 사항이 있습니다. 당신은 또한 볼 수 있습니다/sbin/nologin
/usr/bin/python3
원격 사용자의 로그인 셸을 모르고 SSH를 통해 임의의 간단한 명령을 어떻게 실행할 수 있습니까?
답변2
아니요, SSH는 명령을 실행할 때가 아니라 셸에 로그인할 때만 로그인 셸을 호출합니다. 즉, 로그인 초기화 파일을 실행하려면(예 ~/.profile
: ) 이를 명시적으로 수행해야 합니다. 이는 의도적인 디자인 선택이었습니다. 대부분의 로그인이 텍스트 터미널에 이루어졌던 시절에는 많은 사용자가 .profile
대화형 세션에 로그인했을 때만 의미가 있는 명령을 그곳에서 실행했습니다. (요즘에는 대부분의 사람들이 그래픽 세션에 로컬로 로그인하기 때문에 이것은 덜 일반적입니다.) 이메일을 받기 위해 Emacs를 빠르게 실행하고 모뎀을 켜는 것을 원하지는 않습니다 ssh example.com ls
!rsync example.com:somefile .
SSH의 명령은 명령줄 인수를 중간 공백과 연결하여 얻은 문자열입니다. 예를 들어, ssh u@h shopt -q login_shell
명령을 실행하십시오 shopt -q login_shell
. ssh u@h 'shopt -q login_shell'
, 또는 ssh u@h 'shopt -q' login_shell
등과 완전히 동일합니다 .
SSH는 이 문자열을 사용자의 로그인 셸에 전달합니다. SSH는 다른 쉘에 대해 알지 못합니다. 서버는 Unix가 아닌 시스템에서 실행 중이거나 또는 sh
이라는 프로그램이 없는 제한된 환경 에서 실행 중일 수 있습니다 bash
.
SSH 서버는 사용자 데이터베이스에 나열된 실행 파일을 사용자의 로그인 셸로 실행하지만 반드시 로그인 셸로 실행할 필요는 없습니다. 명령줄이 비어 있지 않으면 세 개의 인수 목록이 전달됩니다.
argv[0]
일반적인 규칙을 따르는 프로그램의 기본 이름입니다.argv[1]
문자열입니다-c
.argv[2]
클라이언트가 전달한 명령입니다.
빈 명령줄의 경우 SSH 서버는 사용자의 로그인 셸을 호출합니다.로그인 쉘로. 이는 매개변수가 하나만 있는 목록을 의미합니다.
argv[0]
대시(-
) 뒤에 프로그램의 기본 이름이 옵니다.
ssh localhost 'cat /proc/$$/cmdline | tr \\0 \\n'
예를 들어 다음은 Linux 시스템의 출력입니다.
sh
-c
cat /proc/$$/cmdline | tr \\0 \\n
로그인 쉘의 경우 로그인 쉘 자체가 다른 프로그램을 실행하는 경우가 많기 때문에 이를 관찰하기가 더 어렵습니다. 무슨 일이 일어나고 있는지 확인하는 쉬운 방법은 로그인 셸의 초기화 파일을 일시적으로 비활성화하는 것입니다. 예를 들어 일시적으로 이름을 바꾸 ~/.profile
거나 사용 중인 셸에 따라 , 등으로 변경합니다 ~/.bash_profile
. 다음은 계정을 로그인 셸로 ~/.zprofile
사용하는 예입니다 ./bin/sh
$ mv ~/.profile ~/not.profile
$ ssh localhost
(/etc/motd content goes here)
Last login: Mon Apr 24 18:00:30 2023
$ cat /proc/$$/cmdline; echo
-sh
$ exit
Connection to localhost closed.
$ mv ~/not.profile ~/.profile