Chrooted tunnelled read-write CVS server

Note 20 April 2000

I have been working on a much-improved version of scvs program, called tcvs, which is in fact a full-fledged many-to-many cvs proxy. As soon as I finish writing tcvs (and I unfortunately do not have time for this project until July 2000), I will rewrite this HOWTO. I will also write another version of this document, tailored for some Linux distribution.


This HOWTO describes the steps necessary to setup a very network-secure CVS server, allowing anonymous read-only repository access as well as read-write access for a relatively trusted group of developers. It is not necessary for these developers to have shell accounts on the server box.

The setup described here uses the combination of two well-established techniques, namely running CVS pserver in a chroot jail, and only allowing access to the server from the localhost itself, through a SSH tunnel.

This HOWTO was written with the assumption that the server will operate on FreeBSD.

Table of Contents

Requirements for the server
Requirements for the client
Requirements for the administrator
Server setup
Client setup
     UNIX client setup
     Windows NT client setup


Vadim Belman <>, Dmitry Karasik <>, John Polstra <>, and Phil Regnauld <> read the draft version of this HOWTO and made useful suggestions and corrections, both factual and stylistic.


CVS is the most popular version control system in the free software community, used by Netscape, *BSD, many Linux projects, and others.

Initially, CVS was designed to provide version control for a group of developers working on a single machine. There was a CVS repository somewhere on the file system, and every developer working on a project had to have a read-write access to the repository files, including auxiliary files used by cvs program itself.

With the advent of the Internet the need for accessing remote repositories arose.

Currently, CVS has several methods of doing this:

The :pserver: method is quite convenient for implementing remotely accessible CVS repositories, but its major drawback is that it is very insecure.

Two ways to increase the security of :pserver: are suggested:

The combination of these two techniques is the subject of this HOWTO.


When I installed CVS repository for PRIMA project, I tried to find a kind of tutorial about how to set up a fairly secure CVS server allowing the remote access to the repository without giving away the accounts on the CVS box. The second requirement was to allow the developers from Windows NT machines to access the repository.

Since I was not able to find such a tutorial, I decided to write it myself. So this HOWTO is in fact the by-product of that installation.

Requirements for the server

This HOWTO assumes that the server will run FreeBSD version 3.3 or later. It does not mean, of course, that it is not possible to setup similarly configured server on a UNIX box running different operating system. It simply means that the exact steps below are for FreeBSD.

The computer should:

Requirements for the client

Any UNIX or Windows NT machine with the Internet connection that has:

Requirements for the administrator

The administrator should:

The instructions below are fairly detailed to allow even very inexperienced sysadmin to setup the server.

