Jed Reynolds
06/24/2003
Bellingham, WA

CVS in Jail

Summary

Many distributed software development projects need to use CVS as their version control software, and need to use it over the Internet without the overhead of a VPN. A secure manner to provide the CVS service is to host the CVS service such that it is chrooted and accessable only over SSH. Previously published methods of creating a chrooted CVS service typically require the compilation of a chroot indirection mechanism. This essay describes how to chroot a CVS service using the uan Manuel Casillas's Chroot Jail Project instead of compiling a chroot wrapper for the CVS server.

Motivations

Compiling a CVS wrapper places cvs configuration directives inside the binary. The only way to change those directives it thru recompilation. Such directives are clearly declarative and are intended to exist in isolation of the server binary, or compiled proxies. Using teh Chroot Jail, one achieves this in conjunction with the configurations possible using xinetd.

Requirements

Briefly: xinetd, chroot jail, cvs. Have those installed. You can use inetd but it's tougher; you'll get into managing hosts.allow and hosts.deny using tcpd if you do.

Installation

1) create the users that will be chrooted, set their home directories to the chroot directory
adduser -d /home/cvs -s /usr/local/bin/jail cvsuser

2) create the chrooted environment
mkjailenv /home/cvs
addjailsw /home/cvs
addjailsw /home/cvs -P


3) add the jailed user to the jailed environment
addjailuser /home/cvs /home/cvsuser /usr/bin/cvs cvsuser

Note that we've made the user's shell /usr/bin/cvs. (The full, unchrooted pathname would be /home/cvs/usr/bin/cvs.)

Next we want to configure xinetd. Add a "cvspserver" file to /etc/xinet.d/ with these contents:
service cvspserver
{
        disable         = yes
        flags           = REUSE
        socket_type     = stream
        wait            = no
        user            = cvsuser
        server          = /usr/local/bin/jail
        server_args     = -f --allow-root /home/cvsuser/blug-library pserver
        passenv         =
        log_on_failure  += USERID
        only_from       = 127.0.0.1
        bind            = 127.0.0.1
        nice            = 5
}

Note that we've made the binary invoked for that service the Jail wrapper. Now the service will automatically start the login shell, /home/cvs/usr/bin/cvs. Xinetd will automatically pass the server_args switches to the login shell (there's the magic).

Restart your xinetd.
If you have only an inet.d installation (no xinet.d), enter this line into your /etc/inetd.conf file:
cvspserver stream tcp nowait.400 cvsuser /usr/local/bin/jail \
    cvs -f --allow-root /home/cvsuser/blug-library pserver

To limit Internet clients from connecting directly to this service you will have to restrict access using iptables or using tcpd and configuring your hosts.allow and hosts.deny files. (I purposefully omit that here.)
These are the CVS configuration tasks:
1) create a repository
root# cd /home/cvs/home/cvsuser
root# cvs -d /home/cvs/home/cvsuser/blug-library init
root# chown -R cvsuser .


2) create user passwords in CVSROOT of the repository
root# cd blug-library/CVSROOT
root# htpasswd -bn user1 password1 >> passswd
root# chown -R cvsuser .

3) create "writers" file in CVSROOT listing all cvs accounts you care to have write access to the repository.
root# echo user1 >> writers
root# chown -R cvsuser .


Testing

On a separate machine, test creating your ssh tunnel. Next, set your CVSROOT like so:
:pserver:user1@localhost:/home/cvsuser/blug-library:

Next try a cvs login, login with "password1"
$ cvs login

Next try a cvs import of a file
$ touch test-file
$ cvs import blug-library VTAG RTAG

Conclusion

By using the Chroot Jail we're able to use xinetd to declaratively list the arguments to the cvs pserver, specifying which options (like --allow-root) to accept. Chroot Jail speeds up the creation of a chrooted environment, saving us time. Additionally, Chroot Jail releases us from the need to specially compile a staticly linked version of cvs, because Chroot Jail automatically copies library refrences discovered with ldd.

References

This is the Chroot Jail project.
http://www.gsyc.inf.uc3m.es/~assman/jail/
This is a CVS HOWTO.
http://www.prima.eu.org/tobez/cvs-howto.html
This is a guide to a typical Chrooted, Tunneled CVS server
http://www.netsys.com/library/papers/chrooted-ssh-cvs-server.txt
Likewise.
http://www.idealx.org/prj/idx-chrooted-ssh-cvs/dist/chrooted-ssh-cvs-server.html
The CVS Homepage.
http://www.cvshome.org