Archive for the ‘Cvs Server’ Category

CVS Access Control List Extension Patch

December 11, 2007 1 comment

CVSACL is a patch for CVS. It adds two new subcommands (acl & racl) to cvs for access control list management. It provides advanced ACL definitions per modules, directories, and files on branch/tag for remote cvs repository connections. Execution of all CVS subcommands can be controlled with eight different permissions.
ACL definitions works for only remote connections, local users can access and modify repository, if unix file system permissions allow. If you want all users to make remote connections to repository, and not allow local users to access repository, you have to set CVSServerRunAsUser keyword in aclconfig file (explained below). Still local users can use acl and racl subcommands to set permissions on directories or files if they have acl admin rights (p) on related directories or files.
So, in order to control all access to repository with this ACL extension, you should use CVSServerRunAsUser keyword and force all users to make remote connections. CVS repository administrator or project managers have to use acl and racl subcommands to manage permissions. But there is no gui client supporting these subcommands, so you have to use cvs client itself either locally or remotely.

Download current version 1.2.5 (June 10, 2006) project page
cvsacl-announce mailing list
cvsacl-users mailing list
How to install
Permission types
ACL config keywords
Command line usage information
Command line usage samples


  • copy the file acl.c under src directory of CVS source distribution.
    cp acl.c /path/to/cvs-1.11.x/src/
  • copy the patch file cvsacl-patch-1.2.x under CVS source distribution directory.
    cp cvsacl-patch-1.2.x /path/to/cvs-1.11.x/
  • cd to CVS source directory.
    cd /path/to/cvs-1.11.x/
  • apply the patch.
    patch -p0 < cvsacl-patch-1.2.x
  • if you are initializing the repository after applying patch, related config files will be created with init command.
    cvs -d /path/to/repository init
  • if you already have a repository, you have to add the aclconfig file to your $CVSROOT/CVSROOT/. aclconfig.default is the default configuration file, you can rename it to aclconfig, and use it .
  • modify aclconfig file, if you need to change some options.
  • as the last step, you have to define yourself as acl administrator.
    cvs -d /path/to/repository racl yourname:p -r ALL -d ALL
    this command gives p (acl admin) rights to user (yourname), on all repository and tags/branches.

Permission Types

  • no access
    Command line character: n
    If a user given n permission, it is not allowed for any action on repository.
  • read
    Command line character: r
    r permission gives only read access on repository. With r permission you are allowed to run cvs subcommands: annotate, checkout, diff, export, log, rannotate, rdiff, rlog, status.
  • write
    Command line character: w
    w permission allows only cvs commit/checkin action. With w permission, you are not allowed to add/remove any file to/from repository, other permissions should be defines for that.
  • tag
    Command line character: t
    t permission allows cvs tag and rtag subcommands to run, so you may control tagging and untagging operations. t permission includes r permission, since without reading you can not tag/untag a file. However t permission does not include write permission, you can not commit a file with only t permission.
  • create
    Command line character: c
    c permission allows cvs add and import subcommands to run. To add or import a file/directory to repository, you have to given a c permission. Again, c permission does not include write permission, thus you may only add or import files, but you can not modify any existing file. After issuing add subcommand, you have to commit the file to complete adding. This commit subcommand is allowed because you are adding file and not modifying existing one.
  • delete
    Command line character: d
    d permission allows cvs remove command to run. To remove a file/directory from repository, d permission have to set. It does not include write permission, so you can not modify contents of an existing file on repository.
  • full access except admin rights
    Command line character: a
    a permission gives all access (above permissions) to repository, but it can not modify permissions. Only acl admins may modify the acl definitions.
  • acl admin
    Command line character: p
    p permission means that user is an acl admin, so it is allowed to make anything on repository.

ACL Config Keywords

The administrative file aclconfig contains miscellaneous settings which affect the behaviour of ACL extension. Currently defined keywords are:

UseCVSACL=valueUse ACL definitions if set to yes. If you do not want to use ACLs for some repositories in a patched CVS server, set this keyword to no. The default is no.

UseCVSACLDefaultPermissions=value Value can be any combination of valid permission types (w,r,t,c,d,t,a,p). if there is no defined ACL and default permission in access file, or no access file at all, this permissions are used. The default is p (admin rights), if aclconfig file is created with cvs init.

UseCVSGroups=valueCVS does not have a CVSROOT/passwd file. However it can be created manually (format should be same as /etc/group). If value set to yes, CVS checks for groups in file $CVSROOT/CVSROOT/group The default value is no.

UseSystemGroups=valueGroup memberships for users are checked in file /etc/group, if value is set to yes. The default value is no.

CVSACLFileLocation=valueOriginally access file is put under CVSROOT/CVSROOT, if you want a different location, set value to a valid path. The default value is $CVSROOT/CVSROOT/access.

CVSGroupsFileLocation=valueIF UseCVSGroups is set to yes, CVS looks for a group file under $CVSROOT/CVSROOT. To use a different location for group file set value to a valid path to group. The default value is $CVSROOT/CVSROOT/group.

