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.rolf
can contribute theCasandrix
project but not to thePortman
project). With these instructions,rolf
can 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 forcvsowner
is 6000, and the gid forcvs
is 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
cd
to 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
chroot
system 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-cvs
Then copy this somewhere where Ordinary People can't run it, since will end up being run as
root
byinetd
In my case, I put it into /usr/local/sbin/run-cvs.
- Set up the
chroot
environment. This involves duplicating just enough of the unix directory hierarchy to satisfy the program. Thechroot
system call 'hoists' a given directory to act as/
. IN our calse,/home/cvsowner/cvs-server-root
will 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/group
and put this in it:cvs::350:- create
/home/cvsowner/cvs-server-root/etc/passwd
and put this in it:cvsowner:*:6000:350::: cvs:hlAmN0pdL98yo:6000:350:::- create
/home/cvsowner/cvs-server-root/etc/nsswitch.conf
and 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 -HUP
yourinetd
.
- 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/passwd
and 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
readers
with 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
cvswrappers
to 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/passwd
file: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/passwd
file. 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 theSystemAuth
parameter 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. Usingtruss
I 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 $