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.
<voland@plab.ku.dk>
,
Dmitry Karasik <dk@plab.ku.dk>
,
John Polstra <jdp@polstra.com>
,
and Phil Regnauld <regnauld@ftf.net>
read the draft version of this
HOWTO and made useful suggestions and corrections, both factual
and stylistic.
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:
These
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.
This
access method allows a direct client connection to the server using
password authentication. The inetd
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
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, almost).
These methods allow secure direct client connection. The :gserver:
uses GSSAPI, the generic interface to network security systems such as
Kerberos 5. The :kserver:
methods uses the Kerberos version 4 network security system.
: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:
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)
UNIX syscall, then changes its own credentials to those of some
unpriviledged user, and exec
s
cvs pserver
.
A method implementing this technique to set up a CVS server is described here.
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
, 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.
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.
The computer should:
sshd
up and running;
cvs
installed (1.10 will
suffice);
cvs
installed;
ssh
installed;
The instructions below are fairly detailed to allow even very inexperienced sysadmin to setup the server.
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/nologinOf 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:
cvs:*:287:
mkdir -p /usr/local/site/cvsroot chown cvs.cvs /usr/local/site/cvsroot chmod 700 /usr/local/site/cvsrootIf 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 directory.
cd /usr/local/site/cvsroot mkdir bin dev etc tmp chown cvs.cvs bin dev etc tmp chmod 555 bin dev etc
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 projectnameIf you plan to serve several distinct repositories, repeat this step as necessary.
null
device in dev
.
cd dev mknod null c 2 2 chown 0.0 null chmod 666 null cd ..
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.cFind 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
passwd
and group
files.
We need some passwd
and group
files in
/usr/local/site/cvsroot/etc
directory.
cd etc vi master.passwdNote the absence of '/' above. Add the line
cvs::287:287::0:0:CVS account:/:/bin/cvsThe shell line can be anything, but it is better if nobody including
cvs
program itself can write to it. Save the file.
vi groupAdd the line
cvs:*:287:Save the file. Now run
pwd_mkdb -d . master.passwd cd ..
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.
cd projectname/CVSROOT vi passwdIf you are planning to provide anonymous read-only access to the projectname repository, add the following line:
cvs::cvsFor every non-anonymous developer add the line of the form:
developerusername:encryptedpassword:cvsWhere encryptedpassword is obtained from the cleartext password (which either yourself or a particular developer has chosen) with the standard system
crypt
(3)
function. If you do not know how to obtain encrypted version of a
password yourself, download this program,
and compile it:
cd directory/with/ppw.c cc -o ppw ppw.c -lcryptIt 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.
cd /usr/local/site/cvsroot/projectname/CVSROOT vi writersAdd the line of the form
developerusernamefor 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
cvs.cvs.
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.
cd CVSROOT vi writersAdd the lines to this file as described above and save the file. Issue the commands:
cvs add writers cvs commit -m initial cd .. cvs -Q release -d CVSROOT rm -rf CVSThen 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.
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.cInstall 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/
.
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).
Add the following line to /etc/inetd.conf
file:
cvspserver stream tcp nowait root /usr/local/site/sbin/run-cvs run-cvsand save the file.
Choose the port value. I use 2410. Add the port description into
/etc/services
file:
cvssshpserver 2410/tcp #CVS super-duper secure network serverThen add the following line to
/etc/inetd.conf
file:
cvssshpserver stream tcp nowait root /usr/local/site/sbin/run-cvs run-cvs
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.
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/binNow 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/zzhThe 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.
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:
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
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 : denyOf course you have to put your real server DNS name (or IP address) there.
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
.
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 yesand restart
sshd
:
kill -HUP `cat /var/run/sshd.pid`
The server setup has been completed.
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/binNow you a ready to go. To test the setup, run
scvs -d :pserver:developername@server.host.server.domain/projectname loginIf 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.
Enjoy.
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.
If you have any questions or suggestions, write E-mail to me using this address: Anton Berezin <tobez@tobez.org>.
Strangely, the online CVS manual is located elsewhere.
The instructions on setting up chrooted CVS pserver (no ssh tunnelling) can be found on www.unixtools.org.
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.