Enterprise Software

Remote control CVS

The Concurrent Versions System (CVS) is a remarkable tool for developers. This tool allows you to share your vision with other developers online. In order to do this, you need the proper tools. Vincent Danen is here to show you how to share your toys!

Vincent Danen has been dealing with the Concurrent Versions System for quite some time. During the time he has served as a programmer for Linux-Mandrake, CVS has become his best friend. Vincent has covered CVS a number of times for TechProGuild. Read more about CVS in these articles:


In the previous Daily Drill Downs in the source code management series, I've dealt primarily with installing and using the Concurrent Versions System (CVS). At this point, you should be familiar enough with CVS to understand its many benefits and use it with some degree of confidence.

In the last part of this series, “More control with CVS,” you learned how to use ssh to access CVS repositories by remote. This is the most secure method of accessing a CVS repository remotely. Unfortunately, while being the preferred method, it may not be the most realistic method. For instance, SourceForge is perhaps one of the biggest hosting repositories of source code for open-source software. One of the tools SourceForge relies heavily on is CVS for each of the developers on the site. For SourceForge to create user accounts for and provide shell access to everybody who wanted it would not only be unrealistic but also an invitation for disaster. Having many thousands of users with shell access on systems with heavy traffic is nothing short of insane. So what can you do if you are unable or unwilling to provide ssh access to all of the users who want to access your CVS repository?

In this Daily Drill Down, I will look at two alternatives. The first is pserver, the password server that comes with CVS. Using pserver is similar to accessing CVS remotely via ssh but without the need for creating user accounts for everyone. Unfortunately, pserver is not very secure because it transmits all data (source code, passwords, etc.) in clear text across the Internet.

The other option is a program called cvsweb, a Web interface for CVS. This program provides solely read-only access to the CVS repository, but it may be adequate for your needs if you simply want to share your source with others and not allow open participation in your projects.

pserver
Before setting up pserver, make sure that you have your CVS repository built. It does not necessarily need to contain any modules, but the CVSROOT directory must be made. This is accomplished with the init command. (See the first Daily Drill Down of this series—“Source Code Management: Installing CVS.”) Then, edit your /etc/services file and make sure there is an entry similar to the following:
cvspserver 2401/tcp

The next step is to edit your /etc/inetd.conf file. There are two ways you can call CVS: one with tcpwrappers and one without. The method you choose depends upon the type of system you are using. The first method, shown below, is the inetd entry without tcpwrappers:
cvspserver stream tcp nowait root /usr/bin/cvs cvs –f
 —allow-root=/usr/local/cvsroot pserver

The above command is one line. It is broken up in the above listing for clarity.
The following entry would be used if you do make use of tcpwrappers support:
cvspserver stream tcp nowait root /usr/sbin/tcpd /usr/bin/cvs cvs –f
 —allow-root=/usr/local/cvsroot pserver

Again, the above command is only one line, but it has been broken up for clarity.
In either case, you can change the —allow-root option to specify your real $CVSROOT. You can also specify more than one CVS repository by using multiple —allow-root options to point to different repositories. For example,
—allow-root=/usr/local/cvsroot -allow-root=/home/cvsroot

will make both CVS repositories in /usr/local/cvsroot and /home/cvsroot available remotely.

Once you have made these changes, restart inetd. On a Linux-Mandrake or Red Hat system, the command to do so is as follows:
/etc/rc.d/init.d/inet restart

You can also use pserver with xinetd, which is a more powerful replacement for inetd. The configuration is a little different for xinetd when compared to inetd, but it’s easy enough to use. Most distributions that use xinetd will have the xinetd configuration files in the /etc/xinetd.d directory, with one file per service.

Create a new file called /etc/xinetd.d/cvspserver with the following contents:
service cvspserver
{
socket_type     = stream
protocol     = tcp
wait     = yes
user     = root
server     = /usr/bin/cvs
server_args     = -f —allow-root=/usr/local/cvsroot pserver
disable     = no
}


Now, you can restart xinetd in the same fashion as inetd using
/etc/rc.d/init.d/xinetd restart

or an equivalent command if you are using xinetd on a system running a version of Linux other than Linux-Mandrake or Red Hat.

The next step is to create the password file for the users whom you want to be able to access the pserver. This can be a little bit of work. What we need to do is change some of the configuration information in the CVSROOT directory below our CVS repository. This is where the administrative information is kept.

The user who set up the CVS repository (typically, root) will need to modify the permissions on the CVSROOT directory to allow a regular user, who will be in charge of the repository, read and write access to the directory. The reason for this is although the root users can check out the CVSROOT module, they are unable to commit changes to the repository or add new files. Only a regular user is able to make changes to a file stored in a CVS repository. If you want user joe to be able to administer the repository, you would run the following commands:
su -
cd $CVSROOT
chown -R root.joe CVSROOT
exit


