Ключевые слова:chroot, cvs, (найти похожие документы)
From: Anton Berezin <firstname.lastname@example.org>
Date: Mon, 9 Dec 2003 14:31:37 +0000 (UTC)
Subject: CVS сервер с шифорванием и в chroot окружении (англ.)
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
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
ThisHOWTO was written with the assumption that the server will operate on
Vadim Belman <email@example.com>, Dmitry Karasik <firstname.lastname@example.org>, John
Polstra <email@example.com>, and Phil Regnauld <firstname.lastname@example.org> read
the draft version of this HOWTO and made useful suggestions and
corrections, both factual and stylistic.
CVS (http://www.cyclic.com/) is the most popular version control system in the free
software community, used by Netscape, *BSD, many Linux projects, and
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
Currently, CVS has several methods of doing this:
* :ext: and :server: methods.
access methods make use of a remote shell rsh or (:ext: method only)
a replacement, such as the secure shell (SSH).
The developer accessing the repository using this method must have
a shell account on the machine where the repository is located.
* :pserver: method.
access method allows a direct client connection to the
server using password authentication. The inetd
(http://www.freebsd.org/cgi/man.cgi?query=inetd&apropos=0&sektion=8) daemon on the
server machine starts the command cvs pserver when it receives a
TCP connection on a specific port (usually port 2401). All
communication between the client and the server goes using the
CVS (http://www.loria.fr/~molli/cvs/doc/cvsclient_toc.html) protocol.
This method does not require every developer to have an account on
the server box, but no communication over the network is
encrypted, including passwords which are sent as cleartext (well,
* :gserver: and :kserver: methods.
These methods allow secure direct client connection. The
uses GSSAPI, the generic interface to network
security systems such as Kerberos 5.
The :kserver: (http://www.loria.fr/~molli/cvs/doc/cvs_2.html#SEC34) methods
uses the Kerberos version 4 network security system.
The :pserver: method is quite convenient for implementing remotely
accessible CVS repositories, but its major drawback is that it is very
Two ways to increase the security of :pserver: are suggested:
* Running CVS server in chrooted jail.
One of the main problems with cvs pserver is the fact that the
developer accessing the repository can in fact gain an access to
any file on the server system. This situation gets worse if the
developer has read-write access to the repository; in this case it
is possible that he/she will have the ability to write any file
owned be the user the pserver runs as. But anyway, even read
access to your system can be bad enough!
The standard solution for this type of services is to use an
intermediate program that first carries out a chroot(2) (http://www.freebsd.org/cgi/man.cgi?query=chroot&apropos=0&sektion=2) UNIX
syscall, then changes its own credentials to those of some
unpriviledged user, and execs (http://www.freebsd.org/cgi/man.cgi?query=exec&sektion=3&apropos=0) cvs pserver.
A method implementing this technique to set up a CVS server is
described here. (http://www.unixtools.org/cvs/server-how-to.html)
* Using SSH tunnelling feature.
The second major problem with the cvs pserver is that all data
transferred during the CVS remote session is unencrypted.
The :gserver: and :kserver: access methods do not have this
problem, if setup properly. However, I do not consider them here
--- this HOWTO is only concerned with :pserver: access method.
Luckily, the popular secure replacement of rsh, ssh, (http://www.ssh.org/) has a
feature called TCP port forwarding, also known as tunnelling.
The idea is that ssh client allocates a socket listening to the
specified port on the local machine, and any connection made to
this local port (normally from localhost) is automatically
forwarded to the remote side over an encrypted channel. If you
have never used this feature but you are a user of ssh, chances
are that you have used it anyway without knowing it --- ssh, in
its most typical configuration, automatically forwards all X11
connections this way.
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:
* be connected to the Internet;
* have operational C compiler with standard libraries;
* have sshd up and running;
* have recent enough version of cvs installed (1.10 will suffice);
* ideally be running or able to run a firewall software.
Requirements for the client
Any UNIX or Windows NT machine with the Internet connection that has:
* cvs installed;
* ssh installed;
* Perl (http://www.perl.com/) 5 interpreter installed.
Requirements for the administrator
The administrator should:
* have root privileges on the server machine;
* have basic understanding of CVS workings;
* be able to tweak hard-coded paths and host names in C and Perl
* be able to compile and install C programs.
The instructions below are fairly detailed to allow even very
inexperienced sysadmin to setup the server.
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
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:
Of course, you might choose a different home directory for the cvs
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 (http://cuba.xs4all.nl/~tim/) TimeWaster.
Edit /etc/group file using your favorite text editor, and add the
2. Create repository directory structure.
+ First, create cvs user home directory, if you have not
created it already:
mkdir -p /usr/local/site/cvsroot
chown cvs.cvs /usr/local/site/cvsroot
chmod 700 /usr/local/site/cvsroot
If you would like to have less restricted permissions for the
cvs user home directory, do so.
The CVS server will be chroot'd right into cvs user home
directory. It is trivial to modify the steps below if you
would like to make a jail in a subdirectory of the home
+ Next, create subdirectories necessary for the proper jail
mkdir bin dev etc tmp
chown cvs.cvs bin dev etc tmp
chmod 555 bin dev etc
3. Create CVS repository.
For a project called projectname, create a repository in a
usual (http://www.loria.fr/~molli/cvs/doc/cvs_2.html#SEC23) 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.
mknod null c 2 2
chown 0.0 null
chmod 666 null
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), (http://www.freebsd.org/cgi/man.cgi?query=initgroups&apropos=0&sektion=3) which uses syscall
setgroups(2) (http://www.freebsd.org/cgi/man.cgi?query=setgroups&apropos=0&sektion=2) internally, likes to spit out error messages on
stderr in case of trouble. CVS server uses initgroups(3) (http://www.freebsd.org/cgi/man.cgi?query=initgroups&apropos=0&sektion=3)
unconditionally, though it should better not do it in our setup.
We will edit server.c file:
- 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:
cp /usr/obj/usr/src/gnu/usr.bin/cvs/cvs/cvs /usr/local/site/cvsroot/bin
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
Note the absence of '/' above. Add the line
The shell line can be anything, but it is better if nobody
including cvs program itself can write to it. Save the file.
Add the line
Save the file. Now run
pwd_mkdb -d . master.passwd
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.
+ Manual creation.
If you are planning to provide anonymous read-only access to
the projectname repository, add the following line:
For every non-anonymous developer add the line of the form:
Where encryptedpassword is obtained from the cleartext
password (which either yourself or a particular developer has
chosen) with the standard system crypt(3) (http://www.freebsd.org/cgi/man.cgi?query=crypt&apropos=0&sektion=3) function. If
you do not know how to obtain encrypted version of a password
yourself, download this program (http://www.prima.eu.org/tobez/sources/ppw.c),
and compile it:
cc -o ppw ppw.c -lcrypt
It is important that you compile and run this program on the
very same machine on which CVS server will be installed.
Launch this program as ./ppw md5 if your system passwords are
MD5-based. If you have DES passwords, launch it as ./ppw des.
If you have some other password system, you are on your own
at this step.
If you don't know what kind of passwords your local
crypt(3) function supports, you might want to have a look
at the /etc/master.passwd file. If the password field for
user accounts starts with $1$, you have MD5-based passwords.
If there is no $ sign at the beginning of the password field,
you have DES passwords. Otherwise, you have something else.
Save the passwd file.
Add the line of the form
for every developer who will have the write access to the
projectname repository. Save the file.
Do not forget to chown the passwd and writers files to
+ Checkout and commit.
This method is better than the previous one because you save
the history of changes made to writers. But you have to use
manual creation method for passwd file anyway.
As root, cd to some (preferably empty) directory and issue
the following command:
cvs -d /usr/local/site/cvsroot/projectname checkout .
The current copy of the whole repository will be checked out.
Add the lines to this file as described above and save the
file. Issue the commands:
cvs add writers
cvs commit -m initial
cvs -Q release -d CVSROOT
rm -rf CVS
Then go back to /usr/local/site/cvsroot/projectname/CVSROOT
and change the owner of the files back to cvs. Note then you
will not need to do it later, when the system will be fully
operational --- you will simply use remote checkouts and
commits instead of doing this locally as root.
8. Compile and install chroot wrapper.
Download this program (http://www.prima.eu.org/tobez/sources/run-cvs.c)
and modify it according to the instructions in the source code (this program
is a modified for FreeBSD version of the wrapper suggested here).
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).
+ Using default CVS port.
Add the following line to /etc/inetd.conf file:
cvspserver stream tcp nowait root /usr/local/site/sbin/run-cvs run-cvs
and save the file.
+ Using different port.
Choose the port value. I use 2410. Add the port description
into /etc/services file:
cvssshpserver 2410/tcp #CVS super-duper secure network server
Then add the following line to /etc/inetd.conf file:
cvssshpserver stream tcp nowait root /usr/local/site/sbin/run-cvs run-cvs
In either case, restart the inetd daemon:
kill -HUP `cat /var/run/inetd.pid`
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 (http://www.prima.eu.org/tobez/sources/zzh.c)
(again, a slightly modified version of
the original Tim (http://cuba.xs4all.nl/~tim/scvs/) 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:
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
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:
+ Using ipfw firewall.
This method is just plain great if you are already using ipfw
on the server machine.
Just disable TCP connections to your run-cvs port (2401, or
2410 and 2401, see step 9) coming through external
interfaces, like in this example:
ipfw add 2000 deny log tcp from any to any 2401 via fxp0
ipfw add 2000 deny log tcp from any to any 2410 via fxp0
+ Using TCP wrappers-enabled inetd.
In recent versions of FreeBSD the inetd daemon has built-in
TCP wrappers support. In even more recent versions (>= 3.3)
everything is controlled by a single file, /etc/hosts.allow.
Here is what you put at the beginning of this file:
run-cvs : localhost : allow
run-cvs : server.host.server.domain : allow
run-cvs : ALL : deny
Of course you have to put your real server DNS name (or IP
You will have to restart inetd with -w switch in order to
have TCP wrappers enabled. Also put inetd_flags="-w" into /etc/rc.conf.
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
and restart sshd:
kill -HUP `cat /var/run/sshd.pid`
13. That's it!
The server setup has been completed.
UNIX client setup
Download scvs Perl program (http://www.prima.eu.org/tobez/sources/scvs)
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 (http://cuba.xs4all.nl/~tim/scvs/) TimeWaster.
Do not forget to change the shebang line (#!/usr/bin/perl) if
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 :pserver:email@example.com/projectname 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 (http://sourceware.cygnus.com/cygwin/download.html)
Unix Compatibility toolkit. You will also have
to edit scvs a bit more, since the paths will almost definitely be
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 <firstname.lastname@example.org>.
The Cyclic (http://www.cyclic.com/) 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
(http://www.unixtools.org/cvs/server-how-to.html) CVS pserver (no ssh
tunnelling) can be found on www.unixtools.org. (http://www.unixtools.org/)
I also used Tim (http://cuba.xs4all.nl/~tim/) TimeWaster's page describing
the setup (http://cuba.xs4all.nl/~tim/scvs/) 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 (http://www.freebsd.org/) project website was my source of online UNIX manual
pages referenced in the text.