タイトルの通りなのですが、なぜ `/bin/false` がログインシェルでも-NLオプションでポート転送ができるのでしょうか。  
試したところ、`/sbin/nologin` ではポート転送はできませんでした。

自分で調べたところ、`/etc/shells` に追加すると、FTP などを使うことができたりするということは納得したのですが、しかし試した環境では
`/bin/false` も `/sbin/nologin` も `/etc/shells`
に追加していません。ご教授いただけましたら幸いです。どうかよろしくお願いします。

サーバの環境は Debian 7.10、sshd のバージョンは OpenSSH_6.0p1 Debian-4+deb7u4, OpenSSL 1.0.1e
11 Feb 2013 です。  
クライアントの ssh のバージョンは OpenSSH_6.9p1, LibreSSL 2.1.8 です。
CC BY-SA 3.0
2016-04-30T09:21:39.063
24475
2016-05-01T10:45:28.533
2016-04-30T10:21:41.180
3061
15339
question
ssh
なぜ /bin/false がログインシェルでも ssh の -NL オプションでポート転送ができるのでしょうか?
SSH サーバー `sshd`(8) がユーザーのシェルの存在を確認し、存在しないときには拒否するからです。Debian なら認証動作については
`/var/log/auth.log` を確認しましょう。次のようなログがあると思います。

```

    Apr 30 19:07:17 sugar sshd[13663]: User fumiyas not allowed because shell /sbin/nologin does not exist
    
```

`sshd` はファイルが存在して所有者か所有グループかそのほかの実行権限が付いているかどうかだけ確認しているので、例えば次のようにすると SSH
ポート転送が許可されます。

```

    # touch /sbin/nologin
    # chmod 0100 /sbin/nologin
    
```

Debian / Ubuntu には `/sbin/nologin` は存在しませんが、`/usr/sbin/nologin`
は存在して実行権限が付いているので、そいつをシェルに指定すればポート転送できます。

`sshd` 自身は `shells`(5) は評価しません。必要であれば `sshd_config`(5) で `UsePAM yes`
を設定し、`pam.conf`(5) で `pam_shells`(8) を利用することになります。
CC BY-SA 3.0
2016-04-30T10:12:00.703
24477
2016-05-01T05:24:02.660
2016-05-01T05:24:02.660
3061
3061
24475
answer
参考情報ですが、ログインシェルが存在しない、もしくは実行権限がない場合でも port forwarding
が可能になる場合がありますので、その点について少し記述しておきます。

実行環境は以下の通りです。

```

        OS: Linux 4.4.0
    Distro: Ubuntu 16.04
      sshd: OpenSSH 7.2p2
    
```

**openssh-7.2p2/auth.c**

```

    int
    allowed_user(struct passwd * pw)
    {
                  :
      /*
       * Deny if shell does not exist or is not executable unless we
       * are chrooting.
       */
      if (options.chroot_directory == NULL ||
          strcasecmp(options.chroot_directory, "none") == 0) {
        char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
            _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
    
        if (stat(shell, &st) != 0) {
          logit("User %.100s not allowed because shell %.100s "
              "does not exist", pw->pw_name, shell);
                       :
    
```

上記の部分では `options.chroot_directory` の内容を検査していますが、これは `sshd_config` ファイルにおける
`ChrootDirectory` に相当します。

```

    srv$ ls -l /sbin/nologin
    ls: cannot access '/sbin/nologin': No such file or directory
    srv$ sudo chsh -s /sbin/nologin nemo
    chsh: Warning: /sbin/nologin does not exist
    srv$ getent passwd nemo
    nemo:x:1001:100:testing:/nonexistent:/sbin/nologin
    
```

client 側から server(IP address:192.168.0.3)側へ (local) port forwarding を行います。

```

    cli$ ssh -fNL 10000:127.0.0.1:8023 nemo@192.168.0.3
    nemo@192.168.0.3's password: 
    Permission denied, please try again.
                :
    Permission denied (publickey,password). 
    
```

失敗したので、次は server 側の `/etc/ssh/sshd_config` に `ChrootDirectory` の設定を追加して、

**/etc/ssh/sshd_config**

```

    Match User nemo
      ChrootDirectory /chroot
    
```

sshd を再起動します。

```

    srv$ ls -ld /chroot
    drwxr-xr-x 2 root root 4096 /chroot/
    srv$ sudo service sshd restart 
    
```

再度、port forwarding を行ってみます。

```

    cli$ ssh -fNL 10000:127.0.0.1:8023 nemo@192.168.0.3
    nemo@192.168.0.3's password: 
    
```

client 上で 10000 番ポートにアクセスします。

```

    cli$ telnet localhost 10000
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    
```

その他にも先のソースコードから読み取れる様に、ログインシェルが設定されていない場合も同様に port forwarding が可能になります。

```

    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
    
```

このコメントにある通り、ログインシェルは `/bin/sh` である、として処理が継続されてしまいます。

```

    srv$ sudo chsh -s '' nemo
    chsh: Warning:  does not exist
    srv$ getent passwd nemo
    nemo:x:1001:100:testing:/nonexistent:
    
```

`sshd_config` の `ChrootDirectory` の設定を削除して sshd を再起動してから試してみると、port forwarding
が可能になっています。

`ChrootDirectory` の設定はともかく、ログインシェルの設定が空という状況は想定しづらいのですが、考慮しておくに越したことはないかと思います。

* * *

ただ、質問の意図が「ユーザー別に port forwarding の可否をコントロールしたい」という事であれば、先程の `Match User`
を使う方法もあります。

**/etc/ssh/sshd_config**

```

    Match User nemo
      AllowTcpForwarding no
    
```

ログインシェルを `/bin/false` にして port forwarding を実行します。

```

    $ ls -l /bin/false
    -rwxr-xr-x 1 root root 26364 /bin/false
    srv$ sudo chsh -s /bin/false nemo
    srv$ getent passwd nemo
    nemo:x:1001:100:testing:/nonexistent:/bin/false
    
    cli$ ssh -fNL 10000:localhost:8023 nemo@192.168.0.3
    nemo@192.168.0.3's password: 
    cli$ telnet localhost 10000
    Trying 127.0.0.1...
    Connected to localhost.
    channel 1: open failed: administratively prohibited: open failed
    Escape character is '^]'.
    Connection closed by foreign host.
    
```
CC BY-SA 3.0
2016-05-01T10:45:28.533
24489
2016-05-01T10:45:28.533
24475
answer