OPTIONS
PROPFIND
+
"
2009/01/11
僕はこれまでに Mac OSX の Apache を何度もインストールし直している。もっと正確に言えば、僕が愛用しているサーバは Plan 9 で動いており、僕はそのサーバの上で、僕が設計した Web サーバである Pegasus (http://plan9.aichi-u.ac.jp/pegasus/) を動かしている。僕は Pegasus の開発のために時々 Apache を動かして実験する必要に迫られる。従って実験が終われば Apache は用済みになって、そしてまた忘れた頃になって Apache を動かしに行く。今回もそうだ。
今回は Pegasus の WebDAV スクリプトを Perl から Lua に書き換えた。書き換えるだけではなく、ついでに全体のロジックを見直そうと思った。そこで僕は Apache の WebDAV はどのように行っているかを確認しようとしたのだ。これまでは、また初めから僕の記憶を頼りに Apache の再設定を行って来たが、そろそろ僕も記憶力が悪くなっており、この際、次の事を考えて記録を採りましょうと、このメモを書き出した。
Apache は Mac Mini (以下 mmac と言う)にインストールされている。OSX のバージョンは Leopard(10.5) である。過去 G4 Power Mac (以下 pmac) に Apache をインストールした記憶はあるが、 mmac にインストールした事があるか否かの記憶はない。
OSX には標準的に Apache がインストールされており、最低限の機能であれば「システム環境設定」の「共有」を開いて「Web 共有」にチェックマークを付けるだけで Web のサービスが開始される。動作の確認は mmac からブラウザで http://localhost/ にアクセスし「あなたの予想に反して、このページが見えているでしょうか?」のページが見えていれば OK。
当然の事であるが、他のコンピュータからも mmac の名前でアクセスできるようにするためには、それらのコンピュータに mmac を登録する必要がある。
さて「Web 共有」にチェックマークを付けると httpd が動き出す。この事はターミナルから
-bash$ ps -ax|grep httpd 2974 ?? 0:00.42 /usr/sbin/httpd -D FOREGROUND 2978 ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND 3002 ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND 3032 ttys000 0:00.00 grep httpd -bash$
で確認できる。
使用中の httpd のバージョンは
-bash$ /usr/sbin/httpd -v Server version: Apache/2.2.8 (Unix) Server built: Mar 4 2008 21:37:02
つまりこの場合「Apache/2.2.8」である。
ところでどうして httpd が3つも動いているの? (この問題は後回し* )
さてアクセスに成功すると「あなたの予想に反して、このページが見えているでしょうか?」のページが現れるが、このページには Apache のマニュアルへのリンクがある。ホスト名が設定されていないなら
http://localhost/manual/
であるが、僕の場合には
http://mmac/manual/
である。
僕の mmac を見ると Apache の基本設定ファイルである httpd.conf が
/private/etc/httpd/httpd.conf
と
/private/etc/apatch2/httpd.conf
の2カ所にある。いやこの事に気付いたのは後のことで、僕は httpd/httpd.conf
の方を変更していて、「なんで変更が反映されないの?」と悩んでいたのである。どうやら
/private/etc/apatch2/httpd.conf
の方が使われているのだ。
この内容の主なものは
ServerRoot "/usr" Listen 80 ServerAdmin you@example.com #ServerName www.example.com:80 DocumentRoot "/Library/WebServer/Documents" ErrorLog /private/var/log/apache2/error_log CustomLog /private/var/log/apache2/access_log common
ここで "ServerRoot
" の値 "/usr
" は httpd.conf
の中に現れるファイルの相対パスで指定されているパス名に作用し、"ServerRoot
" で指定された値(このケースでは "/usr
" )を前に付けて解釈する。実際にはこれが活用されているのは LoadModule
であり、例えば
LoadModule authn_file_module libexec/apache2/mod_authn_file.so
とあるのは、このモジュールの場所が
/usr/libexec/apache2/mod_authn_file.so
であることを意味する。実際にこの場所にモジュールが存在するのが確認できる。
先に
http://localhost/
で動作確認できると言ったが、その時に現れたメッセージ「あなたの予想に反して、このページが見えているでしょうか?」は確かに "DocumentRoot
" で指定された "/Library/WebServer/Documents
" の中の "index.html.ja.iso2022-jp
" の内容そのものである。
実験レベルでは httpd.conf の標準設定を変える必要はあまりない。実際の運用では
ServerAdmin you@example.com
#ServerName www.example.com:80
は現実に即して変更する必要がある。
Apache のリスタートは apachectl で行う。
/usr/sbin/apachectl restart
apachectl に関する詳しい解説は
に載っている。
OSX を使っていると、Mac の平均的なユーザを意識した、システムファイルに対する過剰なまでの保護が鼻につく。
例えば /private/etc/apatch2/httpd.conf
を OSX 付属のテキストエディタで編集できない。UNIX のパーミッションの設定で可能なはずなのにである。
この問題はもっと根深いらしい。次の結果がそれをよく表している。
-bash$ cp httpd.conf /tmp -bash$ emacs /tmp/httpd.conf -bash$ cp /tmp/httpd.conf . cp: ./httpd.conf: Permission denied -bash$ pwd /private/etc/apache2 -bash$ ls -l httpd.conf -rw-rw-r-- 1 root arisawa 17614 Sep 24 2007 httpd.conf -bash$ ls -ld . drwxrwxr-x 9 root arisawa 306 Nov 20 2007 . -bash$
つまり TextEdit.app だけではなく UNIX の標準的なコマンドである cp でもダメなのだ。
僕の嫌なのは OSX ではセキュリティモデルがはっきりしていないことだ。UNIX のようで UNIX ではないのが嫌だ。ただ実際問題として httpd.conf を tmp にコピーして、それをエディタで編集し、その結果を cp で元に戻すのは、悪い変え方ではない。ただその場合には cp は root 権限で行わなくてはならないが...
さて WebDAV に向かってまっしぐらに進む事にする。
/private/etc/apatch2/httpd.conf
の中に dav に関する若干の設定がある。
#Include /private/etc/apache2/extra/httpd-dav.conf
と書いてあるが、これのコメントを外す必要がある。("#
" の削除)
これで
/private/etc/apache2/extra/httpd-dav.conf
が dav に関する設定ファイルとして取り込まれる。さてこの中に
DavLockDB "/usr/var/DavLock" Alias /uploads "/usr/uploads" <Directory "/usr/uploads">
などの記述があるが、"/usr/....
" とあるのは、サーバのこの場所に LockDB ファイルや、アップロードするファイルを置く事を意味する。つまりこの場所がサーバ上のファイルの置き場所になる。また
Alias /upload "/usr/uploads"
とあるのは、クライアントからは
http://mmac/uploads
のようにして URL でアップロードの場所を指定することを意味する。("mmac
" は WebDAV のサーバマシン)
今回僕は、まあ実験に過ぎないので、
/private/etc/apache2/uploads
を作り、そこをアップロードファイルの置き場所にした。またロックデータペースは
/private/etc/apache2/davlock
に置く事にした。だから
DavLockDB "/private/etc/apache2/davlock" Alias /uploads "/private/etc/apache2/uploads" <Directory "/private/etc/apache2/uploads">
としたのであるが、"DavLockDB
" に関しては間違っていた。(後に解説する)
認証などに関する五月蝿いものは当面外す。
<Directory "/private/etc/apache2/uploads"> Dav On Order Allow,Deny Allow from all #AuthType Digest #AuthName DAV-upload # You can use the htdigest program to create the password database: # htdigest -c "/usr/user.passwd" DAV-upload admin #AuthUserFile "/usr/user.passwd" # Allow universal read-access, but writes are restricted # to the admin user. #<LimitExcept GET OPTIONS> # require user admin #</LimitExcept> </Directory>
OPTIONS
さて次のデータをサーバに送ってやる。WebDAV のクライアントは、最初に OPTIONS
から入るので、ここでも OPTIONS
から入る。
term% connect tcp!mmac!80 OPTIONS /uploads/ HTTP/1.1 translate: f User-Agent: Microsoft-WebDAV-MiniRedir/5.1.2600 Host: mmac Content-Length: 0 Connection: close
ここに
connect tcp!mmac!80
は UNIX ではほぼ
telnet mmac 80
だと思ってよい。(connect は僕が Plan9 の為に作った簡単なツールで telnet よりもシンプルである。)
応答は
HTTP/1.1 200 OK Date: Sun, 11 Jan 2009 03:10:08 GMT Server: Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.7l DAV/2 DAV: 1,2 DAV: <http://apache.org/dav/propset/fs/1> MS-Author-Via: DAV Allow: OPTIONS,GET,HEAD,POST,DELETE,TRACE,PROPFIND,PROPPATCH,COPY,MOVE,LOCK,UNLOCK Content-Length: 0 Connection: close Content-Type: httpd/unix-directory
サーバは "/uploads
" が WebDAV 用である事をちゃんと認識している。
Apache は、クライアントが
OPTIONS /uploads HTTP/1.1
とやるとリダイレクションをクライアントに指示する。これはマイクロソフト系のクライアントに対しては問題で、"httpd-dav.conf
" の中を見ると、ブラウザ毎にリダイレクションの指示をしないようにできるらしい。このような複雑さが発生するのは、実は Apache の作り込みに若干の問題を抱えているからである*。
PROPFIND
term% connect tcp!mmac!80 PROPFIND /uploads/ HTTP/1.1 User-Agent: WebDAVFS/1.4.1 (01418000) Darwin/8.8.1 (i386) Accept: */* Content-Type: text/xml Depth: 0 Content-Length: 161 Connection: close Host: mmac <?xml version="1.0" encoding="utf-8"?> <D:propfind xmlns:D="DAV:"> <D:prop> <D:getlastmodified/> <D:getcontentlength/> <D:resourcetype/> </D:prop> </D:propfind>
応答は
HTTP/1.1 207 Multi-Status Date: Sun, 11 Jan 2009 03:27:29 GMT Server: Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.7l DAV/2 Content-Length: 554 Connection: close Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8"?> <D:multistatus xmlns:D="DAV:" xmlns:ns0="DAV:"> <D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/" xmlns:g0="DAV:"> <D:href>/uploads/</D:href> <D:propstat> <D:prop> <lp1:getlastmodified>Sat, 10 Jan 2009 05:15:25 GMT</lp1:getlastmodified> <lp1:resourcetype><D:collection/></lp1:resourcetype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> <D:propstat> <D:prop> <g0:getcontentlength/> </D:prop> <D:status>HTTP/1.1 404 Not Found</D:status> </D:propstat> </D:response> </D:multistatus>
ここまで来れば僕の目標はほぼ達成しているし、また実用的に使いたい場合にはサーバ保護に必要なセキュリティ上の設定をすればよい。(実はそうでもなかった)
どうやらファイルのアップロードに失敗しているようなので、小さなファイル(たった6文字のファイル)をアップロードしてみた。
term% connect tcp!mmac!80 PUT /uploads/b.txt HTTP/1.1 User-Agent: WebDAVFS/1.4.1 (01418000) Darwin/8.8.1 (i386) Accept: */* Content-Length: 6 Connection: close Host: mmac Hello
応答
HTTP/1.1 500 Internal Server Error Date: Sun, 11 Jan 2009 06:39:50 GMT Server: Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.7l DAV/2 Content-Length: 535 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>500 Internal Server Error</title> </head><body> <h1>Internal Server Error</h1> <p>The server encountered an internal error or misconfiguration and was unable to complete your request.</p> <p>Please contact the server administrator, you@example.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.</p> <p>More information about this error may be available in the server error log.</p> </body></html>
エラーログ
The locks could not be queried for verification against a possible "If:" header. [500, #0] Could not open the lock database. [500, #400] (13)Permission denied: Could not open property database. [500, #1]
いったいこれは何だ。ネットでこのメッセージをクグってみると、あった。
どうやら僕は "DavLockDB
" で指定されたパスの意味を取り間違えていたらしい。ネットの記事によると、このパスはファイル名でもディレクトリ名でもないらしい。そこで次のように書き直してみた。
DavLockDB "/private/etc/apache2/davlock/LockDB"
大切な事は "davlock
" が、("/tmp
" のように)どのプロセスからも書き込み可能になっていることらしい。
そこで
chmod 777 /private/etc/apache2/davlock
としておいたら、"Internal Server Error
" がクリアされた。そして "davlock
" の中に次の2つのファイルが生成されていた。
-rw-r--r-- 1 _www nobody 0 Jan 11 16:32 LockDB.dir -rw-r--r-- 1 _www nobody 0 Jan 11 16:32 LockDB.pag
である。設定ファイル "httpd-dav.conf
" の中に "DavLockDB
" の件が少し説明されていたが、具体的に何が生成されるのかは書かれていなかった。この2つが生成される事が分かるように書いてあれば、もっと対応は楽だったと思われる。
そして、僕はもっと早くからモヤモヤした気分を整理しておくべきであった。それは httpd が誰のプロセスかと言うプログラムを理解する上での基本問題である。
# ps -lax ... 0 31856 1 4000 0 31 0 77948 3416 - Ss 2e9b250 ?? 0:01.07 /usr/sbin/httpd -D FOREGROUND 70 31857 31856 100 0 31 0 77948 1736 - S 4eba2b0 ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND 70 31858 31856 100 0 31 0 77948 1768 - S 4eb9720 ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND ...
3つの内の最初の httpd は root 権限(uid 0)で、そして残りの2つは uid 70 である。第3フィールドから分かるように uid 70 のプロセスは uid 0 のプロセスから生成されている。そして uid 70 とは "/etc/passwd
" を見るに
_www:*:70:70:World Wide Web Server:/Library/WebServer:/usr/bin/false
となっている。つまりプロセスのオーナーは "_www
" だ。だから "LockDB.dir
" も "LockDB.pag
" もオーナーは "_www
" となっている。
以上の事から次の極めて大切な事が判明する: "davlock
" は "_www
" による書き込みを可能にしておく必要があり、ログファイルもアップロード用のディレクトリ "uploads
" もまた然りである。
僕は httpd が nobody の権限で動いていると誤解していたので、"davlock
" も "uploads
" も "log
" も正しくオーナーの設定をしていない。正しくは
chown _www davlock
あるいは
chown _www:_www davlock
である。セキュリティを上げたければ後者を採用すれば良いが、窮屈なのでグループに関しては便利さを重視した方が良いだろう。
僕は何年か前に OSX の WebDAV の動作を調べ、酷評してきた。何しろ「非効率で重くて実用にならないではないか」と。当時は Tiger の時代だったと思う*。しかし今回の Apache との組み合わせで使ってみた限り(今は認証部分を外しているが)気持ちよく使えるではないか。(少なくとも LAN 内で接続され、強力なサーバーだと) 速いし、安定しているし十分に実用になる。どこが改善されたのか、じっくり調べてみたい。
さて $HOME/Sites
の index.html
には「ここはあなた専用の Web サイトです」と書かれている。この内容はブラウザからは
http://mmac/~arisawa/
で見えるはずである。しかし
404 Forbidden
でアクセスが拒否された。error_log
には
(13)Permission denied: access to /~arisawa/ denied
となっている。念のために $HOME/Sites
までのパスのパーミッションを調べた。
drwxr-xr-x+ 5 arisawa arisawa 170 Mar 1 2007 Sites -bash$ cd Sites -bash$ ls -l total 16 drwxr-xr-x 5 arisawa arisawa 170 Mar 1 2007 images -rw-r--r-- 1 arisawa arisawa 6161 Mar 1 2007 index.html
うん、ここまでは異常はない。しかし
-bash$ pwd /Users drwxrwx---+ 33 arisawa arisawa 1122 Dec 1 08:26 arisawa -bash$ ls -ld drwxr-xr-x 6 root admin 204 Nov 20 2007 .
えー、/Users/arisawa
へは httpd が侵入できない! アクセスが拒否されるのは当然である! そこで
chmod 775 $HOME
しかしやっぱり
404 Forbidden
である。但し今度はエラーログが異なる。
client denied by server configuration: /Users/arisawa/Sites/
どうやら Apache の設定ファイルの内容に問題があるらしい。
次のキーワードでクグってみる。
osx apache Sites forbidden
とうやら僕がここで出会ったのと同じ問題が多くの Mac ユーザを悩ましているらしい。そしてどうやら結論は
???
らしい。ソースコードが必要だなあ...
+
"さて、ls -l の出力でしばしば
drwxrwx---+ 33 arisawa arisawa 1122 Dec 1 08:26 arisawa
のように、許可ビットの最後に "+
" が付いているのがある。これは何だ? Mac を使っていると、僕の知識の外にあるようなものがしばしば現れる。これもその一つであり、僕はこれまでいい加減にしてきた。良く似たものとして "@
" がある。
マニュアルで調べると
-bash$ man ls
...If the file or directory has extended security information,
the permissions field printed by the -l option is followed by a '+' character.
"+
" に関する話題はネット上には
で取り上げられている。このサイトでは
man lis
に次のように書かれていると書いてある。
If the file or directory has extended attributes,
the permissions field printed by the -l option is followed by a '@' character.
Otherwise, if the file or directory has extended security information,
the permissions field printed by the -l option is followed by a '+' character.
つまり古いマニュアルには "@
" の説明が含まれていたのだ。
なお "+
" に関しては chmod の "ACL MANIPULATION OPTIONS" に詳しい解説がある。この解説によると
拡張パーミッションの内容は
ls -le
で分かる。
-bash$ pwd /Users -bash$ ls -le drwxrwxr-x+ 33 arisawa arisawa 1122 Dec 1 08:26 arisawa 0: group:everyone deny delete -bash$ pwd /Users/arisawa -bash$ ls -le drwxr-xr-x+ 5 arisawa arisawa 170 Mar 1 2007 Sites 0: group:everyone deny delete
どうやら Win 的な ACL を "+" によってサポートしようとしているらしい。