UseSeparateACLFileForEachDir=valueIf value is set to yes, a separate ACL file (access) is created for each directory in repository. If you have a really big repository (directories>10,000 and files>100,000), performance may drop due to a big acl file, access. Setting the value to yes, may increase performance. Normally, you will not need this. The default value is no.

CVSServerRunAsUser=valueSet CVSServerRunAsUser keyword to a valid system user.
Keyword iseffective only in PServer connections. When a user make a remote pserver connection to CVS, after successfull authentication cvs process switch to run as that user, or defined system user in $CVSROOT/CVSROOT/passwd. So, you also have to set unix file permissions accordingly.
A better solution:
Add a user and group such as both cvsadm.
Set CVSServerRunAsUser keyword to cvsadm.
Change unix file system permissions for your repository,
make cvsadm user and group owner, and read,write,execute permissions and setgid.
(chown cvsadm -R /path/to/your/repository)
(chgrp cvsadm -R /path/to/your/repository)
(chmod 2770 -R /path/to/your/repository)
Add yourself to cvsadm group (since you are ACL administrator).
Therefore, only users making remote connections will have access to repository if you give rights. Local users can not access to repository via a cvs client or directly.

Command Line Usage Information

acl command is used on checked out files or directories. racl command is used on repository without a working copy. Usage information can be obtained with standard cvs –help command.
Output of cvs –help acl and cvs –help racl:

Usage: cvs racl [user||group:permissions] [-Rl] [-r tag] [directories...] [files...]
        -R      Process directories recursively.
        -r rev  Existing revision/tag.
        -l      List defined ACLs.

Usage: cvs acl [user||group:permissions] [-Rl] [-r tag] [directories...] [files...]
        -R      Process directories recursively.
        -r rev  Existing revision/tag.
        -l      List defined ACLs.

NOTICE: There is no more -d -f options for directory and files, acl/racl subcommands runs like other cvs subcommands.

You may directly set permissions for a user or group or add/remove permissions with + and – signs to/from existing permissions.
If you do not give the branch/tag information, default value of HEAD (main branch) will be used. You have to give branch/tag name with -r option. You may type ALL for branch/tag field.

While checking for permissions, it goes thorough the list below. So the highest significant permission is the first item in list.

  • permissions assigned to username for specific directory or file.
  • permissions assigned to group name for specific directory or file.
  • permissions as defaults for specific directory or file.
  • permissions as repository defaults.
  • permissions in aclconfig file.


      |	       |
      |        +---CVSROOT/
      |        |
      |        +---lib/
      |        |     |
      |        |     +---gnulib/
      |        |     |
      |        |     +---zlib/
      |        |
      |        +---src/
      |        |     |
      |        |     +---main.c
      |        |     |
      |        |     +---server.c
      |        |     |
      |        |     +---client.c
      |        |
      |        +---gui/

We have above directory structure for a cvs repository, and no defined permissions.

Setting main default permissions:

$ cvs -d /cvs/projectA racl cvsadmin:p -r ALL ALL
$ cvs -d /cvs/projectA racl ALL:r -r ALL ALL

User cvsadmin will be an acl admin, and all other users will have only read rights on all branches/tags in projectA repository. This is the default acl definition and it overwrites default permissions in $CVSROOT/CVSROOT/aclconfig file.

$ cvs -d /cvs/projectA racl ALL:r -r ALL ALL
$ cvs -d /cvs/projectA racl ALL:n -r ALL gui

After executing these two commands, all users will have read access on all directories and files except gui directory. Everyone will be denied to access to gui directory becase no access, n, permissions is set.

Setting permissions directly on a file or directory:

$ cvs -d /cvs/projectA racl userX:wcd lib
$ cvs -d /cvs/projectA racl group1:w lib

First command will set write, create, and delete permissions for userX on directory lib with branch HEAD (since no branch/tag information given, branch defaults to HEAD). Second command will set only write permission for group1 on directory lib with branch HEAD. Members of group1 will have only commit rights on lib directory, branch HEAD, they can not add or remove any file, just modify existing files.
If userX is also a member of group1, userX will have write, create, and delete permissions because it is specifically given these permissions.

$ cvs -d /cvs/projectA racl userY:wcd -r develStream lib
$ cvs -d /cvs/projectA racl userY:r -r integStream lib

These commands will give wcd permissions to userY on lib directory with tag develstream, and r permissions on lib directory with tag integStream.

$ cvs -d /cvs/projectA racl userZ:wcd src
$ cvs -d /cvs/projectA racl userZ:r src/main.c

First command will give wcd permissions to userZ on src directory, but only read permission on file main.c in src directory.

Using + and – signs to set permissions on a file or directory:

$ cvs -d /cvs/projectA racl userZ:+t src
$ cvs -d /cvs/projectA racl userZ:-cd src
$ cvs -d /cvs/projectA racl userZ:-wt src

Before the first command, userZ has wcd permissions on src directory, after issuing command it will have wcdt permissions. Tag permission will be added. UserZ has wcdt permissions, and we execute the second command to remove create and delete permissions. So userZ has wt permissions. In the last command we also remove wt permissions, finally userZ has no defined permissions left, and it will use the default permissions if set.

