Go to the previous, next section.

The Repository

Figure 3 below shows a typical setup of a repository. Only directories are shown below.

/usr
 |
 +--local
 |   |
 |   +--cvsroot
 |   |    | 
 |   |    +--CVSROOT
          |      (administrative files) 
          | 
          +--gnu
          |   | 
          |   +--diff
          |   |   (source code to GNU diff) 
          |   | 
          |   +--rcs
          |   |   (source code to RCS)
          |   | 
          |   +--cvs
          |       (source code to CVS) 
          | 
          +--yoyodyne
              | 
              +--tc
              |    |
              |    +--man
              |    |
              |    +--testing
              | 
              +--(other Yoyodyne software)

There are a couple of different ways to tell CVS where to find the repository. You can name the repository on the command line explicitly, with the -d (for "directory") option:

cvs -d /usr/local/cvsroot checkout yoyodyne/tc

Or you can set the $CVSROOT environment variable to an absolute path to the root of the repository, `/usr/local/cvsroot' in this example. To set $CVSROOT, all csh and tcsh users should have this line in their `.cshrc' or `.tcshrc' files:

setenv CVSROOT /usr/local/cvsroot

sh and bash users should instead have these lines in their `.profile' or `.bashrc':

CVSROOT=/usr/local/cvsroot
export CVSROOT

A repository specified with -d will override the $CVSROOT environment variable. Once you've checked a working copy out from the repository, it will remember where its repository is (the information is recorded in the `CVS/Root' file in the working copy).

The -d option and the `CVS/Root' file both override the $CVSROOT environment variable. If -d option differs from `CVS/Root', the former is used (and specifying -d will cause `CVS/Root' to be updated). Of course, for proper operation they should be two ways of referring to the same repository.

There is nothing magical about the name `/usr/local/cvsroot'. You can choose to place the repository anywhere you like. See section Remote repositories to learn how the repository can be on a different machine than your working copy of the sources.

Note: For compatibility with older versions, CVS will treat any repository name that contains a colon as an indication of a remote repository (See section Remote repositories). If the name of your local repository contains a colon, you should prepend the string `:local:' to the pathname to tell CVS that it is, indeed, a local repository. For example, you might use this command line under Windows NT:

cvs -d :local:c:\src\cvsroot checkout yoyodyne/tc

The repository is split in two parts. `$CVSROOT/CVSROOT' contains administrative files for CVS. The other directories contain the actual user-defined modules.

User modules

  $CVSROOT
    |
    +--yoyodyne
    |   |
    |   +--tc
    |   |   |
            +--Makefile,v
            +--backend.c,v
            +--driver.c,v
            +--frontend.c,v
            +--parser.c,v
            +--man
            |    |
            |    +--tc.1,v
            |     
            +--testing
                 |
                 +--testpgm.t,v
                 +--test2.t,v

The figure above shows the contents of the `tc' module inside the repository. As you can see all file names end in `,v'. The files are history files. They contain, among other things, enough information to recreate any revision of the file, a log of all commit messages and the user-name of the person who committed the revision. CVS uses the facilities of RCS, a simpler version control system, to maintain these files. For a full description of the file format, see the man page rcsfile(5).

File permissions

All `,v' files are created read-only, and you should not change the permission of those files. The directories inside the repository should be writable by the persons that have permission to modify the files in each directory. This normally means that you must create a UNIX group (see group(5)) consisting of the persons that are to edit the files in a project, and set up the repository so that it is that group that owns the directory.

This means that you can only control access to files on a per-directory basis.

CVS tries to set up reasonable file permissions for new directories that are added inside the tree, but you must fix the permissions manually when a new directory should have different permissions than its parent directory.

Since CVS was not written to be run setuid, it is unsafe to try to run it setuid. You cannot use the setuid features of RCS together with CVS.

The administrative files

The directory `$CVSROOT/CVSROOT' contains some administrative files. See section Reference manual for the Administrative files, for a complete description. You can use CVS without any of these files, but some commands work better when at least the `modules' file is properly set up.

The most important of these files is the `modules' file. It defines all modules in the repository. This is a sample `modules' file.

CVSROOT         CVSROOT
modules         CVSROOT modules
cvs             gnu/cvs
rcs             gnu/rcs
diff            gnu/diff
tc              yoyodyne/tc

