Password authentication 

*References*: cvs.ps

Setting up the server for password authentication 

First of all, you probably want to tighten the permissions on the `$CVSROOT' and `$CVSROOT/CVSROOT' directories. See Section 2.9.3.3 [Password authentication security], page 24, for more details.

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. This can also be sepcified in the CVSROOT variable (see Section 2.9 [Remote repositories], page 19) or overridden with the CVS CLIENT PORT environment variable (see Appendix D [Environment variables], page 143). If your inetd allows raw port numbers in `/etc/inetd.conf', then the following (all on a single line in `inetd.conf') should be suffcient:

2401 stream tcp nowait root /usr/local/bin/cvs
cvs -f --allow-root=/usr/cvsroot pserver

You could also use the `-T' option to specify a temporary directory.

The `—allow-root' option specifies the allowable cvsroot directory. Clients which attempt to use a different cvsroot directory will not be allowed to connect. If there is more than one cvsroot directory which you want to allow, repeat the option. (Unfortunately, many versions of inetd have very small limits on the number of arguments and/or the total length of the command. The usual solution to this problem is to have inetd run a shell script which then invokes cvs with the necessary arguments.)

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 2.9.3.3 [Password authentication security], page 24, for details), a separate cvs password file is generally used, so people don't compromise their regular passwords when they access the repository. This file is `$CVSROOT/CVSROOT/passwd' (see Section 2.4 [Intro administrative files], page 16). It uses a colon-separated format, similar to `/etc/passwd' on Unix systems, except that it has fewer fields: cvs username, optional password, and an optional system username for cvs to run as if authentication succeeds. Here is an example `passwd' file with five entries:

anonymous:
bach:ULtgRLXo7NRxs
spwang:1sOp854gDF3DY
melissa:tGX1fS8sun6rY:pubcvs
qproj:XR4EZcEs0szik:pubcvs

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

The first line in the example will grant access to any cvs client attempting to authenti- cate as user anonymous, no matter what password they use, including an empty password. (This is typical for sites granting anonymous read-only access; for information on how to do the "read-only" part, see Section 2.10 [Read-only access], page 26.)

The second and third lines will grant access to bach and spwang if they supply their respective plaintext passwords.

The fourth line will grant access to melissa, if she supplies the correct password, but her cvs operations will actually run on the server side under the system user pubcvs. Thus, there need not be any system user named melissa, but there must be one named pubcvs.

The fifth line shows that system user identities can be shared: any client who successfully authenticates as qproj will actually run as pubcvs, just as melissa does. That way you could create a single, shared system user for each project in your repository, and give each developer their own line in the `$CVSROOT/CVSROOT/passwd' file. The cvs username on each line would be different, but the system username would be the same. The reason to have different cvs usernames is that cvs will log their actions under those names: when melissa commits a change to a project, the checkin is recorded in the project's history under the name melissa, not pubcvs. And the reason to have them share a system username is so that you can arrange permissions in the relevant area of the repository such that only that account has write-permission there.

If the system-user field is present, all password-authenticated cvs commands run as that user; if no system user is specified, cvs simply takes the cvs username as the system username and runs commands as that user. In either case, if there is no such user on the

system, then the cvs operation will fail (regardless of whether the client supplied a valid password).

The password and system-user fields can both be omitted (and if the system-user field is omitted, then also omit the colon that would have separated it from the encrypted password). For example, this would be a valid `$CVSROOT/CVSROOT/passwd' file:

anonymous::pubcvs
fish:rKa5jzULzmhOo:kfogel
sussman:1sOp854gDF3DY

When the password field is omitted or empty, then the client's authentication attempt will succeed with any password, including the empty string. However, the colon after the cvs username is always necessary, even if the password is empty.

cvs can also fall back to use system authentication. When authenticating a password, the server first checks for the user in the `$CVSROOT/CVSROOT/passwd' file. If it finds the user, it will use that entry for authentication as described above. But if it does not find the user, or if the cvs `passwd' file does not exist, then the server can try to authenticate the username and password using the operating system's user-lookup routines (this "fallback" behavior can be disabled by setting SystemAuth=no in the cvs `config' file, see Section C.13 [config], page 141). Be aware, however, that falling back to system authentication might be a security risk: cvs operations would then be authenticated with that user's regular login password, and the password flies across the network in plaintext. See Section 2.9.3.3 [Password authentication security], page 24 for more on this.

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.

Unlike many of the files in `$CVSROOT/CVSROOT', it is normal to edit the `passwd' file in-place, rather than via cvs. This is because of the possible security risks of having the `passwd' file checked out to people's working copies. If you do want to include the `passwd' file in checkouts of `$CVSROOT/CVSROOT', see Section C.10 [checkoutlist], page 139.

Using the client with password authentication 

To run a cvs command on a remote repository via the password-authenticating server, one specifies the pserver protocol, optional username, repository host, an optional port number, and path to the repository. For example:

cvs -d :pserver:faun.example.org:/usr/local/cvsroot checkout someproj

or

CVSROOT=:pserver:bach@faun.example.org:2401/usr/local/cvsroot
cvs checkout someproj

However, unless you're connecting to a public-access repository (i.e., one where that username doesn't require a password), you'll need to supply a password or log in first. Logging in verifies your password with the repository and stores it in a file. It's done with the login command, which will prompt you interactively for the password if you didn't supply one as part of $CVSROOT:

cvs -d :pserver:bach@faun.example.org:/usr/local/cvsroot login
CVS password:

or

cvs -d :pserver:bach:p4ss30rd@faun.example.org:/usr/local/cvsroot login

After you enter the password, cvs verifies it with the server. If the verification succeeds, then that combination of username, host, repository, and password is permanently recorded, so future transactions with that repository won't require you to run cvs login. (If verification fails, cvs will exit complaining that the password was incorrect, and nothing will be recorded.)

The records are stored, by default, in the file `$HOME/.cvspass'. That file's format is human-readable, and to a degree human-editable, but note that the passwords are not stored in cleartext|they are trivially encoded to protect them from "innocent" compromise (i.e., inadvertent viewing by a system administrator or other non-malicious person).

You can change the default location of this file by setting the CVS_PASSFILE environment variable. 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.

Once you have logged in, all cvs commands using that remote repository and username will authenticate with the stored password. So, for example

cvs -d :pserver:bach@faun.example.org:/usr/local/cvsroot checkout foo

should just work (unless the password changes on the server side, in which case you'll have to re-run cvs login).

Note that if the `:pserver:' were not present in the repository specification, cvs would assume it should use rsh to connect with the server instead (see Section 2.9.2 [Connecting via rsh], page 20).

Of course, 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 can deduce the repository from the working copy's `CVS' subdirectory.

The password for a given remote repository can be removed from the CVS_PASSFILE by using the cvs logout command.

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 2.9.3.1 [Password authentication server], page 21) allows people to use a different password for repository access than for login access. On the other hand, once a user has non-read-only 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.

Note that because the `$CVSROOT/CVSROOT' directory contains `passwd' and other files which are used to check security, you must control the permissions on this directory as tightly as the permissions on `/etc'. The same applies to the `$CVSROOT' directory itself and any directory above it in the tree. Anyone who has write access to such a directory will have the ability to become any user on the system. Note that these permissions are typically tighter than you would use if you are not using pserver.

In summary, anyone who gets the password gets repository access (which may imply 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.