summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/contrib/cvs_acls.in
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/contrib/cvs_acls.in')
-rwxr-xr-xcontrib/cvs/contrib/cvs_acls.in963
1 files changed, 0 insertions, 963 deletions
diff --git a/contrib/cvs/contrib/cvs_acls.in b/contrib/cvs/contrib/cvs_acls.in
deleted file mode 100755
index 8ee8bb3..0000000
--- a/contrib/cvs/contrib/cvs_acls.in
+++ /dev/null
@@ -1,963 +0,0 @@
-#! @PERL@ -T
-# -*-Perl-*-
-
-# Copyright (C) 1994-2005 The Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-###############################################################################
-###############################################################################
-###############################################################################
-#
-# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE
-# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE
-# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS
-# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND
-# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE
-# <@PACKAGE_BUGREPORT@> MAILING LIST.
-#
-# For more on general Perl security and taint-checking, please try running the
-# `perldoc perlsec' command.
-#
-###############################################################################
-###############################################################################
-###############################################################################
-
-=head1 Name
-
-cvs_acls - Access Control List for CVS
-
-=head1 Synopsis
-
-In 'commitinfo':
-
- repository/path/to/restrict $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER][-f <logfile>]
-
-where:
-
- -d turns on debug information
- -u passes the client-side userId to the cvs_acls script
- -f specifies an alternate filename for the restrict_log file
-
-In 'cvsacl':
-
- {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]
-
-where:
-
- allow|deny - allow: commits are allowed; deny: prohibited
- user - userId to be allowed or restricted
- repos - file or directory to be allowed or restricted
- branch - branch to be allowed or restricted
-
-See below for examples.
-
-=head1 Licensing
-
-cvs_acls - provides access control list functionality for CVS
-
-Copyright (c) 2004 by Peter Connolly <peter.connolly@cnet.com>
-All rights reserved.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-=head1 Description
-
-This script--cvs_acls--is invoked once for each directory within a
-"cvs commit". The set of files being committed for that directory as
-well as the directory itself, are passed to this script. This script
-checks its 'cvsacl' file to see if any of the files being committed
-are on the 'cvsacl' file's restricted list. If any of the files are
-restricted, then the cvs_acls script passes back an exit code of 1
-which disallows the commits for that directory.
-
-Messages are returned to the committer indicating the file(s) that
-he/she are not allowed to committ. Additionally, a site-specific
-set of messages (e.g., contact information) can be included in these
-messages.
-
-When a commit is prohibited, log messages are written to a restrict_log
-file in $CVSROOT/CVSROOT. This default file can be redirected to
-another destination.
-
-The script is triggered from the 'commitinfo' file in $CVSROOT/CVSROOT/.
-
-=head1 Enhancements
-
-This section lists the bug fixes and enhancements added to cvs_acls
-that make up the current cvs_acls.
-
-=head2 Fixed Bugs
-
-This version attempts to get rid the following bugs from the
-original version of cvs_acls:
-
-=over 2
-
-=item *
-Multiple entries on an 'cvsacl' line will be matched individually,
-instead of requiring that all commit files *exactly* match all
-'cvsacl' entries. Commiting a file not in the 'cvsacl' list would
-allow *all* files (including a restricted file) to be committed.
-
-[IMO, this basically made the original script unuseable for our
-situation since any arbitrary combination of committed files could
-avoid matching the 'cvsacl's entries.]
-
-=item *
-Handle specific filename restrictions. cvs_acls didn't restrict
-individual files specified in 'cvsacl'.
-
-=item *
-Correctly handle multiple, specific filename restrictions
-
-=item *
-Prohibit mix of dirs and files on a single 'cvsacl' line
-[To simplify the logic and because this would be normal usage.]
-
-=item *
-Correctly handle a mixture of branch restrictions within one work
-directory
-
-=item *
-$CVSROOT existence is checked too late
-
-=item *
-Correctly handle the CVSROOT=:local:/... option (useful for
-interactive testing)
-
-=item *
-Replacing shoddy "$universal_off" logic
-(Thanks to Karl-Konig Konigsson for pointing this out.)
-
-=back
-
-=head2 Enhancements
-
-=over 2
-
-=item *
-Checks modules in the 'cvsacl' file for valid files and directories
-
-=item *
-Accurately report restricted entries and their matching patterns
-
-=item *
-Simplified and commented overly complex PERL REGEXPs for readability
-and maintainability
-
-=item *
-Skip the rest of processing if a mismatch on portion of the 'cvsacl' line
-
-=item *
-Get rid of opaque "karma" messages in favor of user-friendly messages
-that describe which user, file(s) and branch(es) were disallowed.
-
-=item *
-Add optional 'restrict_msg' file for additional, site-specific
-restriction messages.
-
-=item *
-Take a "-u" parameter for $USER from commit_prep so that the script
-can do restrictions based on the client-side userId rather than the
-server-side userId (usually 'cvs').
-
-(See discussion below on "Admin Setup" for more on this point.)
-
-=item *
-Added a lot more debug trace
-
-=item *
-Tested these restrictions with concurrent use of pserver and SSH
-access to model our transition from pserver to ext access.
-
-=item *
-Added logging of restricted commit attempts.
-Restricted commits can be sent to a default file:
-$CVSROOT/CVSROOT/restrictlog or to one passed to the script
-via the -f command parameter.
-
-=back
-
-=head2 ToDoS
-
-=over 2
-
-=item *
-Need to deal with pserver/SSH transition with conflicting umasks?
-
-=item *
-Use a CPAN module to handle command parameters.
-
-=item *
-Use a CPAN module to clone data structures.
-
-=back
-
-=head1 Version Information
-
-This is not offered as a fix to the original 'cvs_acls' script since it
-differs substantially in goals and methods from the original and there
-are probably a significant number of people out there that still require
-the original version's functionality.
-
-The 'cvsacl' file flags of 'allow' and 'deny' were intentionally
-changed to 'allow' and 'deny' because there are enough differences
-between the original script's behavior and this one's that we wanted to
-make sure that users will rethink their 'cvsacl' file formats before
-plugging in this newer script.
-
-Please note that there has been very limited cross-platform testing of
-this script!!! (We did not have the time or resources to do exhaustive
-cross-platform testing.)
-
-It was developed and tested under Red Hat Linux 9.0 using PERL 5.8.0.
-Additionally, it was built and tested under Red Hat Linux 7.3 using
-PERL 5.6.1.
-
-$Id: cvs_acls.in,v 1.4.4.6 2005/09/01 13:44:49 dprice Exp $
-
-This version is based on the 1.11.13 version of cvs_acls
-peter.connolly@cnet.com (Peter Connolly)
-
- Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
- Branch specific controls added by voisine@bytemobile.com (Aaron Voisine)
-
-=head1 Installation
-
-To use this program, do the following four things:
-
-0. Install PERL, version 5.6.1 or 5.8.0.
-
-1. Admin Setup:
-
- There are two choices here.
-
- a) The first option is to use the $ENV{"USER"}, server-side userId
- (from the third column of your pserver 'passwd' file) as the basis for
- your restrictions. In this case, you will (at a minimum) want to set
- up a new "cvsadmin" userId and group on the pserver machine.
- CVS administrators will then set up their 'passwd' file entries to
- run either as "cvs" (for regular users) or as "cvsadmin" (for power
- users). Correspondingly, your 'cvsacl' file will only list 'cvs'
- and 'cvsadmin' as the userIds in the second column.
-
- Commentary: A potential weakness of this is that the xinetd
- cvspserver process will need to run as 'root' in order to switch
- between the 'cvs' and the 'cvsadmin' userIds. Some sysadmins don't
- like situations like this and may want to chroot the process.
- Talk to them about this point...
-
- b) The second option is to use the client-side userId as the basis for
- your restrictions. In this case, all the xinetd cvspserver processes
- can run as userId 'cvs' and no 'root' userId is required. If you have
- a 'passwd' file that lists 'cvs' as the effective run-time userId for
- all your users, then no changes to this file are needed. Your 'cvsacl'
- file will use the individual, client-side userIds in its 2nd column.
-
- As long as the userIds in pserver's 'passwd' file match those userIds
- that your Linux server know about, this approach is ideal if you are
- planning to move from pserver to SSH access at some later point in time.
- Just by switching the CVSROOT var from CVSROOT=:pserver:<userId>... to
- CVSROOT=:ext:<userId>..., users can switch over to SSH access without
- any other administrative changes. When all users have switched over to
- SSH, the inherently insecure xinetd cvspserver process can be disabled.
- [http://ximbiot.com/cvs/manual/cvs-1.11.17/cvs_2.html#SEC32]
-
- :TODO: The only potential glitch with the SSH approach is the possibility
- that each user can have differing umasks that might interfere with one
- another, especially during a transition from pserver to SSH. As noted
- in the ToDo section, this needs a good strategy and set of tests for that
- yet...
-
-2. Put two lines, as the *only* non-comment lines, in your commitinfo file:
-
- ALL $CVSROOT/CVSROOT/commit_prep
- ALL $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER ][-f <logfilename>]
-
- where "-d" turns on debug trace
- "-u $USER" passes the client-side userId to cvs_acls
- "-f <logfilename"> overrides the default filename used to log
- restricted commit attempts.
-
- (These are handled in the processArgs() subroutine.)
-
-If you are using client-side userIds to restrict access to your
-repository, make sure that they are in this order since the commit_prep
-script is required in order to pass the $USER parameter.
-
-A final note about the repository matching pattern. The example above
-uses "ALL" but note that this means that the cvs_acls script will run
-for each and every commit in your repository. Obviously, in a large
-repository this adds up to a lot of overhead that may not be necesary.
-A better strategy is to use a repository pattern that is more specific
-to the areas that you wish to secure.
-
-3. Install this file as $CVSROOT/CVSROOT/cvs_acls and make it executable.
-
-4. Create a file named CVSROOT/cvsacl and optionally add it to
- CVSROOT/checkoutlist and check it in. See the CVS manual's
- administrative files section about checkoutlist. Typically:
-
- $ cvs checkout CVSROOT
- $ cd CVSROOT
- [ create the cvsacl file, include 'commitinfo' line ]
- [ add cvsacl to checkoutlist ]
- $ cvs add cvsacl
- $ cvs commit -m 'Added cvsacl for use with cvs_acls.' cvsacl checkoutlist
-
-Note: The format of the 'cvsacl' file is described in detail immediately
-below but here is an important set up point:
-
- Make sure to include a line like the following:
-
- deny||CVSROOT/commitinfo CVSROOT/cvsacl
- allow|cvsadmin|CVSROOT/commitinfo CVSROOT/cvsacl
-
- that restricts access to commitinfo and cvsacl since this would be one of
- the easiest "end runs" around this ACL approach. ('commitinfo' has the
- line that executes the cvs_acls script and, of course, all the
- restrictions are in 'cvsacl'.)
-
-5. (Optional) Create a 'restrict_msg' file in the $CVSROOT/CVSROOT directory.
- Whenever there is a restricted file or dir message, cvs_acls will look
- for this file and, if it exists, print its contents as part of the
- commit-denial message. This gives you a chance to print any site-specific
- information (e.g., who to call, what procedures to look up,...) whenever
- a commit is denied.
-
-=head1 Format of the cvsacl file
-
-The 'cvsacl' file determines whether you may commit files. It contains lines
-read from top to bottom, keeping track of whether a given user, repository
-and branch combination is "allowed" or "denied." The script will assume
-"allowed" on all repository paths until 'allow' and 'deny' rules change
-that default.
-
-The normal pattern is to specify an 'deny' rule to turn off
-access to ALL users, then follow it with a matching 'allow' rule that will
-turn on access for a select set of users. In the case of multiple rules for
-the same user, repository and branch, the last one takes precedence.
-
-Blank lines and lines with only comments are ignored. Any other lines not
-beginning with "allow" or "deny" are logged to the restrict_log file.
-
-Lines beginning with "allow" or "deny" are assumed to be '|'-separated
-triples: (All spaces and tabs are ignored in a line.)
-
- {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]
-
- 1. String starting with "allow" or "deny".
- 2. Optional, comma-separated list of usernames.
- 3. Optional, comma-separated list of repository pathnames.
- These are pathnames relative to $CVSROOT. They can be directories or
- filenames. A directory name allows or restricts access to all files and
- directories below it. One line can have either directories or filenames
- but not both.
- 4. Optional, comma-separated list of branch tags.
- If not specified, all branches are assumed. Use HEAD to reference the
- main branch.
-
-Example: (Note: No in-line comments.)
-
- # ----- Make whole repository unavailable.
- deny
-
- # ----- Except for user "dgg".
- allow|dgg
-
- # ----- Except when "fred" or "john" commit to the
- # module whose repository is "bin/ls"
- allow|fred, john|bin/ls
-
- # ----- Except when "ed" commits to the "stable"
- # branch of the "bin/ls" repository
- allow|ed|/bin/ls|stable
-
-=head1 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 that are to be committed.
-
-The script walks through the 'cvsacl' file looking for matches on
-the username, repository and branch.
-
-A username match is simply the user's name appearing in the second
-column of the cvsacl line in a space-or-comma separate list. If
-blank, then any user will match.
-
-A repository match:
-
-=over 2
-
-=item *
-Each entry in the modules section of the current 'cvsacl' line is
-examined to see if it is a dir or a file. The line must have
-either files or dirs, but not both. (To simplify the logic.)
-
-=item *
-If neither, then assume the 'cvsacl' file was set up in error and
-skip that 'allow' line.
-
-=item *
-If a dir, then each dir pattern is matched separately against the
-beginning of each of the committed files in @ARGV.
-
-=item *
-If a file, then each file pattern is matched exactly against each
-of the files to be committed in @ARGV.
-
-=item *
-Repository and branch must BOTH match together. This is to cover
-the use case where a user has multiple branches checked out in
-a single work directory. Commit files can be from different
-branches.
-
-A branch match is either:
-
-=over 4
-
-=item *
-When no branches are listed in the fourth column. ("Match any.")
-
-=item *
-All elements from the fourth column are matched against each of
-the tag names for $ARGV[1..$#ARGV] found in the %branches file.
-
-=back
-
-=item *
-'allow' match remove that match from the tally map.
-
-=item *
-Restricted ('deny') matches are saved in the %repository_matches
-table.
-
-=item *
-If there is a match on user, repository and branch:
-
- If repository, branch and user match
- if 'deny'
- add %repository_matches entries to %restricted_entries
- else if 'allow'
- remove %repository_matches entries from %restricted_entries
-
-=item *
-At the end of all the 'cvsacl' line checks, check to see if there
-are any entries in the %restricted_entries. If so, then deny the
-commit.
-
-=back
-
-=head2 Pseudocode
-
- read CVS/Entries file and create branch{file}->{branch} hash table
- + for each 'allow' and 'deny' line in the 'cvsacl' file:
- | user match?
- | - Yes: set $user_match = 1;
- | repository and branch match?
- | - Yes: add to %repository_matches;
- | did user, repository match?
- | - Yes: if 'deny' then
- | add %repository_matches -> %restricted_entries
- | if 'allow' then
- | remove %repository_matches <- %restricted_entries
- + end for loop
- any saved restrictions?
- no: exit,
- set exit code allowing commits and exit
- yes: report restrictions,
- set exit code prohibiting commits and exit
-
-=head2 Sanity Check
-
- 1) file allow trumps a dir deny
- deny||java/lib
- allow||java/lib/README
- 2) dir allow can undo a file deny
- deny||java/lib/README
- allow||java/lib
- 3) file deny trumps a dir allow
- allow||java/lib
- deny||java/lib/README
- 4) dir deny trumps a file allow
- allow||java/lib/README
- deny||java/lib
- ... so last match always takes precedence
-
-=cut
-
-$debug = 0; # Set to 1 for debug messages
-
-%repository_matches = (); # hash of match file and pattern from 'cvsacl'
- # repository_matches --> [branch, matching-pattern]
- # (Used during module/branch matching loop)
-
-%restricted_entries = (); # hash table of restricted commit files (from @ARGV)
- # restricted_entries --> branch
- # (If user/module/branch all match on an 'deny'
- # line, then entries added to this map.)
-
-%branch; # hash table of key: commit file; value: branch
- # Built from ".../CVS/Entries" file of directory
- # currently being examined
-
-# ---------------------------------------------------------------- get CVSROOT
-$cvsroot = $ENV{'CVSROOT'};
-die "Must set CVSROOT\n" if !$cvsroot;
-if ($cvsroot =~ /:([\/\w]*)$/) { # Filter ":pserver:", ":local:"-type prefixes
- $cvsroot = $1;
-}
-
-# ------------------------------------------------------------- set file paths
-$entries = "CVS/Entries"; # client-side file???
-$cvsaclfile = $cvsroot . "/CVSROOT/cvsacl";
-$restrictfile = $cvsroot . "/CVSROOT/restrict_msg";
-$restrictlog = $cvsroot . "/CVSROOT/restrict_log";
-
-# --------------------------------------------------------------- process args
-$user_name = processArgs(\@ARGV);
-
-print("$$ \@ARGV after processArgs is: @ARGV.\n") if $debug;
-print("$$ ========== Begin $PROGRAM_NAME for \"$ARGV[0]\" repository. ========== \n") if $debug;
-
-# --------------------------------------------------------------- filter @ARGV
-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
-
-print("$$ \@ARGV after shift processing contains:",join("\, ",@ARGV),".\n") if $debug;
-
-# ---------------------------------------------------------------- get cvsroot
-($repository = shift) =~ s:^$cvsroot/::;
-grep($_ = $repository . '/' . $_, @ARGV);
-
-print("$$ \$cvsroot is: $cvsroot.\n") if $debug;
-print "$$ Repos: $repository\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
-
-$exit_val = 0; # presume good exit value for commit
-
-# ----------------------------------------------------------------------------
-# ---------------------------------- create hash table $branch{file -> branch}
-# ----------------------------------------------------------------------------
-
-# Here's a typical Entries file:
-#
-# /checkoutlist/1.4/Wed Feb 4 23:51:23 2004//
-# /cvsacl/1.3/Tue Feb 24 23:05:43 2004//
-# ...
-# /verifymsg/1.1/Fri Mar 16 19:56:24 2001//
-# D/backup////
-# D/temp////
-
-open(ENTRIES, $entries) || die("Cannot open $entries.\n");
-print("$$ File / Branch\n") if $debug;
-my $i = 0;
-while(<ENTRIES>) {
- chop;
- next if /^\s*$/; # Skip blank lines
- $i = $i + 1;
- if (m|
- / # 1st slash
- ([\w.-]*) # file name -> $1
- / # 2nd slash
- .* # revision number
- / # 3rd slash
- .* # date and time
- / # 4th slash
- .* # keyword
- / # 5th slash
- T? # 'T' constant
- (\w*) # branch -> #2
- |x) {
- $branch{$repository . '/' . $1} = ($2) ? $2 : "HEAD";
- print "$$ CVS Entry $i: $1/$2\n" if $debug;
- }
-}
-close(ENTRIES);
-
-# ----------------------------------------------------------------------------
-# ------------------------------------- evaluate each active line from 'cvsacl'
-# ----------------------------------------------------------------------------
-open (CVSACL, $cvsaclfile) || exit(0); # It is ok for cvsacl file not to exist
-while (<CVSACL>) {
- chop;
- next if /^\s*\#/; # skip comments
- next if /^\s*$/; # skip blank lines
- # --------------------------------------------- parse current 'cvsacl' line
- print("$$ ==========\n$$ Processing \'cvsacl\' line: $_.\n") if $debug;
- ($cvsacl_flag, $cvsacl_userIds, $cvsacl_modules, $cvsacl_branches) = split(/[\s,]*\|[\s,]*/, $_);
-
- # ------------------------------ Validate 'allow' or 'deny' line prefix
- if ($cvsacl_flag !~ /^allow/ && $cvsacl_flag !~ /^deny/) {
- print ("Bad cvsacl line: $_\n") if $debug;
- $log_text = sprintf "Bad cvsacl line: %s", $_;
- write_restrictlog_record($log_text);
- next;
- }
-
- # -------------------------------------------------- init loop match flags
- $user_match = 0;
- %repository_matches = ();
-
- # ------------------------------------------------------------------------
- # ---------------------------------------------------------- user matching
- # ------------------------------------------------------------------------
- # $user_name considered "in user list" if actually in list or is NULL
- $user_match = (!$cvsacl_userIds || grep ($_ eq $user_name, split(/[\s,]+/,$cvsacl_userIds)));
- print "$$ \$user_name: $user_name \$user_match match flag is: $user_match.\n" if $debug;
- if (!$user_match) {
- next; # no match, skip to next 'cvsacl' line
- }
-
- # ------------------------------------------------------------------------
- # ---------------------------------------------------- repository matching
- # ------------------------------------------------------------------------
- if (!$cvsacl_modules) { # blank module list = all modules
- if (!$cvsacl_branches) { # blank branch list = all branches
- print("$$ Adding all modules to \%repository_matches; null " .
- "\$cvsacl_modules and \$cvsacl_branches.\n") if $debug;
- for $commit_object (@ARGV) {
- $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_modules];
- print("$$ \$repository_matches{$commit_object} = " .
- "[$branch{$commit_object}, $cvsacl_modules].\n") if $debug;
- }
- }
- else { # need to check for repository match
- @branch_list = split (/[\s,]+/,$cvsacl_branches);
- print("$$ Branches from \'cvsacl\' record: ", join(", ",@branch_list),".\n") if $debug;
- for $commit_object (@ARGV) {
- if (grep($branch{$commit_object}, @branch_list)) {
- $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_modules];
- print("$$ \$repository_matches{$commit_object} = " .
- "[$branch{$commit_object}, $cvsacl_modules].\n") if $debug;
- }
- }
- }
- }
- else {
- # ----------------------------------- check every argument combination
- # parse 'cvsacl' modules to array
- my @module_list = split(/[\s,]+/,$cvsacl_modules);
- # ------------- Check all modules in list for either file or directory
- my $fileType = "";
- if (($fileType = checkFileness(@module_list)) eq "") {
- next; # skip bad file types
- }
- # ---------- Check each combination of 'cvsacl' modules vs. @ARGV files
- print("$$ Checking matches for \@module_list: ", join("\, ",@module_list), ".\n") if $debug;
- # loop thru all command-line commit objects
- for $commit_object (@ARGV) {
- # loop thru all modules on 'cvsacl' line
- for $cvsacl_module (@module_list) {
- print("$$ Is \'cvsacl\': $cvsacl_modules pattern in: \@ARGV " .
- "\$commit_object: $commit_object?\n") if $debug;
- # Do match of beginning of $commit_object
- checkModuleMatch($fileType, $commit_object, $cvsacl_module);
- } # end for commit objects
- } # end for cvsacl modules
- } # end if
-
- print("$$ Matches for: \%repository_matches: ", join("\, ", (keys %repository_matches)), ".\n") if $debug;
-
- # ------------------------------------------------------------------------
- # ----------------------------------------------------- setting exit value
- # ------------------------------------------------------------------------
- if ($user_match && %repository_matches) {
- print("$$ An \"$cvsacl_flag\" match on User(s): $cvsacl_userIds; Module(s):" .
- " $cvsacl_modules; Branch(es): $cvsacl_branches.\n") if $debug;
- if ($cvsacl_flag eq "deny") {
- # Add all matches to the hash of restricted modules
- foreach $commitFile (keys %repository_matches) {
- print("$$ Adding \%repository_matches entry: $commitFile.\n") if $debug;
- $restricted_entries{$commitFile} = $repository_matches{$commitFile}[0];
- }
- }
- else {
- # Remove all matches from the restricted modules hash
- foreach $commitFile (keys %repository_matches) {
- print("$$ Removing \%repository_matches entry: $commitFile.\n") if $debug;
- delete $restricted_entries{$commitFile};
- }
- }
- }
- print "$$ ==== End of processing for \'cvsacl\' line: $_.\n" if $debug;
-}
-close(CVSACL);
-
-# ----------------------------------------------------------------------------
-# --------------------------------------- determine final 'commit' disposition
-# ----------------------------------------------------------------------------
-if (%restricted_entries) { # any restricted entries?
- $exit_val = 1; # don't commit
- print("**** Access denied: Insufficient authority for user: '$user_name\' " .
- "to commit to \'$repository\'.\n**** Contact CVS Administrators if " .
- "you require update access to these directories or files.\n");
- print("**** file(s)/dir(s) restricted were:\n\t", join("\n\t",keys %restricted_entries), "\n");
- printOptionalRestrictionMessage();
- write_restrictlog();
-}
-elsif (!$exit_val && $debug) {
- print "**** Access allowed: Sufficient authority for commit.\n";
-}
-
-print "$$ ==== \$exit_val = $exit_val\n" if $debug;
-exit($exit_val);
-
-# ----------------------------------------------------------------------------
-# -------------------------------------------------------------- end of "main"
-# ----------------------------------------------------------------------------
-
-
-# ----------------------------------------------------------------------------
-# -------------------------------------------------------- process script args
-# ----------------------------------------------------------------------------
-sub processArgs {
-
-# This subroutine is passed a reference to @ARGV.
-
-# If @ARGV contains a "-u" entry, use that as the effective userId. In this
-# case, the userId is the client-side userId that has been passed to this
-# script by the commit_prep script. (This is why the commit_prep script must
-# be placed *before* the cvs_acls script in the commitinfo admin file.)
-
-# Otherwise, pull the userId from the server-side environment.
-
- my $userId = "";
- my ($argv) = shift; # pick up ref to @ARGV
- my @argvClone = (); # immutable copy for foreach loop
- for ($i=0; $i<(scalar @{$argv}); $i++) {
- $argvClone[$i]=$argv->[$i];
- }
-
- print("$$ \@_ to processArgs is: @_.\n") if $debug;
-
- # Parse command line arguments (file list is seen as one arg)
- foreach $arg (@argvClone) {
- print("$$ \$arg for processArgs loop is: $arg.\n") if $debug;
- # Set $debug flag?
- if ($arg eq '-d') {
- shift @ARGV;
- $debug = 1;
- print("$$ \$debug flag set on.\n") if $debug;
- print STDERR "Debug turned on...\n";
- }
- # Passing in a client-side userId?
- elsif ($arg eq '-u') {
- shift @ARGV;
- $userId = shift @ARGV;
- print("$$ client-side \$userId set to: $userId.\n") if $debug;
- }
- # An override for the default restrictlog file?
- elsif ($arg eq '-f') {
- shift @ARGV;
- $restrictlog = shift @ARGV;
- }
- else {
- next;
- }
- }
-
- # No client-side userId passed? then get from server env
- if (!$userId) {
- $userId = $ENV{"USER"} if !($userId = $ENV{"LOGNAME"});
- print("$$ server-side \$userId set to: $userId.\n") if $debug;
- }
-
- print("$$ processArgs returning \$userId: $userId.\n") if $debug;
- return $userId;
-
-}
-
-
-# ----------------------------------------------------------------------------
-# --------------------- Check all modules in list for either file or directory
-# ----------------------------------------------------------------------------
-sub checkFileness {
-
-# Module patterns on the 'cvsacl' record can be files or directories.
-# If it's a directory, we pattern-match the directory name from 'cvsacl'
-# against the left side of the committed filename to see if the file is in
-# that hierarchy. By contrast, files use an explicit match. If the entries
-# are neither files nor directories, then the cvsacl file has been set up
-# incorrectly; we return a "" and the caller skips that line as invalid.
-#
-# This function determines whether the entries on the 'cvsacl' record are all
-# directories or all files; it cannot be a mixture. This restriction put in
-# to simplify the logic (without taking away much functionality).
-
- my @module_list = @_;
- print("$$ Checking \"fileness\" or \"dir-ness\" for \@module_list entries.\n") if $debug;
- print("$$ Entries are: ", join("\, ",@module_list), ".\n") if $debug;
- my $filetype = "";
- for $cvsacl_module (@module_list) {
- my $reposDirName = $cvsroot . '/' . $cvsacl_module;
- my $reposFileName = $reposDirName . "\,v";
- print("$$ In checkFileness: \$reposDirName: $reposDirName; \$reposFileName: $reposFileName.\n") if $debug;
- if (((-d $reposDirName) && ($filetype eq "file")) || ((-f $reposFileName) && ($filetype eq "dir"))) {
- print("Can\'t mix files and directories on single \'cvsacl\' file record; skipping entry.\n");
- print(" Please contact a CVS administrator.\n");
- $filetype = "";
- last;
- }
- elsif (-d $reposDirName) {
- $filetype = "dir";
- print("$$ $reposDirName is a directory.\n") if $debug;
- }
- elsif (-f $reposFileName) {
- $filetype = "file";
- print("$$ $reposFileName is a regular file.\n") if $debug;
- }
- else {
- print("***** Item to commit was neither a regular file nor a directory.\n");
- print("***** Current \'cvsacl\' line ignored.\n");
- print("***** Possible problem with \'cvsacl\' admin file. Please contact a CVS administrator.\n");
- $filetype = "";
- $text = sprintf("Module entry on cvsacl line: %s is not a valid file or directory.\n", $cvsacl_module);
- write_restrictlog_record($text);
- last;
- } # end if
- } # end for
-
- print("$$ checkFileness will return \$filetype: $filetype.\n") if $debug;
- return $filetype;
-}
-
-
-# ----------------------------------------------------------------------------
-# ----------------------------------------------------- check for module match
-# ----------------------------------------------------------------------------
-sub checkModuleMatch {
-
-# This subroutine checks for a match between the directory or file pattern
-# specified in the 'cvsacl' file (i.e., $cvsacl_modules) versus the commit file
-# objects passed into the script via @ARGV (i.e., $commit_object).
-
-# The directory pattern only has to match the beginning portion of the commit
-# file's name for a match since all files under that directory are considered
-# a match. File patterns must exactly match.
-
-# Since (theoretically, if not normally in practice) a working directory can
-# contain a mixture of files from different branches, this routine checks to
-# see if there is also a match on branch before considering the file
-# comparison a match.
-
- my $match_flag = "";
-
- print("$$ \@_ in checkModuleMatch is: @_.\n") if $debug;
- my ($type,$commit_object,$cvsacl_module) = @_;
-
- if ($type eq "file") { # Do exact file match of $commit_object
- if ($commit_object eq $cvsacl_module) {
- $match_flag = "file";
- } # Do dir match at beginning of $commit_object
- }
- elsif ($commit_object =~ /^$cvsacl_module\//) {
- $match_flag = "dir";
- }
-
- if ($match_flag) {
- print("$$ \$repository: $repository matches \$commit_object: $commit_object.\n") if $debug;
- if (!$cvsacl_branches) { # empty branch pattern matches all
- print("$$ blank \'cvsacl\' branch matches all commit files.\n") if $debug;
- $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_module];
- print("$$ \$repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_module].\n") if $debug;
- }
- else { # otherwise check branch hash table
- @branch_list = split (/[\s,]+/,$cvsacl_branches);
- print("$$ Branches from \'cvsacl\' record: ", join(", ",@branch_list),".\n") if $debug;
- if (grep(/$branch{$commit_object}/, @branch_list)) {
- $repository_matches{$commit_object} = [$branch{$commit_object}, $cvsacl_module];
- print("$$ \$repository_matches{$commit_object} = [$branch{$commit_object}, " .
- "$cvsacl_module].\n") if $debug;
- }
- }
- }
-
-}
-
-# ----------------------------------------------------------------------------
-# ------------------------------------------------------- check for file match
-# ----------------------------------------------------------------------------
-sub printOptionalRestrictionMessage {
-
-# This subroutine optionally prints site-specific file restriction information
-# whenever a restriction condition is met. If the file 'restrict_msg' does
-# not exist, the routine immediately exits. If there is a 'restrict_msg' file
-# then all the contents are printed at the end of the standard restriction
-# message.
-
-# As seen from examining the definition of $restrictfile, the default filename
-# is: $CVSROOT/CVSROOT/restrict_msg.
-
- open (RESTRICT, $restrictfile) || return; # It is ok for cvsacl file not to exist
- while (<RESTRICT>) {
- chop;
- # print out each line
- print("**** $_\n");
- }
-
-}
-
-# ----------------------------------------------------------------------------
-# ---------------------------------------------------------- write log message
-# ----------------------------------------------------------------------------
-sub write_restrictlog {
-
-# This subroutine iterates through the list of restricted entries and logs
-# each one to the error logfile.
-
- # write each line in @text out separately
- foreach $commitfile (keys %restricted_entries) {
- $log_text = sprintf "Commit attempt by: %s for: %s on branch: %s",
- $user_name, $commitfile, $branch{$commitfile};
- write_restrictlog_record($log_text);
- }
-
-}
-
-# ----------------------------------------------------------------------------
-# ---------------------------------------------------------- write log message
-# ----------------------------------------------------------------------------
-sub write_restrictlog_record {
-
-# This subroutine receives a scalar string and writes it out to the
-# $restrictlog file as a separate line. Each line is prepended with the date
-# and time in the format: "2004/01/30 12:00:00 ".
-
- $text = shift;
-
- # return quietly if there is a problem opening the log file.
- open(FILE, ">>$restrictlog") || return;
-
- (@time) = localtime();
-
- # write each line in @text out separately
- $log_record = sprintf "%04d/%02d/%02d %02d:%02d:%02d %s.\n",
- $time[5]+1900, $time[4]+1, $time[3], $time[2], $time[1], $time[0], $text;
- print FILE $log_record;
- print("$$ restrict_log record being written: $log_record to $restrictlog.\n") if $debug;
-
- close(FILE);
-}
OpenPOWER on IntegriCloud