Listing permissions on a file or directory:

$ cvs -d /cvs/projectA racl -l src
$ cvs -d /cvs/projectA racl -l src
$ cvs -d /cvs/projectA racl -l src/main.c

First command will list the permissions for src directory.
Example output:
d src HEAD | userX:wcd group1:r | defaults:r
userX and group1 has assigned permissions, all other users will have default permissions, which is only read.

Second command will list the permissions for files in src directory.
Example output:
f src/main.c HEAD | userX:wcd group1:r | defaults:r
f src/server.c HEAD | userX:wcd group1:r | defaults:r
f src/client.c HEAD | userX:wcd group1:r | defaults:r

Third command will list the permissions for main.c file in src directory.
Example output:
f src/main.c HEAD | userX:wcd group1:r | defaults:r <!–

CVS server main site
WinCVS – a visual CVS client for Windows
jCVS – a visual CVS client, OS independent

Categories: Cvs Server

Security considerations with password authentication in CVS

December 8, 2007 Leave a comment

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 Password authentication server) 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.

Categories: Cvs Server

Setting up the server for password authentication

December 8, 2007 Leave a comment

First of all, you probably want to tighten the permissions on the $CVSROOT and $CVSROOT/CVSROOT directories. See Password authentication security, 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 specified in the CVSROOT variable (see Remote repositories) or overridden with the CVS_CLIENT_PORT environment variable (see Environment variables).

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 -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.

If your system uses xinetd instead of inetd, the procedure is slightly different. Create a file called /etc/xinetd.d/cvspserver containing the following:

     service cvspserver
        port        = 2401
        socket_type = stream
        protocol    = tcp
        wait        = no
        user        = root
        passenv     = PATH
        server      = /usr/local/bin/cvs
        server_args = -f --allow-root=/usr/cvsroot pserver

(If cvspserver is defined in /etc/services, you can omit the port line.)

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

If you are having trouble setting this up, see Connection.

Because the client stores and transmits passwords in cleartext (almost—see Password authentication security, 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 Intro administrative files). 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:


(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 authenticate 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 Read-only access.)

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:


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 config).

The default fallback behavior is to look in /etc/passwd for this system user unless your system has PAM (Pluggable Authentication Modules) and your cvs server executable was configured to use it at compile time (using ./configure --enable-pam – see the INSTALL file for more). In this case, PAM will be consulted instead. This means that cvs can be configured to use any password authentication source PAM can be configured to use (possibilities include a simple UNIX password, NIS, LDAP, and others) in its global configuration file (usually /etc/pam.conf or possibly /etc/pam.d/cvs). See your PAM documentation for more details on PAM configuration.

Note that PAM is an experimental feature in cvs and feedback is encouraged. Please send a mail to one of the cvs mailing lists ( or if you use the cvs PAM support.

WARNING: Using PAM gives the system administrator much more flexibility about how cvs users are authenticated but no more security than other methods. See below for more.

CVS needs an “auth”, “account” and “session” module in the PAM configuration file. A typical PAM configuration would therefore have the following lines in /etc/pam.conf to emulate the standard cvs system /etc/passwd authentication:

     cvs	auth	    required
     cvs	account	    required
     cvs	session	    required

The the equivalent /etc/pam.d/cvs would contain

     auth	    required
     account	    required
     session	    required

Some systems require a full path to the module so that (Linux) would become something like /usr/lib/security/$ISA/ (Sun Solaris). See the contrib/pam subdirectory of the cvs source distribution for further example configurations.

The PAM service name given above as “cvs” is just the service name in the default configuration and can be set using ./configure --with-hardcoded-pam-service-name=<pam-service-name> before compiling. cvs can also be configured to use whatever name it is invoked as as its PAM service name using ./configure --without-hardcoded-pam-service-name, but this feature should not be used if you may not have control of the name cvs will be invoked as.

Be aware, also, 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 Password authentication security for more on this. This may be more of a problem with PAM authentication because it is likely that the source of the system password is some central authentication service like LDAP which is also used to authenticate other services.

On the other hand, PAM makes it very easy to change your password regularly. If they are given the option of a one-password system for all of their activities, users are often more willing to change their password on a regular basis.

In the non-PAM configuration where the password is stored in the CVSROOT/passwd file, it is difficult to change passwords on a regular basis since only administrative users (or in some cases processes that act as an administrative user) are typically given access to modify this file. Either there needs to be some hand-crafted web page or set-uid program to update the file, or the update needs to be done by submitting a request to an administrator to perform the duty by hand. In the first case, having to remember to update a separate password on a periodic basis can be difficult. In the second case, the manual nature of the change will typically mean that the password will not be changed unless it is absolutely necessary.

Note that PAM administrators should probably avoid configuring one-time-passwords (OTP) for cvs authentication/authorization. If OTPs are desired, the administrator may wish to encourage the use of one of the other Client/Server access methods. See the section on see Remote repositories for a list of other methods.

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 checkoutlist

Categories: Cvs Server


December 8, 2007 Leave a comment
Categories: Cvs Server