Anonymous CVS access via ssh

Because the design and the security ramifications of CVS's pserver scare me, I do not offer traditional anonymous cvs access to my CVS repository. However, you can access it using an anonymous CVS over ssh method that I've hacked together.

It's pretty easy to use this - just as easy as using pserver I think. There are two methods you can use; for either method, you will need this file.

  1. Download the file, make it executable, put it somewhere, say, ~/bin/sshanoncvs. Then set the CVS_RSH environment variable to point to it and use cvs as you normally would. For example, just run this command to check out all of mooix:
    SSH_AUTH_SOCK= CVS_RSH=~/bin/sshanoncvs cvs -d :ext:cvs@cvs.kitenet.net:/home/cvs/repository checkout mooix
    
  2. Or you can just use the file as a ssh key file without making it executable. Download it, set its permissions to 600, and put it in ~/.ssh/sshanoncvs. Then add the following to your ~/.ssh/config:
    Host cvs.kitenet.net
    User cvs
    IdentityFile ~/.ssh/sshanoncvs
    ForwardAgent no
    ForwardX11 no
    Compression yes
    
    Then just set CVS_RSH=ssh and checkout as normal:
    
    SSH_AUTH_SOCK= CVS_RSH=ssh cvs -d :ext:cvs@cvs.kitenet.net:/home/cvs/repository checkout mooix
    
Note that either of the two methods above require you be able to use ssh 2. if you are stuck with ssh 1, you can use method #2, just use this file instead.

How this works

The basic idea is to use CVS's standard rsh method of accessing repositories. But since rsh is insecure, it uses ssh instead. Sshd can be configured so people connecting to an account using a specific authentication key are only allowed to run one pre-defined command, and cannot use ssh to do anything else on the server. Another similar use of ssh is by the Debian project's push-mirroring scheme, which is explained here.

To make this work, everyone who wants to access the server has to have a copy of the "private" ssh key. Once you have the key, you can cause the command to be run on the remote server by telling ssh to use the key as its identity file. Since ssh 2 uses nicely formatted textual keys as its private keys, I was able to embed one inside a simple shell script that runs ssh, telling it to use the same shell script as its identity file.

CVS is told to use the sshanoncvs script as a replacement for rsh, so when you tell cvs to access the remote repository, it runs it, enters "cvs server" into what it thinks is a shell on the remote host, and expects to be connecting to a cvs server on the remote end. From there on out the client side is completly normal CVS.

How to set up a similar server

On the server side, you need a dedicated user for anonymous cvs, I call mine just "cvs". This user should not be able to log in, set their password entry to "*" in /etc/passwd. They do need to have a valid login shell however.

The user needs to have a normal ssh key pair generated for them. After running ssh-keygen -t dsa (specify an empty password), copy .ssh/id_dsa.pub to .ssh/authorized_keys2 and prepend this text to the beginning of the line in that file:

no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command="/usr/bin/cvs server"
One that is set up, any one who tries to ssh in as that user with the proper "private" key will be dumped right into cvs server and will have to way to get out or do port forwarding or exploit ssh in other ways.

Setting up the repository

Once you have all this set up, you're almost there, but there is one more stumbling block. CVS by default wants to have write access to directories in a repository before checking anything out of them so it can write lock files. This won't work for anonymous cvs, because the user you created cannot be allowed to write to your repository (unless you want anonymous read+write cvs!). Luckily cvs can be told to write the lock files elsewhere. Just edit CVSROOT/config and add a "LockDir=/some/dir" line. Then make the directory you specified, and allow your anonymous cvs user (plus anyone else who needs to be able to access your repository) to write to it. You will also need to fiddle with the permissions of the cvs history file, or delete it.

Is it really secure?

We're pretty sure that the method of using ssh to allow "cvs server" and only "cvs server" to be executed works as planned. After that, we enter the murky realm of the cvs client protocol, and how secure that is, is a matter of some debate.

First of all, be aware that any repository the dedicated cvs user can access, can be accessed by any remote user. The cvs protocol does not allow limiting the remote user to a given repository; they can use what ever cvs root directory they can find. If you have private repositories on the server, you need to protect them with file permissions.

I have been told that if your ssh server is configured to enable the sftp subsystem, ssh ignores the constraints in the authorized_keys file, and so remote users will be able to see your entire filesystem. So don't do that (and make sure that your distribution isn't enabling it by default).

Other than that, it should be as secure as any other anonymous cvs setup.