lighttpd + fastcgi + suExecでtracを動かす

tracは、チケットやWikiのデータを触ったり、subversionに触ったり、結構色々するプログラムである。httpdを動かしているユーザーにこれらの権限を与えたくないのでsuexecすることにする。

調べて分かったこと

  • lighttpdのパッケージにはsuexecは含まれていない。

  • apacheからsuexecのソースを持ってきてコンパイルする。

  • Debianなら、apache-commonかapache2-commonをインストールすれば入る。

  • lighttpd自体にはapacheの様にsuexecのパスを知っていたり、configuration次第で透過的にsuexecしてくれたり、そういう機能は無い。

  • fastcgiプログラムごとに、bin-pathに指定するしかない。

See Also:

やってみる

とりあえず、lighttpdのドキュメントに書いてあるphpの場合に合わせてやってみた。各pathはdebian sargeの場合。私はapache2-commonをインストールしたので実行ファイル名はsuexec2になってる。

起動スクリプトを用意

なんか、ドキュメントのやりかただとfastcgiプログラムごとに一々起動スクリプトが必要な気がするんだけど。

/usr/local/lib/trac/trac.fcgi.suexec にこんな感じのファイルを書いた。で、実行ビットを立てる。

#!/bin/sh

user=trac
group=trac

cd /var/www/trac
exec /usr/lib/apache2/suexec2 $user $group trac.fcgi

環境変数設定

/var/www/trac/trac.fcgi にこんな感じのものを置いた。suexecがコンパイル時規定の DOCUMENT_ROOT 外のスクリプトは拒絶するので、必ず /var/www 配下に置く。

#!/bin/sh
exec env TRAC_ENV_PARENT_DIR=/var/trac /usr/share/trac/cgi-bin/trac.fcgi

このファイルは必ず、実行したいユーザーとグループの所有にしておく。でないとsuexecが拒絶する。

lighttpdの設定

で、あとは、bin-pathにさっきの起動スクリプトを設定。

fastcgi.server = (
        "/trac" => (
                "trac" => (
                        "socket" => "/var/run/fastcgi/trac.sock",
                        "bin-path" => "/usr/local/lib/trac/trac.fcgi.suexec",
                        "check-local" => "disable",
                        "bin-environment" => (
                                "TRAC_ENV_PARENT_DIR" => "/var/trac"
                        ),
                        "min-procs" => 1,
                        "max-procs" => 4,
                        "idle-timeout" => 20
                )
        )
)

ちょっと直してみる

一応、上記がドキュメントに従った設定。でも、fastcgiプログラムごとに起動スクリプトを書くのは嫌な感じだ。で、こんなのを書いてみた。

/usr/local/lib/suexec/suexec.sh:

#!/bin/sh

if [ "_$PATH_TRANSLATED" = "_" ]; then
        exit 1
fi

DIR=`dirname $PATH_TRANSLATED`
COMMAND=`basename $PATH_TRANSLATED`

USER=`stat -c '%U' $PATH_TRANSLATED`
GROUP=`stat -c '%G' $PATH_TRANSLATED`

cd $DIR
exec /usr/lib/apache2/suexec2 $USER $GROUP $COMMAND

lighttpdの設定も直す。

fastcgi.server = (
        "/trac" => (
                "trac" => (
                        "socket" => "/var/run/fastcgi/trac.sock",
                        "bin-path" => "/usr/local/lib/suexec/suexec.sh",
                        "check-local" => "disable",
                        "bin-environment" => (
                                "PATH_TRANSLATED" => "/var/www/trac/trac.fcgi"
                        ),
                        "min-procs" => 1,
                        "max-procs" => 4,
                        "idle-timeout" => 20
                )
        )
)

/etc/init.d/lighttpd

なんか、suexec経由で走らせる様にしたら、lighttpdをstopするときにfastcgiプロセスが止まらずにinit(8)に引き継がれてしまう。止める直前に見てみるとfastcgiプロセスのPPIDはlighttpdになってるんだけど。このへんの挙動ってexecに影響されたっけ?

仕方がないから、/etc/init.d/lighttpdのstop処理部分をこんな風にしてみた。

   stop)
         log_daemon_msg "Stopping $DESC" $NAME
+         PID=`cat $PIDFILE`
+         SID=`ps -p $PID -o sid --no-headers`
         if start-stop-daemon --quiet --stop --pidfile $PIDFILE --exec $DAEMON; then
+                 PIDS=`ps -s $SID -o pid --no-headers`
+                 if [ "_" != "_$PIDS" ]; then
+                         kill -INT $PIDS > /dev/null
+                 fi
                 rm -f $PIDFILE
         log_end_msg 0
         else
         log_end_msg 1
         exit 1
     fi
         ;;