]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/contrib/cvs_acls.in
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / contrib / cvs / contrib / cvs_acls.in
1 #! @PERL@
2 # -*-Perl-*-
3 #
4 # Access control lists for CVS.  dgg@ksr.com (David G. Grubbs)
5 # Branch specific controls added by voisine@bytemobile.com (Aaron Voisine)
6 #
7 # CVS "commitinfo" for matching repository names, running the program it finds
8 # on the same line.  More information is available in the CVS man pages.
9 #
10 # ==== INSTALLATION:
11 #
12 # To use this program as I intended, do the following four things:
13 #
14 # 0. Install PERL.  :-)
15 #
16 # 1. Put one line, as the *only* non-comment line, in your commitinfo file:
17 #
18 #       DEFAULT         /usr/local/bin/cvs_acls
19 #
20 # 2. Install this file as /usr/local/bin/cvs_acls and make it executable.
21 #
22 # 3. Create a file named CVSROOT/avail and optionally add it to
23 #    CVSROOT/checkoutlist and check it in.  See the CVS manual's
24 #    administrative files section about checkoutlist.  Typically:
25 #
26 #    $ cvs checkout CVSROOT
27 #    $ cd CVSROOT
28 #    [ create the avail file ]
29 #    [ add avail to checkoutlist ]
30 #    $ cvs add avail
31 #    $ cvs commit -m 'Added avail for use with cvs_acls.' avail checkoutlist
32 #
33 # ==== FORMAT OF THE avail FILE:
34 #
35 # The avail file determines whether you may commit files.  It contains lines
36 # read from top to bottom, keeping track of a single "bit".  The "bit"
37 # defaults to "on".  It can be turned "off" by "unavail" lines and "on" by
38 # "avail" lines.  ==> Last one counts.
39 #
40 # Any line not beginning with "avail" or "unavail" is ignored.
41 #
42 # Lines beginning with "avail" or "unavail" are assumed to be '|'-separated
43 # triples: (All spaces and tabs are ignored in a line.)
44 #
45 # {avail.*,unavail.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]
46 #
47 #    1. String starting with "avail" or "unavail".
48 #    2. Optional, comma-separated list of usernames.
49 #    3. Optional, comma-separated list of repository pathnames.
50 #       These are pathnames relative to $CVSROOT.  They can be directories or
51 #       filenames.  A directory name allows access to all files and
52 #       directories below it.
53 #    4. Optional, comma-separated list of branch tags.
54 #       If not specified, all branches are assumed. Use HEAD to reference the
55 #       main branch.
56 #
57 # Example:  (Text from the ';;' rightward may not appear in the file.)
58 #
59 #       unavail                 ;; Make whole repository unavailable.
60 #       avail|dgg               ;; Except for user "dgg".
61 #       avail|fred, john|bin/ls ;; Except when "fred" or "john" commit to
62 #                               ;; the module whose repository is "bin/ls"
63 #       avail|ed|/bin/ls|stable ;; Except when "ed" commits to the "stable"
64 #                               ;; branch of the "bin/ls" repository 
65 #
66 # PROGRAM LOGIC:
67 #
68 #       CVS passes to @ARGV an absolute directory pathname (the repository
69 #       appended to your $CVSROOT variable), followed by a list of filenames
70 #       within that directory.
71 #
72 #       We walk through the avail file looking for a line that matches the
73 #       username, repository and branch.
74 #
75 #       A username match is simply the user's name appearing in the second
76 #       column of the avail line in a space-or-comma separate list.
77 #
78 #       A repository match is either:
79 #               - One element of the third column matches $ARGV[0], or some
80 #                 parent directory of $ARGV[0].
81 #               - Otherwise *all* file arguments ($ARGV[1..$#ARGV]) must be
82 #                 in the file list in one avail line.
83 #           - In other words, using directory names in the third column of
84 #             the avail file allows committing of any file (or group of
85 #             files in a single commit) in the tree below that directory.
86 #           - If individual file names are used in the third column of
87 #             the avail file, then files must be committed individually or
88 #             all files specified in a single commit must all appear in
89 #             third column of a single avail line.
90 #
91 #       A branch match is either:
92 #               - When no branches are listed in the fourth column.
93 #               - One element from the fourth column matches each of the tag
94 #                 names for $ARGV[1..$#ARGV] found in the CVS/Entries file.
95 #               - HEAD specified in the fourth column will match if there
96 #                 is no tag listed in the CVS/Entries file.
97 #
98
99 $debug = 0;
100 $cvsroot = $ENV{'CVSROOT'};
101 $availfile = $cvsroot . "/CVSROOT/avail";
102 $entries = "CVS/Entries";
103 $myname = $ENV{"USER"} if !($myname = $ENV{"LOGNAME"});
104
105 eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
106     while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
107 exit 255 if $die;               # process any variable=value switches
108
109 die "Must set CVSROOT\n" if !$cvsroot;
110 ($repos = shift) =~ s:^$cvsroot/::;
111 grep($_ = $repos . '/' . $_, @ARGV);
112
113 print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
114
115 $exit_val = 0;                          # Good Exit value
116
117 $universal_off = 0;
118
119 my %branch;
120 my $f;
121
122 open(ENTRIES, $entries) || die("Cannot open $entries.\n");
123 while(<ENTRIES>) {
124     chop;
125     next if /^\s*$/;
126     if(m|^[^/]*/([^/]*)/(?:[^/]*/)*[^/]?([^/]*)$|) {
127         $branch{$repos . '/' . $1} = ($2) ? $2 : "HEAD"; 
128         print "$$ $1/$2\n" if $debug;
129     }
130 }
131 close(ENTRIES);
132
133 open (AVAIL, $availfile) || exit(0);    # It is ok for avail file not to exist
134 while (<AVAIL>) {
135     chop;
136     next if /^\s*\#/;
137     next if /^\s*$/;
138     ($flagstr, $u, $m, $b) = split(/[\s,]*\|[\s,]*/, $_);
139
140     # Skip anything not starting with "avail" or "unavail" and complain.
141     (print "Bad avail line: $_\n"), next
142         if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/);
143
144     # Set which bit we are playing with. ('0' is OK == Available).
145     $flag = (($& eq "avail") ? 0 : 1);
146
147     # If we find a "universal off" flag (i.e. a simple "unavail") remember it
148     $universal_off = 1 if ($flag && !$u && !$m && !$b);
149
150     # $myname considered "in user list" if actually in list or is NULL
151     $in_user = (!$u || grep ($_ eq $myname, split(/[\s,]+/,$u)));
152     print "$$ \$myname($myname) in user list: $_\n" if $debug && $in_user;
153
154     # Module matches if it is a NULL module list in the avail line.  If module
155     # list is not null, we check every argument combination.
156     if (!($in_repo = !$m)) {
157         my @tmp = split(/[\s,]+/,$m);
158         for $j (@tmp) {
159             # If the repos from avail is a parent(or equal) dir of $repos, OK
160             $in_repo = 1, last if ($repos eq $j || $repos =~ /^$j\//);
161         }
162         if (!$in_repo) {
163             $in_repo = 1;
164             for $j (@ARGV) {
165                 last if !($in_repo = grep ($_ eq $j, @tmp));
166             }
167         }
168     }
169     print "$$ \$repos($repos) in repository list: $_\n" if $debug && $in_repo;
170
171     # Branch matches if it is in the branch list in the avail line, the branch
172     # list is NULL, or there is no branch and HEAD is in the branch list.
173     if(!($in_branch = !$b)) {
174         @bls = split (/[\s,]+/,$b);
175
176         for $j (@ARGV) {
177            $f = $j;
178            last if !($in_branch = grep($_ eq $branch{$j}, @bls)); 
179         }
180     }
181     print "$$ \$branch($branch{$f}) in branch list: $_\n"
182         if $debug && $in_branch;
183
184     $exit_val = $flag if ($in_user && $in_repo && $in_branch);
185     print "$$ ==== \$exit_val = $exit_val\n$$ ==== \$flag = $flag\n" if $debug;
186 }
187 close(AVAIL);
188 print "$$ ==== \$exit_val = $exit_val\n" if $debug;
189 print "**** Access denied: Insufficient Karma ($myname|$repos|$branch{$f})\n"
190         if $exit_val;
191 print "**** Access allowed: Personal Karma exceeds Environmental Karma.\n"
192         if $universal_off && !$exit_val;
193 exit($exit_val);