The `modules' file is line oriented. In its simplest form each line contains the name of the module, whitespace, and the directory where the module resides. The directory is a path relative to $CVSROOT. The last four lines in the example above are examples of such lines.

The line that defines the module called `modules' uses features that are not explained here. See section The modules file, for a full explanation of all the available features.

Editing administrative files

You edit the administrative files in the same way that you would edit any other module. Use `cvs checkout CVSROOT' to get a working copy, edit it, and commit your changes in the normal way.

It is possible to commit an erroneous administrative file. You can often fix the error and check in a new revision, but sometimes a particularly bad error in the administrative file makes it impossible to commit new revisions.

Multiple repositories

In some situations it is a good idea to have more than one repository, for instance if you have two development groups that work on separate projects without sharing any code. All you have to do to have several repositories is to specify the appropriate repository, using the CVSROOT environment variable, the `-d' option to CVS, or (once you have checked out a working directory) by simply allowing CVS to use the repository that was used to check out the working directory (see section The Repository).

Notwithstanding, it can be confusing to have two or more repositories.

None of the examples in this manual show multiple repositories.

Creating a repository

To set up a CVS repository, choose a directory with ample disk space available for the revision history of the source files. It should be accessable (directly or via a networked file system) from all machines which want to use CVS in server or local mode; the client machines need not have any access to it other than via the CVS protocol.

To create a repository, run the cvs init command. It will set up an empty repository in the CVS root specified in the usual way (see section The Repository). For example,

cvs -d /usr/local/cvsroot init

cvs init is careful to never overwrite any existing files in the repository, so no harm is done if you run cvs init on an already set-up repository.

cvs init will enable history logging; if you don't want that, remove the history file after running cvs init. See section The history file.

Remote repositories

Your working copy of the sources can be on a different machine than the repository. Generally, using a remote repository is just like using a local one, except that the format of the repository name is:

        :method:user@hostname:/path/to/repository

The details of exactly what needs to be set up depend on how you are connecting to the server.

Connecting with rsh

CVS uses the `rsh' protocol to perform these operations, so the remote user host needs to have a `.rhosts' file which grants access to the local user.

For example, suppose you are the user `mozart' on the local machine `anklet.grunge.com', and the server machine is `chainsaw.brickyard.com'. On chainsaw, put the following line into the file `.rhosts' in `bach''s home directory:

anklet.grunge.com  mozart

Then test that rsh is working with

rsh -l bach chainsaw.brickyard.com echo $PATH

Next you have to make sure that rsh will be able to find the server. Make sure that the path which rsh printed in the above example includes the directory containing a program named cvs which is the server. You need to set the path in `.bashrc', `.cshrc', etc., not `.login' or `.profile'. Alternately, you can set the environment variable CVS_SERVER on the client machine to the filename of the server you want to use, for example `/usr/local/bin/cvs-1.6'.

There is no need to edit inetd.conf or start a CVS server daemon.

Continuing our example, supposing you want to access the module `foo' in the repository `/usr/local/cvsroot/', on machine `chainsaw.brickyard.com', you are ready to go:

cvs -d :server:bach@chainsaw.brickyard.com:/usr/local/cvsroot checkout foo

