シェルスクリプトの自動運転でsudoのタイムアウトを設ける

シェルスクリプトの自動運転でsudoのタイムアウトを設ける

シェルスクリプトの自動運転でsudoを使うには、NOPASSWDで、かつ !requiretty な設定をすればよいのだが、うっかりsudoできないユーザーでこれを実行してしまった場合、いつまでもパスワードの入力待ちで止まってしまう。これに気付かず後続処理が走ってしまうのは怖いのだが、 /etc/sudoers.d/ユーザー名 のファイルをgrepして判断しようにもsudoを使わないといけない(rootで実行すればよいとか言わないで><)。

そこでぽぽは考えましたよ。「(ぴこーん!) 最初にsudoで何かしらの無害なコマンドを叩かせて終了ステータスを捕まえればええんやぁ!」

というわけでこんな処理をスクリプトの最初に仕込んでやればよい。

[amazonjs asin=”4904807480″ locale=”JP” title=”シェルスクリプトマガジン vol.51″]

sudoコマンドの前にtimeoutコマンドを挟む

SUDO_EXIT_STATUS=$(timeout 1 sudo echo -en "" > /dev/null ; echo $?)
if [ ! ${SUDO_EXIT_STATUS} = 0 ];
then
  echo "sudoコマンド使えまへん"
  exit 1
fi

sudoコマンドの前にtimeoutコマンドを挟んでおけば、sudoersにいないユーザーがこれを実行しようとすると必ずパスワード入力待ちになる。つまり、人間の入力待ちで必然的にタイムアウトする仕組みを利用している。sudoersにいるユーザーといないユーザーで手動実行結果を比較してみるとこうなる。

[nullpopopo@marina ~]$ timeout 1 sudo echo -en "" > /dev/null ; echo $?
0

[nullpopopo@marina ~]$ sudo su - marina
最終ログイン: 2017/12/05 (火) 06:50:08 JST日時 pts/0

[marina@marina ~]$ timeout 1 sudo echo -en "" > /dev/null ; echo $?

あなたはシステム管理者から通常の講習を受けたはずです。
これは通常、以下の3点に要約されます:

    #1) 他人のプライバシーを尊重すること。
    #2) タイプする前に考えること。
    #3) 大いなる力には大いなる責任が伴うこと。

[sudo] marina のパスワード:
124

sudoersに設定のあるnullpopopoユーザーがechoコマンドを実行して正常終了している、つまり終了ステータスが0であるのに対し、sudoersに設定のないmarinaユーザーはtimeoutコマンドで異常終了している、つまり終了ステータスが0ではない、ということである。

ちなみにbashの内部コマンドで : があるじゃないか、という声がどこかから聞こえてきたのでついでを言うと、 : は正常終了を返すコマンドであるので、(前段のtimeoutコマンドで異常終了するとはいえ)成否判定に用いるのは不適切である。かつ、bashの内部コマンドであるためPATHが通っていないので、終了ステータスを捕まえる以前に使いにくい。

[nullpopopo@marina ~]$ timeout 1 sudo : > /dev/null ; echo $?
sudo: :: コマンドが見つかりません
1

[nullpopopo@marina ~]$ timeout 1 : > /dev/null ; echo $?
timeout: コマンド `:' の実行に失敗しました: そのようなファイルやディレクトリはありません
127

だったら、echoでも吐いておけという判断になる。シェルスクリプトの自動実行で少しでもハマりポイントが減らせればこれ幸い。ね、簡単でしょう?

[amazonjs asin=”4798049050″ locale=”JP” title=”ちょっとだけLinuxにさわってみたい人のための Bash on Ubuntu on Windows入門”]