第7章 うまくいかない時は

Last Modified: Sun Mar 13 00:13:48 UTC 2011

OpenSSH のような複雑なソフトウェアで問題が発生した場合、 その原因をつきとめるのは時に多くの労力を要することがあります。 本章では OpenSSH のインストールから運用に至るまでの さまざまな状況に対して、原因の追及と対策を考えていきます。

7.1. インストール時のトラブル

本節では OpenSSH をソースコードからコンパイルしたときに発生する症状とその解決方法を説明します。

7.1.1. OpenSSL ライブラリが見つからない

OpenSSH は暗号化のために OpenSSL ライブラリを使用しています。 ソースコードから OpenSSH をコンパイルする場合、このライブラリは必要不可欠です。 ./configure スクリプトを実行中に、 以下のようなエラーが出た場合、OpenSSL がインストールされていない可能性があります:

configure: error: OpenSSL version header not found.
または
configure: error: *** Can't find recent OpenSSL libcrypto (see config.log for details) ***

このような場合は OpenSSL 公式サイト [脚注: http://www.openssl.org/ ] からダウンロードして インストールしてください。

ライブラリをインストールしたにもかかわらず、以下のようなエラー

configure: error: Your OpenSSL headers do not match your library.
が表示された場合は、複数個の OpenSSL がシステムの別々の場所にインストールされていて ./configure スクリプトがお互いに異なるバージョン用の ライブラリファイルとインクルードファイルを発見したことが原因だと思われます。 このような場合 --with-ssl-dir オプションでパスを指定してください。 なお、ディストリビューションによっては最初から OpenSSL のインクルードファイルと ライブラリファイルのバージョンが違っていることがあり、 このような場合には OpenSSL をインストールしなおす必要があります。

7.1.2. "zlib too old" というエラーがでる

./configure スクリプトを実行中に、 次のようなエラーが表示されることがあります。

configure: error: *** zlib too old - check config.log ***
Your reported zlib version has known security problems.  It's possible your
vendor has fixed these problems without changing the version number.  If you
are sure this is the case, you can disable the check by running
"./configure --without-zlib-version-check".
If you are in doubt, upgrade zlib to version 1.2.3 or greater.
See http://www.gzip.org/zlib/ for details.

通常 configure はシステムにインストールされている zlib のバージョンを検査し、 それが脆弱性のあるバージョン (1.2.2 以前) の場合は続行を拒否します。 しかし多くのシステムではセキュリティ・アップデートにより zlib の脆弱性が回避されたあとも、 互換性を保つために zlib のバージョン番号を変更せず以前のままにしておく傾向があります。 このような場合、オペレーティングシステムのベンダーなどが配布する最新のセキュリティ・アップデートを適用して システムの zlib に脆弱性がないことを確信できるのであれば、 --without-zlib-version-check オプションをつけて警告を回避してください。

7.1.3. 特定の機能が yes にならない

configure--with-xxx オプションで 特定の機能を有効化する指定を行なった場合、通常はその機能を組みこむために必要なライブラリがないとエラーが発生します。 しかし configure では未知の --with-xxx オプションがあっても エラーを出さないため、 --with-xxx オプションをタイプミスすると そのオプションは単に無視され、最後に表示されるメッセージで指定したはずの機能が yes にならないことがあります。 このような場合は configure に与えるオプションに間違いがないかどうか確認してください。

7.2. サーバが起動しない

sshd サーバデーモンは起動時に致命的なエラーが発生すると すぐに終了します。このエラーは標準エラー出力に表示されることもあり、 ログファイルに残されることもあります。たいていの場合は、標準エラー出力の内容や、 /var/log/messages または /var/log/syslog などに記録されている ログに残されたメッセージを見ることで原因が判明します。

ログファイルの例:

Mar 25 21:47:53 server sshd[43656]: error: Bind to port xxxx on 0.0.0.0 failed: Address already in use.
Mar 25 21:47:53 server sshd[43656]: fatal: Cannot bind any address.

7.2.1. sshd_config 設定ファイルの文法エラー

以下のようなメッセージが表示される場合は、sshd_config 設定ファイルに 文法上の誤りがあります。このような場合は表示された行を確認してください。

/etc/ssh/sshd_config: line 120: Bad configuration option: asswordAuthentication

代表的なメッセージ:

7.2.2. sshd の初期化に関するエラー

7.3. 動かない原因を追及するには

OpenSSH のクライアントやサーバが期待どおりの動作をしない場合は、 できるだけ多くの情報を集めることが必要です。 OpenSSH に含まれている sshsshd などのコマンドにはデバッグ用の オプションが用意されているので、これらのオプションを与えて実行してみてください。

7.3.1. ssh をデバッグモードで実行する

ssh を、コマンドラインから実行するさいに -v オプションを与えるとデバッグ出力を表示できます。 -v オプションを繰り返し指定すると、指定回数に比例して詳細な出力を得ることができます。 最高 3つまでの -v オプションがサポートされています。
ssh をデバッグモードで実行する
$ ssh [-v [-v [-v]]] [オプション] 引数1 引数2 ...

実行例:

$ ssh -v yusuke@server.example.com
OpenSSH_4.3p2, OpenSSL 0.9.7e-p1 25 Oct 2004
debug1: Reading configuration data /home/yusuke/.ssh/config
debug1: Applying options for server.example.com
debug1: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to server.example.com [xx.xx.xx.xx] port xx.
debug1: Connection established.
debug1: identity file /home/yusuke/.ssh/id_rsa type 1
debug1: Remote protocol version 1.99, remote software version OpenSSH_4.3
debug1: match: OpenSSH_4.3 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_4.3
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
...

サーバ側からのデバッグ情報

ssh コマンドでデバッグ出力を表示した場合、 以下のようにサーバ側からのデバッグ情報が表示されることがあります。

debug1: Remote: X11 forwarding disabled in user configuration file.
ここに含まれる「Remote:」という文字列は、 これがリモートホストからの情報であることを示しています。 このような情報は原因の追及に役立ちますが、一般的に OpenSSH ではセキュリティ向上のため サーバ側がクライアント側に情報を渡すことはほとんどありません。 したがって、ログインできない場合はおもに サーバ側のログを見て原因を追及する必要があります。

7.3.2. sshd をデバッグモードで実行する

sshd サーバデーモンは、 コマンドラインから -d オプションを与えて直接実行することにより デバッグモードで実行できます。-d オプションを与えられると、サーバはバックグラウンドに移行せず、 標準エラー出力にデバッグ出力を表示します。 最高 3つまでの -d オプションがサポートされています。 また sshd はデバッグモードではクライアントからの接続を一度だけしか受けつけず、 クライアントの接続が切れるとすぐに終了します。 なお sshd サーバデーモンの起動時には必ずフルパス名を指定する必要があります。 すでに sshd が動作中で再起動できない場合は、 /var/log/messages/var/log/syslog などに記録されている ログ出力を見ることも有用です (5.5.2. sshd のログを見る も参照してください)。
sshd をデバッグモードで起動する
$ /絶対パス名/sshd [-d [-d [-d]]] [オプション]

実行例:

# /usr/sbin/sshd -d
debug1: sshd version OpenSSH_4.3p2
debug1: read PEM private key done: type RSA
debug1: private host key: #0 type 1 RSA
debug1: read PEM private key done: type DSA
debug1: private host key: #1 type 2 DSA
debug1: rexec_argv[0]='/usr/sbin/sshd'
debug1: rexec_argv[1]='-d'
socket: Address family not supported by protocol
debug1: Bind to port xxx on 0.0.0.0.
Server listening on 0.0.0.0 port xxx.
...

7.4. ログインできない

ユーザが ssh コマンドを実行してから sshd サーバデーモンがログインを許可するまでには 多くの段階が存在し、さまざまな設定ファイルが介在しています。 図 openssh-layers はログインまでの各段階で関連する設定ファイルを それぞれクライアント側とサーバ側とでまとめたものです。


図 openssh-layers. ログインまでの各段階と関連ファイル

7.4.1. TCP/IP ネットワーク上のトラブル

ssh コマンドを実行してもまったく反応しないか、 あるいは "Connection refused"、 "Name or service not known" といったエラーが表示され、すぐに終了してしまう場合は、 sshd サーバデーモンへの TCP 接続が可能かどうか確認してください。

まず sshd サーバデーモンが接続を待ち受けている TCPポート番号を調べ、 telnet 相手先ホスト ポート番号 などと実行して、 OpenSSH のバージョン情報 (SSH-1.99-OpenSSH_4.3SSH-2.0-OpenSSH_4.3 など) が返されるかどうかを確認します。

$ telnet server.example.com 22
Trying xx.xx.xx.xx...
Connected to server.example.com.
Escape character is '^]'.
SSH-1.99-OpenSSH_4.3

このようなメッセージが現れない場合は、以下のことを確認してください。

7.4.2. SSH プロトコル上のトラブル

クライアントがサーバに接続してから 以下のようなメッセージが表示される場合は、認証以前の段階で SSH プロトコル上のトラブルが発生しています。 この場合はクライアント側の ~/.ssh/config 個人設定ファイル (あるいは ssh_config 設定ファイル) および、サーバ側の sshd_config 設定ファイルを確認してください。

7.4.3. ログインできない (公開鍵認証、パスワード認証、Hostbased認証共通)

デフォルトの OpenSSH の設定では、 クライアントがユーザ認証に成功してサーバにログインすると /etc/motd のメッセージや 前回ログインした時刻が表示されます。 クライアント側で以下のように表示される場合は、 サーバ側のユーザ認証が失敗したことを示しています。

$ ssh yusuke@server.example.com
Permission denied (publickey,password,keyboard-interactive,hostbased).

この場合は、まず (…) 内に表示されている文字列を確認してください。 これらはサーバ側が許可している認証方式で、それぞれ 公開鍵認証 ("publickey")、 パスワード認証 ("password")、 PAM を経由したパスワード認証 ("keyboard-interactive")、 Hostbased認証 ("hostbased") を表します。 クライアントとサーバの双方で正しい認証方法を許可しているか確認してください。 それぞれ該当する設定項目をクライアント側とサーバ側の両方で yes に設定する必要があります。

また、特定のユーザ (例えば yusuke) がログインできたかどうかはサーバ側の "Accepted publickey for yusuke ...", "Accepted password for yusuke ..." などのログ項目で確認することができます。 ユーザがログインできていない場合は、サーバ側で以下を確認してください。

7.4.4. ログインできない (公開鍵認証)

ユーザが公開鍵認証でログインできない場合、以下のような原因が考えられます。

7.4.5. ログインできない (Hostbased 認証)

Hostbased 認証がうまく動かない場合には、以下のような原因が考えられます。

7.5. ログイン後のトラブル

本節では通常のログインが成功した後に起きるトラブルについて説明します。

7.5.1. X11転送が使えない

通常、X11転送が使える場合は、サーバにログインすると 環境変数 DISPLAY に "localhost:10.0" などの値が設定されています。サーバ上で X11 アプリケーションがうまく動作しない場合には 以下のような原因が考えられます。

7.5.2. ポート転送、VPN が使えない

ポート転送や VPN は通常のシェルとは独立して起動されます。 ポート転送が正しく実行されている場合、 ローカル→リモート (L) のポート転送ではクライアント上で、 リモート→ローカル (R) のポート転送ではサーバ上で、 netstat -an コマンドを実行すれば、 それぞれ listen しているポート番号が表示されます。

ポート転送がうまく動かない場合は、以下のような原因が考えられます。

7.5.3. VPN のトラブル

VPN のトンネリングが動かない場合は、クライアント側で ssh コマンドのデバッグ出力に以下のようなエラーが表示されます。

7.5.4. ログアウト後に ssh が止まってしまう

リモートホストのシェルからログアウトした際、 ssh コマンドが終了せずに止まってしまうことがあります。 これは ssh コマンドがリモートホスト上で実行したプロセスがすべて終了するのを待っているために起こります。 ここでいう「プロセス」とはサーバ上のシェルから実行したすべての フォアグラウンドおよびバックグラウンドのプロセス、それから X11 転送やポート転送、および VPN トンネリングも含まれます。

ssh が止まってしまう例:

client$ ssh yusuke@server.example.com
...
server$ sleep 10 &                       (sleep コマンドをバックグラウンドで実行する)
server$ exit                              (ログアウトする)
logout
(ssh が止まってしまう)

このような場合は、ssh コマンドに SIGHUP シグナルを 送って強制的に終了するか、あるいはエスケープシーケンスを使って sshコマンドをバックグラウンドに移行させることができます (4.1.3. 公開鍵認証でログインする 参照)。 ssh が止まってしまったあとでも端末からの入力はまだ受けつけられていますので、 チルダ文字 (~) のあとにピリオド (.) を押すと ssh は終了し、 チルダ文字のあとに Control-Z を押すと ssh はバックグラウンドに移行します。 なお、 ssh を強制的に終了させても、リモートホスト上の バックグラウンド プロセスは終了しません。

また、リモートホストにおいてコマンドをバックグラウンドで実行させるときに、 そのプロセスの標準入出力をすべて端末から切り離した状態にしておくと、 このような現象は発生しません。具体的には、プロセスの実行時に そのプロセスの標準入力、標準出力、標準エラー出力をすべて 特定のファイルかあるいは /dev/null にリダイレクトしておけばよいのです。 こうすることにより、そのプロセスが端末に対して入出力をおこなわ ないことが保証されるため、ssh はそのプロセスの完了を待たずに終了できるのです。

プロセスを端末から切り離す:

client$ ssh yusuke@server.example.com
...
server$ sleep 10 >/dev/null 2>&1 </dev/null &         (sleep コマンドを端末から切り離した状態で実行する)
server$ exit                                              (ログアウトする)
logout
client$

7.5.5. ssh 以外のコマンド (scp, sftp, rsync, cvs, svn) のトラブル

ssh 以外のコマンド (sftprsynccvs など) で OpenSSH に関連したエラーが発生する場合、おもに以下の 2つの原因が考えられます。

これらのエラーが発生した場合、呼び出された ssh はすぐに終了します。 たいていのプログラムは ssh を単なる TCP 接続の代わりとして使っているために、 このような場合は「データが送られて来ない」「0バイトしか転送されない」といった エラーメッセージを表示し、とくにそれが OpenSSH によるものかどうかを区別しません。 したがって、これらのエラーが発生した場合は、まず通常の ssh コマンドで サーバに正しくログインできるかどうかを確認してください。サーバにログインできる場合は、 そのアプリケーションが実行するであろうコマンドがサーバ上で正しく実行できるかどうかを 確かめてください。sshコマンドを使う 各アプリケーションの代表的なエラーメッセージを以下に示します。

scp コマンドのエラーメッセージ

client$ scp yusuke@server.example.comm
ssh: server.example.comm: hostname nor servname provided, or not known     (sshでログインできない)

client$ scp yusuke@server.example.com
bash: scp: command not found                                               (サーバ上でリモートコマンドが実行できない)

sftp コマンドのエラーメッセージ

client$ sftp yusuke@server.example.comm
ssh: server.example.comm: hostname nor servname provided, or not known     (sshでログインできない)

client$ sftp yusuke@server.example.com
bash: sftp: command not found                                             (サーバ上でリモートコマンドが実行できない)
Request for subsystem 'sftp' failed on channel 0
Couldn't read packet: Connection reset by peer

rsync コマンドのエラーメッセージ

client$ rsync -a yusuke@server.example.comm:/opt/yusuke backup
ssh: server.example.comm: hostname nor servname provided, or not known     (sshでログインできない)
rsync: connection unexpectedly closed (0 bytes read so far)
rsync error: error in rsync protocol data stream (code 12) at io.c(189)

client$ rsync -a yusuke@server.example.com:/opt/yusuke backup
bash: rsync: command not found                                             (サーバ上でリモートコマンドが実行できない)
rsync: connection unexpectedly closed (0 bytes read so far)
rsync error: error in rsync protocol data stream (code 12) at io.c(189)

CVS のエラーメッセージ

client$ cvs -d :ext:yusuke@cvs.example.comm:/cvs checkout docs
ssh: cvs.example.comm: hostname nor servname provided, or not known     (sshでログインできない)
cvs [checkout aborted]: end of file from server (consult above messages if any)

client$ cvs -d :ext:yusuke@cvs.example.com:/cvs checkout docs
bash: cvs: command not found                                             (サーバ上でリモートコマンドが実行できない)
cvs [checkout aborted]: end of file from server (consult above messages if any)

Subversion のエラーメッセージ

client$ svn checkout svn+ssh://yusuke@svn.example.comm/svn/pyvnc2swf/
ssh: svn.example.comm: hostname nor servname provided, or not known     (sshでログインできない)
svn: Connection closed unexpectedly

client$ svn checkout svn+ssh://yusuke@svn.example.com/svn/pyvnc2swf/
bash: svnserve: command not found                                       (サーバ上でリモートコマンドが実行できない)
svn: Connection closed unexpectedly
コラム - 公開鍵認証がすべて安全とは限らない
公開鍵暗号技術はユーザ認証や電子署名に広く用いられていますが、 じつはこれを正しく使うのは簡単ではありません。使い方をまちがえると、 簡単にユーザのなりすましができてしまうことがあるのです。

たとえば初期の SSH プロトコルでは、クライアントは公開鍵認証のさいに サーバに対するレスポンスとして「秘密鍵の証明(K) + ユーザ名(U) + 現在時刻(T)」を 送っていました。現在時刻を送る必要があるのはなぜかといと、 もしここに現在時刻が含まれていない場合、第三者はこの情報を覚えておいて、 あとで同じ情報をサーバに送りつけることでログインできてしまうからです。 この情報は暗号化されているため、第三者が解読したり改ざんしたりすることはできませんが、 盗聴した情報を覚えておいてあとで再利用することを 「再送攻撃 (repetition attack)」と呼びます。

初期の SSH プロトコルはこの種の単純な再送攻撃を防ぐように設計されてはいましたが、 じつは別の再送攻撃を受けてしまう欠陥がありました。ユーザが異なるサーバ 1 と サーバ2 に対して 同じ公開鍵 A を使っていたと仮定します。第三者はユーザがサーバ 1 にログインする瞬間、 サーバ 2 にもチャレンジを送り、サーバ 1 に送られたのとまったく同じ レスポンスをサーバ 2 に送ることで、サーバ 2 にログインできてしまうのです。 第三者が暗号を解読する必要はありません。 これはレスポンスを受け取るサーバが、「そのレスポンスがどこに宛てられたものか」 を判定できないために起こる問題です。 したがって現在の SSH プロトコルでは、クライアントはレスポンスに受けとり先のサーバ名も含ませた 「秘密鍵の証明(K) + ユーザ名(U) + 現在時刻(T) + ログインするサーバ名(S)」を 送るようになっています。こうすればサーバは自分以外に向けられたレスポンスを検出し、 受け取りを拒否することができるからです。このような暗号の使い方に関する 一連の仕組みは「暗号プロトコル」と呼ばれ、現在もさかんに研究がされています。 しかしこの例から見ても、本当に安全な暗号プロトコルを考案するのは 困難な作業であることがわかります。


図 repetition-attack. 第三者がレスポンスを再利用する

参考文献: Martin Abadi and Roger Needham, "Prudent Engineering Practice for Cryptographic Protocols," SRC Research Report 125, 1994.


Yusuke Shinyama