These instructions were inspired by the server how-to page over at unixtools.org.
The Problem
I wanted to set up CVS for both anonymous read-only access by anybody, as well as read-write access for anyone with proper authorization. I didn't set up seperate access controls (e.g.rolfcan contribute theCasandrixproject but not to thePortmanproject). With these instructions,rolfcan contribute to both projects. I didn't want to cope with the added complexity a finer grain of control would entail.I wanted something with a little more security than your standard CVS setup. Described here is a chroot'd environment, meaning that the cvs server runs in its own little protected "sandbox", which should keep most malicious goons at bay.
A Solution
These instructions are based on Solaris 2.6, but should be applicable to most unix variants.
- make a user to own everything. I used "
cvsowner". Give it a home directory. I'm using/home/cvsowner. I also made a seperate group for them,cvs. For example purposes the uid forcvsowneris 6000, and the gid forcvsis 350.For the instructions that follow, I presume you're logged in as
cvsowner
- Create the following directory structure:
/home/cvsowner/cvs-server-root/cvs-server-root/cvsweb /home/cvsowner/cvs-server-root/cvs-server-root/bin /home/cvsowner/cvs-server-root/cvs-server-root/dev /home/cvsowner/cvs-server-root/cvs-server-root/etc /home/cvsowner/cvs-server-root/cvs-server-root/lib /home/cvsowner/cvs-server-root/cvs-server-root/usr- Obtain and compile cvs. I used version 1.10.7, available from Cyclic Software
- unzip and untar the distribution
cdto the distribution directory./configure --prefix=/home/cvsowner/cvs-server-root
gmake
gmake install
The unixtools.org page said that they compiled it statically. I tried doing that, but was foiled several of the necessary Solaris libraries used symbols that only occured in shared libraries. oh well.
- Snarf run-cvs.c and compile it. This is a little program that Joseph Kizzier sent me that uses the
chrootsystem call. Modify it to match the user ID and group ID for yourcvsowner.
Here's how I compiled it:gcc run-cvs.c -o run-cvsThen copy this somewhere where Ordinary People can't run it, since will end up being run as
rootbyinetd
In my case, I put it into /usr/local/sbin/run-cvs.
- Set up the
chrootenvironment. This involves duplicating just enough of the unix directory hierarchy to satisfy the program. Thechrootsystem call 'hoists' a given directory to act as/. IN our calse,/home/cvsowner/cvs-server-rootwill become/as far as CVS is concerned.I'm presuming you have
sudo. If you don't have sudo, then consider everything done with command to have been done byroot
- make the /dev entries:
sudo mknod /home/cvsowner/cvs-server-root/dev/zero c 13 12 sudo mknod /home/cvsowner/cvs-server-root/dev/null c 13 2
- Copy over any shared libraries and make symlinks:
cd /home/cvsowner/cvs-server-root/lib cp /usr/lib/libsocket.so . ln -s libsocket.so libsocket.so.1 cp /usr/lib/libnsl.so . ln -s libnsl.so libnsl.so.1 cp /usr/lib/libsec.so . ln -s libsec.so libsec.so.1 cp /usr/lib/libc.so . ln -s libc.so libc.so.1 cp /usr/lib/libdl.so . ln -s libdl.so libdl.so.1 cp /usr/lib/libmp.so . ln -s libmp.so libmp.so.2 cp /usr/lib/nss_files.so.1 .- Symlink /usr/lib to point ot lib:
cd /home/cvsowner/cvs-server-root/usr ln -s cd /home/cvsowner/cvs-server-root/lib .- create
/home/cvsowner/cvs-server-root/etc/groupand put this in it:cvs::350:- create
/home/cvsowner/cvs-server-root/etc/passwdand put this in it:cvsowner:*:6000:350::: cvs:hlAmN0pdL98yo:6000:350:::- create
/home/cvsowner/cvs-server-root/etc/nsswitch.confand put this in it:passwd: files group: files- Now that we're done with the chroot environment, It's time to configure other aspects of the machine
- Add this to
/etc/services:cvspserver 2401/tcp- Add this to
/etc/inetd.conf:cvspserver stream tcp nowait root /usr/local/sbin/run-cvsand thensudo kill -HUPyourinetd.
- Now with all of that happy stuff done, it's time to actually configure your cvs installation:
- Create the repository:
cvs -d /home/cvsowner/cvs-server-root/cvsweb init(we usually have our CVSROOTs living at /cvsweb, hence the use of the name)
- create the passwd file for CVS (which is different than the /etc/passwd file).
Create/home/cvsowner/cvs-server-root/cvsweb/CVSROOT/passwdand put this in it:anonymous:dk8WOr2n1uZ3g:cvs(this password is "anonymous")
- Check out the CVSROOT somewhere to work on configuration files:
cd $HOME cvs -d /home/cvsowner/cvs-server-root/cvsweb checkout CVSROOT- creat the file
readerswith this content:anonymousand check it in. This says that the CVS username 'anonymous' has read-only access. everyone else has read/write access.See the Random Notes section below for some notes on passwords and
passwd
- (optional) edit
cvswrappersto include the Usual Binary Files (this prevents keyword expansion inside of binary files):*.gif -k 'b' *.jpg -k 'b' *.png -k 'b'Be sure to check this back in so that it will update the CVS config databases
- Add any users who have read/write access to
/home/cvsowner/cvs-server-root/etc/passwdfile:markd:laXnp91olPDyI:6000:350::: rolf:aoXnp91llDP0I:6000:350::: adadmin:rBNmheIl9sx1o:6000:350:::If you don't have any access to a program that will create the encrypted password entries, you can snarf my
pwcrypt.c. I had found a Perl script out of a book, but it didn't work correctly on Solaris.
- And then test your installation.
cvs -d :pserver:anonymous@the.machine.name:/cvsweb cvs login (enter password) cvs checkout CVSROOTIf this works, you're golden.Random Notes
Regarding passwords. CVS has two modes when checking usernames and passowrds. It looks in its local
$CVSROOT/CVSROOT/passwdfile. If it doesn't find the user in there (or the password doesn't authenticate), it can fall back and look in the system's /etc/passwd and compare the username/password against that, but only if theSystemAuthparameter is set to "yes".I've decided to do it this way, and take advantage of this fall-back effect. Only anonymous lives in the CVS
$CVSROOT/CVSROOT/passwd. All other cvs users live in the/etc/passwd(which is acutally/home/cvs-owner/cvs-server-root/etc/passwd).One 'feature' of CVS I discovered is that anyone with anonymous access can get the CVSROOT project and see the configuration. There's not a whole lot that can be gleaned from this, except that the passwd file has encrypted passwords, making it an easy target for some
L4M3 L3Et H4X0R, so with the authorized user passwords in the "/etc/passwd", the usernames and encrypted passwords are safely hidden away.There's two handy tricks I used to determine which set of libraries to use. I kept doing
sudo chroot /home/cvsowner/cvs-server-root /bin/cvs
until it stopped complaining about not finding libraries.I also had problems with cvs not being able to acquire the passwd entry for a given user. After a little grovelling around in the cvs sources, I discovered the system call
getpwnam()was failing. I wrote a little getpwnam.c program, and ran it under the Solaris programtruss, which shows a trace of all system calls. UsingtrussI was able to determine that it was missing yet another shared library.
RavenBlack dropped me an email with a handy Linux tip:Under Linux (not sure about this under any other OS) you can do "
ldd cvs" and get a list of the libraries cvs is going to require. I'm writing a setup script that makes a CVS repository in this chrooted manner (because I like the setup and it's a pain in the arse to do it again manually whenever I end up shifting to a different server), which sets up the proper chroot libraries thus:for f in `ldd /usr/bin/cvs | cut -d' ' -f3`; do cp "$f" lib doneThough that does rely on ldd having a very consistent output layout, and might be better done with a sed match rather than a cut.
$Id: chroot.html,v 1.3 2001/04/09 14:37:18 markd Exp $