summaryrefslogtreecommitdiffabout
path: root/git/gitaclhook
Side-by-side diff
Diffstat (limited to 'git/gitaclhook') (more/less context) (ignore whitespace changes)
-rwxr-xr-xgit/gitaclhook371
1 files changed, 0 insertions, 371 deletions
diff --git a/git/gitaclhook b/git/gitaclhook
deleted file mode 100755
index dd31dd8..0000000
--- a/git/gitaclhook
+++ b/dev/null
@@ -1,371 +0,0 @@
-#! /usr/bin/perl
-# Copyright (C) 2013 Sergey Poznyakoff <gray@gnu.org>
-#
-# 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 3, 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, see <http://www.gnu.org/licenses/>.
-
-use strict;
-use File::Spec;
-use Pod::Man;
-use Pod::Usage;
-
-=head1 NAME
-
-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 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:
-
-=over 4
-
-I<VERB> I<PROJECT> I<USER> [I<OP> I<REF>]
-
-=back
-
-where brackets denote optional parts. The parts of an ACL are:
-
-=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>.
-
-An asterisk matches any project name.
-
-=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:
-
-=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
-
-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.
-
-=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
-
-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;
-my $logfile;
-my $quiet;
-my ($user_name) = getpwuid $<;
-my $git_dir = $ENV{GIT_DIR};
-my $ref = $ARGV[0];
-my $old = $ARGV[1];
-my $new = $ARGV[2];
-
-my $project_name;
-my $op;
-
-my %opstr = ('C' => 'create',
- 'D' => 'delete',
- 'U' => 'update',
- 'R' => 'rewind/rebase');
-
-sub logmsg($$;$) {
- return 0 unless $logfile;
-
- my $status = shift;
- my $message = shift;
- my $loc = shift;
- my $fd;
-
- open($fd, $logfile);
- if ($loc) {
- print $fd "$status:$loc: $message\n";
- } else {
- print $fd "$status: $message\n";
- }
- close($fd);
-}
-
-sub deny($;$) {
- my $msg = shift;
- my $loc = shift;
-
- logmsg("DENY",
- "$project_name:$user_name:$opstr{$op}:$ref:$old:$new: $msg",
- $loc);
-
- print STDERR "debug: denied by $loc\n" if ($debug and $loc);
- print STDERR "denied: $msg\n" unless $quiet;
- exit 1;
-}
-
-sub allow($) {
- logmsg("ALLOW",
- "$project_name:$user_name:$opstr{$op}:$ref:$old:$new",
- $_[0]);
- print STDERR "debug: allow $_[0]\n" if $debug;
- exit 0;
-}
-
-sub info($) {
- logmsg("INFO", $_[0]);
- print STDERR "info: $_[0]\n" if $debug;
-}
-
-sub git_value(@) {
- my $fd;
-
- open($fd,'-|','git',@_);
- local $_ = <$fd>;
- chop;
- close($fd);
- return $_;
-}
-
-sub match_user($) {
- my $user = shift;
- return 1 if ($user eq 'all');
- return 0 if ($user eq 'none');
- if ($user =~ /^%(.+)/) {
- my ($name,$passwd,$gid,$members) = getgrnam($1) or return 0;
- my @a = split(/\s+/,$members);
- for (my $i = 0; $i <= $#a; $i++) {
- return 1 if $a[$i] eq $user_name;
- }
- } elsif ($user eq $user_name) {
- return 1;
- }
- return 0;
-}
-
-sub match_ref($) {
- my $expr = shift;
- return ($ref =~ /$expr/) if ($expr =~ /^\^/);
- return ("$ref/" eq $expr or index($ref, $expr) == 0) if ($expr =~ /\/$/);
- return $ref eq $expr;
-}
-
-sub check_acl($$$) {
- my $project = shift;
- my $op = shift;
- my $ref = shift;
- my $fd;
- my $line = 0;
- my @ret;
-
- my $filename = git_value('config', 'hooks.aclfile');
- allow("no ACL configured for $project")
- unless defined($filename);
-
- open($fd, "<", $filename) or deny("cannot open configuration file: $!");
- while (<$fd>) {
- ++$line;
- chomp;
- s/^\s+//;
- s/\s+$//;
- s/#.*//;
- next if ($_ eq "");
- my @x = split(/\s+/, $_, 5);
-
- deny("unknown keyword", "$filename:$line")
- unless ($x[0] eq 'allow' || $x[0] eq 'deny');
- deny("malformed line", "$filename:$line")
- unless $#x >= 2;
-
- 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]));
-
- allow("$filename:$line") if ($x[0] eq 'allow');
- deny("you are not permitted to " . $opstr{$op} . " $ref",
- "$filename:$line");
- }
- close($fd);
- allow("default rule");
-}
-
-####
-
-# Sanity checks
-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');
-if ($logfile && $logfile !~ /[>|]/) {
- $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}$/;
-deny "bad new value $new" unless $new =~ /^[a-z0-9]{40}$/;
-deny "no such user" unless $user_name;
-allow "no change requested" if $old eq $new;
-
-$project_name = File::Spec->rel2abs($git_dir);
-$project_name =~ m,/([^/]+)(?:\.git|/\.git)$,;
-$project_name = $1;
-
-if ($old =~ /^0{40}$/) {
- $op = 'C';
-} elsif ($new =~ /^0{40}$/) {
- $op = 'D';
-} elsif ($ref =~ m,^heads/, && $old eq git_value('merge-base',$old,$new)) {
- $op = 'U';
-} else {
- $op = 'R';
-}
-
-info "$user_name requested $opstr{$op} on $ref in $project_name";
-
-check_acl($project_name, $op, $ref);
-
-# Finis
-
-
-
-
-
-

Return to:

Send suggestions and report system problems to the System administrator.