]> git.pld-linux.org Git - packages/cvs.git/blame - cvs-acl.patch
- removed ACL patch (its no longer maintained + it has memleaks and possible SEGVs)
[packages/cvs.git] / cvs-acl.patch
CommitLineData
fe149767 1diff -urN cvs-1.11.19.orig/INSTALL.cvsacl cvs-1.11.19/INSTALL.cvsacl
2--- cvs-1.11.19.orig/INSTALL.cvsacl 1970-01-01 01:00:00.000000000 +0100
3+++ cvs-1.11.19/INSTALL.cvsacl 2004-11-26 13:48:57.000000000 +0100
09f63587 4@@ -0,0 +1,23 @@
5+
6+Installation
7+
8+- copy the file acl.c under src directory of CVS source distribution.
fe149767 9+ "cp acl.c /path/to/cvs-1.11.18/src/"
10+- copy the patch file cvsacl-patch-1.2.2 under CVS source distribution
09f63587 11+ directory.
fe149767 12+ "cp cvsacl-patch-1.2.2 /path/to/cvs-1.11.18/"
09f63587 13+- cd to CVS source directory.
fe149767 14+ "cd /path/to/cvs-1.11.18/"
09f63587 15+- apply the patch.
fe149767 16+ "patch -p0 < cvsacl-patch-1.2.2"
09f63587 17+- if you are initializing the repository after applying patch, related
18+ config files will be created with init command.
19+ "cvs -d /path/to/repository init"
20+- if you already have a repository, you have to add the aclconfig file
21+ to your $CVSROOT/CVSROOT/. aclconfig.default is the default configuration
22+ file, you can rename it to aclconfig, and use it .
23+- modify aclconfig file, if you need to change some options.
24+- as the last step, you have to define yourself as acl administrator.
25+ "cvs -d /path/to/repository racl yourname:p -r ALL -d ALL"
26+ this command gives p (acl admin) rights to user (yourname),
27+ on all repository and tags/branches.
fe149767 28diff -urN cvs-1.11.19.orig/README.cvsacl cvs-1.11.19/README.cvsacl
29--- cvs-1.11.19.orig/README.cvsacl 1970-01-01 01:00:00.000000000 +0100
30+++ cvs-1.11.19/README.cvsacl 2004-11-26 13:47:23.000000000 +0100
09f63587 31@@ -0,0 +1,282 @@
32+
33+CVS Access Control List Extension Patch
34+
35+http://cvsacl.sourceforge.net/
36+sbaris@users.sourceforge.net
37+
38+CVSACL is a patch for CVS. It adds two new subcommands
39+(acl & racl) to cvs for access control list management. It
40+provides advanced ACL definitions per modules, directories,
41+and files on branch/tag for remote cvs repository connections.
42+Execution of all CVS subcommands can be controlled with eight
43+different permissions.
44+ACL definitions works for only remote connections, local users
45+can access and modify repository, if unix file system permissions
46+allow. If you want all users to make remote connections to
47+repository, and not allow local users to access repository, you
48+have to set CVSServerRunAsUser keyword in aclconfig file
49+(explained below).
50+Still local users can use acl and racl subcommands to set
51+permissions on directories or files if they have acl admin rights (p)
52+on related directories or files.
53+So, in order to control all access to repository with this ACL
54+extension, you should use CVSServerRunAsUser keyword and force all
55+users to make remote connections. CVS repository administrator or
56+project managers have to use acl and racl subcommands to manage
57+permissions. But there is no gui client supporting these subcommands,
58+so you have to use cvs client itself either locally or remotely.
59+
60+
61+
62+
63+Permission Types
64+
65+- no access
66+ Command line character: n
67+ If a user given n permission, it is not allowed for any action on repository.
68+- read
69+ Command line character: r
70+ r permission gives only read access on repository.
71+ With r permission you are allowed to run cvs subcommands: annotate,
72+ checkout, diff, export, log, rannotate, rdiff, rlog, status.
73+- write
74+ Command line character: w
75+ w permission allows only cvs commit/checkin action.
76+ With w permission, you are not allowed to add/remove any file to/from
77+ repository, other permissions should be defines for that.
78+- tag
79+ Command line character: t
80+ t permission allows cvs tag and rtag subcommands to run, so you may
81+ control tagging and untagging operations. t permission includes r
82+ permission, since without reading you can not tag/untag a file.
83+ However t permission does not include write permission, you can not
84+ commit a file with only t permission.
85+- create
86+ Command line character: c
87+ c permission allows cvs add and import subcommands to run. To add or
88+ import a file/directory to repository, you have to given a c
89+ permission. Again, c permission does not include write permission,
90+ thus you may only add or import files, but you can not modify any
91+ existing file. After issuing add subcommand, you have to commit the file
92+ to complete adding. This commit subcommand is allowed because you are
93+ adding file and not modifying existing one.
94+- delete
95+ Command line character: d
96+ d permission allows cvs remove command to run. To remove a file/directory
97+ from repository, d permission have to set. It does not include write
98+ permission, so you can not modify contents of an existing file on repository.
99+- full access except admin rights
100+ Command line character: a
101+ a permission gives all access (above permissions) to repository, but it
102+ can not modify permissions. Only acl admins may modify the acl definitions.
103+- acl admin
104+ Command line character: p
105+ p permission means that user is an acl admin, so it is allowed to make anything on repository.
106+
107+
108+ACL Config Keywords
109+The administrative file aclconfig contains miscellaneous settings which
110+affect the behaviour of ACL extension. Currently defined keywords are:
111+
112+UseCVSACL=value
113+Use ACL definitions if set to yes. If you do not want to use ACLs for
114+some repositories in a patched CVS server, set this keyword to no. The default is no.
115+
116+UseCVSACLDefaultPermissions=value
117+Value can be any combination of valid permission types (w,r,t,c,d,t,a,p).
118+if there is no defined ACL and default permission in access file, or no
119+access file at all, this permissions are used. The default is p (admin rights),
120+if aclconfig file is created with cvs init.
121+
122+UseCVSGroups=value
123+CVS does not have a CVSROOT/passwd file. However it can be created manually
124+(format should be same as /etc/group). If value set to yes, CVS checks for
125+groups in file $CVSROOT/CVSROOT/group The default value is no.
126+
127+UseSystemGroups=value
128+Group memberships for users are checked in file /etc/group, if value is set
129+to yes. The default value is no.
130+
131+CVSACLFileLocation=value
132+Originally access file is put under CVSROOT/CVSROOT, if you want a different
133+location, set value to a valid path. The default value is $CVSROOT/CVSROOT/access.
134+
135+CVSGroupsFileLocation=value
136+IF UseCVSGroups is set to yes, CVS looks for a group file under $CVSROOT/CVSROOT.
137+To use a different location for group file set value to a valid path to group.
138+The default value is $CVSROOT/CVSROOT/group.
139+
c52fdbcd 140+UseSeparateACLFileForEachDir=value
141+If value is set to yes, a separate ACL file (access) is created for each
09f63587 142+directory in repository. If you have a really big repository
143+(directories>10,000 and files>100,000), performance may drop due to a big
144+acl file, access. Setting the value to yes, may increase performance. Normally,
145+you will not need this. The default value is no.
146+
147+StopAtFirstPermissionDenied=value
148+If StopAtFirstPermissionDenied is set to yes
149+operation will stop at first permission denied message.
150+e.g. when you send commit command for a directory, if you dont
151+have write permission for just one file under the directory,
152+by default you will have a warning and commit will continue
153+on the other files. If you set this keyword to 'no', then
154+commit operation will be stopped when inaccassable file found.
155+Default is no.
156+
157+CVSServerRunAsUser=value
158+Set CVSServerRunAsUser keyword to a valid system user.
159+When a user make a remote connection to CVS, after successfull authentication
160+cvs process switch to run as that user, or defined system user in
161+$CVSROOT/CVSROOT/passwd. So, you also have to set unix file permissions accordingly.
162+A better solution:
163+Add a user and group such as both cvsadm.
164+Set CVSServerRunAsUser keyword to cvsadm.
165+Change unix file system permissions for your repository,
166+make cvsadm user and group owner, and read,write,execute permissions and setgid.
167+(chown cvsadm -R /path/to/your/repository)
168+(chgrp cvsadm -R /path/to/your/repository)
169+(chmod 2770 -R /path/to/your/repository)
170+Add yourself to cvsadm group (since you are ACL administrator).
171+Therefore, only users making remote connections will have access to repository
172+if you give rights. Local users can not access to repository via a cvs client or directly.
173+
174+
175+Command Line Usage Information
176+acl command is used on checked out files or directories. racl command is
177+used on repository without a working copy. Usage information can be obtained
178+with standard cvs --help command.
179+Output of cvs --help acl and cvs --help racl:
180+
181+Usage: cvs racl [user||group:permissions] [-Rl] [-r tag]
182+ -d [directory] -f [file]
183+ -R Process directories recursively.
184+ -r rev Existing revision/tag.
185+ -l List defined ACLs.
186+ -d dir Process on given directory.
187+ -f file Process on given file.
188+
189+Usage: cvs acl [user||group:permissions] [-Rl] [-r tag]
190+ -d [directory] -f [file]
191+ -R Process directories recursively.
192+ -r rev Existing revision/tag.
193+ -l List defined ACLs.
194+ -d dir Process on given directory.
195+ -f file Process on given file.
196+
197+You may directly set permissions for a user or group or add/remove
198+permissions with + and - signs to/from existing permissions.
199+If you do not give the branch/tag information, default value of HEAD
200+(main branch) will be used. You have to give branch/tag name with -r option.
201+You may type ALL for branch/tag field.
202+
203+While checking for permissions, it goes thorough the list below. So the highest
204+significant permission is the first item in list.
205+
206+- permissions assigned to username for specific directory or file.
207+- permissions assigned to group name for specific directory or file.
208+- permissions as defaults for specific directory or file.
209+- permissions assigned to parent folders (inherits from the first parent
210+ which permissions are assigned).
211+- permissions as repository defaults.
212+- permissions in aclconfig file.
213+
214+
215+
216+
217+Examples
218+ /cvs/
219+ |
220+ |
221+ +--projectA/
222+ | |
223+ | +---CVSROOT/
224+ | |
225+ | +---lib/
226+ | | |
227+ | | +---gnulib/
228+ | | |
229+ | | +---zlib/
230+ | |
231+ | +---src/
232+ | | |
233+ | | +---main.c
234+ | | |
235+ | | +---server.c
236+ | | |
237+ | | +---client.c
238+ | |
239+ | +---gui/
240+ |
241+ +--projectB/
242+We have above directory structure for a cvs repository, and no defined permissions.
243+
244+Setting main default permissions:
245+
246+$ cvs -d /cvs/projectA racl cvsadmin:p -r ALL -d ALL
247+$ cvs -d /cvs/projectA racl ALL:r -r ALL -d ALL
248+User cvsadmin will be an acl admin, and all other users will have only read
249+rights on all branches/tags in projectA repository. This is the default acl
250+definition and it overwrites default permissions in $CVSROOT/CVSROOT/aclconfig file.
251+
252+$ cvs -d /cvs/projectA racl ALL:r -r ALL -d ALL
253+$ cvs -d /cvs/projectA racl ALL:n -r ALL -d gui
254+After executing these two commands, all users will have read access on all
255+directories and files except gui directory. Everyone will be denied to access to gui
256+directory becase no access, n, permissions is set.
257+
258+Setting permissions directly on a file or directory:
259+
260+$ cvs -d /cvs/projectA racl userX:wcd -d lib
261+$ cvs -d /cvs/projectA racl group1:w -d lib
262+First command will set write, create, and delete permissions for userX on directory
263+lib with branch HEAD (since no branch/tag information given, branch defaults to HEAD).
264+Second command will set only write permission for group1 on directory lib with branch HEAD.
265+Members of group1 will have only commit rights on lib directory, branch HEAD, they can
266+not add or remove any file, just modify existing files.
267+If userX is also a member of group1, userX will have write, create, and delete permissions
268+because it is specifically given these permissions.
269+
270+$ cvs -d /cvs/projectA racl userY:wcd -r develStream -d lib
271+$ cvs -d /cvs/projectA racl userY:r -r integStream -d lib
272+These commands will give wcd permissions to userY on lib directory with tag develstream,
273+and r permissions on lib directory with tag integStream.
274+
275+$ cvs -d /cvs/projectA racl userZ:wcd -d src
276+$ cvs -d /cvs/projectA racl userZ:r -f src/main.c
277+First command will give wcd permissions to userZ on src directory, but only read
278+permission on file main.c in src directory.
279+
280+Using + and - signs to set permissions on a file or directory:
281+
282+$ cvs -d /cvs/projectA racl userZ:+t -d src
283+$ cvs -d /cvs/projectA racl userZ:-cd -d src
284+$ cvs -d /cvs/projectA racl userZ:-wt -d src
285+Before the first command, userZ has wcd permissions on src directory, after issuing
286+command it will have wcdt permissions. Tag permission will be added. UserZ has wcdt
287+permissions, and we execute the second command to remove create and delete permissions.
288+So userZ has wt permissions. In the last command we also remove wt permissions, finally
289+userZ has no defined permissions left, and it will use the default permissions if set.
290+
291+Listing permissions on a file or directory:
292+
293+$ cvs -d /cvs/projectA racl -l -d src
294+$ cvs -d /cvs/projectA racl -l -f src
295+$ cvs -d /cvs/projectA racl -l -f src/main.c
296+
297+First command will list the permissions for src directory.
298+Example output:
299+d src HEAD | userX:wcd group1:r | defaults:r
300+userX and group1 has assigned permissions, all other users will have default
301+permissions, which is only read.
302+
303+Second command will list the permissions for files in src directory.
304+Example output:
305+f src/main.c HEAD | userX:wcd group1:r | defaults:r
306+f src/server.c HEAD | userX:wcd group1:r | defaults:r
307+f src/client.c HEAD | userX:wcd group1:r | defaults:r
308+
309+Third command will list the permissions for main.c file in src directory.
310+Example output:
311+f src/main.c HEAD | userX:wcd group1:r | defaults:r
312+
313+
fe149767 314diff -urN cvs-1.11.19.orig/aclconfig.default cvs-1.11.19/aclconfig.default
315--- cvs-1.11.19.orig/aclconfig.default 1970-01-01 01:00:00.000000000 +0100
316+++ cvs-1.11.19/aclconfig.default 2004-11-26 13:47:34.000000000 +0100
4905fec9 317@@ -0,0 +1,33 @@
318+# Set `UseCVSACL' to yes to use CVS ACL feature.
319+UseCVSACL=yes
320+
321+# Default CVS ACL Permission are to use.
322+#CVSACLDefaultPermissions=a
323+
324+# Default file location for CVS ACL file (access) is CVSROOT/access.
325+# If you want to use a different location, define it below.
326+#CVSACLFileLocation=/path/to/cvs/access
327+
328+# Set `UseSystemGroups' to yes to use system group definitions (/etc/group).
329+UseSystemGroups=yes
330+
331+# Set `UseCVSGroups' to yes to use another group file.
332+#UseCVSGroups=yes
333+
334+# Default file location for CVS groups file is CVSROOT/group.
335+# If you want to use a different location, define it below.
336+#CVSGroupsFileLocation=/path/to/cvs/group
337+
338+# Set UseSeparateACLFileForEachDir to yes in order to use a
339+# separate 'access' file for each directory.
340+# This increased the performance if you have really big repository.
341+#UseSeparateACLFileForEachDir=no
342+
343+# If StopAtFirstPermissionDenied is set to yes
344+# operation will stop at first permission denied message.
345+# Default is no.
346+#StopAtFirstPermissionDenied=no
347+
348+# Set CVSServerRunAsUser to a system user, in order CVS server
349+# to run as.
350+#CVSServerRunAsUser=runascvsuser
fe149767 351diff -urN cvs-1.11.19.orig/src/Makefile.am cvs-1.11.19/src/Makefile.am
352--- cvs-1.11.19.orig/src/Makefile.am 2005-03-14 19:49:29.000000000 +0100
353+++ cvs-1.11.19/src/Makefile.am 2005-03-14 19:55:09.000000000 +0100
354@@ -31,6 +31,7 @@
4905fec9 355
356 # The cvs executable
357 cvs_SOURCES = \
358+ acl.c \
359 add.c \
360 admin.c \
361 annotate.c \
fe149767 362diff -urN cvs-1.11.19.orig/src/Makefile.in cvs-1.11.19/src/Makefile.in
363--- cvs-1.11.19.orig/src/Makefile.in 2005-02-01 00:11:15.000000000 +0100
364+++ cvs-1.11.19/src/Makefile.in 2005-03-14 19:55:09.000000000 +0100
365@@ -69,20 +69,20 @@
4905fec9 366 am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)"
367 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
368 PROGRAMS = $(bin_PROGRAMS)
369-am_cvs_OBJECTS = add.$(OBJEXT) admin.$(OBJEXT) annotate.$(OBJEXT) \
370- buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \
371- classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \
372- create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \
373- edit.$(OBJEXT) entries.$(OBJEXT) error.$(OBJEXT) \
fe149767 374- expand_path.$(OBJEXT) fileattr.$(OBJEXT) filesubr.$(OBJEXT) \
375- find_names.$(OBJEXT) hardlink.$(OBJEXT) hash.$(OBJEXT) \
376- history.$(OBJEXT) ignore.$(OBJEXT) import.$(OBJEXT) \
377- lock.$(OBJEXT) log.$(OBJEXT) login.$(OBJEXT) logmsg.$(OBJEXT) \
378- main.$(OBJEXT) mkmodules.$(OBJEXT) modules.$(OBJEXT) \
379- myndbm.$(OBJEXT) no_diff.$(OBJEXT) parseinfo.$(OBJEXT) \
380- patch.$(OBJEXT) rcs.$(OBJEXT) rcscmds.$(OBJEXT) \
381- recurse.$(OBJEXT) release.$(OBJEXT) remove.$(OBJEXT) \
382- repos.$(OBJEXT) root.$(OBJEXT) run.$(OBJEXT) \
4905fec9 383+am_cvs_OBJECTS = acl.$(OBJEXT) add.$(OBJEXT) admin.$(OBJEXT) \
384+ annotate.$(OBJEXT) buffer.$(OBJEXT) checkin.$(OBJEXT) \
385+ checkout.$(OBJEXT) classify.$(OBJEXT) client.$(OBJEXT) \
386+ commit.$(OBJEXT) create_adm.$(OBJEXT) cvsrc.$(OBJEXT) \
fe149767 387+ diff.$(OBJEXT) edit.$(OBJEXT) entries.$(OBJEXT) \
388+ error.$(OBJEXT) expand_path.$(OBJEXT) fileattr.$(OBJEXT) \
389+ filesubr.$(OBJEXT) find_names.$(OBJEXT) hardlink.$(OBJEXT) \
390+ hash.$(OBJEXT) history.$(OBJEXT) ignore.$(OBJEXT) \
391+ import.$(OBJEXT) lock.$(OBJEXT) log.$(OBJEXT) login.$(OBJEXT) \
392+ logmsg.$(OBJEXT) main.$(OBJEXT) mkmodules.$(OBJEXT) \
393+ modules.$(OBJEXT) myndbm.$(OBJEXT) no_diff.$(OBJEXT) \
394+ parseinfo.$(OBJEXT) patch.$(OBJEXT) rcs.$(OBJEXT) \
395+ rcscmds.$(OBJEXT) recurse.$(OBJEXT) release.$(OBJEXT) \
396+ remove.$(OBJEXT) repos.$(OBJEXT) root.$(OBJEXT) run.$(OBJEXT) \
397 scramble.$(OBJEXT) server.$(OBJEXT) stack.$(OBJEXT) \
398 status.$(OBJEXT) subr.$(OBJEXT) tag.$(OBJEXT) update.$(OBJEXT) \
399 version.$(OBJEXT) vers_ts.$(OBJEXT) watch.$(OBJEXT) \
400@@ -206,6 +206,7 @@
4905fec9 401
402 # The cvs executable
403 cvs_SOURCES = \
404+ acl.c \
405 add.c \
406 admin.c \
407 annotate.c \
fe149767 408@@ -384,6 +385,7 @@
4905fec9 409 distclean-compile:
410 -rm -f *.tab.c
411
412+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl.Po@am__quote@
413 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add.Po@am__quote@
414 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/admin.Po@am__quote@
415 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/annotate.Po@am__quote@
fe149767 416diff -urN cvs-1.11.19.orig/src/acl.c cvs-1.11.19/src/acl.c
417--- cvs-1.11.19.orig/src/acl.c 1970-01-01 01:00:00.000000000 +0100
418+++ cvs-1.11.19/src/acl.c 2004-11-26 13:50:48.000000000 +0100
419@@ -0,0 +1,2032 @@
09f63587 420+/*
421+ *
422+ * CVS ACCESS CONTROL LIST EXTENSION
423+ *
424+ * sbaris@users.sourceforge.net
425+ *
426+ * http://cvsacl.sourceforge.net/
427+ *
c52fdbcd 428+ * CVSACL is a patch for CVS versions
fe149767 429+ * - cvs-1.11.18
c52fdbcd 430+ *
09f63587 431+ * It adds two new subcommands (acl & racl) to cvs for access control
432+ * list management.
433+ * It provides advanced ACL definitions per modules, directories,
434+ * and files on branch/tag for remote cvs repository connections.
435+ * Execution of all CVS subcommands can be controlled with eight
436+ * different permissions.
437+ * ACL definitions works for only remote connections, local users can
438+ * access and modify repository, if unix file system permissions allow.
439+ * If you want all users to make remote connections to repository,
440+ * and not allow local users to access repository, you have to set
441+ * CVSServerRunAsUser keyword in aclconfig file (explained below).
442+ * Still local users can use acl and racl subcommands to set permissions
443+ * on directories or files if they have acl admin rights (p) on related
444+ * directories or files.
445+ * So, in order to control all access to repository with this ACL extension,
446+ * you should use CVSServerRunAsUser keyword and force all users to make
447+ * remote connections.
448+ * CVS repository administrator or project managers have to use acl and racl
449+ * subcommands to manage permissions. But there is no gui client supporting
450+ * these subcommands, so you have to use cvs client itself either
451+ * locally or remotely.
452+ *
453+ *
454+ * Permission Types:
455+ * - no permission (n) (1)
456+ * - all permissions (a) (2)
457+ * - write permission (w) (3)
458+ * - tag permission (t) (4)
459+ * - read permission (r) (5)
460+ * - add permission (c) (6)
461+ * - remove permission (d) (7)
462+ * - permission change (p) (8)
463+ *
464+ *
465+ *
466+ *
467+ * ********************************************************************
468+ * This program is free software; you can redistribute it and/or modify
469+ * it under the terms of the GNU General Public License as published by
470+ * the Free Software Foundation; either version 1, or (at your option)
471+ * any later version.
472+ *
473+ * This program is distributed in the hope that it will be useful,
474+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
475+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
476+ * GNU General Public License for more details.
477+ * *******************************************************************
478+ *
479+ */
480+
481+#include "cvs.h"
482+#include "getline.h"
483+#include <grp.h>
484+
485+static int acl_fileproc PROTO ((void *callerdat, struct file_info *finfo));
486+static Dtype acl_dirproc PROTO ((void *callerdat, const char *dir, const char *repos,
487+ const char *update_dir, List *entries));
488+
489+static int acllist_fileproc PROTO ((void *callerdat, struct file_info *finfo));
490+static Dtype acllist_dirproc PROTO ((void *callerdat, const char *dir, const char *repos,
491+ const char *update_dir, List *entries));
492+
493+static void acllist_print PROTO ((char *line, const char *obj));
494+
495+static int racl_proc PROTO((int argc, char **argv, char *xwhere,
496+ char *mwhere, char *mfile, int shorten,
497+ int local_specified, char *mname, char *msg));
498+
67ba4c3a 499+FILE *open_accessfile (char *xmode, const char *repos, char **fname);
09f63587 500+FILE *open_groupfile (char *xmode);
501+
502+char *get_perms (char *xperms);
503+char *make_perms (char *xperms, char *xfounduserpart, char **xerrmsg);
504+
505+static char *cache_repository;
506+static int cache_retval;
507+static int founddeniedfile;
508+static int cache_perm;
509+
510+static int is_racl;
511+
512+int use_cvs_acl = 0;
513+char *cvs_acl_default_permissions;
514+int use_cvs_groups = 0;
515+int use_system_groups = 0;
c52fdbcd 516+int use_separate_acl_file_for_each_dir = 0;
09f63587 517+char *cvs_acl_file_location = NULL;
518+char *cvs_groups_file_location = NULL;
519+char *cvs_server_run_as = NULL;
520+int stop_at_first_permission_denied = 0;
521+
522+char *tag = NULL;
523+
524+char *muser;
525+char *mperms;
526+static int defaultperms;
527+
528+static char *default_perms_object;
529+char *default_part_perms_accessfile;
530+
531+int acldir = 0;
532+int aclfile = 0;
533+int listacl = 0;
534+
535+int userfound;
536+int groupfound;
537+
538+char *dirs[25];
539+
540+int aclconfig_default_used;
541+
542+static const char *const acl_usage[] =
543+ {
544+ "Usage: %s %s [user||group:permissions] [-Rl] [-r tag]\n -d [directory] -f [file]\n",
545+ "\t-R\tProcess directories recursively.\n",
546+ "\t-r rev\tExisting revision/tag.\n",
547+ "\t-l\tList defined ACLs.\n",
548+ "\t-d dir\tProcess on given directory.\n",
549+ "\t-f file\tProcess on given file.\n",
550+ "(Specify the --help global option for a list of other help options)\n",
551+ NULL
552+ };
553+
554+static const char *const racl_usage[] =
555+ {
556+ "Usage: %s %s [user||group:permissions] [-Rl] [-r tag]\n -d [directory] -f [file]\n",
557+ "\t-R\tProcess directories recursively.\n",
558+ "\t-r rev\tExisting revision/tag.\n",
559+ "\t-l\tList defined ACLs.\n",
560+ "\t-d dir\tProcess on given directory.\n",
561+ "\t-f file\tProcess on given file.\n",
562+ "(Specify the --help global option for a list of other help options)\n",
563+ NULL
564+ };
565+
566+
567+int
568+access_allowed (file, repos, tag, perm, mline, mpos, usecache)
569+char *file;
570+char *repos;
571+char *tag;
572+int perm;
573+char **mline;
574+int *mpos;
575+int usecache;
576+{
577+ int retval = 0;
578+ int foundline = 0;
579+ FILE *accessfp;
580+
581+ char *line = NULL;
582+ size_t line_allocated = 0;
583+
584+ char *part_type = NULL;
585+ char *part_object = NULL;
586+ char *part_tag = NULL;
587+ char *part_perms = NULL;
588+ char *xline;
67ba4c3a 589+ int x;
09f63587 590+
591+ char *iline;
592+
593+ char *tempv;
594+ char *tempc;
595+ size_t tempsize;
596+ int intcount;
597+
598+ int oneaccessfile = 0;
599+ int accessfilecount;
600+
67ba4c3a 601+ int signlevel = -1;
09f63587 602+
603+ int dadmin = 0;
604+
605+ const char *repository;
606+ char *filefullname = NULL;
607+
608+
609+ userfound = 0;
610+ groupfound = 0;
611+
612+
613+ if (defaultperms)
614+ {
615+ repository = xstrdup ("ALL");
616+ }
617+ else
618+ repository = Short_Repository (repos);
619+
620+ /* cache */
621+ if (usecache
622+ && cache_repository != NULL
623+ && strcmp (cache_repository, repository) == 0
624+ && !founddeniedfile
625+ && perm == cache_perm)
626+ return (cache_retval);
627+ else
628+ {
629+ free(cache_repository);
630+ cache_repository = xstrdup(repository);
631+ cache_perm = perm;
632+ }
633+
634+ if (file != NULL)
635+ {
636+ filefullname = xmalloc (strlen (repository)
637+ + strlen (file)
638+ + 2);
639+
640+ strcpy (filefullname, repository);
641+ strcat (filefullname, "/");
642+ strcat (filefullname, file);
643+ }
644+
645+
646+ iline = xstrdup(repository);
647+
648+ tempv = strtok(iline, "/\t");
649+ tempc = xstrdup(tempv);
650+ tempsize = strlen(tempc);
651+
652+ intcount = 0;
653+
654+ dirs[intcount] = xstrdup(tempc);
655+
656+ while ((tempv = strtok(NULL, "/\t")) != NULL)
657+ {
658+ intcount++;
659+
660+ xrealloc_and_strcat(&tempc, &tempsize, "/");
661+ xrealloc_and_strcat(&tempc, &tempsize, tempv);
662+
663+ dirs[intcount] = xstrdup(tempc);
664+ }
665+
fe149767 666+ accessfilecount = intcount;
667+
09f63587 668+ if (file != NULL)
669+ {
670+ intcount++;
671+ dirs[intcount] = xstrdup(filefullname);
672+ }
673+
67ba4c3a 674+ for (accessfilecount; accessfilecount >= 0 && !oneaccessfile; accessfilecount--)
09f63587 675+ {
c52fdbcd 676+ if (!use_separate_acl_file_for_each_dir)
09f63587 677+ oneaccessfile = 1;
c52fdbcd 678+ else if (use_separate_acl_file_for_each_dir)
09f63587 679+ oneaccessfile = 0;
680+
67ba4c3a 681+ if (acldir || aclfile)
682+ oneaccessfile = 1;
683+
09f63587 684+ if (oneaccessfile)
67ba4c3a 685+ accessfp = open_accessfile ("r", repository, NULL);
09f63587 686+ else
687+ accessfp = open_accessfile ("r", dirs[accessfilecount], NULL);
688+
689+ if (accessfp != NULL)
690+ {
691+ while (getline (&line, &line_allocated, accessfp) >= 0)
692+ {
67ba4c3a 693+
09f63587 694+ if (line[0] == '#' || line[0] == '\0' || line[0] == '\n')
695+ continue;
696+
697+ xline = xstrdup (line);
698+ part_type = strtok (line, ":\t");
699+ part_object = strtok (NULL, ":\t");
700+ part_tag = strtok (NULL, ":\t");
701+ part_perms = strtok (NULL, ":\t");
702+
67ba4c3a 703+ for (x = intcount; x >= signlevel && x != -1; x--)
09f63587 704+ {
705+ if (strcmp (dirs[x], part_object) == 0)
706+ {
707+ if (valid_tag (part_tag, tag))
708+ {
709+ foundline = 1;
710+
c52fdbcd 711+ if (listacl || acldir || aclfile)
09f63587 712+ {
713+ *mline = xstrdup (xline);
714+ *mpos = ftell (accessfp);
715+ }
716+
717+ if (valid_perm (part_perms, perm))
718+ {
719+ if (signlevel == x)
720+ {
721+ if (strncmp(part_tag, "ALL", 3) != 0 && !aclconfig_default_used)
722+ retval = 1;
723+ }
724+ else if (!aclconfig_default_used)
725+ {
726+ signlevel = x;
727+ retval = 1;
728+ }
67ba4c3a 729+ else {
730+ }
09f63587 731+ }
732+ else
733+ {
734+ if (signlevel == x)
735+ {
736+ if (strncmp(part_tag, "ALL", 3) != 0 && !aclconfig_default_used)
737+ retval = 0;
738+ }
739+ else if (!aclconfig_default_used)
740+ {
741+ signlevel = x;
742+ retval = 0;
743+
744+ if (strncmp (part_type, "f", 1) == 0)
745+ founddeniedfile = 1;
67ba4c3a 746+ }
747+ else {
09f63587 748+ }
749+ }
750+ }
751+ }
752+ }
753+ if (strncmp (xline, "d:ALL", 5) == 0 && (!groupfound && !userfound || listacl))
754+ {
755+ /* a default found */
756+ if (valid_tag (part_tag, tag))
757+ {
758+ foundline = 1;
759+
760+ default_part_perms_accessfile = xstrdup (part_perms);
761+
762+ if (valid_perm (part_perms, perm))
763+ {
764+ retval = 1;
765+
766+ if (perm == 8)
767+ dadmin = 1;
768+ }
769+ else
770+ retval = 0;
771+ }
772+ }
773+
774+ }
775+ if (fclose (accessfp) == EOF)
776+ error (1, errno, "cannot close 'access' file");
777+
778+ }
779+ }
780+
781+ if (!foundline)
782+ {
783+ /* DEFAULT */
784+ if (valid_perm (NULL, perm))
785+ retval = 1;
786+ else
787+ retval = 0;
788+ }
789+
790+ if (dadmin)
791+ {
792+ retval = dadmin;
793+ }
794+
795+ cache_retval = retval;
796+
797+ free (filefullname);
798+
799+ return (retval);
800+}
801+
802+/* Returns 1 if successful, 0 if not. */
803+int
804+valid_tag (part_tag, tag)
805+char *part_tag;
806+char *tag;
807+{
fe149767 808+ if (acldir || aclfile)
809+ return (0);
810+
09f63587 811+ if (tag == NULL)
812+ tag = xstrdup ("HEAD");
813+
814+ if (strcmp (part_tag, "ALL") == 0)
815+ return (1);
816+
817+ if (strcmp (tag, part_tag) == 0)
818+ return (1);
819+ else
820+ return (0);
821+}
822+
823+/* Returns 1 if successful, 0 if not. */
824+int
825+valid_perm (part_perms, perm)
826+char *part_perms;
827+int perm;
828+{
829+ char *perms;
830+ int retval = 0;
831+
832+ perms = get_perms (part_perms);
833+
834+ /* Allow, if nothing found. */
835+ if (perms[0] == '\0')
836+ return (1);
837+
838+
839+ if (strstr (perms, "n"))
840+ retval = 0; /* no access allowed, exit */
841+ if (strstr (perms, "p"))
842+ retval = 1; /* admin rights */
843+ else if (strstr (perms, "a") && perm != 8)
844+ retval = 1; /* all access allowed, exit */
845+ else
846+ switch (perm)
847+ {
848+ case 3: /* write permission */
849+ if (strstr (perms, "w"))
850+ retval = 1;
851+ break;
852+ case 4: /* tag permission */
853+ if (strstr (perms, "t"))
854+ retval = 1;
855+ break;
856+ case 5: /* read permission */
857+ if (strstr (perms, "w") || strstr (perms, "t") || strstr (perms, "c") ||
858+ strstr (perms, "d") || strstr (perms, "r"))
859+ retval = 1;
860+ break;
861+ case 6: /* create permission */
862+ if (strstr (perms, "c"))
863+ retval = 1;
864+ break;
865+ case 7: /* delete permission */
866+ if (strstr (perms, "d"))
867+ retval = 1;
868+ break;
869+ case 8: /* permission change */
870+ if (strstr (perms, "p"))
871+ retval = 1;
872+ break;
873+ default:
874+ retval = 0; /* never reached */
875+ break;
876+ }
877+
878+ return (retval);
879+}
880+
881+char *
882+get_perms (part_perms)
883+char *part_perms;
884+
885+{
886+ char *username;
887+ char *xperms;
888+ size_t xperms_len = 1;
889+
890+ FILE *groupfp;
891+
892+ char *usr;
893+ char *per;
894+ char *founduser = NULL;
895+ char *foundall = NULL;
896+ int default_checked = 0;
897+
898+ aclconfig_default_used = 0;
899+
900+ xperms = xmalloc (xperms_len);
901+ xperms[0] = '\0';
902+
903+ username = getcaller ();
904+
905+ /* no defined acl, no default acl in access file,
906+ or no access file at all */
907+ if (part_perms == NULL)
908+ if (cvs_acl_default_permissions)
909+ {
910+ aclconfig_default_used = 1;
911+ return (cvs_acl_default_permissions);
912+ }
913+ else
914+ return (xperms);
915+
916+check_default:
917+ founduser = strstr (part_perms, username);
918+ foundall = strstr (part_perms, "ALL!");
919+
920+ if (founduser)
921+ {
922+ usr = strtok (founduser, "!\t");
923+ per = strtok (NULL, ",\t");
924+
925+ if (strcmp (usr, username) == 0)
926+ {
927+ xperms = xstrdup (per);
928+ xperms_len = strlen (xperms);
929+
930+ userfound = 1;
931+ }
932+ }
933+ else
934+ {
935+ if (use_system_groups) {
936+ struct group *griter;
937+ setgrent ();
938+ while (griter = getgrent ()) {
939+ char **users=griter->gr_mem;
940+ int index = 0;
941+ char *userchk = users [index++];
942+ while(userchk != NULL) {
943+ if(strcmp (userchk, username) == 0)
944+ break;
945+ userchk = users[index++];
946+ }
947+ if (userchk != NULL) {
948+ char *grp;
949+ if ((grp = strstr (part_perms, griter->gr_name)) && grp[strlen (griter->gr_name)] == '!') {
950+ char *gperm = strtok (grp, "!\t");
951+ gperm = strtok (NULL, ",\t");
952+ xrealloc_and_strcat (&xperms, &xperms_len, gperm);
953+
954+ groupfound = 1;
955+ }
956+ }
957+ }
958+ endgrent ();
959+ }
960+ else if (use_cvs_groups) {
961+ groupfp = open_groupfile ("r");
962+ if (groupfp != NULL)
963+ {
964+ char *line = NULL;
965+ size_t line_allocated = 0;
966+
967+ while (getline (&line, &line_allocated, groupfp) >= 0)
968+ {
969+ if (strstr (line, username))
970+ {
971+ char *temp;
972+ temp = strstr (line, username);
973+
974+ if (temp[strlen (username)] == ','
975+ || temp[strlen (username)] == ' '
976+ || temp[strlen (username)] == '\n')
977+ {
978+ char *tmp;
979+ tmp = strtok (line, ":\t");
980+ if (strcmp (tmp, username) != 0)
981+ {
982+ char *grp;
983+ if ((grp = strstr (part_perms, tmp)))
984+ if (grp[strlen (tmp)] == '!')
985+ {
986+ char *gperm;
987+ gperm = strtok (grp, "!\t");
988+ gperm = strtok (NULL, ",\t");
989+
990+ xrealloc_and_strcat (&xperms, &xperms_len, gperm);
991+
992+ groupfound = 1;
993+ }
994+ }
995+ }
996+ }
997+ }
998+ if (fclose (groupfp) == EOF)
999+ error (1, errno, "cannot close 'group' file");
1000+ }
1001+ }
1002+ }
1003+
1004+ if (foundall && (!groupfound && !userfound))
1005+ {
1006+ usr = strtok (strstr (part_perms, "ALL!"), "!\t");
1007+ per = strtok (NULL, ",\t");
1008+
1009+ if (!default_checked)
1010+ default_perms_object = xstrdup (per);
1011+
1012+ if (xperms[0] == '\0')
1013+ {
1014+ xperms = xstrdup (per);
1015+ xperms_len = strlen (xperms);
1016+ }
1017+ }
1018+ else if (xperms[0] == '\0' && !default_checked && default_part_perms_accessfile)
1019+ {
1020+ part_perms = xstrdup (default_part_perms_accessfile);
1021+ default_checked = 1;
1022+
1023+ goto check_default;
1024+ }
1025+
1026+ if (xperms[0] != '\0' && strcmp (xperms, "x") == 0)
1027+ {
1028+ if (default_perms_object)
1029+ xperms = xstrdup (default_perms_object);
1030+ else if (default_part_perms_accessfile)
1031+ {
1032+ part_perms = default_part_perms_accessfile;
1033+ default_checked = 1;
1034+ goto check_default;
1035+ }
1036+ else if (cvs_acl_default_permissions)
1037+ {
1038+ aclconfig_default_used = 1;
1039+ xperms = xstrdup (cvs_acl_default_permissions);
1040+ }
1041+ }
1042+
1043+ if (xperms[0] == '\0' && cvs_acl_default_permissions)
1044+ {
1045+ aclconfig_default_used = 1;
1046+ xperms = xstrdup (cvs_acl_default_permissions);
1047+ }
1048+
1049+ return (xperms);
1050+}
1051+
1052+
1053+int
1054+cvsacl (argc, argv)
1055+int argc;
1056+char **argv;
1057+{
1058+ char *chdirrepository;
1059+ int c;
1060+ int err = 0;
1061+ int usetag = 0;
1062+ int recursive = 0;
1063+
1064+ int k;
1065+
1066+ int which;
1067+ char *where;
1068+
1069+ is_racl = (strcmp (cvs_cmd_name, "racl") == 0);
1070+
1071+ if (argc == -1)
1072+ usage (is_racl ? racl_usage : acl_usage);
1073+
1074+ /* parse the args */
1075+ optind = 0;
1076+
1077+ while ((c = getopt (argc, argv, "Rr:dfl")) != -1)
1078+ {
1079+ switch (c)
1080+ {
1081+ case 'R':
1082+ recursive = 1;
1083+ break;
1084+ case 'r':
1085+ tag = xstrdup (optarg);
1086+ break;
1087+ case 'd':
1088+ acldir = 1;
1089+ break;
1090+ case 'f':
1091+ aclfile = 1;
1092+ break;
1093+ case 'l':
1094+ listacl = 1;
1095+ break;
1096+ case '?':
1097+ default:
1098+ usage (is_racl ? racl_usage : acl_usage);
1099+ break;
1100+ }
1101+ }
1102+
1103+ argc -= optind;
1104+ argv += optind;
1105+
1106+ if (!acldir && !aclfile)
1107+ usage (is_racl ? racl_usage : acl_usage);
1108+ if (acldir && aclfile)
1109+ usage (is_racl ? racl_usage : acl_usage);
1110+
1111+ if (listacl)
1112+ if (strstr (argv[0], ":"))
1113+ usage (is_racl ? racl_usage : acl_usage);
1114+ if (!listacl)
1115+ if (!strstr (argv[0], ":"))
1116+ usage (is_racl ? racl_usage : acl_usage);
1117+
1118+ if (argc < (is_racl ? 1 : 1))
1119+ usage (is_racl ? racl_usage : acl_usage);
1120+
1121+#ifdef CLIENT_SUPPORT
1122+
1123+ if (current_parsed_root->isremote)
1124+ {
1125+ start_server ();
1126+ ign_setup ();
1127+
1128+ if(recursive)
1129+ send_arg ("-R");
1130+
1131+ if (acldir)
1132+ send_arg ("-d");
1133+
1134+ if (aclfile)
1135+ send_arg ("-f");
1136+
1137+ if (listacl)
1138+ send_arg ("-l");
1139+
1140+ if(tag)
1141+ {
1142+ send_arg ("-r");
1143+ send_arg (tag);
1144+ }
1145+
1146+ send_arg ("--");
1147+
1148+ if (!listacl)
1149+ {
1150+ send_arg (argv[0]);
1151+
1152+ argc--;
1153+ argv++;
1154+ }
1155+
1156+ if (is_racl)
1157+ {
1158+ int i;
1159+ for (i = 0; i < argc; ++i)
1160+ send_arg (argv[i]);
1161+
1162+ send_to_server ("racl\012",0);
1163+ }
1164+ else
1165+ {
1166+ send_files (argc, argv, recursive, 0, SEND_NO_CONTENTS);
1167+ send_file_names (argc, argv, SEND_EXPAND_WILD);
1168+ send_to_server ("acl\012", 0);
1169+ }
1170+
1171+ return get_responses_and_close ();
1172+ }
1173+#endif
1174+
1175+#ifdef SERVER_SUPPORT
1176+
1177+ if (!listacl)
1178+ {
1179+ muser = strtok (argv[0], ":\t");
1180+ mperms = strtok (NULL, ":\t");
1181+
1182+ /* if set to 'default' */
1183+ if ((strlen (mperms) == 7) && (strncmp (mperms, "default", 7) == 0))
1184+ mperms = xstrdup ("x");
1185+
1186+ /* Check that the given permissions are valid. */
1187+ if (!given_perms_valid (mperms))
1188+ error (1,0,"Invalid permissions: '%s'", mperms);
1189+
1190+ argc--;
1191+ argv++;
1192+ }
1193+
1194+
1195+ if (!tag)
1196+ tag = xstrdup ("HEAD");
1197+
1198+ if (!cvs_casecmp (argv[0], "ALL"))
1199+ {
1200+ argv[0] = xstrdup (".");
1201+ defaultperms = 1;
c52fdbcd 1202+ if (!use_separate_acl_file_for_each_dir)
09f63587 1203+ {
1204+ recursive = 0;
1205+ }
1206+
1207+ }
1208+
1209+ if (is_racl)
1210+ {
1211+ DBM *db;
1212+ int i;
1213+ db = open_module ();
1214+ for (i = 0; i < argc; i++)
1215+ {
1216+ err += do_module (db, argv[i], MISC, "ACL ing: ",
1217+ racl_proc, (char *) NULL, 0, !recursive, 0,
1218+ 0, NULL);
1219+ }
1220+ close_module (db);
1221+ }
1222+ else
1223+ {
1224+ err = racl_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, !recursive, NULL,
1225+ NULL);
1226+ }
1227+ if (err)
1228+ error (1, 0, "an error accured");
1229+
1230+ return (err);
1231+
1232+#endif
1233+}
1234+
1235+static int
1236+racl_proc (argc, argv, xwhere, mwhere, mfile, shorten, local, mname, msg)
1237+int argc;
1238+char **argv;
1239+char *xwhere;
1240+char *mwhere;
1241+char *mfile;
1242+int shorten;
1243+int local;
1244+char *mname;
1245+char *msg;
1246+{
1247+ char *myargv[2];
1248+ int err = 0;
1249+ int which;
1250+ char *repository;
1251+ char *where;
1252+
1253+ if (is_racl)
1254+ {
1255+ repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
1256+ + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
1257+
1258+ (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
1259+ where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
1260+ + 1);
1261+ (void) strcpy (where, argv[0]);
1262+
1263+ /* if mfile isn't null, we need to set up to do only part of the module */
1264+ if (mfile != NULL)
1265+ {
1266+ char *cp;
1267+ char *path;
1268+
1269+ /* if the portion of the module is a path, put the dir part on repos */
1270+ if ((cp = strrchr (mfile, '/')) != NULL)
1271+ {
1272+ *cp = '\0';
1273+ (void) strcat (repository, "/");
1274+ (void) strcat (repository, mfile);
1275+ (void) strcat (where, "/");
1276+ (void) strcat (where, mfile);
1277+ mfile = cp + 1;
1278+ }
1279+
1280+ /* take care of the rest */
1281+ path = xmalloc (strlen (repository) + strlen (mfile) + 5);
1282+ (void) sprintf (path, "%s/%s", repository, mfile);
1283+ if (isdir (path))
1284+ {
1285+ /* directory means repository gets the dir tacked on */
1286+ (void) strcpy (repository, path);
1287+ (void) strcat (where, "/");
1288+ (void) strcat (where, mfile);
1289+ }
1290+ else
1291+ {
1292+ myargv[0] = argv[0];
1293+ myargv[1] = mfile;
1294+ argc = 2;
1295+ argv = myargv;
1296+ }
1297+ free (path);
1298+ }
1299+
1300+ /* cd to the starting repository */
1301+ if ( CVS_CHDIR (repository) < 0)
1302+ {
1303+ error (0, errno, "cannot chdir to %s", repository);
1304+ free (repository);
1305+ return (1);
1306+ }
1307+
1308+ /* End section which is identical to patch_proc. */
1309+
1310+ which = W_REPOS | W_ATTIC;
1311+ }
1312+ else
1313+ {
1314+ where = NULL;
1315+ which = W_LOCAL | W_REPOS | W_ATTIC;
1316+ }
1317+ if (listacl)
1318+ err = start_recursion (acllist_fileproc, NULL, acllist_dirproc, NULL, NULL,
1319+ argc - 1, argv + 1, local, which, 0, 0, (char *) where, 1,
1320+ repository);
1321+ else
1322+ err = start_recursion (acl_fileproc, NULL, acl_dirproc, NULL, NULL,
1323+ argc - 1, argv + 1, local, which, 0, 0, (char *) where, 1,
1324+ repository);
1325+
1326+ return (err);
1327+}
1328+
1329+
1330+static int
1331+acl_fileproc (callerdat, finfo)
1332+void *callerdat;
1333+struct file_info *finfo;
1334+{
1335+ Vers_TS *vers;
1336+
1337+ FILE *accessfp;
1338+
1339+ char *filefullname;
1340+
1341+ char *founduserpart = NULL;
1342+ char *newuserpart = NULL;
1343+ char *otheruserparts = NULL;
1344+ size_t otherslen = 0;
1345+
1346+ const char *frepository;
1347+ int foundline = 0;
1348+
1349+ char *line = NULL;
1350+ size_t line_allocated = 0;
1351+ int linelen;
1352+
1353+ char *part_type = NULL;
1354+ char *part_object = NULL;
1355+ char *part_tag = NULL;
1356+ char *part_perms = NULL;
1357+ char *wperms;
1358+ char *userpart;
1359+
1360+ char *errmsg;
1361+
1362+ int pos;
1363+
1364+ if (!aclfile)
1365+ return (0);
1366+
1367+ frepository = Short_Repository (finfo->repository);
1368+
1369+ filefullname = xmalloc (strlen (frepository)
1370+ + strlen (finfo->file)
1371+ + 2);
1372+ strcpy (filefullname, frepository);
1373+ strcat (filefullname, "/");
1374+ strcat (filefullname, finfo->file);
1375+
1376+ if (!access_allowed (finfo->file, finfo->repository, tag, 8, &line, &pos, 0))
1377+ error (1,0,"You do not have acl admin rights on '%s'", frepository);
1378+
1379+ if (line != NULL)
1380+ {
1381+ part_type = strtok (line, ":\t");
1382+ part_object = strtok (NULL, ":\t");
1383+ part_tag = strtok (NULL, ":\t");
1384+ part_perms = strtok (NULL, ":\t");
1385+
1386+ foundline = 1;
1387+ userpart = strtok (part_perms, ",\t");
1388+
1389+ if (strstr (userpart, muser))
1390+ founduserpart = xstrdup (userpart);
1391+ else
1392+ {
1393+ otheruserparts = xstrdup (userpart);
1394+ otherslen = strlen (otheruserparts);
1395+ }
1396+
1397+ while ((userpart = strtok (NULL, ",\t")) != NULL)
1398+ {
1399+ if (strncmp (userpart, muser, strlen (muser)) == 0)
1400+ founduserpart = xstrdup (userpart);
1401+ else
1402+ {
1403+ if (otheruserparts != NULL)
1404+ {
1405+ xrealloc_and_strcat (&otheruserparts, &otherslen, ",");
1406+ xrealloc_and_strcat (&otheruserparts, &otherslen, userpart);
1407+ }
1408+ else
1409+ {
1410+ otheruserparts = xstrdup (userpart);
1411+ otherslen = strlen (otheruserparts);
1412+ }
1413+ }
1414+ }
1415+ }
1416+
1417+ wperms = make_perms (mperms, founduserpart, &errmsg);
1418+ if (wperms == NULL)
1419+ {
1420+ if (errmsg)
1421+ error (0, 0, "%s %s", filefullname, errmsg);
1422+
1423+ return (0);
1424+ }
1425+ else
1426+ {
1427+ cvs_output ("X ", 0);
1428+ cvs_output (filefullname, 0);
1429+ cvs_output ("\n", 0);
1430+
1431+ write_perms (muser, wperms, founduserpart, foundline,
1432+ otheruserparts, "f", filefullname, tag, pos, finfo->repository);
1433+ }
1434+
1435+ return (0);
1436+}
1437+
1438+static Dtype
1439+acl_dirproc (callerdat, dir, repos, update_dir, entries)
1440+void *callerdat;
1441+const char *dir;
1442+const char *repos;
1443+const char *update_dir;
1444+List *entries;
1445+{
1446+ const char *drepository;
1447+ char *founduserpart = NULL;
1448+ char *newuserpart = NULL;
1449+ char *otheruserparts = NULL;
1450+ size_t otherslen = 0;
1451+ int foundline = 0;
1452+
1453+ char *line = NULL;
1454+ size_t line_allocated = 0;
1455+ int linelen;
1456+
1457+ FILE *accessfp;
1458+ char *part_type = NULL;
1459+ char *part_object = NULL;
1460+ char *part_tag = NULL;
1461+ char *part_perms = NULL;
1462+ char *wperms;
1463+ int i = 0;
1464+ char *userpart;
1465+ int pos;
1466+
1467+ char *errmsg;
1468+
1469+ if (repos[0] == '\0')
1470+ repos = Name_Repository (dir, NULL);
1471+
1472+ if (!acldir)
1473+ return (0);
1474+
1475+ if (!access_allowed (NULL, repos, tag, 8, &line, &pos, 0))
1476+ error (1,0,"You do not have admin rights on '%s'", Short_Repository (repos));
1477+
1478+ drepository = Short_Repository (repos);
1479+
1480+ if (line != NULL)
1481+ {
1482+ part_type = strtok (line, ":\t");
1483+ part_object = strtok (NULL, ":\t");
1484+ part_tag = strtok (NULL, ":\t");
1485+ part_perms = strtok (NULL, ":\t");
1486+
1487+ foundline = 1;
1488+ userpart = strtok (part_perms, ",\t");
1489+
1490+ if (strstr (userpart, muser))
1491+ founduserpart = xstrdup (userpart);
1492+ else
1493+ {
1494+ otheruserparts = xstrdup (userpart);
1495+ otherslen = strlen (otheruserparts);
1496+ }
1497+
1498+ while ((userpart = strtok (NULL, ",\t")) != NULL)
1499+ {
1500+ if (strncmp (userpart, muser, strlen (muser)) == 0)
1501+ founduserpart = xstrdup (userpart);
1502+ else
1503+ {
1504+ if (otheruserparts != NULL)
1505+ {
1506+ xrealloc_and_strcat (&otheruserparts, &otherslen, ",");
1507+ xrealloc_and_strcat (&otheruserparts, &otherslen, userpart);
1508+ }
1509+ else
1510+ {
1511+ otheruserparts = xstrdup (userpart);
1512+ otherslen = strlen (otheruserparts);
1513+ }
1514+ }
1515+ }
1516+ }
1517+
1518+ wperms = make_perms (mperms, founduserpart, &errmsg);
1519+ if (wperms == NULL)
1520+ {
1521+ if (errmsg)
1522+ error (0, 0, "%s %s", drepository, errmsg);
1523+
1524+ return (0);
1525+ }
1526+ else
1527+ {
1528+ if (defaultperms)
1529+ {
1530+ cvs_output ("X ", 0);
1531+ cvs_output ("ALL", 0);
1532+ cvs_output ("\n", 0);
1533+ write_perms (muser, wperms, founduserpart, foundline,
67ba4c3a 1534+ otheruserparts, "d", "ALL", tag, pos, drepository);//baris
09f63587 1535+
1536+ }
1537+ else
1538+ {
1539+ cvs_output ("X ", 0);
1540+ cvs_output (drepository, 0);
1541+ cvs_output ("\n", 0);
1542+ write_perms (muser, wperms, founduserpart, foundline,
67ba4c3a 1543+ otheruserparts, "d", drepository, tag, pos, drepository);//baris `repos`
09f63587 1544+ }
1545+ }
1546+
1547+ return (0);
1548+}
1549+
1550+/* Open CVSROOT/access or defined CVSACLFileLocation file. */
1551+FILE *
1552+open_accessfile (fmode, adir, fname)
1553+char *fmode;
67ba4c3a 1554+const char *adir;
09f63587 1555+char **fname;
1556+{
1557+ char *accessfile;
1558+ FILE *accessfp;
1559+
c52fdbcd 1560+ if (!use_separate_acl_file_for_each_dir)
09f63587 1561+ {
1562+ if (cvs_acl_file_location == NULL)
1563+ {
1564+ accessfile = xmalloc (strlen (current_parsed_root->directory)
1565+ + sizeof (CVSROOTADM)
1566+ + sizeof (CVSROOTADM_ACCESS)
1567+ + 3);
1568+
1569+ strcpy (accessfile, current_parsed_root->directory);
1570+ strcat (accessfile, "/");
1571+ strcat (accessfile, CVSROOTADM);
1572+ strcat (accessfile, "/");
1573+ strcat (accessfile, CVSROOTADM_ACCESS);
1574+ }
1575+ else
1576+ {
1577+ accessfile = xmalloc (strlen (cvs_acl_file_location));
1578+ strcpy (accessfile, cvs_acl_file_location);
1579+ }
1580+ }
1581+ else
1582+ {
1583+ accessfile = xmalloc (strlen (current_parsed_root->directory)
1584+ + strlen (adir)
1585+ + strlen ("access")
1586+ + 3);
1587+
1588+ strcpy (accessfile, current_parsed_root->directory);
1589+ strcat (accessfile, "/");
1590+ strcat (accessfile, adir);
1591+ strcat (accessfile, "/");
1592+ strcat (accessfile, "access");
1593+ }
1594+
1595+ accessfp = CVS_FOPEN (accessfile, fmode);
1596+
1597+ if (accessfp == NULL)
1598+ error (0, 0, "cannot open file: %s", accessfile);
1599+
1600+ if (fname != NULL)
1601+ *fname = xstrdup (accessfile);
1602+
1603+ free (accessfile);
1604+
1605+ return (accessfp);
1606+}
1607+
1608+/* Open /etc/group file if UseSystemGroups=yes in config file. */
1609+/* Open CVSROOT/group file if UseCVSGroups=yes in config file. */
1610+FILE *
1611+open_groupfile (fmode)
1612+char *fmode;
1613+{
1614+ char *groupfile;
1615+ FILE *groupfp;
1616+
1617+ if (use_cvs_groups)
1618+ {
1619+ if (cvs_groups_file_location != NULL)
1620+ {
1621+ groupfile = xmalloc (strlen (cvs_groups_file_location));
1622+ strcpy (groupfile, cvs_groups_file_location);
1623+ }
1624+ else
1625+ {
1626+ groupfile = xmalloc (strlen (current_parsed_root->directory)
1627+ + sizeof (CVSROOTADM)
1628+ + sizeof (CVSROOTADM_GROUP)
1629+ + 3);
1630+
1631+ strcpy (groupfile, current_parsed_root->directory);
1632+ strcat (groupfile, "/");
1633+ strcat (groupfile, CVSROOTADM);
1634+ strcat (groupfile, "/");
1635+ strcat (groupfile, CVSROOTADM_GROUP);
1636+ }
1637+ }
1638+
1639+ else
1640+ {
1641+ return (NULL);
1642+ }
1643+
1644+ groupfp = CVS_FOPEN (groupfile, "r");
1645+
1646+ if (groupfp == NULL)
1647+ error (0, 0, "cannot open file: %s", groupfile);
1648+
1649+ free (groupfile);
1650+
1651+ return (groupfp);
1652+}
1653+
1654+
1655+/* Check whether given permissions are valid or not. */
1656+/* Returns 1 if permissions are valid. */
1657+/* Returns 0 if permissions are NOT valid. */
1658+int
1659+given_perms_valid (cperms)
1660+char *cperms;
1661+{
1662+ int cperms_len;
1663+ int retval;
1664+ int index, i;
1665+
1666+ if (cperms[0] == '+' || cperms[0] == '-')
1667+ index = 1;
1668+ else
1669+ index = 0;
1670+
1671+ cperms_len = strlen (cperms);
1672+
1673+ switch (cperms[index])
1674+ {
1675+ case 'x':
1676+ if ((cperms_len - index) == 1 && cperms_len == 1)
1677+ retval = 1;
1678+ else
1679+ retval = 0;
1680+ break;
1681+ case 'n':
1682+ if ((cperms_len - index) == 1 && cperms_len == 1)
1683+ retval = 1;
1684+ else
1685+ retval = 0;
1686+ break;
1687+ case 'p':
1688+ if ((cperms_len - index) == 1)
1689+ retval = 1;
1690+ else
1691+ retval = 0;
1692+ break;
1693+ case 'a':
1694+ if ((cperms_len - index) == 1)
1695+ retval = 1;
1696+ else
1697+ for (i = index + 1; i < cperms_len; i++)
1698+ if (cperms[i] == 'p')
1699+ retval = 1;
1700+ else
1701+ retval = 0;
1702+ break;
1703+ case 'r':
1704+ if ((cperms_len - index) == 1)
1705+ retval = 1;
1706+ else
1707+ for (i = index + 1; i < cperms_len; i++)
1708+ if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'd')
1709+ retval = 1;
1710+ else
1711+ retval = 0;
1712+ break;
1713+ case 'w':
1714+ if ((cperms_len - index) == 1)
1715+ retval = 1;
1716+ else
1717+ for (i = index + 1; i < cperms_len; i++)
1718+ if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'd')
1719+ retval = 1;
1720+ else
1721+ retval = 0;
1722+ break;
1723+ case 't':
1724+ if ((cperms_len - index) == 1)
1725+ retval = 1;
1726+ else
1727+ for (i = index + 1; i < cperms_len; i++)
1728+ if (cperms[i] == 'w' || cperms[i] == 'c' || cperms[i] == 'd')
1729+ retval = 1;
1730+ else
1731+ retval = 0;
1732+ break;
1733+ case 'c':
1734+ if ((cperms_len - index) == 1)
1735+ retval = 1;
1736+ else
1737+ for (i = index + 1; i < cperms_len; i++)
1738+ if (cperms[i] == 't' || cperms[i] == 'w' || cperms[i] == 'd')
1739+ retval = 1;
1740+ else
1741+ retval = 0;
1742+ break;
1743+ case 'd':
1744+ if ((cperms_len - index) == 1)
1745+ retval = 1;
1746+ else
1747+ for (i = index + 1; i < cperms_len; i++)
1748+ if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'w')
1749+ retval = 1;
1750+ else
1751+ retval = 0;
1752+ break;
1753+ default:
1754+ retval = 0;
1755+ break;
1756+ }
1757+ return (retval);
1758+}
1759+
1760+char *
1761+make_perms (perms, founduserpart, xerrmsg)
1762+char *perms;
1763+char *founduserpart;
1764+char **xerrmsg;
1765+{
1766+ char *fperms;
1767+ size_t perms_len;
1768+ size_t fperms_len;
1769+ char *retperms = NULL;
1770+ char *xperms;
1771+ int i, j;
1772+ int err = 0;
1773+ char *errmsg = NULL;
1774+ size_t retperms_len = 1;
1775+
1776+ retperms = xmalloc (retperms_len);
1777+ retperms[0] = '\0';
1778+
1779+ perms_len = strlen (perms);
1780+
1781+ if (perms[0] == '+' || perms[0] == '-')
1782+ {
1783+ if (founduserpart)
1784+ {
1785+ char *temp;
1786+ temp = strtok (founduserpart, "!\t");
1787+ fperms = strtok (NULL, "!\t");
1788+ fperms_len = strlen (fperms);
1789+
1790+ if (strncmp (fperms, "x", 1) == 0)
1791+ {
1792+ err = 1;
1793+ if (perms[0] == '+')
1794+ *xerrmsg = xstrdup ("cannot add default permission 'x'");
1795+ else
1796+ *xerrmsg = xstrdup ("cannot remove default permission 'x'");
1797+ }
1798+
1799+ for (i = 1; i < perms_len && !err; i++)
1800+ {
1801+ switch (perms[i])
1802+ {
1803+ case 'n':
1804+ err = 1;
1805+ break;
1806+ case 'p':
1807+ if (perms[0] == '+')
1808+ fperms = xstrdup ("p");
1809+ else if (perms[0] == '-')
1810+ {
1811+ fperms_len = 1;
1812+ fperms = xmalloc (fperms_len);
1813+ fperms[0] = '\0';
1814+ }
1815+ break;
1816+ case 'a':
1817+ for (j = 0; j < fperms_len; j++)
1818+ {
1819+ if (fperms[j] == 'p')
1820+ {
1821+ err = 1;
1822+ *xerrmsg = xstrdup ("user has admin rights, cannot use +/- permissions");
1823+ }
1824+ else if (fperms[j] == 'a' && perms[0] == '+')
1825+ {
1826+ err = 1;
1827+ *xerrmsg = xstrdup ("user already has all ('a') permission");
1828+ }
1829+ else if (fperms[j] != 'a' && perms[0] == '-')
1830+ {
1831+ err = 1;
1832+ *xerrmsg = xstrdup ("user does not have all ('a') permission");
1833+ }
1834+ }
1835+ if (perms[0] == '+')
1836+ {
1837+ fperms = xstrdup ("a");
1838+ fperms_len = strlen (fperms);
1839+ }
1840+ else if (perms[0] == '-')
1841+ {
1842+ fperms_len = 1;
1843+ fperms = xmalloc (fperms_len);
1844+ fperms[0] = '\0';
1845+ }
1846+
1847+ break;
1848+ case 'r':
1849+ for (i = 0; i < fperms_len; i++)
1850+ {
1851+ if (fperms[i] == 'n' && perms[0] == '+')
1852+ {
1853+ fperms = xstrdup ("r");
1854+ fperms_len = strlen (fperms);
1855+ }
1856+ else if (fperms[i] == 'r' && perms[0] == '-')
1857+ {
1858+ fperms_len = 1;
1859+ fperms = xmalloc (fperms_len);
1860+ fperms[0] = '\0';
1861+ }
1862+ else if (perms[0] == '-')
1863+ {
1864+ err = 1;
1865+ *xerrmsg = xstrdup ("user has other permissions, cannot remove read ('r') permission");
1866+ }
1867+ else
1868+ {
1869+ err = 1;
1870+ *xerrmsg = xstrdup ("user has other permissions, cannot remove read ('r') permission");
1871+ }
1872+ }
1873+ break;
1874+ case 'w':
1875+ {
1876+ char *tempfperms;
1877+ size_t tempfperms_len = 1;
1878+
1879+ tempfperms = xmalloc (tempfperms_len);
1880+ tempfperms[0] = '\0';
1881+
1882+ for (j = 0; j < fperms_len; j++)
1883+ {
1884+ if (fperms[j] == 't' || fperms[j] == 'c' || fperms[j] == 'd')
1885+ {
1886+ char *temp;
1887+ temp = xmalloc (2);
1888+ temp[0] = fperms[j];
1889+ temp[1] = '\0';
1890+
1891+ xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
1892+ free (temp);
1893+ }
1894+ else if (fperms[j] == 'a' || fperms[j] == 'p')
1895+ {
1896+ err = 1;
1897+ *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- write permissions");
1898+ }
1899+ else if (fperms[j] == 'n' || fperms[j] == 'r')
1900+ {
1901+ if (perms[0] == '-')
1902+ {
1903+ err = 1;
1904+ *xerrmsg = xstrdup ("user does not have write ('w') permission");
1905+ }
1906+ }
1907+ }
1908+
1909+ fperms = xstrdup (tempfperms);
1910+ fperms_len = strlen (fperms);
1911+ free (tempfperms);
1912+
1913+ if (perms[0] == '+')
1914+ {
1915+ xrealloc_and_strcat (&fperms, &fperms_len, "w");
1916+ }
1917+ }
1918+ break;
1919+ case 't':
1920+ {
1921+ char *tempfperms;
1922+ size_t tempfperms_len = 1;
1923+
1924+ tempfperms = xmalloc (tempfperms_len);
1925+ tempfperms[0] = '\0';
1926+
1927+ for (j = 0; j < fperms_len; j++)
1928+ {
1929+ if (fperms[j] == 'w' || fperms[j] == 'c' || fperms[j] == 'd')
1930+ {
1931+ char *temp;
1932+ temp = xmalloc (2);
1933+ temp[0] = fperms[j];
1934+ temp[1] = '\0';
1935+
1936+ xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
1937+ free (temp);
1938+ }
1939+ else if (fperms[j] == 'a' || fperms[j] == 'p')
1940+ {
1941+ err = 1;
1942+ *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- tag permissions");
1943+ }
1944+ else if (fperms[i] == 'n' || fperms[i] == 'r')
1945+ {
1946+ if (perms[0] == '-')
1947+ *xerrmsg = xstrdup ("user does not have tag ('t') permission");
1948+ }
1949+ }
1950+
1951+ fperms = xstrdup (tempfperms);
1952+ fperms_len = strlen (fperms);
1953+ free (tempfperms);
1954+
1955+ if (perms[0] == '+')
1956+ {
1957+ xrealloc_and_strcat (&fperms, &fperms_len, "t");
1958+ }
1959+ }
1960+ break;
1961+ case 'c':
1962+ {
1963+ char *tempfperms;
1964+ size_t tempfperms_len = 1;
1965+
1966+ tempfperms = xmalloc (tempfperms_len);
1967+ tempfperms[0] = '\0';
1968+
1969+ for (j = 0; j < fperms_len; j++)
1970+ {
1971+ if (fperms[j] == 'w' || fperms[j] == 't' || fperms[j] == 'd')
1972+ {
1973+ char *temp;
1974+ temp = xmalloc (2);
1975+ temp[0] = fperms[j];
1976+ temp[1] = '\0';
1977+
1978+ xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
1979+ free (temp);
1980+ }
1981+ else if (fperms[j] == 'a' || fperms[j] == 'p')
1982+ {
1983+ err = 1;
1984+ *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- create permissions");
1985+ }
1986+ else if (fperms[i] == 'n' || fperms[i] == 'r')
1987+ {
1988+ if (perms[0] == '-')
1989+ err = 1;
1990+ *xerrmsg = xstrdup ("user does not have create ('c') permission");
1991+ }
1992+
1993+ }
1994+
1995+ fperms = xstrdup (tempfperms);
1996+ fperms_len = strlen (fperms);
1997+ free (tempfperms);
1998+
1999+ if (perms[0] == '+')
2000+ {
2001+ xrealloc_and_strcat (&fperms, &fperms_len, "c");
2002+ }
2003+ }
2004+ break;
2005+ case 'd':
2006+ {
2007+ char *tempfperms;
2008+ size_t tempfperms_len = 1;
2009+
2010+ tempfperms = xmalloc (tempfperms_len);
2011+ tempfperms[0] = '\0';
2012+
2013+ for (j = 0; j < fperms_len; j++)
2014+ {
2015+ if (fperms[j] == 'w' || fperms[j] == 'c' || fperms[j] == 't')
2016+ {
2017+ char *temp;
2018+ temp = xmalloc (2);
2019+ temp[0] = fperms[j];
2020+ temp[1] = '\0';
2021+
2022+ xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp);
2023+ free (temp);
2024+ }
2025+ else if (fperms[j] == 'a' || fperms[j] == 'p')
2026+ {
2027+ err = 1;
2028+ *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- delete permissions");
2029+ }
2030+ else if (fperms[i] == 'n' || fperms[i] == 'r')
2031+ {
2032+ if (perms[0] == '-')
2033+ err = 1;
2034+ *xerrmsg = xstrdup ("user does not have delete ('d') permission");
2035+ }
2036+ }
2037+
2038+ fperms = xstrdup (tempfperms);
2039+ fperms_len = strlen (fperms);
2040+ free (tempfperms);
2041+
2042+ if (perms[0] == '+')
2043+ {
2044+ xrealloc_and_strcat (&fperms, &fperms_len, "d");
2045+ }
2046+ }
2047+ break;
2048+ default:
2049+ err = 1;
2050+ *xerrmsg = xstrdup ("error in 'access' file format");
2051+ break;
2052+ }
2053+ if (fperms[0] == '\0')
2054+ retperms = xstrdup ("none");
2055+ else
2056+ retperms = xstrdup (fperms);
2057+ }
2058+ }
2059+ else
2060+ {
2061+ err = 1;
2062+ *xerrmsg = xstrdup("user is not given any permissions to remove/add");
2063+ }
2064+ }
2065+
2066+ else
2067+ {
2068+ retperms = xstrdup (perms);
2069+ }
2070+
2071+ if (err)
2072+ return (NULL);
2073+ else
2074+ return (retperms);
2075+}
2076+
2077+int
2078+write_perms (user, perms, founduserpart, foundline, otheruserparts,
2079+ part_type, part_object, part_tag, pos, arepos)
2080+char *user;
2081+char *perms;
2082+char *founduserpart;
2083+int foundline;
2084+char *otheruserparts;
2085+char *part_type;
2086+char *part_object;
2087+char *part_tag;
2088+int pos;
2089+char *arepos;
2090+{
09f63587 2091+ char *accessfile;
2092+ char *tmpaccessout;
2093+ FILE *accessfpin;
2094+ FILE *accessfpout;
2095+
2096+ char *newline = NULL;
2097+ size_t newlinelen = 1;
2098+
2099+ char *line = NULL;
2100+ size_t line_allocated = 0;
2101+
2102+ newline = xmalloc (newlinelen);
2103+ newline[0] = '\0';
2104+
2105+ if (!cvs_casecmp (part_tag, "ALL"))
2106+ part_tag = xstrdup ("ALL");
2107+
2108+ xrealloc_and_strcat (&newline, &newlinelen, part_type);
2109+ xrealloc_and_strcat (&newline, &newlinelen, ":");
2110+ xrealloc_and_strcat (&newline, &newlinelen, part_object);
2111+ xrealloc_and_strcat (&newline, &newlinelen, ":");
2112+ xrealloc_and_strcat (&newline, &newlinelen, part_tag);
2113+ xrealloc_and_strcat (&newline, &newlinelen, ":");
2114+
2115+ if (strncmp (perms, "none", 4) != 0)
2116+ {
2117+ xrealloc_and_strcat (&newline, &newlinelen, user);
2118+ xrealloc_and_strcat (&newline, &newlinelen, "!");
2119+ xrealloc_and_strcat (&newline, &newlinelen, perms);
2120+ if (otheruserparts != NULL)
2121+ xrealloc_and_strcat (&newline, &newlinelen, ",");
2122+ }
2123+
2124+ if (otheruserparts != NULL)
2125+ {
2126+ if (otheruserparts[strlen (otheruserparts) - 1] == '\n')
2127+ otheruserparts[strlen (otheruserparts) - 1] = '\0';
2128+
2129+ xrealloc_and_strcat (&newline, &newlinelen, otheruserparts);
2130+ }
2131+
2132+ xrealloc_and_strcat (&newline, &newlinelen, ":");
2133+
2134+ if (foundline)
2135+ {
2136+ accessfpout = cvs_temp_file (&tmpaccessout);
2137+ accessfpin = open_accessfile ("r", arepos, &accessfile);
2138+
2139+ while (getline (&line, &line_allocated, accessfpin) >= 0)
2140+ {
2141+ if (pos != ftell (accessfpin))
2142+ {
2143+ if (fprintf (accessfpout, line) < 0)
2144+ error (1, errno, "writing temporary file: %s", tmpaccessout);
2145+ }
2146+ else
2147+ {
2148+ if (fprintf (accessfpout, "%s\n", newline) < 0)
2149+ error (1, errno, "writing temporary file: %s", tmpaccessout);
2150+ }
2151+
2152+ }
2153+ if (fclose (accessfpin) == EOF)
2154+ error (1, errno, "cannot close access file: %s", accessfile);
2155+
2156+ if (fclose (accessfpout) == EOF)
2157+ error (1, errno, "cannot close temporary file: %s", tmpaccessout);
2158+
2159+ if (CVS_UNLINK (accessfile) < 0)
2160+ error (0, errno, "cannot remove %s", accessfile);
2161+
2162+ copy_file (tmpaccessout, accessfile);
2163+
2164+ if (CVS_UNLINK (tmpaccessout) < 0)
2165+ error (0, errno, "cannot remove temporary file: %s", tmpaccessout);
2166+ }
2167+ else
2168+ {
2169+ accessfpout = open_accessfile ("r+", arepos, &accessfile);
2170+
2171+ if (accessfpout == NULL)
2172+ {
2173+ if (existence_error (errno))
2174+ {
2175+ accessfpout = open_accessfile ("w+", arepos, &accessfile);
2176+ }
2177+ }
67ba4c3a 2178+ else {
2179+ if (fseek (accessfpout, 0, 2) != 0)
2180+ error (1, errno, "cannot fseek access file: %s", accessfile);
2181+ }
09f63587 2182+
2183+ if (fprintf (accessfpout, "%s\n", newline) < 0)
2184+ error (1, errno, "writing access file: %s", accessfile);
2185+
2186+ if (fclose (accessfpout) == EOF)
2187+ error (1, errno, "cannot close access file: %s", accessfile);
2188+ }
2189+
2190+ free (newline);
2191+
2192+ chmod(accessfile, 0644);
2193+
2194+ return (0);
2195+}
2196+
2197+
2198+static int
2199+acllist_fileproc (callerdat, finfo)
2200+void *callerdat;
2201+struct file_info *finfo;
2202+{
2203+
2204+ char *filefullname;
2205+ const char *frepository;
2206+ char *line = NULL;
2207+ int pos;
2208+
2209+ if (!aclfile)
2210+ return (0);
2211+
2212+ frepository = Short_Repository (finfo->repository);
2213+
2214+ filefullname = xmalloc (strlen (frepository)
2215+ + strlen (finfo->file)
2216+ + 2);
2217+ strcpy (filefullname, frepository);
2218+ strcat (filefullname, "/");
2219+ strcat (filefullname, finfo->file);
2220+
2221+ if (!access_allowed (finfo->file, finfo->repository, tag, 5, &line, &pos, 0))
2222+ error (1,0,"You do not have admin rights on '%s'", frepository);
2223+
09f63587 2224+ acllist_print (line, filefullname);
2225+
2226+ return (0);
2227+}
2228+
2229+static Dtype
2230+acllist_dirproc (callerdat, dir, repos, update_dir, entries)
2231+void *callerdat;
2232+const char *dir;
2233+const char *repos;
2234+const char *update_dir;
2235+List *entries;
2236+{
2237+
2238+ char *line = NULL;
2239+ const char *drepository;
2240+ int pos;
2241+
2242+ if (repos[0] == '\0')
2243+ repos = Name_Repository (dir, NULL);
2244+
2245+ if (!acldir)
2246+ return (0);
2247+
2248+ drepository = Short_Repository (repos);
2249+
2250+ if (!access_allowed (NULL, repos, tag, 5, &line, &pos, 0))
2251+ error (1, 0, "You do not have admin rights on '%s'", drepository);
2252+
2253+ acllist_print (line, drepository);
2254+
2255+ return (0);
2256+}
2257+
2258+
2259+void
2260+acllist_print (line, obj)
2261+char *line;
2262+const char *obj;
2263+{
2264+ char *temp;
2265+ char *temp2;
2266+ int x;
2267+ int c = 0;
2268+
2269+ char *printedusers[255];
2270+ printedusers[0] = NULL;
2271+
2272+ if (line != NULL)
2273+ {
2274+ temp = strtok (line, ":\t");
2275+
2276+ if (acldir)
2277+ cvs_output ("d ", 0);
2278+ else if (aclfile)
2279+ cvs_output ("f ", 0);
2280+
2281+ temp = strtok (NULL, ":\t");
2282+
2283+ cvs_output(obj, 0);
2284+ cvs_output (" | ", 0);
2285+
2286+ temp = strtok (NULL, ":\t");
2287+ cvs_output (temp, 0);
2288+ cvs_output (" | ", 0);
2289+
2290+ while ((temp = strtok (NULL, "!\t")) != NULL)
2291+ {
2292+ if (strncmp (temp, ":", 1) == 0)
2293+ break;
2294+
2295+ if (strcmp (temp, "ALL") == 0)
2296+ {
2297+ temp = strtok (NULL, ",\t");
2298+ continue;
2299+ }
2300+
2301+ cvs_output (temp, 0);
2302+ cvs_output (":", 0);
2303+
2304+ while (printedusers[c] != NULL)
2305+ c++;
2306+
2307+ printedusers[c] = xstrdup (temp);
2308+ c++;
2309+ printedusers[c] = NULL;
2310+
2311+ temp = strtok (NULL, ",\t");
2312+
2313+ if (temp != NULL && temp[strlen (temp) - 2] == ':')
2314+ temp[strlen (temp) - 2] = '\0';
2315+
2316+ cvs_output (temp, 0);
2317+ cvs_output (" ", 0);
2318+ }
2319+
2320+ if (default_perms_object)
2321+ {
2322+ cvs_output ("| defaults ", 0);
2323+ cvs_output ("ALL:", 0);
2324+ cvs_output (default_perms_object, 0);
2325+ }
2326+ else if (default_part_perms_accessfile)
2327+ {
2328+ size_t i;
2329+ i = strlen (default_part_perms_accessfile);
2330+ xrealloc_and_strcat (&default_part_perms_accessfile, &i, ",");
2331+
2332+ free(line);
2333+ line = xstrdup(default_part_perms_accessfile);
2334+
2335+ cvs_output ("| defaults ", 0);
2336+
2337+ temp = strtok (line, "!\t");
2338+ cvs_output (temp, 0);
2339+ cvs_output (":", 0);
2340+
2341+ temp = strtok (NULL, ",\t");
2342+
2343+ cvs_output (temp, 0);
2344+ cvs_output (" ", 0);
2345+
2346+ while ((temp = strtok (NULL, "!\t")) != NULL)
2347+ {
2348+ int printed = 0;
2349+ int c2 = 0;
2350+ while (printedusers[c2] != NULL && printed == 0)
2351+ {
2352+ if (strcmp (printedusers[c2], temp) == 0)
2353+ {
2354+ printed = 1;
2355+ break;
2356+ }
2357+ c2++;
2358+ }
2359+
2360+ if (printed == 0)
2361+ {
2362+ cvs_output (temp, 0);
2363+ cvs_output (":", 0);
2364+ }
2365+
2366+ temp = strtok (NULL, ",\t");
2367+
2368+ if (temp[strlen (temp) - 2] == ':')
2369+ temp[strlen (temp) - 2] = '\0';
2370+
2371+ if (printed == 0)
2372+ {
2373+ cvs_output (temp, 0);
2374+ cvs_output (" ", 0);
2375+ }
2376+ }
2377+ }
2378+ else if (cvs_acl_default_permissions)
2379+ {
2380+ cvs_output ("| defaults ", 0);
2381+ cvs_output ("ALL: ", 0);
2382+ cvs_output (cvs_acl_default_permissions, 0);
2383+ }
2384+
2385+ cvs_output ("\n", 0);
2386+
2387+ }
2388+ else
2389+ {
2390+ if (acldir)
2391+ cvs_output ("d ", 0);
2392+ else if (aclfile)
2393+ cvs_output ("f ", 0);
2394+ cvs_output (obj, 0);
2395+ cvs_output (" | ", 0);
2396+ cvs_output (tag, 0);
2397+ cvs_output (" | ", 0);
2398+
2399+ if (default_perms_object)
2400+ {
2401+ cvs_output ("| defaults ", 0);
2402+ cvs_output ("ALL:", 0);
2403+ cvs_output (default_perms_object, 0);
2404+ cvs_output ("\n", 0);
2405+ }
2406+ else if (default_part_perms_accessfile)
2407+ {
2408+ free(line);
2409+ line = xstrdup(default_part_perms_accessfile);
2410+
2411+ cvs_output ("| defaults ", 0);
2412+
2413+ temp = strtok (line, "!\t");
2414+ cvs_output (temp, 0);
2415+ cvs_output (":", 0);
2416+
2417+ temp = strtok (NULL, ",\t");
2418+
2419+ if (temp[strlen (temp) - 2] == ':')
2420+ temp[strlen (temp) - 2] = '\0';
2421+
2422+ cvs_output (temp, 0);
2423+ cvs_output (" ", 0);
2424+
2425+ while ((temp = strtok (NULL, "!\t")) != NULL)
2426+ {
2427+ cvs_output (temp, 0);
2428+ cvs_output (":", 0);
2429+
2430+ temp = strtok (NULL, ",\t");
2431+
2432+ if (temp[strlen (temp) - 2] == ':')
2433+ temp[strlen (temp) - 2] = '\0';
2434+
2435+ cvs_output (temp, 0);
2436+ cvs_output (" ", 0);
2437+ }
2438+ cvs_output ("\n", 0);
2439+ }
2440+ else if (cvs_acl_default_permissions)
2441+ {
2442+ cvs_output ("| defaults ", 0);
2443+ cvs_output ("ALL: ", 0);
2444+ cvs_output (cvs_acl_default_permissions, 0);
2445+ cvs_output ("\n", 0);
2446+ }
2447+ else
2448+ cvs_output ("default:p (no perms)\n", 0);
2449+ }
2450+
2451+}
fe149767 2452diff -urN cvs-1.11.19.orig/src/add.c cvs-1.11.19/src/add.c
2453--- cvs-1.11.19.orig/src/add.c 2005-01-31 23:09:18.000000000 +0100
2454+++ cvs-1.11.19/src/add.c 2005-03-14 19:55:09.000000000 +0100
2455@@ -405,6 +405,24 @@
09f63587 2456 }
2457 else
2458 {
2459+/* cvsacl patch */
2460+#ifdef SERVER_SUPPORT
2461+ if (use_cvs_acl && server_active)
2462+ {
2463+ if (!access_allowed (finfo.file, repository, vers->tag, 6,
2464+ NULL, NULL, 1))
2465+ {
2466+ if (stop_at_first_permission_denied)
2467+ error (1, 0, "permission denied for %s",
2468+ Short_Repository (finfo.repository));
2469+ else
2470+ error (0, 0, "permission denied for %s/%s",
2471+ Short_Repository (finfo.repository), finfo.file);
2472+
2473+ return (0);
2474+ }
2475+ }
2476+#endif
2477 /* There is a user file, so build the entry for it */
2478 if (build_entry (repository, finfo.file, vers->options,
2479 message, entries, vers->tag) != 0)
fe149767 2480@@ -679,6 +697,26 @@
09f63587 2481 && isdir (finfo.file)
2482 && !wrap_name_has (finfo.file, WRAP_TOCVS))
2483 {
2484+
2485+/* cvsacl patch */
2486+#ifdef SERVER_SUPPORT
2487+ if (use_cvs_acl && server_active)
2488+ {
2489+ if (!access_allowed (NULL, repository, NULL, 6,
2490+ NULL, NULL, 1))
2491+ {
2492+ if (stop_at_first_permission_denied)
2493+ error (1, 0, "permission denied for %s",
2494+ Short_Repository (finfo.repository));
2495+ else
2496+ error (0, 0, "permission denied for %s/%s",
2497+ Short_Repository (finfo.repository), finfo.file);
2498+
2499+ return (0);
2500+ }
2501+ }
2502+#endif
2503+
2504 err += add_directory (&finfo);
2505 }
2506 else
fe149767 2507diff -urN cvs-1.11.19.orig/src/admin.c cvs-1.11.19/src/admin.c
2508--- cvs-1.11.19.orig/src/admin.c 2005-01-31 23:09:57.000000000 +0100
2509+++ cvs-1.11.19/src/admin.c 2005-03-14 19:55:09.000000000 +0100
2510@@ -566,6 +566,25 @@
2511
2512 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
2513
2514+/* cvsacl patch */
2515+#ifdef SERVER_SUPPORT
2516+ if (use_cvs_acl && server_active)
2517+ {
2518+ if (!access_allowed (finfo->file, finfo->repository, NULL, 2,
2519+ NULL, NULL, 1))
2520+ {
2521+ if (stop_at_first_permission_denied)
2522+ error (1, 0, "permission denied for %s",
2523+ Short_Repository (finfo->repository));
2524+ else
2525+ error (0, 0, "permission denied for %s/%s",
2526+ Short_Repository (finfo->repository), finfo->file);
2527+
2528+ return (0);
2529+ }
2530+ }
2531+#endif
2532+
2533 version = vers->vn_user;
2534 if (version != NULL && strcmp (version, "0") == 0)
2535 {
2536diff -urN cvs-1.11.19.orig/src/annotate.c cvs-1.11.19/src/annotate.c
2537--- cvs-1.11.19.orig/src/annotate.c 2005-01-31 23:10:09.000000000 +0100
2538+++ cvs-1.11.19/src/annotate.c 2005-03-14 19:55:09.000000000 +0100
2539@@ -281,6 +281,25 @@
09f63587 2540 if (version == NULL)
2541 return 0;
2542
2543+/* cvsacl patch */
2544+#ifdef SERVER_SUPPORT
2545+ if (use_cvs_acl && server_active)
2546+ {
2547+ if (!access_allowed (finfo->file, finfo->repository, version, 5,
2548+ NULL, NULL, 1))
2549+ {
2550+ if (stop_at_first_permission_denied)
2551+ error (1, 0, "permission denied for %s",
2552+ Short_Repository (finfo->repository));
2553+ else
2554+ error (0, 0, "permission denied for %s/%s",
2555+ Short_Repository (finfo->repository), finfo->file);
2556+
2557+ return (0);
2558+ }
2559+ }
2560+#endif
2561+
2562 /* Distinguish output for various files if we are processing
2563 several files. */
2564 cvs_outerr ("\nAnnotations for ", 0);
fe149767 2565diff -urN cvs-1.11.19.orig/src/commit.c cvs-1.11.19/src/commit.c
2566--- cvs-1.11.19.orig/src/commit.c 2005-01-31 23:11:19.000000000 +0100
2567+++ cvs-1.11.19/src/commit.c 2005-03-14 19:55:09.000000000 +0100
2568@@ -1304,6 +1304,34 @@
c52fdbcd 2569 return 0;
09f63587 2570
2571 ci = p->data;
2572+
2573+/* cvsacl patch */
2574+#ifdef SERVER_SUPPORT
2575+ if (use_cvs_acl && server_active)
2576+ {
2577+ int whichperm;
2578+ if (ci->status == T_MODIFIED)
2579+ whichperm = 3;
2580+ else if (ci->status == T_ADDED)
2581+ whichperm = 6;
2582+ else if (ci->status == T_REMOVED)
2583+ whichperm = 7;
2584+
2585+ if (!access_allowed (finfo->file, finfo->repository, ci->tag, whichperm,
2586+ NULL, NULL, 1))
2587+ {
2588+ if (stop_at_first_permission_denied)
2589+ error (1, 0, "permission denied for %s",
2590+ Short_Repository (finfo->repository));
2591+ else
2592+ error (0, 0, "permission denied for %s/%s",
2593+ Short_Repository (finfo->repository), finfo->file);
2594+
2595+ return (0);
2596+ }
2597+ }
2598+#endif
2599+
2600 if (ci->status == T_MODIFIED)
2601 {
2602 if (finfo->rcs == NULL)
fe149767 2603diff -urN cvs-1.11.19.orig/src/cvs.h cvs-1.11.19/src/cvs.h
2604--- cvs-1.11.19.orig/src/cvs.h 2005-03-14 19:49:29.000000000 +0100
2605+++ cvs-1.11.19/src/cvs.h 2005-03-14 19:55:09.000000000 +0100
2606@@ -200,6 +200,11 @@
09f63587 2607 #define CVSROOTADM_PASSWD "passwd"
2608 #define CVSROOTADM_CONFIG "config"
2609
2610+/* cvsacl patch */
2611+#define CVSROOTADM_ACLCONFIG "aclconfig"
2612+#define CVSROOTADM_ACCESS "access"
2613+#define CVSROOTADM_GROUP "group"
2614+
2615 #define CVSNULLREPOS "Emptydir" /* an empty directory */
2616
2617 /* Other CVS file names */
fe149767 2618@@ -572,6 +577,18 @@
09f63587 2619 /* LockDir setting from CVSROOT/config. */
2620 extern char *lock_dir;
2621
2622+/* cvsacl patch */
2623+/* ACL Patch settings from CVSROOT/config */
2624+extern int use_cvs_acl;
2625+extern char *cvs_acl_default_permissions;
2626+extern int use_cvs_groups;
2627+extern int use_system_groups;
c52fdbcd 2628+extern int use_separate_acl_file_for_each_dir;
09f63587 2629+extern char *cvs_acl_file_location;
2630+extern char *cvs_groups_file_location;
2631+extern char *cvs_server_run_as;
2632+extern int stop_at_first_permission_denied;
2633+
2634 void Scratch_Entry PROTO((List * list, const char *fname));
2635 void ParseTag PROTO((char **tagp, char **datep, int *nonbranchp));
2636 void WriteTag PROTO ((const char *dir, const char *tag, const char *date,
fe149767 2637@@ -867,6 +884,10 @@
09f63587 2638 int editors PROTO ((int argc, char **argv));
2639 int watchers PROTO ((int argc, char **argv));
2640 extern int annotate PROTO ((int argc, char **argv));
2641+
2642+/* cvsacl patch */
2643+extern int cvsacl PROTO ((int argc, char **argv));
2644+
2645 extern int add PROTO ((int argc, char **argv));
2646 extern int admin PROTO ((int argc, char **argv));
2647 extern int checkout PROTO ((int argc, char **argv));
fe149767 2648diff -urN cvs-1.11.19.orig/src/diff.c cvs-1.11.19/src/diff.c
2649--- cvs-1.11.19.orig/src/diff.c 2005-01-31 23:12:09.000000000 +0100
2650+++ cvs-1.11.19/src/diff.c 2005-03-14 19:55:09.000000000 +0100
2651@@ -479,6 +479,43 @@
09f63587 2652 {
2653 /* Skip all the following checks regarding the user file; we're
2654 not using it. */
2655+
2656+/* cvsacl patch */
2657+#ifdef SERVER_SUPPORT
2658+ if (use_cvs_acl && server_active)
2659+ {
2660+ if (diff_rev1)
2661+ {
2662+ if (!access_allowed (NULL, finfo->repository, diff_rev1, 5,
2663+ NULL, NULL, 1))
2664+ {
2665+ if (stop_at_first_permission_denied)
2666+ error (1, 0, "permission denied for %s",
2667+ Short_Repository (finfo->repository));
2668+ else
2669+ error (0, 0, "permission denied for %s/%s",
2670+ Short_Repository (finfo->repository), finfo->file);
2671+
2672+ return (0);
2673+ }
2674+ }
2675+ if (diff_rev2)
2676+ {
2677+ if (!access_allowed (NULL, finfo->repository, diff_rev2, 5))
2678+ {
2679+ if (stop_at_first_permission_denied)
2680+ error (1, 0, "permission denied for %s",
2681+ Short_Repository (finfo->repository));
2682+ else
2683+ error (0, 0, "permission denied for %s/%s",
2684+ Short_Repository (finfo->repository), finfo->file);
2685+
2686+ return (0);
2687+ }
2688+ }
2689+ }
2690+#endif
2691+
2692 }
2693 else if (vers->vn_user == NULL)
2694 {
fe149767 2695@@ -832,6 +869,42 @@
09f63587 2696 if (!isdir (dir))
2697 return (R_SKIP_ALL);
2698
2699+/* cvsacl patch */
2700+#ifdef SERVER_SUPPORT
2701+ if (use_cvs_acl && server_active)
2702+ {
2703+ if (diff_rev1)
2704+ {
2705+ if (!access_allowed (NULL, update_dir, diff_rev1, 5,
2706+ NULL, NULL, 1))
2707+ {
2708+ if (stop_at_first_permission_denied)
2709+ error (1, 0, "permission denied for %s",
2710+ Short_Repository (update_dir));
2711+ else
2712+ error (0, 0, "permission denied for %s/%s",
2713+ Short_Repository (update_dir), update_dir);
2714+
2715+ return (0);
2716+ }
2717+ }
2718+ if (diff_rev2)
2719+ {
2720+ if (!access_allowed (NULL, update_dir, diff_rev2, 5))
2721+ {
2722+ if (stop_at_first_permission_denied)
2723+ error (1, 0, "permission denied for %s",
2724+ Short_Repository (update_dir));
2725+ else
2726+ error (0, 0, "permission denied for %s/%s",
2727+ Short_Repository (update_dir), update_dir);
2728+
2729+ return (0);
2730+ }
2731+ }
2732+ }
2733+#endif
2734+
2735 if (!quiet)
2736 error (0, 0, "Diffing %s", update_dir);
2737 return (R_PROCESS);
fe149767 2738diff -urN cvs-1.11.19.orig/src/import.c cvs-1.11.19/src/import.c
2739--- cvs-1.11.19.orig/src/import.c 2005-01-31 23:13:00.000000000 +0100
2740+++ cvs-1.11.19/src/import.c 2005-03-14 19:55:09.000000000 +0100
2741@@ -319,6 +319,20 @@
09f63587 2742 error (1, 0, "attempt to import the repository");
2743 }
2744
2745+/* cvsacl patch */
2746+#ifdef SERVER_SUPPORT
2747+ if (use_cvs_acl && server_active)
2748+ {
2749+ if (!access_allowed (NULL, repository, argv[1], 6, NULL, NULL, 1))
2750+ {
2751+ error (stop_at_first_permission_denied, 0, "permission denied for %s",
2752+ Short_Repository (repository));
2753+
2754+ return (0);
2755+ }
2756+ }
2757+#endif
2758+
2759 /*
2760 * Make all newly created directories writable. Should really use a more
2761 * sophisticated security mechanism here.
fe149767 2762diff -urN cvs-1.11.19.orig/src/log.c cvs-1.11.19/src/log.c
2763--- cvs-1.11.19.orig/src/log.c 2005-02-03 15:50:51.000000000 +0100
2764+++ cvs-1.11.19/src/log.c 2005-03-14 19:55:09.000000000 +0100
2765@@ -853,6 +853,25 @@
09f63587 2766 return 1;
2767 }
2768
2769+/* cvsacl patch */
2770+#ifdef SERVER_SUPPORT
2771+ if (use_cvs_acl && server_active)
2772+ {
2773+ if (!access_allowed (finfo->file, finfo->repository, NULL, 5,
2774+ NULL, NULL, 1))
2775+ {
2776+ if (stop_at_first_permission_denied)
2777+ error (1, 0, "permission denied for %s",
2778+ Short_Repository (finfo->repository));
2779+ else
2780+ error (0, 0, "permission denied for %s/%s",
2781+ Short_Repository (finfo->repository), finfo->file);
2782+
2783+ return (0);
2784+ }
2785+ }
2786+#endif
2787+
2788 if (log_data->sup_header || !log_data->nameonly)
2789 {
2790
fe149767 2791diff -urN cvs-1.11.19.orig/src/main.c cvs-1.11.19/src/main.c
2792--- cvs-1.11.19.orig/src/main.c 2005-03-14 19:49:29.000000000 +0100
2793+++ cvs-1.11.19/src/main.c 2005-03-14 19:55:09.000000000 +0100
2794@@ -102,6 +102,10 @@
09f63587 2795 } cmds[] =
2796
2797 {
2798+ /* cvsacl patch */
2799+ { "acl", NULL, NULL, cvsacl, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
2800+ { "racl", NULL, NULL, cvsacl, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
2801+
2802 { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
2803 { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
2804 { "annotate", "ann", NULL, annotate, CVS_CMD_USES_WORK_DIR },
fe149767 2805@@ -968,6 +972,9 @@
09f63587 2806 if we didn't, then there would be no way to check in a new
2807 CVSROOT/config file to fix the broken one! */
2808 parse_config (current_parsed_root->directory);
2809+
2810+ /* cvsacl patch */
2811+ parse_aclconfig (current_parsed_root->directory);
2812 }
2813
2814 #ifdef CLIENT_SUPPORT
fe149767 2815diff -urN cvs-1.11.19.orig/src/mkmodules.c cvs-1.11.19/src/mkmodules.c
2816--- cvs-1.11.19.orig/src/mkmodules.c 2005-01-31 23:14:17.000000000 +0100
2817+++ cvs-1.11.19/src/mkmodules.c 2005-03-14 19:55:09.000000000 +0100
2818@@ -316,6 +316,44 @@
09f63587 2819 NULL
2820 };
2821
2822+/* cvsacl patch */
2823+static const char *const aclconfig_contents[] = {
2824+ "# Set `UseCVSACL' to yes to use CVSACL feature.\n",
2825+ "UseCVSACL=yes\n",
2826+ "\n",
2827+ "# Default CVSACL Permission to use.\n",
2828+ "#CVSACLDefaultPermissions=p\n",
2829+ "\n",
2830+ "# Default file location for CVS ACL file (access) is CVSROOT/access.\n",
2831+ "# If you want to use a different location, define it below.\n",
2832+ "#CVSACLFileLocation=/path/to/cvs/access\n",
2833+ "\n",
2834+ "# Set `UseSystemGroups' to yes to use system group definitions (/etc/group).\n",
2835+ "UseSystemGroups=yes\n",
2836+ "\n",
2837+ "# Set `UseCVSGroups' to yes to use another group file.\n",
2838+ "#UseCVSGroups=yes\n",
2839+ "\n",
2840+ "# Default file location for CVS groups file is CVSROOT/group.\n",
2841+ "# If you want to use a different location, define it below.\n",
2842+ "#CVSGroupsFileLocation=/path/to/cvs/group\n",
2843+ "\n",
c52fdbcd 2844+ "# Set UseSeparateACLFileForEachDir to yes in order to use a\n",
2845+ "# separate 'access' file for each directory.\n",
09f63587 2846+ "# This increased the performance if you have really big repository.\n",
c52fdbcd 2847+ "#UseSeparateACLFileForEachDir=no\n",
09f63587 2848+ "\n",
2849+ "# If StopAtFirstPermissionDenied is set to yes\n",
2850+ "# operation will stop at first permission denied message.\n",
2851+ "# Default is no.\n",
2852+ "#StopAtFirstPermissionDenied=no\n",
2853+ "\n",
2854+ "# Set CVSServerRunAsUser to a system user, in order CVS server\n",
2855+ "# to run as.\n",
2856+ "#CVSServerRunAsUser=runascvsuser",
2857+ NULL
2858+};
2859+
2860 static const struct admin_file filelist[] = {
2861 {CVSROOTADM_LOGINFO,
2862 "no logging of 'cvs commit' messages is done without a %s file",
fe149767 2863@@ -378,7 +416,12 @@
09f63587 2864 {CVSROOTADM_CONFIG,
2865 "a %s file configures various behaviors",
2866 config_contents},
2867- {NULL, NULL, NULL}
2868+
2869+ /* cvsacl patch */
2870+ {CVSROOTADM_ACLCONFIG,
2871+ "a %s file configures Access Control List behaviors",
2872+ aclconfig_contents},
2873+ {NULL, NULL, NULL}
2874 };
2875
2876 /* Rebuild the checked out administrative files in directory DIR. */
fe149767 2877@@ -962,6 +1005,26 @@
09f63587 2878 because xchmod() is too shy. */
2879 chmod (info, 0666);
2880 }
2881+
2882+ /* cvsacl patch */
2883+ /* Make an empty 'CVSROOT/access' file */
2884+ strcpy (info, adm);
2885+ strcat (info, "/");
2886+ strcat (info, CVSROOTADM_ACCESS);
2887+ if (!isfile (info))
2888+ {
2889+ FILE *fp;
2890+
2891+ fp = open_file (info, "w");
2892+ if (fputs ("# CVS ACL definitions file. DO NOT EDIT MANUALLY\n",
2893+ fp) < 0)
2894+ error (1, errno, "cannot write %s", info);
2895+
2896+ if (fclose (fp) < 0)
2897+ error (1, errno, "cannot close %s", info);
2898+
2899+ chmod (info, 0644);
2900+ }
2901
2902 /* Make an empty val-tags file to prevent problems creating it later. */
2903 strcpy (info, adm);
fe149767 2904diff -urN cvs-1.11.19.orig/src/parseinfo.c cvs-1.11.19/src/parseinfo.c
2905--- cvs-1.11.19.orig/src/parseinfo.c 2005-01-31 23:14:54.000000000 +0100
2906+++ cvs-1.11.19/src/parseinfo.c 2005-03-14 19:55:09.000000000 +0100
2907@@ -453,3 +453,192 @@
09f63587 2908 free (line);
2909 return -1;
2910 }
2911+/* cvsacl patch */
2912+int
2913+parse_aclconfig (cvsroot)
2914+ char *cvsroot;
2915+{
2916+ char *infopath;
2917+ FILE *fp_info;
2918+ char *line = NULL;
2919+ size_t line_allocated = 0;
2920+ size_t len;
2921+ char *p;
2922+ /* FIXME-reentrancy: If we do a multi-threaded server, this would need
2923+ to go to the per-connection data structures. */
2924+ static int parsed = 0;
2925+
2926+ /* Authentication code and serve_root might both want to call us.
2927+ Let this happen smoothly. */
2928+ if (parsed)
2929+ return 0;
2930+ parsed = 1;
2931+
2932+ infopath = xmalloc (strlen (cvsroot)
2933+ + sizeof (CVSROOTADM_ACLCONFIG)
2934+ + sizeof (CVSROOTADM)
2935+ + 10);
2936+ if (infopath == NULL)
2937+ {
2938+ error (0, 0, "out of memory; cannot allocate infopath");
2939+ goto error_return;
2940+ }
2941+
2942+ strcpy (infopath, cvsroot);
2943+ strcat (infopath, "/");
2944+ strcat (infopath, CVSROOTADM);
2945+ strcat (infopath, "/");
2946+ strcat (infopath, CVSROOTADM_ACLCONFIG);
2947+
2948+ fp_info = CVS_FOPEN (infopath, "r");
2949+ if (fp_info == NULL)
2950+ {
2951+ /* If no file, don't do anything special. */
2952+ if (!existence_error (errno))
2953+ {
2954+ /* Just a warning message; doesn't affect return
2955+ value, currently at least. */
2956+ error (0, errno, "cannot open %s", infopath);
2957+ }
2958+ free (infopath);
2959+ return 0;
2960+ }
2961+
2962+ while (getline (&line, &line_allocated, fp_info) >= 0)
2963+ {
2964+ /* Skip comments. */
2965+ if (line[0] == '#')
2966+ continue;
2967+
2968+ len = strlen (line) - 1;
2969+ if (line[len] == '\n')
2970+ line[len] = '\0';
2971+
2972+ /* Skip blank lines. */
2973+ if (line[0] == '\0')
2974+ continue;
2975+
2976+ /* The first '=' separates keyword from value. */
2977+ p = strchr (line, '=');
2978+ if (p == NULL)
2979+ {
2980+ /* Probably should be printing line number. */
2981+ error (0, 0, "syntax error in %s: line '%s' is missing '='",
2982+ infopath, line);
2983+ goto error_return;
2984+ }
2985+
2986+ *p++ = '\0';
2987+
2988+ if (strcmp (line, "UseCVSACL") == 0)
2989+ {
2990+ if (strcmp (p, "no") == 0)
2991+ use_cvs_acl = 0;
2992+ else if (strcmp (p, "yes") == 0)
2993+ use_cvs_acl = 1;
2994+ else
2995+ {
2996+ error (0, 0, "unrecognized value '%s' for UseCVSACL", p);
2997+ goto error_return;
2998+ }
2999+ }
c52fdbcd 3000+ else if (strcmp (line, "UseSeparateACLFileForEachDir") == 0)
09f63587 3001+ {
3002+ if (strcmp (p, "no") == 0)
c52fdbcd 3003+ use_separate_acl_file_for_each_dir = 0;
09f63587 3004+ else if (strcmp (p, "yes") == 0)
c52fdbcd 3005+ use_separate_acl_file_for_each_dir = 1;
09f63587 3006+ else
3007+ {
c52fdbcd 3008+ error (0, 0, "unrecognized value '%s' for UseSeparateACLFileForEachDir", p);
09f63587 3009+ goto error_return;
3010+ }
3011+ }
3012+ else if (strcmp (line, "StopAtFirstPermissionDenied") == 0)
3013+ {
3014+ if (strcmp (p, "no") == 0)
3015+ stop_at_first_permission_denied = 0;
3016+ else if (strcmp (p, "yes") == 0)
3017+ stop_at_first_permission_denied = 1;
3018+ else
3019+ {
3020+ error (0, 0, "unrecognized value '%s' for StopAtFirstPermissionDenied", p);
3021+ goto error_return;
3022+ }
3023+ }
3024+ else if (strcmp (line, "CVSACLDefaultPermissions") == 0)
3025+ {
3026+ if (cvs_acl_default_permissions != NULL)
3027+ free (cvs_acl_default_permissions);
3028+ if (!given_perms_valid (p))
3029+ error (1,0,"Invalid CVS ACL Default Permissions: '%s' in CVSROOT/aclconfig", p);
3030+ cvs_acl_default_permissions = xstrdup (p);
3031+ }
3032+ else if (strcmp (line, "UseCVSGroups") == 0)
3033+ {
3034+ if (strcmp (p, "no") == 0)
3035+ use_cvs_groups = 0;
3036+ else if (strcmp (p, "yes") == 0)
3037+ use_cvs_groups = 1;
3038+ else
3039+ {
3040+ error (0, 0, "unrecognized value '%s' for UseCVSGroups", p);
3041+ goto error_return;
3042+ }
3043+ }
3044+ else if (strcmp (line, "UseSystemGroups") == 0)
3045+ {
3046+ if (strcmp (p, "no") == 0)
3047+ use_system_groups = 0;
3048+ else if (strcmp (p, "yes") == 0)
3049+ use_system_groups = 1;
3050+ else
3051+ {
3052+ error (0, 0, "unrecognized value '%s' for UseSystemGroups", p);
3053+ goto error_return;
3054+ }
3055+ }
3056+ else if (strcmp (line, "CVSACLFileLocation") == 0)
3057+ {
3058+ if (cvs_acl_file_location != NULL)
3059+ free (cvs_acl_file_location);
3060+ cvs_acl_file_location = xstrdup (p);
3061+ }
3062+ else if (strcmp (line, "CVSGroupsFileLocation") == 0)
3063+ {
3064+ if (cvs_groups_file_location != NULL)
3065+ free (cvs_groups_file_location);
3066+ cvs_groups_file_location = xstrdup (p);
3067+ }
3068+ else if (strcmp (line, "CVSServerRunAsUser") == 0)
3069+ {
3070+ if (cvs_server_run_as != NULL)
3071+ free (cvs_server_run_as);
3072+ cvs_server_run_as = xstrdup (p);
3073+ }
3074+
3075+ }
3076+
3077+ if (ferror (fp_info))
3078+ {
3079+ error (0, errno, "cannot read %s", infopath);
3080+ goto error_return;
3081+ }
3082+ if (fclose (fp_info) < 0)
3083+ {
3084+ error (0, errno, "cannot close %s", infopath);
3085+ goto error_return;
3086+ }
3087+ free (infopath);
3088+ if (line != NULL)
3089+ free (line);
3090+ return 0;
3091+
3092+ error_return:
3093+ if (infopath != NULL)
3094+ free (infopath);
3095+ if (line != NULL)
3096+ free (line);
3097+ return -1;
3098+}
3099+
fe149767 3100diff -urN cvs-1.11.19.orig/src/patch.c cvs-1.11.19/src/patch.c
3101--- cvs-1.11.19.orig/src/patch.c 2005-01-31 23:15:02.000000000 +0100
3102+++ cvs-1.11.19/src/patch.c 2005-03-14 19:55:09.000000000 +0100
3103@@ -503,6 +503,43 @@
09f63587 3104 goto out2;
3105 }
3106
3107+/* cvsacl patch */
3108+#ifdef SERVER_SUPPORT
3109+ if (use_cvs_acl && server_active)
3110+ {
3111+ if (rev1)
3112+ {
3113+ if (!access_allowed (finfo->file, finfo->repository, rev1, 5,
3114+ NULL, NULL, 1))
3115+ {
3116+ if (stop_at_first_permission_denied)
3117+ error (1, 0, "permission denied for %s",
3118+ Short_Repository (finfo->repository));
3119+ else
3120+ error (0, 0, "permission denied for %s/%s",
3121+ Short_Repository (finfo->repository), finfo->file);
3122+
3123+ return (0);
3124+ }
3125+ }
3126+ if (rev2)
3127+ {
3128+ if (!access_allowed (finfo->file, finfo->repository, rev2, 5,
3129+ NULL, NULL, 1))
3130+ {
3131+ if (stop_at_first_permission_denied)
3132+ error (1, 0, "permission denied for %s",
3133+ Short_Repository (finfo->repository));
3134+ else
3135+ error (0, 0, "permission denied for %s/%s",
3136+ Short_Repository (finfo->repository), finfo->file);
3137+
3138+ return (0);
3139+ }
3140+ }
3141+ }
3142+#endif
3143+
3144 /* Create 3 empty files. I'm not really sure there is any advantage
3145 * to doing so now rather than just waiting until later.
3146 *
fe149767 3147diff -urN cvs-1.11.19.orig/src/remove.c cvs-1.11.19/src/remove.c
3148--- cvs-1.11.19.orig/src/remove.c 2005-01-31 23:15:31.000000000 +0100
3149+++ cvs-1.11.19/src/remove.c 2005-03-14 19:55:09.000000000 +0100
3150@@ -255,6 +255,25 @@
09f63587 3151 {
3152 char *fname;
3153
3154+/* cvsacl patch */
3155+#ifdef SERVER_SUPPORT
3156+ if (use_cvs_acl && server_active)
3157+ {
3158+ if (!access_allowed (finfo->file, finfo->repository, vers->tag, 7,
3159+ NULL, NULL, 1))
3160+ {
3161+ if (stop_at_first_permission_denied)
3162+ error (1, 0, "permission denied for %s",
3163+ Short_Repository (finfo->repository));
3164+ else
3165+ error (0, 0, "permission denied for %s/%s",
3166+ Short_Repository (finfo->repository), finfo->file);
3167+
3168+ return (0);
3169+ }
3170+ }
3171+#endif
3172+
3173 /* Re-register it with a negative version number. */
3174 fname = xmalloc (strlen (vers->vn_user) + 5);
3175 (void) strcpy (fname, "-");
fe149767 3176diff -urN cvs-1.11.19.orig/src/server.c cvs-1.11.19/src/server.c
3177--- cvs-1.11.19.orig/src/server.c 2005-03-14 19:49:29.000000000 +0100
3178+++ cvs-1.11.19/src/server.c 2005-03-14 19:55:09.000000000 +0100
09f63587 3179@@ -773,6 +773,10 @@
3180 nothing. But for rsh, we need to do it now. */
3181 parse_config (current_parsed_root->directory);
3182
3183+ /* cvsacl patch */
3184+ parse_aclconfig (current_parsed_root->directory);
3185+
3186+
3187 path = xmalloc (strlen (current_parsed_root->directory)
3188 + sizeof (CVSROOTADM)
3189 + 2);
c52fdbcd 3190@@ -3761,6 +3765,23 @@
09f63587 3191 do_cvs_command ("rlog", cvslog);
3192 }
3193
3194+/* cvsacl patch */
3195+static void
3196+serve_acl (arg)
3197+ char *arg;
3198+{
3199+ do_cvs_command ("acl", cvsacl);
3200+}
3201+
3202+/* cvsacl patch */
3203+static void
3204+serve_racl (arg)
3205+ char *arg;
3206+{
c52fdbcd 3207+ cvs_cmd_name = "racl";
09f63587 3208+ do_cvs_command ("racl", cvsacl);
3209+}
3210+
3211 static void
3212 serve_add (arg)
3213 char *arg;
4905fec9 3214@@ -4821,6 +4842,11 @@
09f63587 3215 REQ_LINE("diff", serve_diff, 0),
3216 REQ_LINE("log", serve_log, 0),
3217 REQ_LINE("rlog", serve_rlog, 0),
3218+
3219+ /* cvsacl patch */
3220+ REQ_LINE("acl", serve_acl, 0),
3221+ REQ_LINE("racl", serve_racl, 0),
3222+
3223 REQ_LINE("add", serve_add, 0),
3224 REQ_LINE("remove", serve_remove, 0),
3225 REQ_LINE("update-patches", serve_ignore, 0),
4905fec9 3226@@ -5294,6 +5320,10 @@
09f63587 3227 {
3228 struct passwd *pw;
3229
3230+ /* cvsacl patch */
3231+ if (use_cvs_acl && cvs_server_run_as)
3232+ username = cvs_server_run_as;
3233+
3234 pw = getpwnam (username);
3235 if (pw == NULL)
3236 {
4905fec9 3237@@ -5876,6 +5906,9 @@
09f63587 3238 in a new CVSROOT/config file to fix the broken one! */
3239 parse_config (repository);
3240
3241+ /* cvsacl patch */
3242+ parse_aclconfig (repository);
3243+
3244 /* We need the real cleartext before we hash it. */
3245 descrambled_password = descramble (password);
3246 host_user = check_password (username, descrambled_password, repository);
fe149767 3247diff -urN cvs-1.11.19.orig/src/status.c cvs-1.11.19/src/status.c
3248--- cvs-1.11.19.orig/src/status.c 2005-01-31 23:17:28.000000000 +0100
3249+++ cvs-1.11.19/src/status.c 2005-03-14 19:55:09.000000000 +0100
3250@@ -133,7 +133,27 @@
09f63587 3251
3252 status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL,
3253 1, 0, &vers, 0);
3254- sstat = "Classify Error";
3255+
3256+/* cvsacl patch */
3257+#ifdef SERVER_SUPPORT
3258+ if (use_cvs_acl && server_active)
3259+ {
3260+ if (!access_allowed (finfo->file, finfo->repository, vers->tag, 5,
3261+ NULL, NULL, 1))
3262+ {
3263+ if (stop_at_first_permission_denied)
3264+ error (1, 0, "permission denied for %s",
3265+ Short_Repository (finfo->repository));
3266+ else
3267+ error (0, 0, "permission denied for %s/%s",
3268+ Short_Repository (finfo->repository), finfo->file);
3269+
3270+ return (0);
3271+ }
3272+ }
3273+#endif
3274+
3275+ sstat = "Classify Error";
3276 switch (status)
3277 {
3278 case T_UNKNOWN:
fe149767 3279diff -urN cvs-1.11.19.orig/src/tag.c cvs-1.11.19/src/tag.c
3280--- cvs-1.11.19.orig/src/tag.c 2005-01-31 23:17:45.000000000 +0100
3281+++ cvs-1.11.19/src/tag.c 2005-03-14 19:55:09.000000000 +0100
3282@@ -665,6 +665,25 @@
09f63587 3283 * correctly without breaking your link!
3284 */
3285
3286+/* cvsacl patch */
3287+#ifdef SERVER_SUPPORT
3288+ if (use_cvs_acl && server_active)
3289+ {
3290+ if (!access_allowed (finfo->file, finfo->repository, numtag, 4,
3291+ NULL, NULL, 1))
3292+ {
3293+ if (stop_at_first_permission_denied)
3294+ error (1, 0, "permission denied for %s",
3295+ Short_Repository (finfo->repository));
3296+ else
3297+ error (0, 0, "permission denied for %s/%s",
3298+ Short_Repository (finfo->repository), finfo->file);
3299+
3300+ return (0);
3301+ }
3302+ }
3303+#endif
3304+
3305 if (delete_flag)
3306 return (rtag_delete (rcsfile));
3307
fe149767 3308@@ -885,6 +904,21 @@
09f63587 3309 if (nversion == NULL)
3310 goto free_vars_and_return;
3311 }
3312+
3313+/* cvsacl patch */
3314+#ifdef SERVER_SUPPORT
3315+ if (use_cvs_acl && server_active)
3316+ {
3317+ if (!access_allowed (finfo->file, finfo->repository, vers->tag, 4,
3318+ NULL, NULL, 1))
3319+ {
3320+ error (0, 0, "permission denied for %s/%s",
3321+ Short_Repository (finfo->repository), finfo->file);
3322+ return (0);
3323+ }
3324+ }
3325+#endif
3326+
3327 if (delete_flag)
3328 {
3329
fe149767 3330diff -urN cvs-1.11.19.orig/src/update.c cvs-1.11.19/src/update.c
3331--- cvs-1.11.19.orig/src/update.c 2005-01-31 23:18:01.000000000 +0100
3332+++ cvs-1.11.19/src/update.c 2005-03-14 19:55:09.000000000 +0100
3333@@ -601,6 +601,26 @@
09f63587 3334 status = Classify_File (finfo, tag, date, options, force_tag_match,
3335 aflag, &vers, pipeout);
3336
3337+
3338+/* cvsacl patch */
3339+#ifdef SERVER_SUPPORT
3340+ if (use_cvs_acl && server_active)
3341+ {
3342+ if (!access_allowed (finfo->file, finfo->repository, vers->tag, 5,
3343+ NULL, NULL, 1))
3344+ {
3345+ if (stop_at_first_permission_denied)
3346+ error (1, 0, "permission denied for %s",
3347+ Short_Repository (finfo->repository));
3348+ else
3349+ error (0, 0, "permission denied for %s/%s",
3350+ Short_Repository (finfo->repository), finfo->file);
3351+
3352+ return (0);
3353+ }
3354+ }
3355+#endif
3356+
3357 /* Keep track of whether TAG is a branch tag.
3358 Note that if it is a branch tag in some files and a nonbranch tag
3359 in others, treat it as a nonbranch tag. It is possible that case
fe149767 3360diff -urN cvs-1.11.19.orig/src/version.c cvs-1.11.19/src/version.c
3361--- cvs-1.11.19.orig/src/version.c 2005-01-31 23:18:34.000000000 +0100
3362+++ cvs-1.11.19/src/version.c 2005-03-14 19:55:09.000000000 +0100
3363@@ -30,7 +30,8 @@
09f63587 3364 #endif
3365 #endif
3366
3367-
3368+/* cvsacl patch */
fe149767 3369+char *aclpatch_string = "with CVSACL Patch 1.2.2 (cvsacl.sourceforge.net)\n";
09f63587 3370
3371 static const char *const version_usage[] =
3372 {
fe149767 3373@@ -67,6 +68,8 @@
09f63587 3374 released. */
3375 (void) fputs (PACKAGE_STRING, stdout);
3376 (void) fputs (config_string, stdout);
3377+ /* cvsacl patch */
3378+ (void) fputs (aclpatch_string, stdout);
3379
3380 #ifdef CLIENT_SUPPORT
3381 if (current_parsed_root && current_parsed_root->isremote)
This page took 0.635754 seconds and 4 git commands to generate.