diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-06-21 12:12:08 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-06-21 12:12:08 +0300 |
commit | 850a3e03dfc227f058647ff65092a3c791012df8 (patch) | |
tree | 67b5505f14b5365e0903f73da6e3c5bf46cc83d1 | |
parent | 5b089678b03537f27fac73a2a08136ff9b1cbf66 (diff) | |
download | gsc-850a3e03dfc227f058647ff65092a3c791012df8.tar.gz gsc-850a3e03dfc227f058647ff65092a3c791012df8.tar.bz2 |
Improve gitaclhook.
Reformat and improve documentation. Display it if called with the
--help option.
Allow for * in the PROJECT field (matches any project name).
Work with http(s) transport. New configuration variable httpd-user
supplies the name of the user http server runs as.
-rwxr-xr-x | git/gitaclhook | 205 |
1 files changed, 150 insertions, 55 deletions
diff --git a/git/gitaclhook b/git/gitaclhook index f9b3d3a..dd31dd8 100755 --- a/git/gitaclhook +++ b/git/gitaclhook @@ -16,85 +16,171 @@ use strict; use File::Spec; +use Pod::Man; +use Pod::Usage; -=doc -This hook is intended to be run as an "update" hook by git. -It is called by git-receive-pack with arguments: refname old-sha1 new-sha1. +=head1 NAME -If the hooks.aclfile keyword is defined in the repository's config file, +gitaclhook - control access to git repositories + +=head1 SYNOPSIS + +B<gitaclhook> I<refname> I<old-sha1> I<new-sha1> + +B<gitaclhook --help> + +=head1 DESCRIPTION + +This program is intended to be run as an "update" hook by git. +It is called by B<git-receive-pack> with arguments: +I<refname> I<old-sha1> I<new-sha1>. + +If the B<hooks.aclfile> keyword is defined in the repository's config file, this hook will parse the file and allow or deny update depending on -its settings. If hooks.aclfile is not defined, update is allowed +its settings. If B<hooks.aclfile> is not defined, update is allowed unconditionally. +=head1 ACL FILE + The ACL file has the usual line-oriented syntax. Comments are introduced by the # sign and extend to the end of the physical line. Comments and empty lines are ignored. Non-empty lines introduce ACL rules. The syntax is: - VERB PROJECT USER [OP REF] +=over 4 + +I<VERB> I<PROJECT> I<USER> [I<OP> I<REF>] + +=back where brackets denote optional parts. The parts of an ACL are: -VERB Either 'allow' or 'deny', to allow or deny the operation, - correspondingly. +=over 4 + +=item I<VERB> + +Either B<allow> or B<deny>, to allow or deny the operation, correspondingly. + +=item I<PROJECT> + +The name of the project. It is obtained by removing the directory +and suffix parts of the repository pathname. Thus, if the repository +is located in B</var/gitroot/foobar.git>, then the corresponding name of +the project is B<foobar>. -PROJECT The name of the project. It is obtained by removing the directory - and suffix parts of the repository pathname. Thus, if the repository - is located in /var/gitroot/foobar.git, then the corresponding name of - the project is 'foobar'. +An asterisk matches any project name. -USER Name of the user. The word 'all' stands for any user, the word 'none' - matches no one at all. Otherwise, if this part begins with a percent - sign (%), the rest of characters aretreated as the name of the UNIX - group to check and the rule matches any user in that group. Otherwise, - the literal match is assumed. +=item I<USER> + +Name of the user. The word B<all> stands for any user, the word B<none> +matches no one at all. Otherwise, if this part begins with a percent +sign (B<%>), the rest of characters are treated as the name of the UNIX +group to check and the rule matches any user in that group. Otherwise, +the literal match is assumed. + +=back The optional parts are: -OP Requested operation codes. It is a string consisting of one or more - of the following letters (case-insensitive): - - C: create new ref - D: delete existing ref - U: fast-forward existing ref (no commit loss) - R: rewind or rebase existing ref (commit loss) - -REF Affected ref, relative to the git refs/ directory. If it begins with - a caret (^), it is treated as a Perl regular expression (with the ^ - being its part). If it ends with a /, it is treated as a prefix match, - so, e.g., "heads/baz/" matches "refs/heads/baz" and anything below. - Otherwise, it must match exactly the affected ref. - -The rule applies only if its PROJECT and USER parts match the project which is -being updated and the user who requests the update, its OP contains the opcode -of the requested operation and REF matches the affected ref. Missing REF -and/or OP are treated as a match. +=over 4 + +=item I<OP> + +Requested operation codes. It is a string consisting of one or more +of the following letters (case-insensitive): + +=over 8 + +=item B<C> + +Create new ref. + +=item B<D> + +Delete existing ref. + +=item B<U> + +Fast-forward existing ref (no commit loss). + +=item B<R> + +Rewind or rebase existing ref (commit loss). + +=back + +=item I<REF> + +Affected ref, relative to the git B<refs/> directory. If it begins with +a caret (B<^>), it is treated as a Perl regular expression (with the B<^> +being its part). If it ends with a B</>, it is treated as a prefix match, +so, e.g., B<heads/baz/> matches B<refs/heads/baz> and anything below. +Otherwise, it must match exactly the affected ref. + +=back + +=head1 RULE MATCHING + +The rule applies only if its I<PROJECT> and I<USER> parts match the project +which is being updated and the user who requests the update, its I<OP> +contains the opcode of the requested operation and I<REF> matches the affected +ref. Missing I<REF> and/or I<OP> are treated as a match. If no rule applies, the operation is allowed. For example, assume you have the following ACL file: -allow myprog %devel U heads/master -allow myprog %pm CDUR heads/ -allow myprog %pm C ^heads/tags/v\\d+$ -allow myprog admin CDUR -deny myprog all + allow myprog %devel U heads/master + allow myprog %pm CDUR heads/ + allow myprog %pm C ^heads/tags/v\\d+$ + allow myprog admin CDUR + deny myprog all -Then the users from the 'devel' group will be able to push updates to -refs/heads/master, the users from the 'pm' group will be allowed to do -anything with refs under refs/heads and to create tags with names beginning -with 'v' and containing only digits afterwards, and the user 'admin' will +Then the users from the B<devel> group will be able to push updates to +B<refs/heads/master>, the users from the B<pm> group will be allowed to do +anything with refs under B<refs/heads> and to create tags with names beginning +with B<v> and containing only digits afterwards, and the user B<admin> will be allowed to do anything he pleases. No other users will be allowed to update that repository. -Configuration settings: +=head1 CONFIGURATION SETTINGS + +=over 4 + +=item B<hooks.aclfile> STRING + +Name of the ACL file. + +=item B<hooks.acllog> STRING + +Send log info to this file. + +=item B<hooks.acldebug> BOOL -hooks.aclfile STRING Name of the ACL file -hooks.acllog STRING Send log info to this file -hooks.acldebug BOOL Enable debugging -hooks.aclquiet BOOL Suppress diagnostics on stderr +Enable debugging. +=item B<hooks.aclquiet> BOOL + +Suppress diagnostics on stderr. + +=item B<hooks.httpd-user> STRING + +Name of the user httpd runs as. Define it if the repository can be +accessed via HTTP(S). If B<gitaclhook> is run as this user, it will +get the name of the user on behalf of which the update is performed +from the environment variable B<REMOTE_USER>. + +=back + +=head1 SEE ALSO + +B<git-receive-pack>(1). + +=head1 AUTHOR + +Sergey Poznyakoff, <gray@gno.org> + =cut my $debug = $ENV{GIT_UPDATE_DEBUG} > 0; @@ -131,7 +217,7 @@ sub logmsg($$;$) { close($fd); } -sub deny ($;$) { +sub deny($;$) { my $msg = shift; my $loc = shift; @@ -144,7 +230,7 @@ sub deny ($;$) { exit 1; } -sub allow ($) { +sub allow($) { logmsg("ALLOW", "$project_name:$user_name:$opstr{$op}:$ref:$old:$new", $_[0]); @@ -152,12 +238,12 @@ sub allow ($) { exit 0; } -sub info ($) { +sub info($) { logmsg("INFO", $_[0]); print STDERR "info: $_[0]\n" if $debug; } -sub git_value (@) { +sub git_value(@) { my $fd; open($fd,'-|','git',@_); @@ -217,7 +303,7 @@ sub check_acl($$$) { deny("malformed line", "$filename:$line") unless $#x >= 2; - next if ($x[1] ne $project); + next if ($x[1] ne "*" and $x[1] ne $project); next unless match_user($x[2]); next if ($#x >= 3 && index(uc $x[3], $op) == -1); next if ($#x == 4 && !match_ref($x[4])); @@ -233,7 +319,10 @@ sub check_acl($$$) { #### # Sanity checks -deny "don't run this script from the command line" unless ($git_dir); +unless ($git_dir) { + pod2usage(-exitstatus => 0, -verbose => 2) if ($ref eq "--help"); + deny "try \"$0 --help\" for fore info" +} $debug = git_value('config', '--bool', 'hooks.acldebug') unless ($debug); $logfile = git_value('config', 'hooks.acllog'); @@ -242,6 +331,12 @@ if ($logfile && $logfile !~ /[>|]/) { } $quiet = git_value('config', 'hooks.aclquiet') unless ($debug); +my $httpdusr = git_value('config', 'hooks.httpd-user'); +if (defined($httpdusr) and $user_name eq $httpdusr) { + deny "need authenticated user" unless defined($ENV{AUTH_TYPE}); + $user_name = $ENV{REMOTE_USER}; +} + deny "need a ref name" unless $ref; deny "bogus ref $ref" unless $ref =~ s,^refs/,,; deny "bad old value $old" unless $old =~ /^[a-z0-9]{40}$/; |