二〇一二年 皐月 四日 金曜日
■
CGI から sudo を使ってファイルに書き込み
[/links]
この記事は書かれてから1年以上経過しています。内容が古くなっている可能性があります。コメントの受付は終了しました。
私は現在 Lolipop のレンタルサーバーを利用しているが、ここは安いだけに耐障害性が不足しており、私は何度か痛い目にあった。そこで、仮想サーバーを1台まるごと借りるタイプのサービスに乗り換えることにした。
現在、ウェブサイトの移行作業を進めているが、1つ困ったことがあった。このブログは大本が Blosxom なので、データベースを使わず、各記事がファイルになっている。コメントがあると、CGI からファイルに書き込む。Lolipop では、Apache が suEXEC モードで動いているので、書き込むのは簡単だった。しかし、新しいサーバーでは、CGI の実行ユーザーがウェブサーバーなので、FTP でアップしたファイルにそのまま書き込むことができない。
ファイルのアクセス権を変えるという手もあるが、新しい記事をアップするたびに変更するのは面倒だ。ほかに、suEXEC を使う、データベースを使う、記事を書くのにも CGI を使うといった方法もあるが、いずれも大掛かりな作業になる。CGI から sudo を使って書き込みできれば簡単だと考えた。
そもそも、sudo でファイルに書き込むにはどうするか。すぐに思いついたのは次のような方法だが、これではうまくいかない。
sudo echo 書き込む内容 >> ファイル名
sudo を使っても、リダイレクトは元のユーザーの権限になる。調べてみると、tee を使えばよいことが分かった。
sudo でリダイレクト @ レピカ技術者ブログ
sudo でファイルに書き込む方法が分かったので、sudo を設定する。それには /etc/sudoers ファイルを編集するのだが、このファイルは編集を間違えると大変なことになるらしいので、ファイルを直接編集するのではなく、visudo というコマンドを使う。使い方は vi と同じだが、保存の前におかしなところがないかチェックしてくれる。
なお、私が借りているレンタルサーバーの OS である CentOS では、このコマンドにパスが通っていないらしく、私は探すのに手間取ってしまったが、私の環境では /usr/sbin にあった。
CGI から sudo を使う場合、tty 以外からでも使えるようにする必要がある。また、CGI からではパスワードの入力ができないので、パスワードを要求しないようにする。
CGI を root 権限で実行する @ あかぎメモ
私は、次の2行を加えた。
Defaults:apache !requiretty
apache ALL=(webadmin) NOPASSWD: /usr/bin/tee
「Defaults requiretty をコメントアウトする」と書いているサイトが多いけれど、それだとセキュリティー的に不安なので、ウェブサーバー(私の環境では apache)だけに tty 以外からのアクセスを許可している。また、パスワードなしで root 権限を許可するのもどうかと思うので、ウェブファイルの読み書きができるユーザーである webadmin を指定している。さらに、使用できるコマンドを tee に限定した。
さて、ユーザーが入力したコメントを CGI からシェルに渡すとなると、特殊文字をエスケープする必要がある。PHP なら、まさにその目的のための escapeshellarg() という関数があるが、これがやっていることは「文字列をシングルクオートで括り、既存のシングルクオートを全てクオート/エスケープします」ということなので、たとえば Perl なら次のようにすればよい。
my $file; #ファイル名
my $comment; #書き込む内容(適切な文字コードでエンコードしておく)
$comment =~ s/'/'"'"'/g;
qx(echo '$comment' | sudo -u webadmin tee -a $file) or die;
なお、エラーログに audit_log_user_command(): Connection refused と出るが、これは CentOS の「バグ」だそうで、無視してよいが、気になるなら sudo をアップデートすれば直るそうだ。
audit_log_user_command()にハマる @ なぜか数学者にはワイン好きが多い
[このカテゴリをまとめて読む。]
[最新の記事を読む。]
|