sshは(シェル自体ではなく)ログインシェルでコマンドを実行しますか?

sshは(シェル自体ではなく)ログインシェルでコマンドを実行しますか?

によると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つの異なる意味を持つことができます。

  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

  2. 通常、ログイン/sshdによって実行されるログインセッションを初期化するために使用されるシェル呼び出しです。プレフィックスを付けてargv[0]-一部のシェルは-lまたは--loginオプションも許可します)、シェルになどのいくつかのセッション初期化ファイルを解釈するように指示.profileします。.login.zlogin

とにかくshinsshシェル以前sshdと同様に、rshdクライアントが送信したコード(存在する場合)を解釈するために常にシェルが呼び出されます。

実行する場合:

ssh user@host foo    bar

fooここで、引数barは に渡され、スペースsshssh連結され、foo barシェルコードをサーバーに送信します。

サーバーがhost実行されますログインシェル3つのパラメータがありますuser

  1. ログインシェルのデフォルト名です。私としてzsh
  2. -c
  3. 顧客から提供されたコード:foo barこの例では

シェルはそれを独自の構文のコードとして解釈し、実行されません。〜のようにログインシェルargv[0]ではありません-

もしいいえパラメータは、クライアントを呼び出すときと同様にクライアントに渡されます。

ssh user@host

次に、そのモードに入り(rloginコマンドが渡されないときにrsh実行されるモードと同様に)、擬似rlogin ttyと1つの引数()を使用してsshdユーザーのログインシェルを実行します。argv[0]

  1. -私の場合は、ログインシェルのデフォルト名の前に-zsh

これはログインシェルとして実行されており、.zprofile //を読むことをシェルに伝えます.profile.login

結論として:

  • ssh host shell-codersh host shell-codeリモートユーザーのログインシェルにいくつかのコードを解析させることで、リモートでコマンドを実行するのと同じです。
  • ssh hostに似ておりrlogin host、仮想端末でログインシェルモードでログインシェルを起動してリモートでログインします。

1 この非常に単純な場合、すべてのシェルはログインシェルを使用することを好むユーザーを除いてコードを同じに解釈しますが、より/bin/false複雑なシェルにはいくつかの変更があります。また、見ることができます/sbin/nologin/usr/bin/python3リモートユーザーのログインシェルを知らず、SSHを介して任意の単純なコマンドをどのように実行できますか?

答え2

いいえ、SSHはコマンドを実行するのではなく、シェルにログインしたときにのみログインシェルを呼び出します。つまり、ログイン初期化ファイルを実行するには(たとえば~/.profile)、これを明示的に実行する必要があります。これは意図的なデザインの選択でした。ほとんどのログインがテキスト端末で行われた頃は、多くのユーザーが.profile対話型セッションにログインしたときにのみ意味のあるコマンドをそこで実行しました。 (最近では、ほとんどの人がグラフィックセッションにローカルにログインするため、これはあまり一般的ではありません。)Emacsを素早く起動してモデムをオンにしたくないssh example.com lsrsync example.com:somefile .


SSHのコマンドは、コマンドライン引数を中間スペースに連結した文字列です。たとえば、ssh u@h shopt -q login_shellコマンドを実行しますshopt -q login_shellssh 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

関連情報