Server setup

  1. Add cvs user and group.

    Since CVS server will not run as root, we need to create a special cvs user. I use UID 287, username cvs, and GID 287, groupname cvs. Of course you are free to use any UID you like, but remember that using existing real or system UIDs and GIDs is generally a bad idea.

    Needless to say that this operation must be performed as root. To add new robotic users I find it easier to use vipw(8) directly; in vipw editor, add the following line:

    cvs:*:287:287::0:0:CVS account:/usr/local/site/cvsroot:/sbin/nologin
    Of course, you might choose a different home directory for the cvs user.

    Also note, that ``password disabled'' star and /sbin/nologin shell are here temporarily. Subsequently, they will be replaced with ``no password'' void and a special ``sleeping beauty'' shell, written by Tim TimeWaster.

    Edit /etc/group file using your favorite text editor, and add the following line:

  2. Create repository directory structure.

  3. Create CVS repository.

    For a project called projectname, create a repository in a usual way, as follows.

    cvs -d /usr/local/site/cvsroot/projectname init
    chown -R cvs.cvs projectname
    If you plan to serve several distinct repositories, repeat this step as necessary.

  4. Create a null device in dev.

    cd dev
    mknod null c 2 2
    chown 0.0 null
    chmod 666 null
    cd ..
  5. Compile static version of cvs program.

    Ideally, you should have the complete sources of your FreeBSD system installed, since this makes this process so much easier. If it is not an option for you, do this step in some other way.

    Before proceeding, you will need to change just one line of CVS sources. The trouble is, that for some unknown reason, FreeBSD library function initgroups(3), which uses syscall setgroups(2) internally, likes to spit out error messages on stderr in case of trouble. CVS server uses initgroups(3) unconditionally, though it should better not do it in our setup.

    We will edit server.c file:

    cd /usr/src/contrib/cvs/src
    vi server.c
    Find the line
          initgroups (pw->pw_name, pw->pw_gid);
    and comment it out:
          /* initgroups (pw->pw_name, pw->pw_gid); */
    Save the file.

    Now compile and install the cvs program:

    cd /usr/src/gnu/usr.bin/cvs
    make NOSHARED=yes
    cp /usr/obj/usr/src/gnu/usr.bin/cvs/cvs/cvs /usr/local/site/cvsroot/bin
    cd /usr/local/site/cvsroot
    chown cvs.cvs bin/cvs
    chmod 500 bin/cvs
  6. Create fake passwd and group files.

    We need some passwd and group files in /usr/local/site/cvsroot/etc directory.

    cd etc
    vi master.passwd
    Note the absence of '/' above. Add the line
    cvs::287:287::0:0:CVS account:/:/bin/cvs
    The shell line can be anything, but it is better if nobody including cvs program itself can write to it. Save the file.

    vi group
    Add the line
    Save the file. Now run
    pwd_mkdb -d . master.passwd
    cd ..
  7. Create passwd and writers files.

    The actual access control is done by CVS itself. In order to make use of this, we need to create passwd and writers files in the CVSROOT directory in every CVS repository we are serving.

    There are two ways of doing this for writers file, and I will show them both. Only the first method is working for passwd file due to possible security issues.

  8. Compile and install chroot wrapper.

    Download this program and modify it according to the instructions in the source code (this program is a modified for FreeBSD version of the wrapper suggested here).

    Compile it:

    cc -o run-cvs run-cvs.c
    Install it somewhere, make it executable, owned by root.wheel, and make sure nobody except root is able to modify the binary. I keep mine in /usr/local/site/sbin/.

  9. Setup inetd.

    Here you will have to make an important choice. If you ever going to use ``remote'' access to repositories locally from the box where the server operates, you will need to choose a TCP port different from CVS default (2401).

    In either case, restart the inetd daemon:
    kill -HUP `cat /var/run/`
    If for whatever reason you will have to restart inetd completely, make sure you have rather empty environment. In particular, having HOME variable set when you run inetd will hit you badly later.

  10. Installing the ``sleeping beauty'' shell.

    Download this program (again, a slightly modified version of the original Tim TimeWaster's source). Compile it and install it somewhere. I use /usr/local/site/bin/:

    cc -o zzh zzh.c
    chown 0.0 zzh
    chmod 555 zzh
    mv zzh /usr/local/site/bin
    Now use vipw(8) again and change the original cvs user line to this:
    cvs::287:287::0:0:CVS account:/usr/local/site/cvsroot:/usr/local/site/bin/zzh
    The sleeping beauty shell's job is to control the SSH tunnel connection. It is there basically to prevent the nasty ``The following connections are still open'' message from SSH on the client side.

  11. Preventing direct CVS server connections.

    The SSH tunnel will work well and good, but now we need a way to disable somehow normal CVS pserver operations. There are several ways to do it, and here I will describe two of them:

  12. Enabling sshd empty passwords.

    Since the cvs account has no password, you have to enable SSH connections with empty passwords. Put this line into your /usr/local/etc/sshd_config file:

    PermitEmptyPasswords yes
    and restart sshd:
    kill -HUP `cat /var/run/`
  13. That's it!

    The server setup has been completed.

Client setup

UNIX client setup

Download scvs Perl program and make modifications to it. All the tunable variables are at the top of the file, with comments. Again, this is the slightly modified version of the program developed by Tim TimeWaster.

Do not forget to change the shebang line (#!/usr/bin/perl) if necessary.

Install it somewhere in your system path. I use /usr/local/site/bin/:

chown 0.0 scvs
chmod 555 scvs
mv scvs /usr/local/site/bin
Now you a ready to go. To test the setup, run
scvs -d login
If everything is set correctly up, you will be presented with a prompt for developername CVS password.

After entering the password, you continue to use scvs program as if it was a normal cvs command: you can checkout, update, commit files, and execute other CVS commands.


Windows NT client setup

The process is very similar to that required to setup UNIX client. There are some quirks, however; the proper setup of ssh client for Windows NT, so that connection forwarding is supported, can be non-trivial. At the very least, you should be using the most recent version of Cygwin Unix Compatibility toolkit. You will also have to edit scvs a bit more, since the paths will almost definitely be very different.

Write me if you wish I present more detailed information here.


The method described allows to setup fairly secure CVS server.

If you have any questions or suggestions, write E-mail to me using this address: Anton Berezin <>.


The Cyclic Software web site contains useful information about CVS, and many references to other CVS-related sources.

Strangely, the online CVS manual is located elsewhere.

The instructions on setting up chrooted CVS pserver (no ssh tunnelling) can be found on

I also used Tim TimeWaster's page describing the setup of SSH tunnel for CVS pserver access (the page is a bit unclear at times, at least for my level of UNIX system administration).

The FreeBSD project website was my source of online UNIX manual pages referenced in the text.