/contrib/cvs/contrib/cvs_acls.html
https://bitbucket.org/freebsd/freebsd-head/ · HTML · 459 lines · 445 code · 12 blank · 2 comment · 0 complexity · 01250b4aac16784679d3ff4547ff766d MD5 · raw file
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title>cvs_acls</title>
- <link rev="made" href="mailto:root@localhost" />
- </head>
- <body style="background-color: white">
- <p><a name="__index__"></a></p>
- <!-- INDEX BEGIN -->
- <ul>
- <li><a href="#name">Name</a></li>
- <li><a href="#synopsis">Synopsis</a></li>
- <li><a href="#licensing">Licensing</a></li>
- <li><a href="#description">Description</a></li>
- <li><a href="#enhancements">Enhancements</a></li>
- <ul>
- <li><a href="#fixed_bugs">Fixed Bugs</a></li>
- <li><a href="#enhancements">Enhancements</a></li>
- <li><a href="#todos">ToDoS</a></li>
- </ul>
- <li><a href="#version_information">Version Information</a></li>
- <li><a href="#installation">Installation</a></li>
- <li><a href="#format_of_the_cvsacl_file">Format of the cvsacl file</a></li>
- <li><a href="#program_logic">Program Logic</a></li>
- <ul>
- <li><a href="#pseudocode">Pseudocode</a></li>
- <li><a href="#sanity_check">Sanity Check</a></li>
- </ul>
- </ul>
- <!-- INDEX END -->
- <hr />
- <p>
- </p>
- <h1><a name="name">Name</a></h1>
- <p>cvs_acls - Access Control List for CVS</p>
- <p>
- </p>
- <hr />
- <h1><a name="synopsis">Synopsis</a></h1>
- <p>In 'commitinfo':</p>
- <pre>
- repository/path/to/restrict $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER][-f <logfile>]</pre>
- <p>where:</p>
- <pre>
- -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</pre>
- <p>In 'cvsacl':</p>
- <pre>
- {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]</pre>
- <p>where:</p>
- <pre>
- 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</pre>
- <p>See below for examples.</p>
- <p>
- </p>
- <hr />
- <h1><a name="licensing">Licensing</a></h1>
- <p>cvs_acls - provides access control list functionality for CVS
- </p>
- <pre>
- Copyright (c) 2004 by Peter Connolly <peter.connolly@cnet.com>
- All rights reserved.</pre>
- <p>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.</p>
- <p>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.</p>
- <p>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</p>
- <p>
- </p>
- <hr />
- <h1><a name="description">Description</a></h1>
- <p>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.</p>
- <p>Messages are returned to the committer indicating the <a href="#item_file"><code>file(s)</code></a> 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.</p>
- <p>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.</p>
- <p>The script is triggered from the 'commitinfo' file in $CVSROOT/CVSROOT/.</p>
- <p>
- </p>
- <hr />
- <h1><a name="enhancements">Enhancements</a></h1>
- <p>This section lists the bug fixes and enhancements added to cvs_acls
- that make up the current cvs_acls.</p>
- <p>
- </p>
- <h2><a name="fixed_bugs">Fixed Bugs</a></h2>
- <p>This version attempts to get rid the following bugs from the
- original version of cvs_acls:</p>
- <ul>
- <li><strong><a name="item_files">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.</a></strong><br />
- </li>
- [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.]
- <p></p>
- <li><strong><a name="item_handle_specific_filename_restrictions_2e_cvs_acls_">Handle specific filename restrictions. cvs_acls didn't restrict
- individual files specified in 'cvsacl'.</a></strong><br />
- </li>
- <li><strong><a name="item_correctly_handle_multiple_2c_specific_filename_res">Correctly handle multiple, specific filename restrictions</a></strong><br />
- </li>
- <li><strong><a name="item_prohibit_mix_of_dirs_and_files_on_a_single__27cvsa">Prohibit mix of dirs and files on a single 'cvsacl' line
- [To simplify the logic and because this would be normal usage.]</a></strong><br />
- </li>
- <li><strong><a name="item_correctly_handle_a_mixture_of_branch_restrictions_">Correctly handle a mixture of branch restrictions within one work
- directory</a></strong><br />
- </li>
- <li><strong><a name="item__24cvsroot_existence_is_checked_too_late">$CVSROOT existence is checked too late</a></strong><br />
- </li>
- <li><strong><a name="item_option">Correctly handle the CVSROOT=:local:/... option (useful for
- interactive testing)</a></strong><br />
- </li>
- <li><strong><a name="item_logic">Replacing shoddy ``$universal_off'' logic
- (Thanks to Karl-Konig Konigsson for pointing this out.)</a></strong><br />
- </li>
- </ul>
- <p>
- </p>
- <h2><a name="enhancements">Enhancements</a></h2>
- <ul>
- <li><strong><a name="item_checks_modules_in_the__27cvsacl_27_file_for_valid_">Checks modules in the 'cvsacl' file for valid files and directories</a></strong><br />
- </li>
- <li><strong><a name="item_accurately_report_restricted_entries_and_their_mat">Accurately report restricted entries and their matching patterns</a></strong><br />
- </li>
- <li><strong><a name="item_simplified_and_commented_overly_complex_perl_regex">Simplified and commented overly complex PERL REGEXPs for readability
- and maintainability</a></strong><br />
- </li>
- <li><strong><a name="item_skip_the_rest_of_processing_if_a_mismatch_on_porti">Skip the rest of processing if a mismatch on portion of the 'cvsacl' line</a></strong><br />
- </li>
- <li><strong><a name="item_file">Get rid of opaque ``karma'' messages in favor of user-friendly messages
- that describe which user, <code>file(s)</code> and <code>branch(es)</code> were disallowed.</a></strong><br />
- </li>
- <li><strong><a name="item_add_optional__27restrict_msg_27_file_for_additiona">Add optional 'restrict_msg' file for additional, site-specific
- restriction messages.</a></strong><br />
- </li>
- <li><strong><a name="item_userid">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').</a></strong><br />
- </li>
- (See discussion below on ``Admin Setup'' for more on this point.)
- <p></p>
- <li><strong><a name="item_added_a_lot_more_debug_trace">Added a lot more debug trace</a></strong><br />
- </li>
- <li><strong><a name="item_tested_these_restrictions_with_concurrent_use_of_p">Tested these restrictions with concurrent use of pserver and SSH
- access to model our transition from pserver to ext access.</a></strong><br />
- </li>
- <li><strong><a name="item_added_logging_of_restricted_commit_attempts_2e_res">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.</a></strong><br />
- </li>
- </ul>
- <p>
- </p>
- <h2><a name="todos">ToDoS</a></h2>
- <ul>
- <li><strong><a name="item_need_to_deal_with_pserver_2fssh_transition_with_co">Need to deal with pserver/SSH transition with conflicting umasks?</a></strong><br />
- </li>
- <li><strong><a name="item_use_a_cpan_module_to_handle_command_parameters_2e">Use a CPAN module to handle command parameters.</a></strong><br />
- </li>
- <li><strong><a name="item_use_a_cpan_module_to_clone_data_structures_2e">Use a CPAN module to clone data structures.</a></strong><br />
- </li>
- </ul>
- <p>
- </p>
- <hr />
- <h1><a name="version_information">Version Information</a></h1>
- <p>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.</p>
- <p>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.</p>
- <p>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.)</p>
- <p>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.</p>
- <p>$Id: cvs_acls.html,v 1.1.2.2 2005/09/01 13:44:49 dprice Exp $</p>
- <p>This version is based on the 1.11.13 version of cvs_acls
- <a href="mailto:peter.connolly@cnet.com">peter.connolly@cnet.com</a> (Peter Connolly)</p>
- <pre>
- Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
- Branch specific controls added by voisine@bytemobile.com (Aaron Voisine)</pre>
- <p>
- </p>
- <hr />
- <h1><a name="installation">Installation</a></h1>
- <p>To use this program, do the following four things:</p>
- <p>0. Install PERL, version 5.6.1 or 5.8.0.</p>
- <p>1. Admin Setup:</p>
- <pre>
- There are two choices here.</pre>
- <pre>
- 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.</pre>
- <pre>
- 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...</pre>
- <pre>
- 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.</pre>
- <pre>
- 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.
- [<a href="http://ximbiot.com/cvs/manual/cvs-1.11.17/cvs_2.html#SEC32">http://ximbiot.com/cvs/manual/cvs-1.11.17/cvs_2.html#SEC32</a>]</pre>
- <pre>
- :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...</pre>
- <p>2. Put two lines, as the *only* non-comment lines, in your commitinfo file:</p>
- <pre>
- ALL $CVSROOT/CVSROOT/commit_prep
- ALL $CVSROOT/CVSROOT/cvs_acls [-d][-u $USER ][-f <logfilename>]</pre>
- <pre>
- 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.</pre>
- <pre>
- (These are handled in the processArgs() subroutine.)</pre>
- <p>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.</p>
- <p>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.</p>
- <p>3. Install this file as $CVSROOT/CVSROOT/cvs_acls and make it executable.</p>
- <p>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:</p>
- <pre>
- $ 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</pre>
- <p>Note: The format of the 'cvsacl' file is described in detail immediately
- below but here is an important set up point:</p>
- <pre>
- Make sure to include a line like the following:</pre>
- <pre>
- deny||CVSROOT/commitinfo CVSROOT/cvsacl
- allow|cvsadmin|CVSROOT/commitinfo CVSROOT/cvsacl</pre>
- <pre>
- 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'.)</pre>
- <p>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.</p>
- <p>
- </p>
- <hr />
- <h1><a name="format_of_the_cvsacl_file">Format of the cvsacl file</a></h1>
- <p>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.</p>
- <p>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.</p>
- <p>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.</p>
- <p>Lines beginning with ``allow'' or ``deny'' are assumed to be '|'-separated
- triples: (All spaces and tabs are ignored in a line.)</p>
- <pre>
- {allow.*,deny.*} [|user,user,... [|repos,repos,... [|branch,branch,...]]]</pre>
- <pre>
- 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.</pre>
- <p>Example: (Note: No in-line comments.)</p>
- <pre>
- # ----- Make whole repository unavailable.
- deny</pre>
- <pre>
- # ----- Except for user "dgg".
- allow|dgg</pre>
- <pre>
- # ----- Except when "fred" or "john" commit to the
- # module whose repository is "bin/ls"
- allow|fred, john|bin/ls</pre>
- <pre>
- # ----- Except when "ed" commits to the "stable"
- # branch of the "bin/ls" repository
- allow|ed|/bin/ls|stable</pre>
- <p>
- </p>
- <hr />
- <h1><a name="program_logic">Program Logic</a></h1>
- <p>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.</p>
- <p>The script walks through the 'cvsacl' file looking for matches on
- the username, repository and branch.</p>
- <p>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.</p>
- <p>A repository match:</p>
- <ul>
- <li><strong><a name="item_each_entry_in_the_modules_section_of_the_current__">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.)</a></strong><br />
- </li>
- <li><strong><a name="item_if_neither_2c_then_assume_the__27cvsacl_27_file_wa">If neither, then assume the 'cvsacl' file was set up in error and
- skip that 'allow' line.</a></strong><br />
- </li>
- <li><strong><a name="item_if_a_dir_2c_then_each_dir_pattern_is_matched_separ">If a dir, then each dir pattern is matched separately against the
- beginning of each of the committed files in @ARGV.</a></strong><br />
- </li>
- <li><strong><a name="item_if_a_file_2c_then_each_file_pattern_is_matched_exa">If a file, then each file pattern is matched exactly against each
- of the files to be committed in @ARGV.</a></strong><br />
- </li>
- <li><strong><a name="item_repository_and_branch_must_both_match_together_2e_">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></strong><br />
- </li>
- A branch match is either:
- <ul>
- <li><strong><a name="item_when_no_branches_are_listed_in_the_fourth_column_2">When no branches are listed in the fourth column. (``Match any.'')</a></strong><br />
- </li>
- <li><strong><a name="item_all_elements_from_the_fourth_column_are_matched_ag">All elements from the fourth column are matched against each of
- the tag names for $ARGV[1..$#ARGV] found in the %branches file.</a></strong><br />
- </li>
- </ul>
- <li><strong><a name="item__27allow_27_match_remove_that_match_from_the_tally">'allow' match remove that match from the tally map.</a></strong><br />
- </li>
- <li><strong><a name="item_restricted">Restricted ('deny') matches are saved in the %repository_matches
- table.</a></strong><br />
- </li>
- <li><strong><a name="item_if_there_is_a_match_on_user_2c_repository_and_bran">If there is a match on user, repository and branch:</a></strong><br />
- </li>
- <pre>
- 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</pre>
- <li><strong><a name="item_at_the_end_of_all_the__27cvsacl_27_line_checks_2c_">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.</a></strong><br />
- </li>
- </ul>
- <p>
- </p>
- <h2><a name="pseudocode">Pseudocode</a></h2>
- <pre>
- 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</pre>
- <p>
- </p>
- <h2><a name="sanity_check">Sanity Check</a></h2>
- <pre>
- 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</pre>
- </body>
- </html>