(The `bach@' can be omitted if the username is the same on both the local and remote hosts.)

Direct connection with password authentication

The CVS client can also connect to the server using a password protocol. This is particularly useful if using rsh is not feasible (for example, the server is behind a firewall), and Kerberos also is not available.

To use this method, it is necessary to make some adjustments on both the server and client sides.

Setting up the server for password authentication

On the server side, the file `/etc/inetd.conf' needs to be edited so inetd knows to run the command cvs pserver when it receives a connection on the right port. By default, the port number is 2401; it would be different if your client were compiled with CVS_AUTH_PORT defined to something else, though.

If your inetd allows raw port numbers in `/etc/inetd.conf', then the following (all on a single line in `inetd.conf') should be sufficient:

2401  stream  tcp  nowait  root  /usr/local/bin/cvs
cvs -b /usr/local/bin pserver

The `-b' option specifies the directory which contains the RCS binaries on the server.

If your inetd wants a symbolic service name instead of a raw port number, then put this in `/etc/services':

cvspserver      2401/tcp

and put cvspserver instead of 2401 in `inetd.conf'.

Once the above is taken care of, restart your inetd, or do whatever is necessary to force it to reread its initialization files.

Because the client stores and transmits passwords in cleartext (almost--see section Security considerations with password authentication for details), a separate CVS password file may be used, so people don't compromise their regular passwords when they access the repository. This file is `$CVSROOT/CVSROOT/passwd' (see section The administrative files). Its format is similar to `/etc/passwd', except that it only has two fields, username and password. For example:

bach:ULtgRLXo7NRxs
cwang:1sOp854gDF3DY

The password is encrypted according to the standard Unix crypt() function, so it is possible to paste in passwords directly from regular Unix `passwd' files.

When authenticating a password, the server first checks for the user in the CVS `passwd' file. If it finds the user, it compares against that password. If it does not find the user, or if the CVS `passwd' file does not exist, then the server tries to match the password using the system's user-lookup routine. When using the CVS `passwd' file, the server runs under as the username specified in the the third argument in the entry, or as the first argument if there is no third argument (in this way CVS allows imaginary usernames provided the CVS `passwd' file indicates corresponding valid system usernames). In any case, CVS will have no privileges which the (valid) user would not have.

Right now, the only way to put a password in the CVS `passwd' file is to paste it there from somewhere else. Someday, there may be a cvs passwd command.

Using the client with password authentication

Before connecting to the server, the client must log in with the command cvs login. Logging in verifies a password with the server, and also records the password for later transactions with the server. The cvs login command needs to know the username, server hostname, and full repository path, and it gets this information from the repository argument or the CVSROOT environment variable.

cvs login is interactive -- it prompts for a password:

cvs -d :pserver:bach@chainsaw.brickyard.com:/usr/local/cvsroot login 
CVS password: 

The password is checked with the server; if it is correct, the login succeeds, else it fails, complaining that the password was incorrect.

Once you have logged in, you can force CVS to connect directly to the server and authenticate with the stored password:

cvs -d :pserver:bach@chainsaw.brickyard.com:/usr/local/cvsroot checkout foo

The `:pserver:' is necessary because without it, CVS will assume it should use rsh to connect with the server (see section Connecting with rsh). (Once you have a working copy checked out and are running CVS commands from within it, there is no longer any need to specify the repository explicitly, because CVS records it in the working copy's `CVS' subdirectory.)

Passwords are stored by default in the file `$HOME/.cvspass'. Its format is human-readable, but don't edit it unless you know what you are doing. The passwords are not stored in cleartext, but are trivially encoded to protect them from "innocent" compromise (i.e., inadvertently being seen by a system administrator who happens to look at that file).

The CVS_PASSFILE environment variable overrides this default. If you use this variable, make sure you set it before cvs login is run. If you were to set it after running cvs login, then later CVS commands would be unable to look up the password for transmission to the server.

The CVS_PASSWORD environment variable overrides all stored passwords. If it is set, CVS will use it for all password-authenticated connections.

Security considerations with password authentication

The passwords are stored on the client side in a trivial encoding of the cleartext, and transmitted in the same encoding. The encoding is done only to prevent inadvertent password compromises (i.e., a system administrator accidentally looking at the file), and will not prevent even a naive attacker from gaining the password.

The separate CVS password file (see section Setting up the server for password authentication) allows people to use a different password for repository access than for login access. On the other hand, once a user has access to the repository, she can execute programs on the server system through a variety of means. Thus, repository access implies fairly broad system access as well. It might be possible to modify CVS to prevent that, but no one has done so as of this writing. Furthermore, there may be other ways in which having access to CVS allows people to gain more general access to the system; noone has done a careful audit.

In summary, anyone who gets the password gets repository access, and some measure of general system access as well. The password is available to anyone who can sniff network packets or read a protected (i.e., user read-only) file. If you want real security, get Kerberos.

Direct connection with kerberos

The main disadvantage of using rsh is that all the data needs to pass through additional programs, so it may be slower. So if you have kerberos installed you can connect via a direct TCP connection, authenticating with kerberos (note that the data transmitted is not encrypted).

To do this, CVS needs to be compiled with kerberos support; when configuring CVS it tries to detect whether kerberos is present or you can use the `--with-krb4' flag to configure.

You need to edit inetd.conf on the server machine to run cvs kserver. The client uses port 1999 by default; if you want to use another port specify it in the CVS_CLIENT_PORT environment variable on the client.

When you want to use CVS, get a ticket in the usual way (generally kinit); it must be a ticket which allows you to log into the server machine. Then you are ready to go:

cvs -d :kserver:chainsaw.brickyard.com:/user/local/cvsroot checkout foo

Previous versions of CVS would fall back to a connection via rsh; this version will not do so.

Go to the previous, next section.