もともと、cvs は cvs を実行したユーザの権限を自由に使ってよいという思想で作られている(としか思えない)ため、サーバ側でアクセス制限を行う場合、 cvs 自身はあまり信用せず、外側で制限することが望ましい。実際、ドキュメントにはリポジトリをアクセスできるようにすることはシステムに比較的自由にアクセスできるようにすることになるかもしれないと警告されている。 (参考: grep 'system access' cvs.texinfo)
そのために、chroot を行なってサーバを実行し、万が一ユーザがサーバ側でコマンドを実行できる権限を手に入れたとしてもそもそもそのコマンドが存在しないようにする。また、chroot jail (chroot システムコールで制限したディレクトリ)内では十分に考慮してパーミッションを設定し、サーバが必要以上のファイルにアクセスできないようにする。
なお、pserver method での read-only アクセスは例外で、匿名アクセスでも問題ないように実装されている(はずである(が、信用できたものではないという意見もある))。
commit 時にそれを通知するメールを送る設定をする。ただし、次の要件を満たすようにする。
これらの要件を満たすために、SMTP で直接メールサーバと通信するようなプログラムを使う。
(commit 時にメールを送信するために) loginfo を使う場合は chroot jail 内に /bin/sh が必要である。なるべく安全性を高めるように、pdksh を使用し、restricted shell とする。 (restricted shell として動作させるための環境変数の設定は cvs コマンドに埋め込む。)
また、cvs から /bin/sh を通さずにコマンドを実行する場合には、コマンドに / が含まれていないことを確認する。
これらの対策により、PATH の外のコマンドが実行されないことを保証する。
commit 時のメールを送信するツールは、loginfo から起動されるが、 commit されるファイルが複数のディレクトリにまたがる場合、 loginfo はそれぞれのディレクトリ毎に起動される。したがって、素朴に毎回メールを送ると各ディレクトリ毎にメールが送信されるが、ここで 1回の commit についてメールを 1通だけ生成するために、 commitinfo を併用するということが行なわれる。 n個のディレクトリにまたがる commit が行なわれた場合、まず commitinfo が n回起動され、その後で loginfo が n回起動される。つまり、まず commitinfo の起動回数をカウントし、 loginfo の起動回数がそれと等しくなった時にメールを送るのである。
しかし、この方法は複数の commit が(時間的に)重ならない場合はうまくいくが、重なる場合には数え間違える可能性がある。そこで、個々の commit を区別するために、process group id が使用される。つまり、ジョブ制御を行なうシェルから起動した cvs およびその子孫のプロセスは unique な process group id を持つので、それをもとに個々の commit を区別し、正しく数えることができる。 (なお、親プロセスの process id を使うことはできない。 loginfo では /bin/sh 経由で呼び出されるため、親プロセスが /bin/sh となって cvs の process id が得られないためである。なお、loginfo で exec すればこの問題を避けられるが、 restricted shell では exec が使用不能なことが多いという問題がある。ただし、pdksh は例外的に restricted shell でも exec を使用可能なようである。)
そして、この方法は cvs を process group leader としないような形で起動した場合、うまく働かない。 pserver method はまさにこの状況にあてはまり、 cvs は inetd から起動され、すべての cvs プロセスが(inetd と)同じ process group id を持ち、個々の commit を区別できない。
この問題には、cvs が自分自身で process group leader になるよう修正して対処する。 (なお、pserver 経由で commit されないのならこの問題は起きない。)
cvsweb で annotate という機能を動作させるにはリポジトリをロックする権限(書き込み権限)が必要である。つまり、CGI にリポジトリの書き込み権限を与えなければならない。これを避けるには次の方法がある。
cvs はリポジトリ全体を取得する手段を提供していない。このため、手元にリポジトリを mirror することができない。そこで、CVSup により、リポジトリ全体を取得する手段を提供する。
なお、cvs client/server protocol によってリポジトリ(のほぼ)全体を取得することは不可能ではないように思われるが、いまのところそのためのツールは作られていないのではないかと思われる。
ssh 経由の anonymous アクセスを実現するには次の方法がある。
管理者権限とユーザ権限のそれぞれに対応したユーザ・グループを作る。
cvs:*:UID-for-cvs:GID-for-cvs:cvs user:/cvs/home/cvs:/bin/sh cvsadmin:*:UID-for-cvs-admin:GID-for-cvs-admin:cvs administrator:/cvs/home/cvsadmin:/bin/sh
cvs:*:GID-for-cvs:cvsadmin cvsadmin:*:GID-for-cvs-admin:
基本的に次の方針で設定する。
/cvs 以下にサーバに必要なファイルをおく場合、例えば次のように設定する。
dr-xr-sr-x cvsadmin cvsadmin /cvs (トップレベルディレクトリ) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot (chroot jail のトップディレクトリ) dr-xr-sr-x cvsadmin cvsadmin /cvs/home (cvs 関連ユーザのホームディレクトリをおくディレクトリ) lrwxrwxrwx cvsadmin cvsadmin /cvs/root -> chroot/cvs/root ($CVSROOT として :local:/cvs/root を使えるようにするトリック。省略可)
dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/cvs (chroot jail 内での /cvs) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/cvs/bin (cvs から実行可能なコマンドをおくディレクトリ) drwxrwsr-t cvsadmin cvs /cvs/chroot/cvs/root ($CVSROOT. stickey bit は /cvs/chroot/cvs/root/CVSROOT の rename を禁止するため。トップレベルの import を許可しないならば 755 でよい) drwxrwsr-t cvsadmin cvs /cvs/chroot/cvs/sample (他の $CVSROOT) lrwxrwxrwx cvsadmin cvsadmin /cvs/chroot/cvs/chroot -> .. (/cvs/chroot への参照を chroot 内外で同じものにするためのトリック) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/root (chroot jail 内での root ユーザのホームディレクトリ) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/cvs/home (chroot jail 内でのホームディレクトリをおくディレクトリ) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/cvs/home/cvs (cvs ユーザのホームディレクトリ) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/bin (実行可能なコマンドをおくディレクトリ) -r-xr-xr-x cvsadmin cvsadmin /cvs/chroot/bin/sh (chroot jail 内での /bin/sh. pdksh) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/dev (chroot jail 内での /dev) crw-rw-rw- cvsadmin cvsadmin /cvs/chroot/dev/null (null デバイス) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/etc (chroot jail 内での /etc) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/var (chroot jail 内での /var) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/lib (chroot jail 内での /lib) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/usr (chroot jail 内での /usr) dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/usr/lib (chroot jail 内での /usr/lib) drwxrwxrwt cvsadmin cvsadmin /cvs/chroot/tmp (chroot jail 内での /tmp)
drwxr-sr-x cvsadmin cvsadmin /cvs/home/cvsadmin (cvsadmin のホームディレクトリ) drwxr-x--- cvsadmin cvs /cvs/home/cvsadmin/sbin (通常ユーザには実行されたくないコマンドをおくディレクトリ) -r-sr-x--- root cvs /cvs/home/cvsadmin/sbin/cvs (setgid/initgroups/chroot/chdir/setuid/setpgid/環境変数の設定などを行なう特別仕様の cvs コマンド) -rwxr-xr-x cvsadmin cvsadmin /cvs/home/cvsadmin/sbin/cvs-pserver (--allow-root つきで cvs コマンドを起動するラッパー) drwxr-sr-x cvs cvs /cvs/home/cvs (cvs のホームディレクトリ) drwx------ cvs cvs /cvs/home/cvs/.ssh (cvs ユーザ用 ssh 設定ディレクトリ) -rw-r--r-- cvs cvs /cvs/home/cvs/.ssh/authorized_keys (comitter の公開鍵で cvs server を実行する設定ファイル)
ユーザデータベースを構成する。 OS によって異なるが、passwd(5), nsswitch.conf(5), pwd_mkdb(8) 等を参照して root と cvs を参照できるように構成する。一例: -r--r--r-- cvsadmin cvsadmin /cvs/chroot/etc/nsswitch.conf -r--r--r-- cvsadmin cvsadmin /cvs/chroot/etc/passwd
commitinfo, loginfo 用のコマンドの実行に必要なファイルを用意する。コマンドは /cvs/chroot/cvs/bin におき、その実行に必要なライブラリを適切な場所におく。 (cf. ldd(1))
一例:
-r-xr-xr-x cvsadmin cvsadmin /cvs/chroot/cvs/bin/cvs-commitinfo (commitinfo 用コマンド) -r-xr-xr-x cvsadmin cvsadmin /cvs/chroot/cvs/bin/cvs-loginfo (loginfo 用コマンド) -r-xr-xr-x cvsadmin cvsadmin /cvs/chroot/cvs/bin/www-update (www 更新用コマンド) -r-xr-xr-x cvsadmin cvsadmin /cvs/chroot/lib/libc.so.6 -r-xr-xr-x cvsadmin cvsadmin /cvs/chroot/lib/ld-linux.so.2 -r--r--r-- cvsadmin cvsadmin /cvs/chroot/lib/libnsl.so.1 -r--r--r-- cvsadmin cvsadmin /cvs/chroot/lib/libdl.so.2 -r--r--r-- cvsadmin cvsadmin /cvs/chroot/lib/libnss_files.so.2 -r--r--r-- cvsadmin cvsadmin /cvs/chroot/lib/libm.so.6 -r--r--r-- cvsadmin cvsadmin /cvs/chroot/lib/libcrypt.so.1 dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/usr/lib/ruby dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/usr/lib/ruby/1.4 dr-xr-sr-x cvsadmin cvsadmin /cvs/chroot/usr/lib/ruby/1.4/i386-linux -r--r--r-- cvsadmin cvsadmin /cvs/chroot/usr/lib/ruby/1.4/i386-linux/socket.so -r--r--r-- cvsadmin cvsadmin /cvs/chroot/usr/lib/ruby/1.4/i386-linux/etc.so drwxrwsr-x cvsadmin cvs /cvs/chroot/var/cvs-info -rw-rw-r-- cvs cvs /cvs/chroot/var/cvs-info/references
cvs -d /cvs/chroot/cvs/root init として作る。 (複数のリポジトリを提供する場合、$CVSROOT のテンプレートを用意しておくと便利である。) 一例: (注: cvs init によって作られるファイルのうち、興味深いものだけをあげてある。)
drwxrwsr-t cvsadmin cvs /cvs/chroot/cvs/root ($CVSROOT. stickey bit は /cvs/chroot/cvs/root/CVSROOT の rename を禁止するため。トップレベルの import を許可しないならば 755 でよい) drwxr-sr-x cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT drwxrwsr-x cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/Emptydir (cvs-1.10.7 以前に cvs init でリポジトリを作った場合にはこのディレクトリができないので、確実に作る) -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/loginfo (DEFAULT cvs-loginfo) -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/loginfo,v -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/commitinfo (DEFAULT cvs-commitinfo) -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/commitinfo,v -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/taginfo (ブランチ主体で開発が行なわれている場合、cvs-taginfo を作って設定すべきであろう。たぶん) -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/taginfo,v -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/modules -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/modules,v -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/config (SystemAuth=no, LockDir=CVSROOT/.lockdir) -r--r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/config,v -rw-rw-rw- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/history (誰でも書き込めるようにする) -rw-rw-rw- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/val-tags (誰でも書き込めるようにする) -rw-r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/readers -rw-r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/writers -rw-r--r-- cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/passwd (cvs では管理<em>しない</em>) drwxrwsrwt cvsadmin cvsadmin <a href="#lockdir">/cvs/chroot/cvs/root/CVSROOT/.lockdir</a> drwxrwsr-x cvsadmin cvsadmin <a href="#lockdir">/cvs/chroot/cvs/root/CVSROOT/.lockdir/CVSROOT</a> dr--r--r-- cvsadmin cvsadmin <a href="#lockdir">/cvs/chroot/cvs/root/CVSROOT/.lockdir/CVSROOT/.lockdir</a> drwxrwsr-x cvs cvs /cvs/chroot/cvs/root/www -r--r--r-- cvs cvs /cvs/chroot/cvs/root/www/index.en.html,v
cvs ユーザ以外でも(ロックを伴う)read only な操作を行なえるようにするために LockDir を設定する。これはとくに cvsweb で必要になる。なお、cvs-1.10.8 では CVSROOT/config 内の LockDir には絶対パスしか使用できないので、 cvs を修正しない場合は絶対パスで指定する。 (なお、複数のリポジトリを用意する場合、$CVSROOT からの相対パスで指定できるように変更するとリポジトリごとに別の設定にしなくて済むので便利である。) また、cvsadmin 以外による CVSROOT の checkout を防ぐために、 /cvs/chroot/cvs/root/CVSROOT/.lockdir/CVSROOT を cvsadmin 以外には書き込めないディレクトリとする。さらに、 cvsadmin によって CVSROOT を checkout したときに無限ループに陥ることを防ぐために、 /cvs/chroot/cvs/root/CVSROOT/.lockdir/CVSROOT/.lockdir を書き込み不能な空のディレクトリにする。
drwxrwsrwt cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/.lockdir drwxrwsr-x cvsadmin cvsadmin /cvs/chroot/cvs/root/CVSROOT/.lockdir/CVSROOT