OpenSSH: Cygwin での /dev/tty 誤認による SSH_ASKPASS 機能不全
Tagged:  •  

ssh の man では:

tty を持たない代わりに、 DISPLAY および SSH_ASKPASS 環境変数が設定されている場合、 SSH_ASKPASS により指定されるコマンドを用いて、 パスフレーズの問い合わせを行う

とありますが、 OpenSSH と Cygwin の組み合わせによっては、 この仕様通りの振る舞いとならない場合があります。

以下、OpenSSH 4.6 と Cygwin 1.5.24 の組み合わせでのソース調査/動作検証について述べます。

SSH_ASKPASS を利用するか否かの判定は、 OpenSSH でのパスフレーズ問い合わせ関数 read_passphrase()(readpass.c) において以下のように実装されています。 最終的に use_askpass が 1 となった場合にのみ、 SSH_ASKPASS が利用されます。

if (flags & RP_USE_ASKPASS)
    use_askpass = 1;
else if (flags & RP_ALLOW_STDIN) {
    if (!isatty(STDIN_FILENO)) {
        debug("read_passphrase: stdin is not a tty");
        use_askpass = 1;
    }
} else {
    rppflags |= RPP_REQUIRE_TTY;
    ttyfd = open(_PATH_TTY, O_RDWR);
    if (ttyfd >= 0)
        close(ttyfd);
    else {
        debug("read_passphrase: can't open %s: %s", _PATH_TTY,
              strerror(errno));
        use_askpass = 1;
    }
}
SSH_ASKPASS 利用の判定

ssh コマンド実行における秘密鍵のパスフレーズ問い合わせ (sshconnect2.c で定義される load_identity_file() からの起動) の際には flag 引数には 0 が設定されているため、 上記コードでは最後の else 節が実行対象となります。 _PATH_TTY マクロには /dev/tty が設定されていますので、 /dev/ttyopen できない = tty が無い場合に use_askpass が 1 となり、 SSH_ASKPASS が利用されます。

ここまでは man ssh に記述された仕様通りと言えるでしょう。

しかし、Cygwin 環境では、 tty を持たない状況であっても /dev/ttyopen は常に成功してしまうらしく、 tty の有無を適切に判定できないようです。 結果、use_askpass は絶対に 1 にはなりません

以上の事から、 Cygwin 環境では SSH_ASKPASS によるパスフレーズ問い合わせは行われないもの、 と考えた方が良いでしょう。

追記:

win-ssh-askpass の作者のサイトでも、 この障害に関する記述がありました。

2004年02月27日付けの記述ですから、 随分前から現状のままなようです。