This will change the ownership of all the files in the CVSROOT directory to be owned by user root and group joe. Make sure the files are read and write for both user and group. Once this is accomplished, joe should check out the module CVSROOT the same as any other module by performing the following commands:
cd ~
mkdir cvs
cd cvs
cvs checkout CVSROOT


This will create a directory called /home/joe/cvs, where we will check out the CVSROOT module. We now have a CVSROOT directory, so change over to it. You will need to create a file called passwd, which will contain the usernames and passwords of the users for whom you want to allow access to your repository. The passwords in this file, like those in your /etc/passwd file, are encrypted with the UNIX crypt() function. This means that you need to encrypt the password before you can enter it into the file since CVS does not give you any tools with which to do this. Unfortunately, there is no standard tool other than the passwd program that will easily create encrypted passwords, and using passwd entails more work than it's worth. Ideally, if you have users on your system who will also be using pserver, you want their pserver passwords to be different from their system passwords because of the insecure transmission of the passwords.

If you have the Apache Web server installed, however, you can use the htpasswd tool to create your passwd file. Because htpasswd can write crypt()-encrypted passwords to a file with the same format as /etc/passwd, which is also the same format that pserver uses, it makes the perfect replacement tool. To use htpasswd like this, run it as shown here:
htpasswd -c -d ~/cvs/CVSROOT/passwd joe

This will create a new file called ~/cvs/CVSROOT/passwd and put the user joe into it. You will be prompted for joe's password on the command line. After you have created the passwd file for the first time, do not use the -c option again because it tells htpasswd to create a new file. Use the -d option to force htpasswd to use crypt() encryption.

The format of the passwd file is
[username]:[encrypted_passwd]:[system_username]

You can use the last parameter if you want to map the username to a real system user. That is, if joe had shell access on the server and were going to use pserver, you might enter the following into the passwd file:
joe:9N83KcqwlF2zk:joe

This is not necessary, however. You can omit the system username whether the user has a real system account or not. For security reasons, you may want to do so. Realistically, if users have shell access to your system, they should be using ssh to connect to the CVS repository instead of pserver anyway.

You can also give anonymous access to a CVS repository. This is useful for allowing the general public read-only access to your repository, which can benefit you with early testing of software by users without creating official releases or snapshots.

To provide anonymous access to your CVS repository, insert the following in your passwd file:
anonymous:

This will allow any user connecting to the repository with any password, including a blank password, access to the repository. To give this user read-only access, you must list the username in the readers file in the $CVSROOT/CVSROOT administrative directory (the same directory that contains passwd). If a username is listed in the readers file, that user will receive read-only access to the repository and will not be able to write. You can also use the writers file to explicitly define the users who should have read/write access to the repository. Anyone connecting to the CVS repository not listed in the writers file will receive read-only access by default. Of course, this works only with pserver and not with other means of connecting to the repository. These files are not used when invoking CVS on the same machine the repository is located on or when accessing the repository via ssh.

Finally, be sure you press [Enter] after you have entered your last user. CVS requires this in any file containing user information, whether it is passwd, readers, or writers. Once you have finished editing the passwd file, you need to add it to the CVS repository (since it does not yet exist) and then commit it. This is the same as adding and committing any other file to the repository and is done by executing the following:
cd ~/cvs/CVSROOT
cvs add passwd
cvs commit


Once the file is committed, users can start to use pserver to access the CVS repository. Accessing a CVS repository via pserver is similar to doing it via ssh. In the third Daily Drill Down of this series, “More control with CVS,” I created three scripts to connect to the remote CVS repository using ssh: checkout, commit, and update. Let's rewrite those same scripts to use the pserver method instead.

The checkout script will now look like this:
#!/bin/sh
CVSROOT=:pserver:joe@remotecvs.com:/usr/local/cvsroot
export CVSROOT
cvs login
cvs -z3 checkout $1
cvs logout


The commit script will now look like this:
#!/bin/sh
CVSROOT=:pserver:joe@remotecvs.com:/usr/local/cvsroot
export CVSROOT
cd $1
cvs login
cvs -z3 commit
cvs logout
cd ..


And the update script will now look like this:
#!/bin/sh
CVSROOT=:pserver:joe@remotecvs.com:/usr/local/cvsroot
export CVSROOT
cd $1
cvs login
cvs -z3 update
cvs logout
cd ..


The calling convention for each script is:
./script module

So, to commit changes to the module called “website,” you would use
./commit website

This is, of course, assuming that you use a logical sandbox directory. For instance, you may have ~/cvs as your homemade CVS root directory. The modules you are working on would be located in subdirectories with the same name as the module, so for the “website” module you would have a directory called ~/cvs/website that contains the files for that module. You would store the three scripts in the ~/cvs directory and execute them from there.

Let's examine the above scripts for a moment. You need to set the CVSROOT environment variable only; you do not need to set CVS_RSH because you are using pserver to connect. The CVSROOT variable is the same as that used with ssh, except instead of using the :ext: identifier (for external), use :pserver:, which indicates that the remote CVS server is using pserver. Before you can execute any CVS commands, you must first log in to the CVS pserver with the login command. After that, you can execute whatever commands you want. Finally, log out of the CVS pserver using the logout command.

