]> git.pld-linux.org Git - packages/cvs.git/commitdiff
- ACL patch for CVS, http://cvsacl.sourceforge.net/
authorhawk <hawk@pld-linux.org>
Sun, 6 Jun 2004 22:19:42 +0000 (22:19 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    cvs-acl.patch -> 1.1

cvs-acl.patch [new file with mode: 0644]

diff --git a/cvs-acl.patch b/cvs-acl.patch
new file mode 100644 (file)
index 0000000..32d7868
--- /dev/null
@@ -0,0 +1,3409 @@
+diff -urN cvs-1.11.15/aclconfig.default cvs-1.11.15-cvsacl/aclconfig.default
+--- cvs-1.11.15/aclconfig.default      1970-01-01 01:00:00.000000000 +0100
++++ cvs-1.11.15-cvsacl/aclconfig.default       2004-04-25 20:04:51.637863856 +0200
+@@ -0,0 +1,33 @@
++# Set `UseCVSACL' to yes to use CVS ACL feature.
++UseCVSACL=yes
++
++# Default CVS ACL Permission are to use.
++#CVSACLDefaultPermissions=a
++
++# Default file location for CVS ACL file (access) is CVSROOT/access.
++# If you want to use a different location, define it below.
++#CVSACLFileLocation=/path/to/cvs/access
++
++# Set `UseSystemGroups' to yes to use system group definitions (/etc/group).
++UseSystemGroups=yes
++
++# Set `UseCVSGroups' to yes to use another group file.
++#UseCVSGroups=yes
++
++# Default file location for CVS groups file is CVSROOT/group.
++# If you want to use a different location, define it below.
++#CVSGroupsFileLocation=/path/to/cvs/group
++
++# Set UseSeperateACLFileForEachDir to yes in order to use a
++# seperate 'access' file for each directory.
++# This increased the performance if you have really big repository.
++#UseSeperateACLFileForEachDir=no
++
++# If StopAtFirstPermissionDenied is set to yes
++# operation will stop at first permission denied message.
++# Default is no.
++#StopAtFirstPermissionDenied=no
++
++# Set CVSServerRunAsUser to a system user, in order CVS server
++# to run as.
++#CVSServerRunAsUser=runascvsuser
+diff -urN cvs-1.11.15/CHANGELOG.cvsacl cvs-1.11.15-cvsacl/CHANGELOG.cvsacl
+--- cvs-1.11.15/CHANGELOG.cvsacl       1970-01-01 01:00:00.000000000 +0100
++++ cvs-1.11.15-cvsacl/CHANGELOG.cvsacl        2004-04-25 20:04:51.660860360 +0200
+@@ -0,0 +1,12 @@
++Release 1.2.0
++      - implemented permission inheritance from parents.
++      - new config keyword: StopAtFirstPermissionDenied.
++      - fixed some errors.
++
++Release 1.1.3
++      - fixed a bug related with default permissions.
++      - fixed a bug related with setting permissions using + - signs. 
++
++Release 1.1.2
++      - fixed bugs reported on sourceforge.
++
+diff -urN cvs-1.11.15/INSTALL.cvsacl cvs-1.11.15-cvsacl/INSTALL.cvsacl
+--- cvs-1.11.15/INSTALL.cvsacl 1970-01-01 01:00:00.000000000 +0100
++++ cvs-1.11.15-cvsacl/INSTALL.cvsacl  2004-04-25 20:04:51.661860208 +0200
+@@ -0,0 +1,23 @@
++
++Installation
++
++- copy the file acl.c under src directory of CVS source distribution.
++  "cp acl.c /path/to/cvs-1.11.14/src/"
++- copy the patch file cvsacl-patch-1.2.0.beta2 under CVS source distribution 
++  directory.
++  "cp cvsacl-patch-1.2.0.beta2 /path/to/cvs-1.11.14/"
++- cd to CVS source directory.
++  "cd /path/to/cvs-1.11.14/"
++- apply the patch.
++  "patch -p0 < cvsacl-patch-1.2.0.beta2"
++- 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. 
+diff -urN cvs-1.11.15/README.cvsacl cvs-1.11.15-cvsacl/README.cvsacl
+--- cvs-1.11.15/README.cvsacl  1970-01-01 01:00:00.000000000 +0100
++++ cvs-1.11.15-cvsacl/README.cvsacl   2004-04-25 20:04:51.666859448 +0200
+@@ -0,0 +1,282 @@
++
++CVS Access Control List Extension Patch
++
++http://cvsacl.sourceforge.net/
++sbaris@users.sourceforge.net
++
++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. 
++
++
++
++
++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=value 
++Use 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=value 
++CVS 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=value 
++Group memberships for users are checked in file /etc/group, if value is set
++to yes. The default value is no.
++
++CVSACLFileLocation=value 
++Originally 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=value 
++IF 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.
++
++UseSeperateACLFileForEachDir=value 
++If value is set to yes, a seperate 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.
++
++StopAtFirstPermissionDenied=value
++If StopAtFirstPermissionDenied is set to yes
++operation will stop at first permission denied message.
++e.g. when you send commit command for a directory, if you dont
++have write permission for just one file under the directory, 
++by default you will have a warning and commit will continue
++on the other files. If you set this keyword to 'no', then 
++commit operation will be stopped when inaccassable file found.
++Default is no.
++
++CVSServerRunAsUser=value 
++Set CVSServerRunAsUser keyword to a valid system user.
++When a user make a remote 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]
++ -d [directory] -f [file]
++        -R      Process directories recursively.
++        -r rev  Existing revision/tag.
++        -l      List defined ACLs.
++        -d dir  Process on given directory.
++        -f file Process on given file.
++
++Usage: cvs acl [user||group:permissions] [-Rl] [-r tag]
++ -d [directory] -f [file]
++        -R      Process directories recursively.
++        -r rev  Existing revision/tag.
++        -l      List defined ACLs.
++        -d dir  Process on given directory.
++        -f file Process on given file.
++
++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 assigned to parent folders (inherits from the first parent
++  which permissions are assigned).
++- permissions as repository defaults. 
++- permissions in aclconfig file. 
++
++
++
++
++Examples
++     /cvs/
++      |
++      |
++      +--projectA/
++      |              |
++      |        +---CVSROOT/
++      |        |
++      |        +---lib/
++      |        |     |
++      |        |     +---gnulib/
++      |        |     |
++      |        |     +---zlib/
++      |        |
++      |        +---src/
++      |        |     |
++      |        |     +---main.c
++      |        |     |
++      |        |     +---server.c
++      |        |     |
++      |        |     +---client.c
++      |        |
++      |        +---gui/
++      |
++      +--projectB/
++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 -d ALL
++$ cvs -d /cvs/projectA racl ALL:r -r ALL -d 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 -d ALL
++$ cvs -d /cvs/projectA racl ALL:n -r ALL -d 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 -d lib
++$ cvs -d /cvs/projectA racl group1:w -d 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 -d lib
++$ cvs -d /cvs/projectA racl userY:r -r integStream -d 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 -d src
++$ cvs -d /cvs/projectA racl userZ:r -f 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 -d src
++$ cvs -d /cvs/projectA racl userZ:-cd -d src
++$ cvs -d /cvs/projectA racl userZ:-wt -d 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 -d src
++$ cvs -d /cvs/projectA racl -l -f src
++$ cvs -d /cvs/projectA racl -l -f 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
++
++
+diff -urN cvs-1.11.15/src/acl.c cvs-1.11.15-cvsacl/src/acl.c
+--- cvs-1.11.15/src/acl.c      1970-01-01 01:00:00.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/acl.c       2004-04-25 20:19:28.506559552 +0200
+@@ -0,0 +1,2028 @@
++/*
++ * 
++ * CVS ACCESS CONTROL LIST EXTENSION
++ *
++ * sbaris@users.sourceforge.net
++ *
++ * http://cvsacl.sourceforge.net/
++ * 
++ * 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.
++ *
++ *
++ * Permission Types:
++ * - no permission                    (n)             (1)
++ * - all permissions                  (a)             (2)
++ * - write permission                 (w)             (3)
++ * - tag permission                   (t)             (4)
++ * - read permission                  (r)             (5)
++ * - add permission                   (c)             (6)
++ * - remove permission                        (d)             (7)
++ * - permission       change                  (p)             (8)
++ * 
++ *
++ *
++ *
++ *   ******************************************************************** 
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU General Public License as published by
++ *   the Free Software Foundation; either version 1, or (at your option)
++ *   any later version.
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details.
++ *   *******************************************************************
++ *
++ */
++
++#include "cvs.h"
++#include "getline.h"
++#include <grp.h>
++
++static int acl_fileproc PROTO ((void *callerdat, struct file_info *finfo));
++static Dtype acl_dirproc PROTO ((void *callerdat, const char *dir, const char *repos,
++                                 const char *update_dir, List *entries));
++
++static int acllist_fileproc PROTO ((void *callerdat, struct file_info *finfo));
++static Dtype acllist_dirproc PROTO ((void *callerdat, const char *dir, const char *repos,
++                                     const char *update_dir, List *entries));
++
++static void acllist_print PROTO ((char *line, const char *obj));
++
++static int racl_proc PROTO((int argc, char **argv, char *xwhere,
++                            char *mwhere, char *mfile, int shorten,
++                            int local_specified, char *mname, char *msg));
++
++FILE *open_accessfile (char *xmode, char *repos, char **fname);
++FILE *open_groupfile (char *xmode);
++
++char *get_perms (char *xperms);
++char *make_perms (char *xperms, char *xfounduserpart, char **xerrmsg);
++
++static char *cache_repository;
++static int cache_retval;
++static int founddeniedfile;
++static int cache_perm;
++
++static int is_racl;
++
++int use_cvs_acl = 0;
++char *cvs_acl_default_permissions;
++int use_cvs_groups = 0;
++int use_system_groups = 0;
++int use_seperate_acl_file_for_each_dir = 0;
++char *cvs_acl_file_location = NULL;
++char *cvs_groups_file_location = NULL;
++char *cvs_server_run_as = NULL;
++int stop_at_first_permission_denied = 0;
++
++char *tag = NULL;
++
++char *muser;
++char *mperms;
++static int defaultperms;
++
++static char *default_perms_object;
++char *default_part_perms_accessfile;
++
++int acldir = 0;
++int aclfile = 0;
++int listacl = 0;
++
++int userfound;
++int groupfound;
++
++char *dirs[25];
++
++int aclconfig_default_used;
++
++static const char *const acl_usage[] =
++        {
++                "Usage: %s %s [user||group:permissions] [-Rl] [-r tag]\n -d [directory] -f [file]\n",
++                "\t-R\tProcess directories recursively.\n",
++                "\t-r rev\tExisting revision/tag.\n",
++                "\t-l\tList defined ACLs.\n",
++                "\t-d dir\tProcess on given directory.\n",
++                "\t-f file\tProcess on given file.\n",
++                "(Specify the --help global option for a list of other help options)\n",
++                NULL
++        };
++
++static const char *const racl_usage[] =
++        {
++                "Usage: %s %s [user||group:permissions] [-Rl] [-r tag]\n -d [directory] -f [file]\n",
++                "\t-R\tProcess directories recursively.\n",
++                "\t-r rev\tExisting revision/tag.\n",
++                "\t-l\tList defined ACLs.\n",
++                "\t-d dir\tProcess on given directory.\n",
++                "\t-f file\tProcess on given file.\n",
++                "(Specify the --help global option for a list of other help options)\n",
++                NULL
++        };
++
++
++int
++access_allowed (file, repos, tag, perm, mline, mpos, usecache)
++char *file;
++char *repos;
++char *tag;
++int perm;
++char **mline;
++int *mpos;
++int usecache;
++{
++      int retval = 0;
++      int foundline = 0;
++      FILE *accessfp;
++
++      char *line = NULL;
++      size_t line_allocated = 0;
++
++      char *part_type = NULL;
++      char *part_object = NULL;
++      char *part_tag = NULL;
++      char *part_perms = NULL;
++      char *xline;
++
++      char *iline;
++
++      char *tempv;
++      char *tempc;
++      size_t tempsize;
++      int intcount;
++
++      int oneaccessfile = 0;
++      int accessfilecount;
++
++      int signlevel = 0;
++
++      int dadmin = 0;
++
++      const char *repository;
++      char *filefullname = NULL;
++
++
++      userfound = 0;
++      groupfound = 0;
++
++
++      if (defaultperms)
++      {
++              repository = xstrdup ("ALL");
++      }
++      else
++              repository = Short_Repository (repos);
++
++      /* cache */
++      if (usecache
++                      && cache_repository != NULL
++                      && strcmp (cache_repository, repository) == 0
++                      && !founddeniedfile
++                      && perm == cache_perm)
++              return (cache_retval);
++      else
++      {
++              free(cache_repository);
++              cache_repository = xstrdup(repository);
++              cache_perm = perm;
++      }
++
++      if (file != NULL)
++      {
++              filefullname = xmalloc (strlen (repository)
++                                      + strlen (file)
++                                      + 2);
++
++              strcpy (filefullname, repository);
++              strcat (filefullname, "/");
++              strcat (filefullname, file);
++      }
++
++
++      iline = xstrdup(repository);
++
++      tempv = strtok(iline, "/\t");
++      tempc = xstrdup(tempv);
++      tempsize = strlen(tempc);
++
++      intcount = 0;
++
++      dirs[intcount] = xstrdup(tempc);
++
++      while ((tempv = strtok(NULL, "/\t")) != NULL)
++      {
++              intcount++;
++
++              xrealloc_and_strcat(&tempc, &tempsize, "/");
++              xrealloc_and_strcat(&tempc, &tempsize, tempv);
++
++              dirs[intcount] = xstrdup(tempc);
++      }
++
++      if (file != NULL)
++      {
++              intcount++;
++              dirs[intcount] = xstrdup(filefullname);
++      }
++
++      for (accessfilecount = intcount; accessfilecount >= 0 && !oneaccessfile; accessfilecount--)
++      {
++              if (!use_seperate_acl_file_for_each_dir)
++                      oneaccessfile = 1;
++              else if (use_seperate_acl_file_for_each_dir)
++                      oneaccessfile = 0;
++
++              if (oneaccessfile)
++                      accessfp = open_accessfile ("r", repos, NULL);
++              else
++                      accessfp = open_accessfile ("r", dirs[accessfilecount], NULL);
++
++              if (accessfp != NULL)
++              {
++                      while (getline (&line, &line_allocated, accessfp) >= 0)
++                      {
++                              int x;
++
++                              if (line[0] == '#' || line[0] == '\0' || line[0] == '\n')
++                                      continue;
++
++                              xline = xstrdup (line);
++                              part_type = strtok (line, ":\t");
++                              part_object = strtok (NULL, ":\t");
++                              part_tag = strtok (NULL, ":\t");
++                              part_perms = strtok (NULL, ":\t");
++
++                              for (x = intcount; x >= signlevel; x--)
++                              {
++                                      if (strcmp (dirs[x], part_object) == 0)
++                                      {
++                                              if (valid_tag (part_tag, tag))
++                                              {
++                                                      foundline  = 1;
++
++                                                      if (listacl)
++                                                      {
++                                                              *mline = xstrdup (xline);
++                                                              *mpos = ftell (accessfp);
++                                                      }
++
++                                                      if (valid_perm (part_perms, perm))
++                                                      {
++                                                              if (signlevel == x)
++                                                              {
++                                                                      if (strncmp(part_tag, "ALL", 3) != 0 && !aclconfig_default_used)
++                                                                              retval = 1;
++                                                              }
++                                                              else if (!aclconfig_default_used)
++                                                              {
++                                                                      signlevel = x;
++                                                                      retval = 1;
++                                                              }
++                                                      }
++                                                      else
++                                                      {
++                                                              if (signlevel == x)
++                                                              {
++                                                                      if (strncmp(part_tag, "ALL", 3) != 0 && !aclconfig_default_used)
++                                                                              retval = 0;
++                                                              }
++                                                              else if (!aclconfig_default_used)
++                                                              {
++                                                                      signlevel = x;
++                                                                      retval = 0;
++
++                                                                      if (strncmp (part_type, "f", 1) == 0)
++                                                                      founddeniedfile = 1;
++
++                                                              }
++                                                      }
++                                              }
++                                      }
++                              }
++                              if (strncmp (xline, "d:ALL", 5) == 0 && (!groupfound && !userfound || listacl))
++                              {
++                                      /* a default found */
++                                      if (valid_tag (part_tag, tag))
++                                      {
++                                              foundline = 1;
++
++                                              default_part_perms_accessfile = xstrdup (part_perms);
++
++                                              if (valid_perm (part_perms, perm))
++                                              {
++                                                      retval = 1;
++
++                                                      if (perm == 8)
++                                                              dadmin = 1;
++                                              }
++                                              else
++                                                      retval = 0;
++                                      }
++                              }
++
++                      }
++                      if (fclose (accessfp) == EOF)
++                              error (1, errno, "cannot close 'access' file");
++
++              }
++      }
++
++      if (!foundline)
++      {
++              /* DEFAULT */
++              if (valid_perm (NULL, perm))
++                      retval = 1;
++              else
++                      retval = 0;
++      }
++
++      if (dadmin)
++      {
++              retval = dadmin;
++      }
++
++      cache_retval = retval;
++
++      free (filefullname);
++
++      return (retval);
++}
++
++/* Returns 1 if successful, 0 if not. */
++int
++valid_tag (part_tag, tag)
++char *part_tag;
++char *tag;
++{
++      if (tag == NULL)
++              tag = xstrdup ("HEAD");
++
++      if (strcmp (part_tag, "ALL") == 0)
++              return (1);
++
++      if (strcmp (tag, part_tag) == 0)
++              return (1);
++      else
++              return (0);
++}
++
++/* Returns 1 if successful, 0 if not. */
++int
++valid_perm (part_perms, perm)
++char *part_perms;
++int perm;
++{
++      char *perms;
++      int retval = 0;
++
++      perms = get_perms (part_perms);
++
++      /* Allow, if nothing found. */
++      if (perms[0] == '\0')
++              return (1);
++
++
++      if (strstr (perms, "n"))
++              retval = 0;             /* no access allowed, exit */
++      if (strstr (perms, "p"))
++              retval = 1;             /* admin rights */
++      else if (strstr (perms, "a") && perm != 8)
++              retval = 1;             /* all access allowed, exit */
++      else
++              switch (perm)
++              {
++              case 3:                         /* write permission */
++                      if (strstr (perms, "w"))
++                              retval = 1;
++                      break;
++              case 4:                         /* tag permission */
++                      if (strstr (perms, "t"))
++                              retval = 1;
++                      break;
++              case 5:                         /* read permission */
++                      if (strstr (perms, "w") || strstr (perms, "t") || strstr (perms, "c") ||
++                                      strstr (perms, "d") || strstr (perms, "r"))
++                              retval = 1;
++                      break;
++              case 6:                         /* create permission */
++                      if (strstr (perms, "c"))
++                              retval = 1;
++                      break;
++              case 7:                         /* delete permission */
++                      if (strstr (perms, "d"))
++                              retval = 1;
++                      break;
++              case 8:                         /* permission change */
++                      if (strstr (perms, "p"))
++                              retval = 1;
++                      break;
++              default:
++                      retval = 0;             /* never reached */
++                      break;
++              }
++
++      return (retval);
++}
++
++char *
++get_perms (part_perms)
++char *part_perms;
++
++{
++      char *username;
++      char *xperms;
++      size_t xperms_len = 1;
++
++      FILE *groupfp;
++
++      char *usr;
++      char *per;
++      char *founduser = NULL;
++      char *foundall = NULL;
++      int default_checked = 0;
++
++      aclconfig_default_used = 0;
++
++      xperms = xmalloc (xperms_len);
++      xperms[0] = '\0';
++
++      username = getcaller ();
++
++      /* no defined acl, no default acl in access file,
++      or no access file at all */
++      if (part_perms == NULL)
++              if (cvs_acl_default_permissions)
++              {
++                      aclconfig_default_used = 1;
++                      return (cvs_acl_default_permissions);
++              }
++              else
++                      return (xperms);
++
++check_default:
++      founduser = strstr (part_perms, username);
++      foundall = strstr (part_perms, "ALL!");
++
++      if (founduser)
++      {
++              usr = strtok (founduser, "!\t");
++              per = strtok (NULL, ",\t");
++
++              if (strcmp (usr, username) == 0)
++              {
++                      xperms = xstrdup (per);
++                      xperms_len = strlen (xperms);
++
++                      userfound = 1;
++              }
++      }
++      else
++      {
++              if (use_system_groups) {
++                      struct group *griter;
++                      setgrent ();
++                      while (griter = getgrent ()) {
++                              char **users=griter->gr_mem;
++                              int index = 0;
++                              char *userchk = users [index++];
++                              while(userchk != NULL) {
++                                      if(strcmp (userchk, username) == 0)
++                                              break;
++                                      userchk = users[index++];
++                              }
++                              if (userchk != NULL) {
++                                      char *grp;
++                                      if ((grp = strstr (part_perms, griter->gr_name)) && grp[strlen (griter->gr_name)] == '!') {
++                                              char *gperm = strtok (grp, "!\t");
++                                              gperm = strtok (NULL, ",\t");
++                                              xrealloc_and_strcat (&xperms, &xperms_len, gperm);
++
++                                              groupfound = 1;
++                                      }
++                              }
++                      }
++                      endgrent ();
++              }
++              else if (use_cvs_groups) {
++                      groupfp = open_groupfile ("r");
++                      if (groupfp != NULL)
++                      {
++                              char *line = NULL;
++                              size_t line_allocated = 0;
++
++                              while (getline (&line, &line_allocated, groupfp) >= 0)
++                              {
++                                      if (strstr (line, username))
++                                      {
++                                              char *temp;
++                                              temp = strstr (line, username);
++
++                                              if (temp[strlen (username)] == ','
++                                                              || temp[strlen (username)] == ' '
++                                                              || temp[strlen (username)] == '\n')
++                                              {
++                                                      char *tmp;
++                                                      tmp = strtok (line, ":\t");
++                                                      if (strcmp (tmp, username) != 0)
++                                                      {
++                                                              char *grp;
++                                                              if ((grp = strstr (part_perms, tmp)))
++                                                                      if (grp[strlen (tmp)] == '!')
++                                                                      {
++                                                                              char *gperm;
++                                                                              gperm = strtok (grp, "!\t");
++                                                                              gperm = strtok (NULL, ",\t");
++
++                                                                              xrealloc_and_strcat (&xperms, &xperms_len, gperm);
++
++                                                                              groupfound = 1;
++                                                                      }
++                                                      }
++                                              }
++                                      }
++                              }
++                              if (fclose (groupfp) == EOF)
++                                      error (1, errno, "cannot close 'group' file");
++                      }
++              }
++      }
++
++      if (foundall && (!groupfound && !userfound))
++      {
++              usr = strtok (strstr (part_perms, "ALL!"), "!\t");
++              per = strtok (NULL, ",\t");
++
++              if (!default_checked)
++                      default_perms_object = xstrdup (per);
++
++              if (xperms[0] == '\0')
++              {
++                      xperms = xstrdup (per);
++                      xperms_len = strlen (xperms);
++              }
++      }
++      else if (xperms[0] == '\0' && !default_checked && default_part_perms_accessfile)
++      {
++              part_perms = xstrdup (default_part_perms_accessfile);
++              default_checked = 1;
++
++              goto check_default;
++      }
++
++      if (xperms[0] != '\0' && strcmp (xperms, "x") == 0)
++      {
++              if (default_perms_object)
++                      xperms = xstrdup (default_perms_object);
++              else if (default_part_perms_accessfile)
++              {
++                      part_perms = default_part_perms_accessfile;
++                      default_checked = 1;
++                      goto check_default;
++              }
++              else if (cvs_acl_default_permissions)
++              {
++                      aclconfig_default_used = 1;
++                      xperms = xstrdup (cvs_acl_default_permissions);
++              }
++      }
++
++      if (xperms[0] == '\0' && cvs_acl_default_permissions)
++      {
++              aclconfig_default_used = 1;
++              xperms = xstrdup (cvs_acl_default_permissions);
++      }
++
++      return (xperms);
++}
++
++
++int
++cvsacl (argc, argv)
++int argc;
++char **argv;
++{
++      char *chdirrepository;
++      int c;
++      int err = 0;
++      int usetag = 0;
++      int recursive = 0;
++
++      int k;
++
++      int which;
++      char *where;
++
++      is_racl = (strcmp (cvs_cmd_name, "racl") == 0);
++
++      if (argc == -1)
++              usage (is_racl ? racl_usage : acl_usage);
++
++      /* parse the args */
++      optind = 0;
++
++      while ((c = getopt (argc, argv, "Rr:dfl")) != -1)
++      {
++              switch (c)
++              {
++              case 'R':
++                      recursive = 1;
++                      break;
++              case 'r':
++                      tag = xstrdup (optarg);
++                      break;
++              case 'd':
++                      acldir = 1;
++                      break;
++              case 'f':
++                      aclfile = 1;
++                      break;
++              case 'l':
++                      listacl = 1;
++                      break;
++              case '?':
++              default:
++                      usage (is_racl ? racl_usage : acl_usage);
++                      break;
++              }
++      }
++
++      argc -= optind;
++      argv += optind;
++
++      if (!acldir && !aclfile)
++              usage (is_racl ? racl_usage : acl_usage);
++      if (acldir && aclfile)
++              usage (is_racl ? racl_usage : acl_usage);
++
++      if (listacl)
++              if (strstr (argv[0], ":"))
++                      usage (is_racl ? racl_usage : acl_usage);
++      if (!listacl)
++              if (!strstr (argv[0], ":"))
++                      usage (is_racl ? racl_usage : acl_usage);
++
++      if (argc < (is_racl ? 1 : 1))
++              usage (is_racl ? racl_usage : acl_usage);
++
++#ifdef CLIENT_SUPPORT
++
++      if (current_parsed_root->isremote)
++      {
++              start_server ();
++              ign_setup ();
++
++              if(recursive)
++                      send_arg ("-R");
++
++              if (acldir)
++                      send_arg ("-d");
++
++              if (aclfile)
++                      send_arg ("-f");
++
++              if (listacl)
++                      send_arg ("-l");
++
++              if(tag)
++              {
++                      send_arg ("-r");
++                      send_arg (tag);
++              }
++
++              send_arg ("--");
++
++              if (!listacl)
++              {
++                      send_arg (argv[0]);
++
++                      argc--;
++                      argv++;
++              }
++
++              if (is_racl)
++              {
++                      int i;
++                      for (i = 0; i < argc; ++i)
++                              send_arg (argv[i]);
++
++                      send_to_server ("racl\012",0);
++              }
++              else
++              {
++                      send_files (argc, argv, recursive, 0, SEND_NO_CONTENTS);
++                      send_file_names (argc, argv, SEND_EXPAND_WILD);
++                      send_to_server ("acl\012", 0);
++              }
++
++              return get_responses_and_close ();
++      }
++#endif
++
++#ifdef SERVER_SUPPORT
++
++      if (!listacl)
++      {
++              muser = strtok (argv[0], ":\t");
++              mperms = strtok (NULL, ":\t");
++
++              /* if set to 'default' */
++              if ((strlen (mperms) == 7) && (strncmp (mperms, "default", 7) == 0))
++                      mperms = xstrdup ("x");
++
++              /* Check that the given permissions are valid. */
++              if (!given_perms_valid (mperms))
++                      error (1,0,"Invalid permissions: '%s'", mperms);
++
++              argc--;
++              argv++;
++      }
++
++
++      if (!tag)
++              tag = xstrdup ("HEAD");
++
++      if (!cvs_casecmp (argv[0], "ALL"))
++      {
++              argv[0] = xstrdup (".");
++              defaultperms = 1;
++              if (!use_seperate_acl_file_for_each_dir)
++              {
++                      recursive = 0;
++              }
++
++      }
++
++      if (is_racl)
++      {
++              DBM *db;
++              int i;
++              db = open_module ();
++              for (i = 0; i < argc; i++)
++              {
++                      err += do_module (db, argv[i], MISC, "ACL ing: ",
++                                        racl_proc, (char *) NULL, 0, !recursive, 0,
++                                        0, NULL);
++              }
++              close_module (db);
++      }
++      else
++      {
++              err = racl_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, !recursive, NULL,
++                               NULL);
++      }
++      if (err)
++              error (1, 0, "an error accured");
++
++      return (err);
++
++#endif
++}
++
++static int
++racl_proc (argc, argv, xwhere, mwhere, mfile, shorten, local, mname, msg)
++int argc;
++char **argv;
++char *xwhere;
++char *mwhere;
++char *mfile;
++int shorten;
++int local;
++char *mname;
++char *msg;
++{
++      char *myargv[2];
++      int err = 0;
++      int which;
++      char *repository;
++      char *where;
++
++      if (is_racl)
++      {
++              repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
++                                    + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
++
++              (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
++              where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
++                               + 1);
++              (void) strcpy (where, argv[0]);
++
++              /* if mfile isn't null, we need to set up to do only part of the module */
++              if (mfile != NULL)
++              {
++                      char *cp;
++                      char *path;
++
++                      /* if the portion of the module is a path, put the dir part on repos */
++                      if ((cp = strrchr (mfile, '/')) != NULL)
++                      {
++                              *cp = '\0';
++                              (void) strcat (repository, "/");
++                              (void) strcat (repository, mfile);
++                              (void) strcat (where, "/");
++                              (void) strcat (where, mfile);
++                              mfile = cp + 1;
++                      }
++
++                      /* take care of the rest */
++                      path = xmalloc (strlen (repository) + strlen (mfile) + 5);
++                      (void) sprintf (path, "%s/%s", repository, mfile);
++                      if (isdir (path))
++                      {
++                              /* directory means repository gets the dir tacked on */
++                              (void) strcpy (repository, path);
++                              (void) strcat (where, "/");
++                              (void) strcat (where, mfile);
++                      }
++                      else
++                      {
++                              myargv[0] = argv[0];
++                              myargv[1] = mfile;
++                              argc = 2;
++                              argv = myargv;
++                      }
++                      free (path);
++              }
++
++              /* cd to the starting repository */
++              if ( CVS_CHDIR (repository) < 0)
++              {
++                      error (0, errno, "cannot chdir to %s", repository);
++                      free (repository);
++                      return (1);
++              }
++
++              /* End section which is identical to patch_proc.  */
++
++              which = W_REPOS | W_ATTIC;
++      }
++      else
++      {
++              where = NULL;
++              which = W_LOCAL | W_REPOS | W_ATTIC;
++      }
++      if (listacl)
++              err = start_recursion (acllist_fileproc, NULL, acllist_dirproc, NULL, NULL,
++                                     argc - 1, argv + 1, local, which, 0, 0, (char *) where, 1,
++                                                              repository);
++      else
++              err = start_recursion (acl_fileproc, NULL, acl_dirproc, NULL, NULL,
++                                     argc - 1, argv + 1, local, which, 0, 0, (char *) where, 1,
++                                                              repository);
++
++      return (err);
++}
++
++
++static int
++acl_fileproc (callerdat, finfo)
++void *callerdat;
++struct file_info *finfo;
++{
++      Vers_TS *vers;
++
++      FILE *accessfp;
++
++      char *filefullname;
++
++      char *founduserpart = NULL;
++      char *newuserpart = NULL;
++      char *otheruserparts = NULL;
++      size_t otherslen = 0;
++
++      const char *frepository;
++      int foundline = 0;
++
++      char *line = NULL;
++      size_t line_allocated = 0;
++      int linelen;
++
++      char *part_type = NULL;
++      char *part_object = NULL;
++      char *part_tag = NULL;
++      char *part_perms = NULL;
++      char *wperms;
++      char *userpart;
++
++      char *errmsg;
++
++      int pos;
++
++      if (!aclfile)
++              return (0);
++
++      frepository = Short_Repository (finfo->repository);
++
++      filefullname = xmalloc (strlen (frepository)
++                              + strlen (finfo->file)
++                              + 2);
++      strcpy (filefullname, frepository);
++      strcat (filefullname, "/");
++      strcat (filefullname, finfo->file);
++
++      if (!access_allowed (finfo->file, finfo->repository, tag, 8, &line, &pos, 0))
++              error (1,0,"You do not have acl admin rights on '%s'", frepository);
++
++      if (line != NULL)
++      {
++              part_type = strtok (line, ":\t");
++              part_object = strtok (NULL, ":\t");
++              part_tag = strtok (NULL, ":\t");
++              part_perms = strtok (NULL, ":\t");
++
++              foundline = 1;
++              userpart = strtok (part_perms, ",\t");
++
++              if (strstr (userpart, muser))
++                      founduserpart = xstrdup (userpart);
++              else
++              {
++                      otheruserparts = xstrdup (userpart);
++                      otherslen = strlen (otheruserparts);
++              }
++
++              while ((userpart = strtok (NULL, ",\t")) != NULL)
++              {
++                      if (strncmp (userpart, muser, strlen (muser)) == 0)
++                              founduserpart = xstrdup (userpart);
++                      else
++                      {
++                              if (otheruserparts != NULL)
++                              {
++                                      xrealloc_and_strcat (&otheruserparts, &otherslen, ",");
++                                      xrealloc_and_strcat (&otheruserparts, &otherslen, userpart);
++                              }
++                              else
++                              {
++                                      otheruserparts = xstrdup (userpart);
++                                      otherslen = strlen (otheruserparts);
++                              }
++                      }
++              }
++      }
++
++      wperms = make_perms (mperms, founduserpart, &errmsg);
++      if (wperms == NULL)
++      {
++              if (errmsg)
++                      error (0, 0, "%s %s", filefullname, errmsg);
++
++              return (0);
++      }
++      else
++      {
++              cvs_output ("X ", 0);
++              cvs_output (filefullname, 0);
++              cvs_output ("\n", 0);
++
++              write_perms (muser, wperms, founduserpart, foundline,
++                           otheruserparts, "f", filefullname, tag, pos, finfo->repository);
++      }
++
++      return (0);
++}
++
++static Dtype
++acl_dirproc (callerdat, dir, repos, update_dir, entries)
++void *callerdat;
++const char *dir;
++const char *repos;
++const char *update_dir;
++List *entries;
++{
++      const char *drepository;
++      char *founduserpart = NULL;
++      char *newuserpart = NULL;
++      char *otheruserparts = NULL;
++      size_t otherslen = 0;
++      int foundline = 0;
++
++      char *line = NULL;
++      size_t line_allocated = 0;
++      int linelen;
++
++      FILE *accessfp;
++      char *part_type = NULL;
++      char *part_object = NULL;
++      char *part_tag = NULL;
++      char *part_perms = NULL;
++      char *wperms;
++      int i = 0;
++      char *userpart;
++      int pos;
++
++      char *errmsg;
++
++      if (repos[0] == '\0')
++              repos = Name_Repository (dir, NULL);
++
++      if (!acldir)
++              return (0);
++
++      if (!access_allowed (NULL, repos, tag, 8, &line, &pos, 0))
++              error (1,0,"You do not have admin rights on '%s'", Short_Repository (repos));
++
++      drepository = Short_Repository (repos);
++
++      if (line != NULL)
++      {
++              part_type = strtok (line, ":\t");
++              part_object = strtok (NULL, ":\t");
++              part_tag = strtok (NULL, ":\t");
++              part_perms = strtok (NULL, ":\t");
++
++              foundline = 1;
++              userpart = strtok (part_perms, ",\t");
++
++              if (strstr (userpart, muser))
++                      founduserpart = xstrdup (userpart);
++              else
++              {
++                      otheruserparts = xstrdup (userpart);
++                      otherslen = strlen (otheruserparts);
++              }
++
++              while ((userpart = strtok (NULL, ",\t")) != NULL)
++              {
++                      if (strncmp (userpart, muser, strlen (muser)) == 0)
++                              founduserpart = xstrdup (userpart);
++                      else
++                      {
++                              if (otheruserparts != NULL)
++                              {
++                                      xrealloc_and_strcat (&otheruserparts, &otherslen, ",");
++                                      xrealloc_and_strcat (&otheruserparts, &otherslen, userpart);
++                              }
++                              else
++                              {
++                                      otheruserparts = xstrdup (userpart);
++                                      otherslen = strlen (otheruserparts);
++                              }
++                      }
++              }
++      }
++
++      wperms = make_perms (mperms, founduserpart, &errmsg);
++      if (wperms == NULL)
++      {
++              if (errmsg)
++                      error (0, 0, "%s %s", drepository, errmsg);
++
++              return (0);
++      }
++      else
++      {
++              if (defaultperms)
++              {
++                      cvs_output ("X ", 0);
++                      cvs_output ("ALL", 0);
++                      cvs_output ("\n", 0);
++                      write_perms (muser, wperms, founduserpart, foundline,
++                                   otheruserparts, "d", "ALL", tag, pos, repos);
++
++              }
++              else
++              {
++                      cvs_output ("X ", 0);
++                      cvs_output (drepository, 0);
++                      cvs_output ("\n", 0);
++                      write_perms (muser, wperms, founduserpart, foundline,
++                                   otheruserparts, "d", drepository, tag, pos, repos);
++              }
++      }
++
++      return (0);
++}
++
++/* Open CVSROOT/access or defined CVSACLFileLocation file. */
++FILE *
++open_accessfile (fmode, adir, fname)
++char *fmode;
++char *adir;
++char **fname;
++{
++      char *accessfile;
++      FILE *accessfp;
++
++      if (!use_seperate_acl_file_for_each_dir)
++      {
++              if (cvs_acl_file_location == NULL)
++              {
++                      accessfile = xmalloc (strlen (current_parsed_root->directory)
++                                            + sizeof (CVSROOTADM)
++                                            + sizeof (CVSROOTADM_ACCESS)
++                                            + 3);
++
++                      strcpy (accessfile, current_parsed_root->directory);
++                      strcat (accessfile, "/");
++                      strcat (accessfile, CVSROOTADM);
++                      strcat (accessfile, "/");
++                      strcat (accessfile, CVSROOTADM_ACCESS);
++              }
++              else
++              {
++                      accessfile = xmalloc (strlen (cvs_acl_file_location));
++                      strcpy (accessfile, cvs_acl_file_location);
++              }
++      }
++      else
++      {
++              accessfile = xmalloc (strlen (current_parsed_root->directory)
++                                                        + strlen (adir)
++                                    + strlen ("access")
++                                    + 3);
++
++              strcpy (accessfile, current_parsed_root->directory);
++              strcat (accessfile, "/");
++              strcat (accessfile, adir);
++              strcat (accessfile, "/");
++              strcat (accessfile, "access");
++      }
++
++      accessfp = CVS_FOPEN (accessfile, fmode);
++
++      if (accessfp == NULL)
++              error (0, 0, "cannot open file: %s", accessfile);
++
++      if (fname != NULL)
++              *fname = xstrdup (accessfile);
++
++      free (accessfile);
++
++      return (accessfp);
++}
++
++/* Open /etc/group file if UseSystemGroups=yes in config file. */
++/* Open CVSROOT/group file if UseCVSGroups=yes in config file. */
++FILE *
++open_groupfile (fmode)
++char *fmode;
++{
++      char *groupfile;
++      FILE *groupfp;
++
++      if (use_cvs_groups)
++      {
++              if (cvs_groups_file_location != NULL)
++              {
++                      groupfile = xmalloc (strlen (cvs_groups_file_location));
++                      strcpy (groupfile, cvs_groups_file_location);
++              }
++              else
++              {
++                      groupfile = xmalloc (strlen (current_parsed_root->directory)
++                                           + sizeof (CVSROOTADM)
++                                           + sizeof (CVSROOTADM_GROUP)
++                                           + 3);
++
++                      strcpy (groupfile, current_parsed_root->directory);
++                      strcat (groupfile, "/");
++                      strcat (groupfile, CVSROOTADM);
++                      strcat (groupfile, "/");
++                      strcat (groupfile, CVSROOTADM_GROUP);
++              }
++      }
++
++      else
++      {
++              return (NULL);
++      }
++
++      groupfp = CVS_FOPEN (groupfile, "r");
++
++      if (groupfp == NULL)
++              error (0, 0, "cannot open file: %s", groupfile);
++
++      free (groupfile);
++
++      return (groupfp);
++}
++
++
++/* Check whether given permissions are valid or not. */
++/* Returns 1 if permissions are valid. */
++/* Returns 0 if permissions are NOT valid. */
++int
++given_perms_valid (cperms)
++char *cperms;
++{
++      int cperms_len;
++      int retval;
++      int index, i;
++
++      if (cperms[0] == '+' || cperms[0] == '-')
++              index = 1;
++      else
++              index = 0;
++
++      cperms_len = strlen (cperms);
++
++      switch (cperms[index])
++      {
++      case 'x':
++              if ((cperms_len - index) == 1 && cperms_len == 1)
++                      retval = 1;
++              else
++                      retval = 0;
++              break;
++      case 'n':
++              if ((cperms_len - index) == 1 && cperms_len == 1)
++                      retval = 1;
++              else
++                      retval = 0;
++              break;
++      case 'p':
++              if ((cperms_len - index) == 1)
++                      retval = 1;
++              else
++                      retval = 0;
++              break;
++      case 'a':
++              if ((cperms_len - index) == 1)
++                      retval = 1;
++              else
++                      for (i = index + 1; i < cperms_len; i++)
++                              if (cperms[i] == 'p')
++                                      retval = 1;
++                              else
++                                      retval = 0;
++              break;
++      case 'r':
++              if ((cperms_len - index) == 1)
++                      retval = 1;
++              else
++                      for (i = index + 1; i < cperms_len; i++)
++                              if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'd')
++                                      retval = 1;
++                              else
++                                      retval = 0;
++              break;
++      case 'w':
++              if ((cperms_len - index) == 1)
++                      retval = 1;
++              else
++                      for (i = index + 1; i < cperms_len; i++)
++                              if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'd')
++                                      retval = 1;
++                              else
++                                      retval = 0;
++              break;
++      case 't':
++              if ((cperms_len - index) == 1)
++                      retval = 1;
++              else
++                      for (i = index + 1; i < cperms_len; i++)
++                              if (cperms[i] == 'w' || cperms[i] == 'c' || cperms[i] == 'd')
++                                      retval = 1;
++                              else
++                                      retval = 0;
++              break;
++      case 'c':
++              if ((cperms_len - index) == 1)
++                      retval = 1;
++              else
++                      for (i = index + 1; i < cperms_len; i++)
++                              if (cperms[i] == 't' || cperms[i] == 'w' || cperms[i] == 'd')
++                                      retval = 1;
++                              else
++                                      retval = 0;
++              break;
++      case 'd':
++              if ((cperms_len - index) == 1)
++                      retval = 1;
++              else
++                      for (i = index + 1; i < cperms_len; i++)
++                              if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'w')
++                                      retval = 1;
++                              else
++                                      retval = 0;
++              break;
++      default:
++              retval = 0;
++              break;
++      }
++      return (retval);
++}
++
++char *
++make_perms (perms, founduserpart, xerrmsg)
++char *perms;
++char *founduserpart;
++char **xerrmsg;
++{
++      char *fperms;
++      size_t perms_len;
++      size_t fperms_len;
++      char *retperms = NULL;
++      char *xperms;
++      int i, j;
++      int err = 0;
++      char *errmsg = NULL;
++      size_t retperms_len = 1;
++
++      retperms = xmalloc (retperms_len);
++      retperms[0] = '\0';
++
++      perms_len = strlen (perms);
++
++      if (perms[0] == '+' || perms[0] == '-')
++      {
++              if (founduserpart)
++              {
++                      char *temp;
++                      temp = strtok (founduserpart, "!\t");
++                      fperms = strtok (NULL, "!\t");
++                      fperms_len = strlen (fperms);
++
++                      if (strncmp (fperms, "x", 1) == 0)
++                      {
++                              err = 1;
++                              if (perms[0] == '+')
++                                      *xerrmsg = xstrdup ("cannot add default permission 'x'");
++                              else
++                                      *xerrmsg = xstrdup ("cannot remove default permission 'x'");
++                      }
++
++                      for (i = 1; i < perms_len && !err; i++)
++                      {
++                              switch (perms[i])
++                              {
++                              case 'n':
++                                      err = 1;
++                                      break;
++                              case 'p':
++                                      if (perms[0] == '+')
++                                              fperms = xstrdup ("p");
++                                      else if (perms[0] == '-')
++                                      {
++                                              fperms_len = 1;
++                                              fperms = xmalloc (fperms_len);
++                                              fperms[0] = '\0';
++                                      }
++                                      break;
++                              case 'a':
++                                      for (j = 0; j < fperms_len; j++)
++                                      {
++                                              if (fperms[j] == 'p')
++                                              {
++                                                      err = 1;
++                                                      *xerrmsg = xstrdup ("user has admin rights, cannot use +/- permissions");
++                                              }
++                                              else if (fperms[j] == 'a' && perms[0] == '+')
++                                              {
++                                                      err = 1;
++                                                      *xerrmsg = xstrdup ("user already has all ('a') permission");
++                                              }
++                                              else if (fperms[j] != 'a' && perms[0] == '-')
++                                              {
++                                                      err = 1;
++                                                      *xerrmsg = xstrdup ("user does not have all ('a') permission");
++                                              }
++                                      }
++                                      if (perms[0] == '+')
++                                      {
++                                              fperms = xstrdup ("a");
++                                              fperms_len = strlen (fperms);
++                                      }
++                                      else if (perms[0] == '-')
++                                      {
++                                              fperms_len = 1;
++                                              fperms = xmalloc (fperms_len);
++                                              fperms[0] = '\0';
++                                      }
++
++                                      break;
++                              case 'r':
++                                      for (i = 0; i < fperms_len; i++)
++                                      {
++                                              if (fperms[i] == 'n' && perms[0] == '+')
++                                              {
++                                                      fperms = xstrdup ("r");
++                                                      fperms_len = strlen (fperms);
++                                              }
++                                              else if (fperms[i] == 'r' && perms[0] == '-')
++                                              {
++                                                      fperms_len = 1;
++                                                      fperms = xmalloc (fperms_len);
++                                                      fperms[0] = '\0';
++                                              }
++                                              else if (perms[0] == '-')
++                                              {
++                                                      err = 1;
++                                                      *xerrmsg = xstrdup ("user has other permissions, cannot remove read ('r') permission");
++                                              }
++                                              else
++                                              {
++                                                      err = 1;
++                                                      *xerrmsg = xstrdup ("user has other permissions, cannot remove read ('r') permission");
++                                              }
++                                      }
++                                      break;
++                              case 'w':
++                                      {
++                                              char *tempfperms;
++                                              size_t tempfperms_len = 1;
++
++                                              tempfperms = xmalloc (tempfperms_len);
++                                              tempfperms[0] = '\0';
++
++                                              for (j = 0; j < fperms_len; j++)
++                                              {
++                                                      if (fperms[j] == 't' || fperms[j] == 'c' || fperms[j] == 'd')
++                                                      {
++                                                              char *temp;
++                                                              temp = xmalloc (2);
++                                                              temp[0] = fperms[j];
++                                                              temp[1] = '\0';
++
++                                                              xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
++                                                              free (temp);
++                                                      }
++                                                      else if (fperms[j] == 'a' || fperms[j] == 'p')
++                                                      {
++                                                              err = 1;
++                                                              *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- write permissions");
++                                                      }
++                                                      else if (fperms[j] == 'n' || fperms[j] == 'r')
++                                                      {
++                                                              if (perms[0] == '-')
++                                                              {
++                                                                      err = 1;
++                                                                      *xerrmsg = xstrdup ("user does not have write ('w') permission");
++                                                              }
++                                                      }
++                                              }
++
++                                              fperms = xstrdup (tempfperms);
++                                              fperms_len = strlen (fperms);
++                                              free (tempfperms);
++
++                                              if (perms[0] == '+')
++                                              {
++                                                      xrealloc_and_strcat (&fperms, &fperms_len, "w");
++                                              }
++                                      }
++                                      break;
++                              case 't':
++                                      {
++                                              char *tempfperms;
++                                              size_t tempfperms_len = 1;
++
++                                              tempfperms = xmalloc (tempfperms_len);
++                                              tempfperms[0] = '\0';
++
++                                              for (j = 0; j < fperms_len; j++)
++                                              {
++                                                      if (fperms[j] == 'w' || fperms[j] == 'c' || fperms[j] == 'd')
++                                                      {
++                                                              char *temp;
++                                                              temp = xmalloc (2);
++                                                              temp[0] = fperms[j];
++                                                              temp[1] = '\0';
++
++                                                              xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
++                                                              free (temp);
++                                                      }
++                                                      else if (fperms[j] == 'a' || fperms[j] == 'p')
++                                                      {
++                                                              err = 1;
++                                                              *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- tag permissions");
++                                                      }
++                                                      else if (fperms[i] == 'n' || fperms[i] == 'r')
++                                                      {
++                                                              if (perms[0] == '-')
++                                                                      *xerrmsg = xstrdup ("user does not have tag ('t') permission");
++                                                      }
++                                              }
++
++                                              fperms = xstrdup (tempfperms);
++                                              fperms_len = strlen (fperms);
++                                              free (tempfperms);
++
++                                              if (perms[0] == '+')
++                                              {
++                                                      xrealloc_and_strcat (&fperms, &fperms_len, "t");
++                                              }
++                                      }
++                                      break;
++                              case 'c':
++                                      {
++                                              char *tempfperms;
++                                              size_t tempfperms_len = 1;
++
++                                              tempfperms = xmalloc (tempfperms_len);
++                                              tempfperms[0] = '\0';
++
++                                              for (j = 0; j < fperms_len; j++)
++                                              {
++                                                      if (fperms[j] == 'w' || fperms[j] == 't' || fperms[j] == 'd')
++                                                      {
++                                                              char *temp;
++                                                              temp = xmalloc (2);
++                                                              temp[0] = fperms[j];
++                                                              temp[1] = '\0';
++
++                                                              xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
++                                                              free (temp);
++                                                      }
++                                                      else if (fperms[j] == 'a' || fperms[j] == 'p')
++                                                      {
++                                                              err = 1;
++                                                              *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- create permissions");
++                                                      }
++                                                      else if (fperms[i] == 'n' || fperms[i] == 'r')
++                                                      {
++                                                              if (perms[0] == '-')
++                                                                      err = 1;
++                                                              *xerrmsg = xstrdup ("user does not have create ('c') permission");
++                                                      }
++
++                                              }
++
++                                              fperms = xstrdup (tempfperms);
++                                              fperms_len = strlen (fperms);
++                                              free (tempfperms);
++
++                                              if (perms[0] == '+')
++                                              {
++                                                      xrealloc_and_strcat (&fperms, &fperms_len, "c");
++                                              }
++                                      }
++                                      break;
++                              case 'd':
++                                      {
++                                              char *tempfperms;
++                                              size_t tempfperms_len = 1;
++
++                                              tempfperms = xmalloc (tempfperms_len);
++                                              tempfperms[0] = '\0';
++
++                                              for (j = 0; j < fperms_len; j++)
++                                              {
++                                                      if (fperms[j] == 'w' || fperms[j] == 'c' || fperms[j] == 't')
++                                                      {
++                                                              char *temp;
++                                                              temp = xmalloc (2);
++                                                              temp[0] = fperms[j];
++                                                              temp[1] = '\0';
++
++                                                              xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
++                                                              free (temp);
++                                                      }
++                                                      else if (fperms[j] == 'a' || fperms[j] == 'p')
++                                                      {
++                                                              err = 1;
++                                                              *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- delete permissions");
++                                                      }
++                                                      else if (fperms[i] == 'n' || fperms[i] == 'r')
++                                                      {
++                                                              if (perms[0] == '-')
++                                                                      err = 1;
++                                                              *xerrmsg = xstrdup ("user does not have delete ('d') permission");
++                                                      }
++                                              }
++
++                                              fperms = xstrdup (tempfperms);
++                                              fperms_len = strlen (fperms);
++                                              free (tempfperms);
++
++                                              if (perms[0] == '+')
++                                              {
++                                                      xrealloc_and_strcat (&fperms, &fperms_len, "d");
++                                              }
++                                      }
++                                      break;
++                              default:
++                                      err  = 1;
++                                      *xerrmsg = xstrdup ("error in 'access' file format");
++                                      break;
++                              }
++                              if (fperms[0] == '\0')
++                                      retperms = xstrdup ("none");
++                              else
++                                      retperms = xstrdup (fperms);
++                      }
++              }
++              else
++              {
++                      err = 1;
++                      *xerrmsg = xstrdup("user is not given any permissions to remove/add");
++              }
++      }
++
++      else
++      {
++              retperms = xstrdup (perms);
++      }
++
++      if (err)
++              return (NULL);
++      else
++              return (retperms);
++}
++
++int
++write_perms (user, perms, founduserpart, foundline, otheruserparts,
++             part_type, part_object, part_tag, pos, arepos)
++char *user;
++char *perms;
++char *founduserpart;
++int foundline;
++char *otheruserparts;
++char *part_type;
++char *part_object;
++char *part_tag;
++int pos;
++char *arepos;
++{
++
++      char *accessfile;
++      char *tmpaccessout;
++      FILE *accessfpin;
++      FILE *accessfpout;
++
++      char *newline = NULL;
++      size_t newlinelen = 1;
++
++      char *line = NULL;
++      size_t line_allocated = 0;
++
++      newline = xmalloc (newlinelen);
++      newline[0] = '\0';
++
++      if (!cvs_casecmp (part_tag, "ALL"))
++              part_tag = xstrdup ("ALL");
++
++      xrealloc_and_strcat (&newline, &newlinelen, part_type);
++      xrealloc_and_strcat (&newline, &newlinelen, ":");
++      xrealloc_and_strcat (&newline, &newlinelen, part_object);
++      xrealloc_and_strcat (&newline, &newlinelen, ":");
++      xrealloc_and_strcat (&newline, &newlinelen, part_tag);
++      xrealloc_and_strcat (&newline, &newlinelen, ":");
++
++      if (strncmp (perms, "none", 4) != 0)
++      {
++              xrealloc_and_strcat (&newline, &newlinelen, user);
++              xrealloc_and_strcat (&newline, &newlinelen, "!");
++              xrealloc_and_strcat (&newline, &newlinelen, perms);
++              if (otheruserparts != NULL)
++                      xrealloc_and_strcat (&newline, &newlinelen, ",");
++      }
++
++      if (otheruserparts != NULL)
++      {
++              if (otheruserparts[strlen (otheruserparts) - 1] == '\n')
++                      otheruserparts[strlen (otheruserparts) - 1] = '\0';
++
++              xrealloc_and_strcat (&newline, &newlinelen, otheruserparts);
++      }
++
++      xrealloc_and_strcat (&newline, &newlinelen, ":");
++
++      if (foundline)
++      {
++              accessfpout = cvs_temp_file (&tmpaccessout);
++              accessfpin = open_accessfile ("r", arepos, &accessfile);
++
++              while (getline (&line, &line_allocated, accessfpin) >= 0)
++              {
++                      if (pos != ftell (accessfpin))
++                      {
++                              if (fprintf (accessfpout, line) < 0)
++                                      error (1, errno, "writing temporary file: %s", tmpaccessout);
++                      }
++                      else
++                      {
++                              if (fprintf (accessfpout, "%s\n", newline) < 0)
++                                      error (1, errno, "writing temporary file: %s", tmpaccessout);
++                      }
++
++              }
++              if (fclose (accessfpin) == EOF)
++                      error (1, errno, "cannot close access file: %s", accessfile);
++
++              if (fclose (accessfpout) == EOF)
++                      error (1, errno, "cannot close temporary file: %s", tmpaccessout);
++
++              if (CVS_UNLINK (accessfile) < 0)
++                      error (0, errno, "cannot remove %s", accessfile);
++
++              copy_file (tmpaccessout, accessfile);
++
++              if (CVS_UNLINK (tmpaccessout) < 0)
++                      error (0, errno, "cannot remove temporary file: %s", tmpaccessout);
++      }
++      else
++      {
++              accessfpout = open_accessfile ("r+", arepos, &accessfile);
++
++              if (accessfpout == NULL)
++              {
++                      if (existence_error (errno))
++                      {
++                              accessfpout = open_accessfile ("w+", arepos, &accessfile);
++                      }
++              }
++
++
++              if (fseek (accessfpout, 0, 2) != 0)
++                      error (1, errno, "cannot fseek access file: %s", accessfile);
++
++              if (fprintf (accessfpout, "%s\n", newline) < 0)
++                      error (1, errno, "writing access file: %s", accessfile);
++
++              if (fclose (accessfpout) == EOF)
++                      error (1, errno, "cannot close access file: %s", accessfile);
++      }
++
++      free (newline);
++
++      chmod(accessfile, 0644);
++
++      return (0);
++}
++
++
++static int
++acllist_fileproc (callerdat, finfo)
++void *callerdat;
++struct file_info *finfo;
++{
++
++      char *filefullname;
++      const char *frepository;
++      char *line = NULL;
++      int pos;
++
++      if (!aclfile)
++              return (0);
++
++      frepository = Short_Repository (finfo->repository);
++
++      filefullname = xmalloc (strlen (frepository)
++                              + strlen (finfo->file)
++                              + 2);
++      strcpy (filefullname, frepository);
++      strcat (filefullname, "/");
++      strcat (filefullname, finfo->file);
++
++      if (!access_allowed (finfo->file, finfo->repository, tag, 5, &line, &pos, 0))
++              error (1,0,"You do not have admin rights on '%s'", frepository);
++
++      /*if (line == NULL) {
++              acldir = 1;
++              inherited = 1;
++              if (!access_allowed (NULL, finfo->repository, tag, 5, &line, &pos, 0))
++                      error (1, 0, "You do not have admin rights on '%s'", frepository);
++              acldir = 0;
++      }
++*/
++      acllist_print (line, filefullname);
++
++      return (0);
++}
++
++static Dtype
++acllist_dirproc (callerdat, dir, repos, update_dir, entries)
++void *callerdat;
++const char *dir;
++const char *repos;
++const char *update_dir;
++List *entries;
++{
++
++      char *line = NULL;
++      const char *drepository;
++      int pos;
++
++      if (repos[0] == '\0')
++              repos = Name_Repository (dir, NULL);
++
++      if (!acldir)
++              return (0);
++
++      drepository = Short_Repository (repos);
++
++      if (!access_allowed (NULL, repos, tag, 5, &line, &pos, 0))
++              error (1, 0, "You do not have admin rights on '%s'", drepository);
++
++      acllist_print (line, drepository);
++
++      return (0);
++}
++
++
++void
++acllist_print (line, obj)
++char *line;
++const char *obj;
++{
++      char *temp;
++      char *temp2;
++      int x;
++      int c = 0;
++
++      char *printedusers[255];
++      printedusers[0] = NULL;
++
++              if (line != NULL)
++              {
++                      temp = strtok (line, ":\t");
++
++                      if (acldir)
++                              cvs_output ("d ", 0);
++                      else if (aclfile)
++                              cvs_output ("f ", 0);
++
++                      temp = strtok (NULL, ":\t");
++
++                      cvs_output(obj, 0);
++                      cvs_output (" | ", 0);
++
++                      temp = strtok (NULL, ":\t");
++                      cvs_output (temp, 0);
++                      cvs_output (" | ", 0);
++
++                      while ((temp = strtok (NULL, "!\t")) != NULL)
++                      {
++                              if (strncmp (temp, ":", 1) == 0)
++                                      break;
++
++                              if (strcmp (temp, "ALL") == 0)
++                              {
++                                      temp = strtok (NULL, ",\t");
++                                      continue;
++                              }
++
++                              cvs_output (temp, 0);
++                              cvs_output (":", 0);
++
++                              while (printedusers[c] != NULL)
++                                      c++;
++
++                              printedusers[c] = xstrdup (temp);
++                              c++;
++                              printedusers[c] = NULL;
++
++                              temp = strtok (NULL, ",\t");
++
++                              if (temp != NULL && temp[strlen (temp) - 2] == ':')
++                                      temp[strlen (temp) - 2] = '\0';
++
++                              cvs_output (temp, 0);
++                              cvs_output (" ", 0);
++                      }
++
++                      if (default_perms_object)
++                      {
++                              cvs_output ("| defaults ", 0);
++                              cvs_output ("ALL:", 0);
++                              cvs_output (default_perms_object, 0);
++                      }
++                      else if (default_part_perms_accessfile)
++                      {
++                              size_t i;
++                              i = strlen (default_part_perms_accessfile);
++                              xrealloc_and_strcat (&default_part_perms_accessfile, &i, ",");
++
++                              free(line);
++                              line = xstrdup(default_part_perms_accessfile);
++
++                              cvs_output ("| defaults ", 0);
++
++                              temp = strtok (line, "!\t");
++                              cvs_output (temp, 0);
++                              cvs_output (":", 0);
++
++                              temp = strtok (NULL, ",\t");
++
++                              cvs_output (temp, 0);
++                              cvs_output (" ", 0);
++
++                              while ((temp = strtok (NULL, "!\t")) != NULL)
++                              {
++                                      int printed = 0;
++                                      int c2 = 0;
++                                      while (printedusers[c2] != NULL && printed == 0)
++                                      {
++                                              if (strcmp (printedusers[c2], temp) == 0)
++                                              {
++                                                      printed = 1;
++                                                      break;
++                                              }
++                                              c2++;
++                                      }
++
++                                      if (printed == 0)
++                                      {
++                                              cvs_output (temp, 0);
++                                              cvs_output (":", 0);
++                                      }
++
++                                      temp = strtok (NULL, ",\t");
++
++                                      if (temp[strlen (temp) - 2] == ':')
++                                              temp[strlen (temp) - 2] = '\0';
++
++                                      if (printed == 0)
++                                      {
++                                              cvs_output (temp, 0);
++                                              cvs_output (" ", 0);
++                                      }
++                              }
++                      }
++                      else if (cvs_acl_default_permissions)
++                      {
++                              cvs_output ("| defaults ", 0);
++                              cvs_output ("ALL: ", 0);
++                              cvs_output (cvs_acl_default_permissions, 0);
++                      }
++
++                      cvs_output ("\n", 0);
++
++              }
++              else
++              {
++                      if (acldir)
++                              cvs_output ("d ", 0);
++                      else if (aclfile)
++                              cvs_output ("f ", 0);
++                      cvs_output (obj, 0);
++                      cvs_output (" | ", 0);
++                      cvs_output (tag, 0);
++                      cvs_output (" | ", 0);
++
++                      if (default_perms_object)
++                      {
++                              cvs_output ("| defaults ", 0);
++                              cvs_output ("ALL:", 0);
++                              cvs_output (default_perms_object, 0);
++                              cvs_output ("\n", 0);
++                      }
++                      else if (default_part_perms_accessfile)
++                      {
++                              free(line);
++                              line = xstrdup(default_part_perms_accessfile);
++
++                              cvs_output ("| defaults ", 0);
++
++                              temp = strtok (line, "!\t");
++                              cvs_output (temp, 0);
++                              cvs_output (":", 0);
++
++                              temp = strtok (NULL, ",\t");
++
++                              if (temp[strlen (temp) - 2] == ':')
++                                      temp[strlen (temp) - 2] = '\0';
++
++                              cvs_output (temp, 0);
++                              cvs_output (" ", 0);
++
++                              while ((temp = strtok (NULL, "!\t")) != NULL)
++                              {
++                                      cvs_output (temp, 0);
++                                      cvs_output (":", 0);
++
++                                      temp = strtok (NULL, ",\t");
++
++                                      if (temp[strlen (temp) - 2] == ':')
++                                              temp[strlen (temp) - 2] = '\0';
++
++                                      cvs_output (temp, 0);
++                                      cvs_output (" ", 0);
++                              }
++                              cvs_output ("\n", 0);
++                      }
++                      else if (cvs_acl_default_permissions)
++                      {
++                              cvs_output ("| defaults ", 0);
++                              cvs_output ("ALL: ", 0);
++                              cvs_output (cvs_acl_default_permissions, 0);
++                              cvs_output ("\n", 0);
++                      }
++                      else
++                              cvs_output ("default:p (no perms)\n", 0);
++              }
++              
++}
+diff -urN cvs-1.11.15/src/add.c cvs-1.11.15-cvsacl/src/add.c
+--- cvs-1.11.15/src/add.c      2004-03-22 16:44:26.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/add.c       2004-04-25 20:04:51.687856256 +0200
+@@ -410,6 +410,24 @@
+                   }
+                   else
+                   {
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo.file, repository, vers->tag, 6,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo.repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo.repository), finfo.file);
++                      
++                      return (0);
++              }
++      }
++#endif
+                       /* There is a user file, so build the entry for it */
+                       if (build_entry (repository, finfo.file, vers->options,
+                                        message, entries, vers->tag) != 0)
+@@ -666,6 +684,26 @@
+           && isdir (finfo.file)
+           && !wrap_name_has (finfo.file, WRAP_TOCVS))
+       {
++
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (NULL, repository, NULL, 6,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo.repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo.repository), finfo.file);
++                      
++                      return (0);
++              }
++      }
++#endif
++
+           err += add_directory (&finfo);
+       }
+       else
+diff -urN cvs-1.11.15/src/annotate.c cvs-1.11.15-cvsacl/src/annotate.c
+--- cvs-1.11.15/src/annotate.c 2004-03-22 16:44:27.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/annotate.c  2004-04-25 20:04:51.689855952 +0200
+@@ -276,6 +276,25 @@
+     if (version == NULL)
+         return 0;
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo->file, finfo->repository, version, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++      }
++#endif
++
+     /* Distinguish output for various files if we are processing
+        several files.  */
+     cvs_outerr ("\nAnnotations for ", 0);
+diff -urN cvs-1.11.15/src/commit.c cvs-1.11.15-cvsacl/src/commit.c
+--- cvs-1.11.15/src/commit.c   2004-04-01 20:53:22.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/commit.c    2004-04-25 20:04:51.696854888 +0200
+@@ -1276,6 +1276,34 @@
+       return (0);
+     ci = p->data;
++
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              int whichperm;
++              if (ci->status == T_MODIFIED)
++                      whichperm = 3;
++              else if (ci->status == T_ADDED)
++                      whichperm = 6;
++              else if (ci->status == T_REMOVED)       
++                      whichperm = 7;
++
++              if (!access_allowed (finfo->file, finfo->repository, ci->tag, whichperm,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++      }
++#endif
++
+     if (ci->status == T_MODIFIED)
+     {
+       if (finfo->rcs == NULL)
+diff -urN cvs-1.11.15/src/cvs.h cvs-1.11.15-cvsacl/src/cvs.h
+--- cvs-1.11.15/src/cvs.h      2004-04-01 20:53:22.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/cvs.h       2004-04-25 20:05:38.416752384 +0200
+@@ -191,6 +191,11 @@
+ #define CVSROOTADM_PASSWD     "passwd"
+ #define CVSROOTADM_CONFIG     "config"
++/* cvsacl patch */
++#define CVSROOTADM_ACLCONFIG  "aclconfig"
++#define CVSROOTADM_ACCESS     "access"
++#define CVSROOTADM_GROUP      "group"
++
+ #define CVSNULLREPOS          "Emptydir"      /* an empty directory */
+ /* Other CVS file names */
+@@ -567,6 +572,18 @@
+ /* LockDir setting from CVSROOT/config.  */
+ extern char *lock_dir;
++/* cvsacl patch */
++/* ACL Patch settings from CVSROOT/config */
++extern int use_cvs_acl;
++extern char *cvs_acl_default_permissions;
++extern int use_cvs_groups;
++extern int use_system_groups;
++extern int use_seperate_acl_file_for_each_dir;
++extern char *cvs_acl_file_location;
++extern char *cvs_groups_file_location;
++extern char *cvs_server_run_as;
++extern int stop_at_first_permission_denied;
++
+ void Scratch_Entry PROTO((List * list, const char *fname));
+ void ParseTag PROTO((char **tagp, char **datep, int *nonbranchp));
+ void WriteTag PROTO ((const char *dir, const char *tag, const char *date,
+@@ -863,6 +880,10 @@
+ int editors PROTO ((int argc, char **argv));
+ int watchers PROTO ((int argc, char **argv));
+ extern int annotate PROTO ((int argc, char **argv));
++
++/* cvsacl patch */
++extern int cvsacl PROTO ((int argc, char **argv));
++
+ extern int add PROTO ((int argc, char **argv));
+ extern int admin PROTO ((int argc, char **argv));
+ extern int checkout PROTO ((int argc, char **argv));
+diff -urN cvs-1.11.15/src/diff.c cvs-1.11.15-cvsacl/src/diff.c
+--- cvs-1.11.15/src/diff.c     2004-03-20 03:06:45.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/diff.c      2004-04-25 20:04:51.708853064 +0200
+@@ -474,6 +474,43 @@
+     {
+       /* Skip all the following checks regarding the user file; we're
+          not using it.  */
++
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (diff_rev1)
++              {
++              if (!access_allowed (NULL, finfo->repository, diff_rev1, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++              }
++              if (diff_rev2)
++              {
++              if (!access_allowed (NULL, finfo->repository, diff_rev2, 5))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++              }
++      }
++#endif
++
+     }
+     else if (vers->vn_user == NULL)
+     {
+@@ -827,6 +864,42 @@
+     if (!isdir (dir))
+       return (R_SKIP_ALL);
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (diff_rev1)
++              {
++              if (!access_allowed (NULL, update_dir, diff_rev1, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (update_dir));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (update_dir), update_dir);
++                      
++                      return (0);
++              }
++              }
++              if (diff_rev2)
++              {
++              if (!access_allowed (NULL, update_dir, diff_rev2, 5))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (update_dir));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (update_dir), update_dir);
++                      
++                      return (0);
++              }
++              }
++      }
++#endif
++
+     if (!quiet)
+       error (0, 0, "Diffing %s", update_dir);
+     return (R_PROCESS);
+diff -urN cvs-1.11.15/src/import.c cvs-1.11.15-cvsacl/src/import.c
+--- cvs-1.11.15/src/import.c   2004-04-02 20:55:49.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/import.c    2004-04-25 20:04:51.714852152 +0200
+@@ -304,6 +304,20 @@
+       error (1, 0, "attempt to import the repository");
+     }
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (NULL, repository, argv[1], 6, NULL, NULL, 1))
++              {
++                      error (stop_at_first_permission_denied, 0, "permission denied for %s",
++                                                      Short_Repository (repository));
++                      
++                      return (0);
++              }
++      }
++#endif
++
+     /*
+      * Make all newly created directories writable.  Should really use a more
+      * sophisticated security mechanism here.
+diff -urN cvs-1.11.15/src/log.c cvs-1.11.15-cvsacl/src/log.c
+--- cvs-1.11.15/src/log.c      2004-04-06 20:54:52.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/log.c       2004-04-25 20:04:51.722850936 +0200
+@@ -837,6 +837,25 @@
+       return 1;
+     }
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo->file, finfo->repository, NULL, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++      }
++#endif
++
+     if (log_data->sup_header || !log_data->nameonly)
+     {
+diff -urN cvs-1.11.15/src/main.c cvs-1.11.15-cvsacl/src/main.c
+--- cvs-1.11.15/src/main.c     2004-03-22 16:44:27.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/main.c      2004-04-25 20:04:51.726850328 +0200
+@@ -104,6 +104,10 @@
+ } cmds[] =
+ {
++    /* cvsacl patch */
++    { "acl",      NULL,       NULL,              cvsacl,    CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
++    { "racl",     NULL,       NULL,              cvsacl,    CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
++    
+     { "add",      "ad",       "new",       add,       CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+     { "admin",    "adm",      "rcs",       admin,     CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
+     { "annotate", "ann",      NULL,        annotate,  CVS_CMD_USES_WORK_DIR },
+@@ -974,6 +978,9 @@
+                  if we didn't, then there would be no way to check in a new
+                  CVSROOT/config file to fix the broken one!  */
+               parse_config (current_parsed_root->directory);
++              
++              /* cvsacl patch */
++              parse_aclconfig (current_parsed_root->directory);
+           }
+ #ifdef CLIENT_SUPPORT
+diff -urN cvs-1.11.15/src/Makefile.am cvs-1.11.15-cvsacl/src/Makefile.am
+--- cvs-1.11.15/src/Makefile.am        2004-02-03 20:05:36.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/Makefile.am 2004-04-25 20:04:51.728850024 +0200
+@@ -29,6 +29,7 @@
+ # The cvs executable
+ cvs_SOURCES = \
++      acl.c \
+       add.c \
+       admin.c \
+       annotate.c \
+diff -urN cvs-1.11.15/src/Makefile.in cvs-1.11.15-cvsacl/src/Makefile.in
+--- cvs-1.11.15/src/Makefile.in        2004-04-14 04:42:00.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/Makefile.in 2004-04-25 20:04:51.732849416 +0200
+@@ -153,6 +153,7 @@
+ # The cvs executable
+ cvs_SOURCES = \
++      acl.c \
+       add.c \
+       admin.c \
+       annotate.c \
+@@ -253,11 +254,11 @@
+ bin_PROGRAMS = cvs$(EXEEXT)
+ PROGRAMS = $(bin_PROGRAMS)
+-am_cvs_OBJECTS = add.$(OBJEXT) admin.$(OBJEXT) annotate.$(OBJEXT) \
+-      buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \
+-      classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \
+-      create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \
+-      edit.$(OBJEXT) entries.$(OBJEXT) error.$(OBJEXT) \
++am_cvs_OBJECTS = acl.$(OBJEXT) add.$(OBJEXT) admin.$(OBJEXT) \
++      annotate.$(OBJEXT) buffer.$(OBJEXT) checkin.$(OBJEXT) \
++      checkout.$(OBJEXT) classify.$(OBJEXT) client.$(OBJEXT) \
++      commit.$(OBJEXT) create_adm.$(OBJEXT) cvsrc.$(OBJEXT) \
++      diff.$(OBJEXT) edit.$(OBJEXT) entries.$(OBJEXT) error.$(OBJEXT) \
+       expand_path.$(OBJEXT) fileattr.$(OBJEXT) filesubr.$(OBJEXT) \
+       find_names.$(OBJEXT) hardlink.$(OBJEXT) hash.$(OBJEXT) \
+       history.$(OBJEXT) ignore.$(OBJEXT) import.$(OBJEXT) \
+@@ -280,34 +281,34 @@
+ DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+ depcomp = $(SHELL) $(top_srcdir)/depcomp
+ am__depfiles_maybe = depfiles
+-@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/add.Po ./$(DEPDIR)/admin.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/annotate.Po ./$(DEPDIR)/buffer.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/checkin.Po ./$(DEPDIR)/checkout.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/classify.Po ./$(DEPDIR)/client.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/commit.Po ./$(DEPDIR)/create_adm.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/cvsrc.Po ./$(DEPDIR)/diff.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/edit.Po ./$(DEPDIR)/entries.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/error.Po ./$(DEPDIR)/expand_path.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/fileattr.Po ./$(DEPDIR)/filesubr.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/find_names.Po ./$(DEPDIR)/hardlink.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/hash.Po ./$(DEPDIR)/history.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/ignore.Po ./$(DEPDIR)/import.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/lock.Po ./$(DEPDIR)/log.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/login.Po ./$(DEPDIR)/logmsg.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/main.Po ./$(DEPDIR)/mkmodules.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/modules.Po ./$(DEPDIR)/myndbm.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/no_diff.Po ./$(DEPDIR)/parseinfo.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/patch.Po ./$(DEPDIR)/rcs.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/rcscmds.Po ./$(DEPDIR)/recurse.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/release.Po ./$(DEPDIR)/remove.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/repos.Po ./$(DEPDIR)/root.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/run.Po ./$(DEPDIR)/scramble.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/server.Po ./$(DEPDIR)/stack.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/status.Po ./$(DEPDIR)/subr.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/tag.Po ./$(DEPDIR)/update.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/vers_ts.Po ./$(DEPDIR)/version.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/watch.Po ./$(DEPDIR)/wrapper.Po \
+-@AMDEP_TRUE@  ./$(DEPDIR)/zlib.Po
++@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/acl.Po ./$(DEPDIR)/add.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/admin.Po ./$(DEPDIR)/annotate.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/buffer.Po ./$(DEPDIR)/checkin.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/checkout.Po ./$(DEPDIR)/classify.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/client.Po ./$(DEPDIR)/commit.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/create_adm.Po ./$(DEPDIR)/cvsrc.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/diff.Po ./$(DEPDIR)/edit.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/entries.Po ./$(DEPDIR)/error.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/expand_path.Po ./$(DEPDIR)/fileattr.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/filesubr.Po ./$(DEPDIR)/find_names.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/hardlink.Po ./$(DEPDIR)/hash.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/history.Po ./$(DEPDIR)/ignore.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/import.Po ./$(DEPDIR)/lock.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/log.Po ./$(DEPDIR)/login.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/logmsg.Po ./$(DEPDIR)/main.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/mkmodules.Po ./$(DEPDIR)/modules.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/myndbm.Po ./$(DEPDIR)/no_diff.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/parseinfo.Po ./$(DEPDIR)/patch.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/rcs.Po ./$(DEPDIR)/rcscmds.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/recurse.Po ./$(DEPDIR)/release.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/remove.Po ./$(DEPDIR)/repos.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/root.Po ./$(DEPDIR)/run.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/scramble.Po ./$(DEPDIR)/server.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/stack.Po ./$(DEPDIR)/status.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/subr.Po ./$(DEPDIR)/tag.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/update.Po ./$(DEPDIR)/vers_ts.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/version.Po ./$(DEPDIR)/watch.Po \
++@AMDEP_TRUE@  ./$(DEPDIR)/wrapper.Po ./$(DEPDIR)/zlib.Po
+ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+ CCLD = $(CC)
+@@ -381,6 +382,7 @@
+ distclean-compile:
+       -rm -f *.tab.c
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/admin.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/annotate.Po@am__quote@
+diff -urN cvs-1.11.15/src/mkmodules.c cvs-1.11.15-cvsacl/src/mkmodules.c
+--- cvs-1.11.15/src/mkmodules.c        2004-02-03 15:39:40.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/mkmodules.c 2004-04-25 20:04:51.736848808 +0200
+@@ -311,6 +311,44 @@
+     NULL
+ };
++/* cvsacl patch */
++static const char *const aclconfig_contents[] = {
++      "# Set `UseCVSACL' to yes to use CVSACL feature.\n",
++      "UseCVSACL=yes\n",
++      "\n",
++      "# Default CVSACL Permission to use.\n",
++      "#CVSACLDefaultPermissions=p\n",
++      "\n",
++      "# Default file location for CVS ACL file (access) is CVSROOT/access.\n",
++      "# If you want to use a different location, define it below.\n",
++      "#CVSACLFileLocation=/path/to/cvs/access\n",
++      "\n",
++      "# Set `UseSystemGroups' to yes to use system group definitions (/etc/group).\n",
++      "UseSystemGroups=yes\n",
++      "\n",
++      "# Set `UseCVSGroups' to yes to use another group file.\n",
++      "#UseCVSGroups=yes\n",
++      "\n",
++      "# Default file location for CVS groups file is CVSROOT/group.\n",
++      "# If you want to use a different location, define it below.\n",
++      "#CVSGroupsFileLocation=/path/to/cvs/group\n",
++      "\n",
++      "# Set UseSeperateACLFileForEachDir to yes in order to use a\n",
++      "# seperate 'access' file for each directory.\n",
++      "# This increased the performance if you have really big repository.\n",
++      "#UseSeperateACLFileForEachDir=no\n",
++      "\n",
++      "# If StopAtFirstPermissionDenied is set to yes\n",
++      "# operation will stop at first permission denied message.\n",
++      "# Default is no.\n",
++      "#StopAtFirstPermissionDenied=no\n",
++      "\n",
++      "# Set CVSServerRunAsUser to a system user, in order CVS server\n",
++      "# to run as.\n",
++      "#CVSServerRunAsUser=runascvsuser",
++    NULL
++};
++
+ static const struct admin_file filelist[] = {
+     {CVSROOTADM_LOGINFO, 
+       "no logging of 'cvs commit' messages is done without a %s file",
+@@ -373,7 +411,12 @@
+     {CVSROOTADM_CONFIG,
+        "a %s file configures various behaviors",
+        config_contents},
+-    {NULL, NULL, NULL}
++     
++     /* cvsacl patch */
++    {CVSROOTADM_ACLCONFIG,
++       "a %s file configures Access Control List behaviors",
++       aclconfig_contents},
++       {NULL, NULL, NULL}
+ };
+ /* Rebuild the checked out administrative files in directory DIR.  */
+@@ -957,6 +1000,26 @@
+            because xchmod() is too shy. */
+         chmod (info, 0666);
+     }
++    
++    /* cvsacl patch */
++    /* Make an empty 'CVSROOT/access' file  */
++    strcpy (info, adm);
++    strcat (info, "/");
++    strcat (info, CVSROOTADM_ACCESS);
++    if (!isfile (info))
++    {
++      FILE *fp;
++
++      fp = open_file (info, "w");
++    if (fputs ("# CVS ACL definitions file. DO NOT EDIT MANUALLY\n",
++               fp) < 0)
++              error (1, errno, "cannot write %s", info);
++
++      if (fclose (fp) < 0)
++          error (1, errno, "cannot close %s", info);
++ 
++        chmod (info, 0644);
++    }
+     /* Make an empty val-tags file to prevent problems creating it later.  */
+     strcpy (info, adm);
+diff -urN cvs-1.11.15/src/parseinfo.c cvs-1.11.15-cvsacl/src/parseinfo.c
+--- cvs-1.11.15/src/parseinfo.c        2004-03-19 21:36:39.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/parseinfo.c 2004-04-25 20:04:51.740848200 +0200
+@@ -448,3 +448,192 @@
+       free (line);
+     return -1;
+ }
++/* cvsacl patch */
++int
++parse_aclconfig (cvsroot)
++    char *cvsroot;
++{
++    char *infopath;
++    FILE *fp_info;
++    char *line = NULL;
++    size_t line_allocated = 0;
++    size_t len;
++    char *p;
++    /* FIXME-reentrancy: If we do a multi-threaded server, this would need
++       to go to the per-connection data structures.  */
++    static int parsed = 0;
++
++    /* Authentication code and serve_root might both want to call us.
++       Let this happen smoothly.  */
++    if (parsed)
++      return 0;
++    parsed = 1;
++
++    infopath = xmalloc (strlen (cvsroot)
++                      + sizeof (CVSROOTADM_ACLCONFIG)
++                      + sizeof (CVSROOTADM)
++                      + 10);
++    if (infopath == NULL)
++    {
++      error (0, 0, "out of memory; cannot allocate infopath");
++      goto error_return;
++    }
++
++    strcpy (infopath, cvsroot);
++    strcat (infopath, "/");
++    strcat (infopath, CVSROOTADM);
++    strcat (infopath, "/");
++    strcat (infopath, CVSROOTADM_ACLCONFIG);
++
++    fp_info = CVS_FOPEN (infopath, "r");
++    if (fp_info == NULL)
++    {
++      /* If no file, don't do anything special.  */
++      if (!existence_error (errno))
++      {
++          /* Just a warning message; doesn't affect return
++             value, currently at least.  */
++          error (0, errno, "cannot open %s", infopath);
++      }
++      free (infopath);
++      return 0;
++    }
++
++    while (getline (&line, &line_allocated, fp_info) >= 0)
++    {
++      /* Skip comments.  */
++      if (line[0] == '#')
++          continue;
++
++      len = strlen (line) - 1;
++      if (line[len] == '\n')
++          line[len] = '\0';
++
++      /* Skip blank lines.  */
++      if (line[0] == '\0')
++          continue;
++
++      /* The first '=' separates keyword from value.  */
++      p = strchr (line, '=');
++      if (p == NULL)
++      {
++          /* Probably should be printing line number.  */
++          error (0, 0, "syntax error in %s: line '%s' is missing '='",
++                 infopath, line);
++          goto error_return;
++      }
++
++      *p++ = '\0';
++
++      if (strcmp (line, "UseCVSACL") == 0)
++      {
++          if (strcmp (p, "no") == 0)
++              use_cvs_acl = 0;
++          else if (strcmp (p, "yes") == 0)
++              use_cvs_acl = 1;
++          else
++          {
++              error (0, 0, "unrecognized value '%s' for UseCVSACL", p);
++              goto error_return;
++          }
++      }
++      else if (strcmp (line, "UseSeperateACLFileForEachDir") == 0)
++      {
++          if (strcmp (p, "no") == 0)
++              use_seperate_acl_file_for_each_dir = 0;
++          else if (strcmp (p, "yes") == 0)
++              use_seperate_acl_file_for_each_dir = 1;
++          else
++          {
++              error (0, 0, "unrecognized value '%s' for UseSeperateACLFileForEachDir", p);
++              goto error_return;
++          }
++      }
++      else if (strcmp (line, "StopAtFirstPermissionDenied") == 0)
++      {
++          if (strcmp (p, "no") == 0)
++              stop_at_first_permission_denied = 0;
++          else if (strcmp (p, "yes") == 0)
++              stop_at_first_permission_denied = 1;
++          else
++          {
++              error (0, 0, "unrecognized value '%s' for StopAtFirstPermissionDenied", p);
++              goto error_return;
++          }
++      }
++      else if (strcmp (line, "CVSACLDefaultPermissions") == 0)
++      {
++          if (cvs_acl_default_permissions != NULL)
++              free (cvs_acl_default_permissions);
++                      if (!given_perms_valid (p))
++                              error (1,0,"Invalid CVS ACL Default Permissions: '%s' in CVSROOT/aclconfig", p);
++              cvs_acl_default_permissions = xstrdup (p);
++      }
++      else if (strcmp (line, "UseCVSGroups") == 0)
++      {
++          if (strcmp (p, "no") == 0)
++              use_cvs_groups = 0;
++          else if (strcmp (p, "yes") == 0)
++              use_cvs_groups = 1;
++          else
++          {
++              error (0, 0, "unrecognized value '%s' for UseCVSGroups", p);
++              goto error_return;
++          }
++      }
++      else if (strcmp (line, "UseSystemGroups") == 0)
++      {
++          if (strcmp (p, "no") == 0)
++              use_system_groups = 0;
++          else if (strcmp (p, "yes") == 0)
++              use_system_groups = 1;
++          else
++          {
++              error (0, 0, "unrecognized value '%s' for UseSystemGroups", p);
++              goto error_return;
++          }
++      }
++      else if (strcmp (line, "CVSACLFileLocation") == 0)
++      {
++          if (cvs_acl_file_location != NULL)
++              free (cvs_acl_file_location);
++              cvs_acl_file_location = xstrdup (p);
++      }
++      else if (strcmp (line, "CVSGroupsFileLocation") == 0)
++      {
++          if (cvs_groups_file_location != NULL)
++              free (cvs_groups_file_location);
++              cvs_groups_file_location = xstrdup (p);
++      }
++      else if (strcmp (line, "CVSServerRunAsUser") == 0)
++      {
++          if (cvs_server_run_as != NULL)
++              free (cvs_server_run_as);
++              cvs_server_run_as = xstrdup (p);
++      }
++
++    }
++      
++    if (ferror (fp_info))
++    {
++      error (0, errno, "cannot read %s", infopath);
++      goto error_return;
++    }
++    if (fclose (fp_info) < 0)
++    {
++      error (0, errno, "cannot close %s", infopath);
++      goto error_return;
++    }
++    free (infopath);
++    if (line != NULL)
++      free (line);
++    return 0;
++
++ error_return:
++    if (infopath != NULL)
++      free (infopath);
++    if (line != NULL)
++      free (line);
++    return -1;
++}
++
+diff -urN cvs-1.11.15/src/patch.c cvs-1.11.15-cvsacl/src/patch.c
+--- cvs-1.11.15/src/patch.c    2004-04-02 21:25:32.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/patch.c     2004-04-25 20:04:51.744847592 +0200
+@@ -498,6 +498,43 @@
+       goto out2;
+     }
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (rev1)
++              {
++              if (!access_allowed (finfo->file, finfo->repository, rev1, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++              }
++              if (rev2)
++              {
++              if (!access_allowed (finfo->file, finfo->repository, rev2, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++              }
++      }
++#endif
++
+     /* Create 3 empty files.  I'm not really sure there is any advantage
+      * to doing so now rather than just waiting until later.
+      *
+diff -urN cvs-1.11.15/src/remove.c cvs-1.11.15-cvsacl/src/remove.c
+--- cvs-1.11.15/src/remove.c   2004-03-20 03:34:32.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/remove.c    2004-04-25 20:04:51.746847288 +0200
+@@ -250,6 +250,25 @@
+     {
+       char *fname;
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo->file, finfo->repository, vers->tag, 7,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++      }
++#endif
++
+       /* Re-register it with a negative version number.  */
+       fname = xmalloc (strlen (vers->vn_user) + 5);
+       (void) strcpy (fname, "-");
+diff -urN cvs-1.11.15/src/server.c cvs-1.11.15-cvsacl/src/server.c
+--- cvs-1.11.15/src/server.c   2004-04-06 22:20:55.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/server.c    2004-04-25 20:30:27.889318136 +0200
+@@ -773,6 +773,10 @@
+        nothing.  But for rsh, we need to do it now.  */
+     parse_config (current_parsed_root->directory);
++    /* cvsacl patch */
++    parse_aclconfig (current_parsed_root->directory);
++      
++
+     path = xmalloc (strlen (current_parsed_root->directory)
+                  + sizeof (CVSROOTADM)
+                  + 2);
+@@ -3667,6 +3671,23 @@
+     do_cvs_command ("rlog", cvslog);
+ }
++/* cvsacl patch */
++static void
++serve_acl (arg)
++    char *arg;
++{
++    do_cvs_command ("acl", cvsacl);
++}
++
++/* cvsacl patch */
++static void
++serve_racl (arg)
++    char *arg;
++{
++    cvs_cmd_name = "racl";
++    do_cvs_command ("racl", cvsacl);
++}
++
+ static void
+ serve_add (arg)
+     char *arg;
+@@ -4726,6 +4747,11 @@
+   REQ_LINE("diff", serve_diff, 0),
+   REQ_LINE("log", serve_log, 0),
+   REQ_LINE("rlog", serve_rlog, 0),
++
++  /* cvsacl patch */
++  REQ_LINE("acl", serve_acl, 0),
++  REQ_LINE("racl", serve_racl, 0),
++  
+   REQ_LINE("add", serve_add, 0),
+   REQ_LINE("remove", serve_remove, 0),
+   REQ_LINE("update-patches", serve_ignore, 0),
+@@ -5199,6 +5225,10 @@
+ {
+     struct passwd *pw;
++      /* cvsacl patch */
++      if (use_cvs_acl && cvs_server_run_as)
++              username = cvs_server_run_as;
++
+     pw = getpwnam (username);
+     if (pw == NULL)
+     {
+@@ -5781,6 +5811,9 @@
+        in a new CVSROOT/config file to fix the broken one!  */
+     parse_config (repository);
++    /* cvsacl patch */
++    parse_aclconfig (repository);
++      
+     /* We need the real cleartext before we hash it. */
+     descrambled_password = descramble (password);
+     host_user = check_password (username, descrambled_password, repository);
+diff -urN cvs-1.11.15/src/status.c cvs-1.11.15-cvsacl/src/status.c
+--- cvs-1.11.15/src/status.c   2004-03-20 02:40:12.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/status.c    2004-04-25 20:04:51.767844096 +0200
+@@ -128,7 +128,27 @@
+     status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL,
+                           1, 0, &vers, 0);
+-    sstat = "Classify Error";
++
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo->file, finfo->repository, vers->tag, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++      }
++#endif
++
++      sstat = "Classify Error";
+     switch (status)
+     {
+       case T_UNKNOWN:
+diff -urN cvs-1.11.15/src/tag.c cvs-1.11.15-cvsacl/src/tag.c
+--- cvs-1.11.15/src/tag.c      2004-04-06 20:37:10.000000000 +0200
++++ cvs-1.11.15-cvsacl/src/tag.c       2004-04-25 20:04:51.772843336 +0200
+@@ -660,6 +660,25 @@
+      * correctly without breaking your link!
+      */
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo->file, finfo->repository, numtag, 4,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++
++                      return (0);
++              }
++      }
++#endif
++
+     if (delete_flag)
+       return (rtag_delete (rcsfile));
+@@ -880,6 +899,21 @@
+         if (nversion == NULL)
+           goto free_vars_and_return;
+     }
++
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo->file, finfo->repository, vers->tag, 4,
++                                                              NULL, NULL, 1))
++              {
++                      error (0, 0, "permission denied for %s/%s",
++                                              Short_Repository (finfo->repository), finfo->file);
++                      return (0);
++              }
++      }
++#endif
++
+     if (delete_flag)
+     {
+diff -urN cvs-1.11.15/src/update.c cvs-1.11.15-cvsacl/src/update.c
+--- cvs-1.11.15/src/update.c   2004-03-22 18:20:26.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/update.c    2004-04-25 20:04:51.782841816 +0200
+@@ -594,6 +594,26 @@
+     status = Classify_File (finfo, tag, date, options, force_tag_match,
+                           aflag, &vers, pipeout);
++
++/* cvsacl patch */
++#ifdef SERVER_SUPPORT
++      if (use_cvs_acl && server_active)
++      {
++              if (!access_allowed (finfo->file, finfo->repository, vers->tag, 5,
++                                                              NULL, NULL, 1))
++              {
++                      if (stop_at_first_permission_denied)
++                              error (1, 0, "permission denied for %s",
++                                                      Short_Repository (finfo->repository));
++                      else
++                              error (0, 0, "permission denied for %s/%s",
++                                                      Short_Repository (finfo->repository), finfo->file);
++                      
++                      return (0);
++              }
++      }
++#endif
++                          
+     /* Keep track of whether TAG is a branch tag.
+        Note that if it is a branch tag in some files and a nonbranch tag
+        in others, treat it as a nonbranch tag.  It is possible that case
+diff -urN cvs-1.11.15/src/version.c cvs-1.11.15-cvsacl/src/version.c
+--- cvs-1.11.15/src/version.c  2004-02-03 15:37:56.000000000 +0100
++++ cvs-1.11.15-cvsacl/src/version.c   2004-04-25 20:04:51.783841664 +0200
+@@ -26,7 +26,8 @@
+ #endif
+ #endif
+-
++/* cvsacl patch */
++char *aclpatch_string = "with CVSACL Patch 1.2.0 (cvsacl.sourceforge.net)\n";
+ static const char *const version_usage[] =
+ {
+@@ -63,6 +64,8 @@
+        released.  */
+     (void) fputs (PACKAGE_STRING, stdout);
+     (void) fputs (config_string, stdout);
++    /* cvsacl patch */
++    (void) fputs (aclpatch_string, stdout);
+ #ifdef CLIENT_SUPPORT
+     if (current_parsed_root && current_parsed_root->isremote)
This page took 0.177136 seconds and 4 git commands to generate.