たまーにsshで直接コマンドを実行する事があるのだが、この場合だと擬似端末(pty)が有効にならない。 こうなると、authorized_keysなどで実行できるコマンドを制限している際、擬似端末が無いと挙動がおかしくなるようなプログラムを実行させる時にちょっと困る事がある。

blacknon@BS-PUB-UBUNTU-01:~$ env | grep -i tty
SSH_TTY=/dev/pts/0
blacknon@BS-PUB-UBUNTU-01:~$ ssh blacknon@bs-pub-ubuntu-02
blacknon@bs-pub-ubuntu-02's password: 

blacknon@BS-PUB-UBUNTU-02 (´ ;ω;`):~$ env | grep -i tty
SSH_TTY=/dev/pts/6
blacknon@BS-PUB-UBUNTU-02 (´ ;ω;`):~$ exit
ログアウト
Connection to bs-pub-ubuntu-02 closed.
blacknon@BS-PUB-UBUNTU-01:~$ ssh blacknon@bs-pub-ubuntu-02 'env | grep -i tty'
blacknon@bs-pub-ubuntu-02's password: 
blacknon@BS-PUB-UBUNTU-01:~$ ssh -t blacknon@bs-pub-ubuntu-02 'env | grep -i tty'
blacknon@bs-pub-ubuntu-02's password: 
SSH_TTY=/dev/pts/6
Connection to bs-pub-ubuntu-02 closed.

上のような感じで、sshからコマンドを指定して接続する際に-tオプションを付与しない場合、 SSH_TTYが払い出されていないのが分かる。 クライアント側でsshコマンドにエイリアスを定義すればその場では解決するのだけど、サーバ側で擬似端末の使用を強制させる場合はどうすれば良いんだろなと思ったので調べてみた。

で、残念ながらsshd自体には擬似端末を強制するオプションは無いみたい(クライアント側で端末がない場合を考慮しているのかな?)なので、他の方法で対応する必要があるようだ。

当初は.sshrcで処理できないかと思ったが、bashの子プロセスとしてキックされているため(当たり前の話だが、親プロセスはkillできない)ため断念。 あまりきれいな方法とは言えないが、sshd側で以下のようなスクリプトを作成し、/bin/bash等のラッパースクリプトとしてssh実行時にキックさせることで、pesudo-ttyを強制させるという方法を取ってみた。 以下、サンプルスクリプト。

#!/bin/bash
if [ ${#SSH_TTY} -eq 0 ];then
    echo "please use pseudo-tty"
    exit
fi

LOGINSHELL=$SHELL
if [ "$LOGINSHELL" = "$0" ];then
    LOGINSHELL="/bin/bash"
fi

if [ ${#@} -eq 0 ];then
    $LOGINSHELL
else
    args=($@)
    unset args[0]
    eval $LOGINSHELL -c \"${args[@]}\"
fi

後は、強制的に使わせるプログラムをスクリプト内で指定して実行させてやればいい。