#!/usr/bin/perl # -*-Perl-*- # WARNING: # This file is maintained under $CVSROOT/CVSROOT/admin via CVS. # All changes to the plaintext copy on the CVS server will be lost. # # Access control lists for CVS. dgg@ksr.com (David G. Grubbs) # # CVS "commitinfo" for matching repository names, running the program it finds # on the same line. More information is available in the CVS man pages. # # PROGRAM LOGIC: # # CVS passes to @ARGV an absolute directory pathname (the repository # appended to your $CVSROOT variable), followed by a list of filenames # within that directory. # # We walk through the avail file looking for a line that matches both # the username and repository. # # A username match is simply the user's name appearing in the second # column of the avail line in a space-or-comma separate list. # # A repository match is either: # - One element of the third column matches $ARGV[0], or some # parent directory of $ARGV[0]. # - Otherwise *all* file arguments ($ARGV[1..$#ARGV]) must be # in the file list in one avail line. # - In other words, using directory names in the third column of # the avail file allows committing of any file (or group of # files in a single commit) in the tree below that directory. # - If individual file names are used in the third column of # the avail file, then files must be committed individually or # all files specified in a single commit must all appear in # third column of a single avail line. # use bytes; use Cwd 'realpath'; $debug = 0; $cvsroot = $ENV{'CVSROOT'}; $cvsroot = realpath($cvsroot); $availfile = $cvsroot . "/CVSROOT/avail"; $myname = $ENV{"USER"} if !($myname = $ENV{"LOGNAME"}); eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';" while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV)); exit 255 if $die; # process any variable=value switches die "Must set CVSROOT\n" if !$cvsroot; $repos = shift; $repos = realpath($repos); $repos =~ s|^$cvsroot/||; grep($_ = $repos . '/' . $_, @ARGV); print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug; $exit_val = 0; # Good Exit value $universal_off = 0; open (AVAIL, $availfile) || exit(0); # It is ok for avail file not to exist while () { chop; next if /^\s*\#/; next if /^\s*$/; ($flagstr, $u, $m) = split(/[\s,]*\|[\s,]*/, $_); # Handle group expansion for users while ($u =~ /\@([\w-]+)/) { my $groupname = $1; if (not defined $G{$groupname}) { my ($name, $passwd, $gid, $members) = getgrnam($groupname); if ($members) { $members =~ s| |,|g; $G{$groupname} = $members; } } if (defined $G{$groupname}) { my $expansion = $G{$groupname}; $u =~ s/\@$groupname/$expansion/; } else { warn "Group $groupname is undefined"; $u =~ s/\@$groupname//; } } # Skip anything not starting with "avail" or "unavail" and complain. (print "Bad avail line: $_\n"), next if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/); # Set which bit we are playing with. ('0' is OK == Available). $flag = (($& eq "avail") ? 0 : 1); # If we find a "universal off" flag (i.e. a simple "unavail") remember it $universal_off = 1 if ($flag && !$u && !$m); # $myname considered "in user list" if actually in list or is NULL $in_user = (!$u || grep ($_ eq $myname, split(/[\s,]+/,$u))); print "$$ \$myname($myname) in user list: $_\n" if $debug && $in_user; # Module matches if it is a NULL module list in the avail line. If module # list is not null, we check every argument combination. if (!($in_repo = !$m)) { @tmp = split(/[\s,]+/,$m); for $j (@tmp) { # If the repos from avail is a parent(or equal) dir of $repos, OK $in_repo = 1, last if ($repos eq $j || "$j/" eq substr($repos,0,length($j)+1)); } if (!$in_repo) { $in_repo = 1; for $j (@ARGV) { last if !($in_repo = grep ($_ eq $j, @tmp)); } } } print "$$ \$repos($repos) in repository list: $_\n" if $debug && $in_repo; $exit_val = $flag if ($in_user && $in_repo); print "$$ ==== \$exit_val = $exit_val\n$$ ==== \$flag = $flag\n" if $debug; } close(AVAIL); print "$$ ==== \$exit_val = $exit_val\n" if $debug; print "**** Access denied: $myname is not in ACL for $repos\n" if $exit_val; print "**** Access allowed: $myname is in ACL for $repos.\n" if !$exit_val; exit($exit_val);