summaryrefslogtreecommitdiffabout
path: root/git/gitaclhook
Side-by-side diff
Diffstat (limited to 'git/gitaclhook') (more/less context) (ignore whitespace changes)
-rwxr-xr-xgit/gitaclhook205
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
@@ -18,12 +18,28 @@ 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
@@ -34,3 +50,7 @@ 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
@@ -38,15 +58,26 @@ 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
@@ -54,20 +85,45 @@ 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.
@@ -77,12 +133,12 @@ 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
@@ -90,9 +146,39 @@ 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
@@ -133,3 +219,3 @@ sub logmsg($$;$) {
-sub deny ($;$) {
+sub deny($;$) {
my $msg = shift;
@@ -146,3 +232,3 @@ sub deny ($;$) {
-sub allow ($) {
+sub allow($) {
logmsg("ALLOW",
@@ -154,3 +240,3 @@ sub allow ($) {
-sub info ($) {
+sub info($) {
logmsg("INFO", $_[0]);
@@ -159,3 +245,3 @@ sub info ($) {
-sub git_value (@) {
+sub git_value(@) {
my $fd;
@@ -219,3 +305,3 @@ sub check_acl($$$) {
- next if ($x[1] ne $project);
+ next if ($x[1] ne "*" and $x[1] ne $project);
next unless match_user($x[2]);
@@ -235,3 +321,6 @@ 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"
+}
@@ -244,2 +333,8 @@ $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;

Return to:

Send suggestions and report system problems to the System administrator.