によると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
ログインシェルこの場合、2つの異なる意味を持つことができます。
アカウントデータベース内のユーザーのログインシェルとして定義されているシェル。
たとえば、
$ 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
inssh
はシェル以前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と1つの引数()を使用して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 サーバーは、ユーザーデータベースにリストされている実行可能ファイルをユーザーのログインシェルとして実行しますが、必ずしもログインシェルとして実行する必要はありません。コマンドラインが空でない場合、3つの引数のリストが渡されます。
argv[0]
一般的な規則に従うプログラムのデフォルト名。argv[1]
文字列です-c
。argv[2]
クライアントが渡したコマンドです。
空のコマンドラインの場合、SSHサーバーはユーザーのログインシェルを呼び出します。ログインシェルとして。これは、パラメータが1つしかないリストを意味します。
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