CVS server HOWTO

Written by Julio Merino.


Step by step setup


Introduction and Purpose (top)

This document explains how to setup a secure CVS server through SSH. The server will be running inside a chroot, so it will have its own set of users (independant from the rest of the system); this means that it is very secure.

Do not get confused. We will be talking a lot about SSH. This is because CVS is not working as a server itself; SSH does its job and passes commands to CVS when needed.

What is CVS? (top)

CVS stands for Concurrent Versions System. It is a version control system, which allows you to keep old versions of files (usually source code), keep a log of who, when, and why changes occurred, etc., like RCS or SCCS.

This document assumes a basic knowledge of CVS, so we will not explain any more about CVS's purpose. For more information, you can consult the cvs(1) manpage.

Step by step setup

Creating the chroot jail (top)

We will start setting up the basic directory structure needed for the chroot jail plus the required binaries. We will also add some auxiliary tools so that the chroot can be useful if we need it.

Lets start creating the directory structure, with their correct permissions. We will be using the /var/chroot/cvs directory in all the examples.

    # mkdir -p /var/chroot/cvs
    # cd /var/chroot/cvs
    # mkdir -p bin dev etc home lib libexec sbin tmp var
    # mkdir -p var/run var/chroot/sshd
    # ln -s . usr
    # chmod 555 home
    # chmod 1777 tmp

As you can see, we are using a small trick to make things easier: the usr subdirectory becomes a symlink to chroot's top directory. This will avoid binary disctintion.

Now we have to copy the required binaries (plus dynamic library loading stuff) inside this new directory structure:

    # cd /var/chroot/cvs
    # cp /bin/sh /usr/bin/cvs /usr/bin/passwd bin
    # cp /sbin/nologin /usr/sbin/pwd_mkdb /usr/sbin/sshd sbin
    # cp /etc/master.passwd /etc/group /etc/passwd.conf etc
    # cp /usr/libexec/ld.elf_so /usr/libexec/ libexec
    # cp -rf /etc/ssh etc

We are missing the device files. We will only create a subset of them, like this:

    # cd /var/chroot/cvs/dev
    # /dev/MAKEDEV std pty0 tty random

And at last, we need required shared libraries. Using ldd(1) and awk(1) it is fairly easy to get all of them inside the chroot:

    # cd /var/chroot/cvs
    # cp `ldd bin/* sbin/* | awk '{print $3}'` lib

Setting up users (top)

The server will only accept connections from users configured inside the chroot jail. Before users, we need to create their groups. We will edit the file etc/group (inside the chroot) that we have copied before and will remove everything that is useless. Aside from this, we will add a new group, cvs, which will hold all the users able to modify the CVS repository. An example:


We have added a single user to the cvs group, called committer. This user will have write access to the repository (as well as any other user in this group). Now it is time to create these users; edit the file etc/master.passwd (inside the chroot) removing everything that is useless. Here is the example:

    root:*:0:0::0:0:CVS administrator,,,:/root:/bin/sh
    sshd:*:16:16::0:0:& pseudo-user:/var/chroot/sshd:/sbin/nologin
    nobody:*:32767:39::0:0:Unprivileged user:/nonexistent:/sbin/nologin
    committer:*:1000:500::0:0:I am a committer,,,:/home:/bin/sh

This is the master password database. Everytime we modify this file, we need to recreate some other files. We can use these commands:

    # cd /var/chroot/cvs
    # pwd_mkdb -d /var/chroot/cvs etc/master.passwd
    # pwd_mkdb -d /var/chroot/cvs -p etc/master.passwd

Creating the cvsroot directory (top)

Now that users are configured, we can create the CVS repository directory, like this:

    # cd /var/chroot/cvs
    # mkdir -p cvsroot
    # chown 1000:500 cvsroot
    # chmod 775 cvsroot

Note that we are using numeric IDs to give permissions, as user/group names may not exist in our "real" system.

Setting up initial passwords (top)

Before continuing, we need to make sure that the chroot jail is configured properly (i.e., it contains everything needed). To do this, we will try to change user's passwords from inside the chroot. Do this:

    # chroot /var/chroot/cvs
    # passwd committer
    Changing local password for committer.
    New password: type password here
    Retype new password: retype password here
    # exit

Remember that you can tune the password cipher algorithm by configuring the file etc/passwd.conf inside the chroot jail.

Setting up the SSH server (top)

To access CVS we will be using a SSH server running inside the chroot. We need to make sure it does not conflict with any other SSH server in the same machine, so we will set it up. The first step is to generate some new keys (or copy the ones you already have):

    # cd /var/chroot/cvs/etc/ssh
    # /usr/bin/ssh-keygen -t rsa1 -b 1024 -f ssh_host_key -N ''
    # /usr/bin/ssh-keygen -t dsa -f ssh_host_dsa_key -N ''
    # /usr/bin/ssh-keygen -t rsa -f ssh_host_rsa_key -N ''

To avoid conflicts with other servers we need to change the port the server uses. Edit the file ssh_config in the directory you are and add this line: Port 11750 (use any port you want).

Starting the SSH server (top)

Everything is ready to start the SSH server, so we will do it now using the following command:

    # chroot /var/chroot/cvs /sbin/sshd

Add this line to your startup scripts if you want it to be started at system bootup.

Setting up the SSH client (top)

The client (in our example, the user committer) needs to setup his SSH client to properly connect to the server (i.e., the non-standard port). This is a simple step: each user who wants to connect to the server requires a file in his home directory, ~/.ssh/config with the following contents (between others that may already exist):

    Port 11750

And try to log in:

    $ ssh

The administrator must have configured a password for the committer user (inside the chroot). Otherwise, access will be denied.

Starting the CVS repository (top)

If everything is working fine we can initialize the CVS repository from the client. To make things simpler we will define some variables (it is a good idea to add them to user's profile):

    $ export
    $ export CVS_RSH=ssh

And now the real command!

    $ cvs init

Be happy if this works. Before doing anything else in with the repository, we will tune permissions by hand (we want the whole group to access the repository):

    # cd /var/chroot/cvs/cvsroot
    # find . -type d -exec chown jmmv:cvs {} \;
    # find . -type d -exec chmod 775 {} \;
    # find . -type f -exec chown jmmv:cvs {} \;
    # find . -type f -exec chmod 664 {} \;

And after this, everything is done! Have fun!

Anonymous CVS (top)

You can use this same configuration to setup an anonymous CVS server. Just be careful with write permissions and add a single user (called anoncvs, for example).