Optionally, you could log in once for the duration of numerous sessions. The login command creates a cache file called ~/.cvpass, which contains your password for the remote CVS server. On subsequent CVS commands, it will try to use the password cached in the ~/.cvpass file before doing anything else. It does store the password in a somewhat encrypted state, but it's hardly secure. Therefore, to keep your password private, you may want to use the above scripts because they log out of the CVS server after every command, which also removes the ~/.cvpass file.

If you are setting up your own pserver, you may have one additional point of failure. Some shells that inetd executes will set the $HOME environment variable. This will confuse CVS and will prevent pserver from working properly. If you encounter a problem connecting to pserver, you may want to unset the $HOME environment variable prior to invoking pserver. You can accomplish this by telling inetd to run a script instead of the CVS command and having the script start pserver. Your script may look something like this:
#!/bin/sh
unset HOME
/usr/bin/cvs -f —allow-root=/usr/local/cvsroot pserver


If you tell inetd to invoke this script instead of CVS directly, you should have no problems. You should only have to do this in the rare case that the $HOME environment variable is set, however, and for most systems this should not be the case.

cvsweb
The other alternative is to the use the cvsweb program, which provides a Web-based interface to a CVS repository. You can obtain cvswebhere. The cvsweb program is a Perl CGI script that provides the front-end Web interface to your CVS repository.

The cvsweb program is very easy to install. Download the archive cvsweb-1.93.tar.gz and save it in /usr/local/src. Unarchive the package using
tar xvzf cvsweb-1.93.tar.gz

Change over to the cvsweb directory. There are a few files here you will need to deal with. Move the cvsweb.cgi file to your Web site's /cgi-bin/ directory. On newer systems, this will probably be /var/www/cgi-bin/. Then move the configuration file cvsweb.conf to your /etc/httpd/conf directory (or wherever you have Apache's configuration files stored). The next step is to move the files in the icons/ subdirectory to your Web site's icons/ directory, which should be /var/www/icons.

Once this is complete, edit the cvsweb.cgi script in your /var/www/cgi-bin/ directory. Go down to line 79, which contains
$config = $ENV{`CVSWEB_CONFIG'} ||
`/usr/local/web/apache/conf/cvsweb.conf';


and change it to this:
$config = $ENV{`CVSWEB_CONFIG'} ||
`/etc/httpd/conf/cvsweb.conf';


Now, change to your /etc/httpd/conf directory and edit the cvsweb.conf file. It's well commented and very easy to follow. There are only two things that need to be edited to get cvsweb working immediately. You need to change the values of the %CVSROOT array and the $cvstreedefault variable. Everything else, such as colors, text displayed, and so forth, you can customize at your leisure. Change
%CVSROOT = (
`Development' => `/usr/local/src/cvsrep',
`Configuration' => `/tmp/cvsroot/conf',
`HTML-Files' => `/tmp/upload'
);


and
$cvstreedefault = `Configuration';

to
%CVSROOT = (
`My-CVS' => `/usr/local/cvsroot'
);


and
$cvstreedefault = `My-CVS';

Point %CVSROOT to wherever your CVS repository is located on the local system. As shown by the default, you can have multiple CVS repositories available via cvsweb.

Now go into your Web browser and point it to www.yourdomain.com/cgi-bin/cvsweb.cgi, and you will see cvsweb in action! The cvsweb program can show you a wealth of information, but that's about all it does. It will not allow you to commit changes to the repository; it will only let you view information on the files in any given module and download them. It is useful for anonymous CVS access to allow others to view your source but not to change it. If you want other developers to collaborate on a project, you will need to give them access to CVS using either ssh or pserver.

Conclusion
As I’ve illustrated over the four Daily Drill Downs in this series, CVS is an extremely powerful and versatile tool. There are many ways to access CVS: locally, remotely using ssh, remotely using pserver, or remotely using cvsweb. While these are the only ways of accessing CVS that I’ve discussed, other methods are available. For many operating systems, there are numerous add-on utilities for CVS.

CVS can be used for virtually anything text related. You can use CVS for your Web site, source code, documentation, and even the configuration files on a server! And, with the flexible means of accessing it, you can enjoy the company of a group of developers to help design and contribute to your projects, or you can become a contributor to someone else's project.

In the next Daily Drill Down of this series, I will take a look at the Revision Control System (RCS). RCS is the predecessor of CVS, so CVS uses many of the RCS utilities. You will see how to convert existing RCS projects to CVS, and I will also show how to use RCS, which may be preferable for single-user projects.
The authors and editors have taken care in preparation of the content contained herein but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for any damages. Always have a verified backup before making any changes.

About Vincent Danen

Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.

Editor's Picks

Free Newsletters, In your Inbox