summaryrefslogtreecommitdiffabout
path: root/git/gitaclhook
Unidiff
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
@@ -16,85 +16,171 @@
16 16
17use strict; 17use strict;
18use File::Spec; 18use File::Spec;
19use Pod::Man;
20use Pod::Usage;
19 21
20=doc 22=head1 NAME
21This hook is intended to be run as an "update" hook by git.
22It is called by git-receive-pack with arguments: refname old-sha1 new-sha1.
23 23
24If the hooks.aclfile keyword is defined in the repository's config file, 24gitaclhook - control access to git repositories
25
26=head1 SYNOPSIS
27
28B<gitaclhook> I<refname> I<old-sha1> I<new-sha1>
29
30B<gitaclhook --help>
31
32=head1 DESCRIPTION
33
34This program is intended to be run as an "update" hook by git.
35It is called by B<git-receive-pack> with arguments:
36I<refname> I<old-sha1> I<new-sha1>.
37
38If the B<hooks.aclfile> keyword is defined in the repository's config file,
25this hook will parse the file and allow or deny update depending on 39this hook will parse the file and allow or deny update depending on
26its settings. If hooks.aclfile is not defined, update is allowed 40its settings. If B<hooks.aclfile> is not defined, update is allowed
27unconditionally. 41unconditionally.
28 42
43=head1 ACL FILE
44
29The ACL file has the usual line-oriented syntax. Comments are introduced 45The ACL file has the usual line-oriented syntax. Comments are introduced
30by the # sign and extend to the end of the physical line. Comments and 46by the # sign and extend to the end of the physical line. Comments and
31empty lines are ignored. 47empty lines are ignored.
32 48
33Non-empty lines introduce ACL rules. The syntax is: 49Non-empty lines introduce ACL rules. The syntax is:
34 50
35 VERB PROJECT USER [OP REF] 51=over 4
52
53I<VERB> I<PROJECT> I<USER> [I<OP> I<REF>]
54
55=back
36 56
37where brackets denote optional parts. The parts of an ACL are: 57where brackets denote optional parts. The parts of an ACL are:
38 58
39VERB Either 'allow' or 'deny', to allow or deny the operation, 59=over 4
40 correspondingly. 60
61=item I<VERB>
62
63Either B<allow> or B<deny>, to allow or deny the operation, correspondingly.
64
65=item I<PROJECT>
66
67The name of the project. It is obtained by removing the directory
68and suffix parts of the repository pathname. Thus, if the repository
69is located in B</var/gitroot/foobar.git>, then the corresponding name of
70the project is B<foobar>.
41 71
42PROJECT The name of the project. It is obtained by removing the directory 72An asterisk matches any project name.
43 and suffix parts of the repository pathname. Thus, if the repository
44 is located in /var/gitroot/foobar.git, then the corresponding name of
45 the project is 'foobar'.
46 73
47USER Name of the user. The word 'all' stands for any user, the word 'none' 74=item I<USER>
48 matches no one at all. Otherwise, if this part begins with a percent 75
49 sign (%), the rest of characters aretreated as the name of the UNIX 76Name of the user. The word B<all> stands for any user, the word B<none>
50 group to check and the rule matches any user in that group. Otherwise, 77matches no one at all. Otherwise, if this part begins with a percent
51 the literal match is assumed. 78sign (B<%>), the rest of characters are treated as the name of the UNIX
79group to check and the rule matches any user in that group. Otherwise,
80the literal match is assumed.
81
82=back
52 83
53The optional parts are: 84The optional parts are:
54 85
55OP Requested operation codes. It is a string consisting of one or more 86=over 4
56 of the following letters (case-insensitive): 87
57 88=item I<OP>
58 C: create new ref 89
59 D: delete existing ref 90Requested operation codes. It is a string consisting of one or more
60 U: fast-forward existing ref (no commit loss) 91of the following letters (case-insensitive):
61 R: rewind or rebase existing ref (commit loss) 92
62 93=over 8
63REF Affected ref, relative to the git refs/ directory. If it begins with 94
64 a caret (^), it is treated as a Perl regular expression (with the ^ 95=item B<C>
65 being its part). If it ends with a /, it is treated as a prefix match, 96
66 so, e.g., "heads/baz/" matches "refs/heads/baz" and anything below. 97Create new ref.
67 Otherwise, it must match exactly the affected ref. 98
68 99=item B<D>
69The rule applies only if its PROJECT and USER parts match the project which is 100
70being updated and the user who requests the update, its OP contains the opcode 101Delete existing ref.
71of the requested operation and REF matches the affected ref. Missing REF 102
72and/or OP are treated as a match. 103=item B<U>
104
105Fast-forward existing ref (no commit loss).
106
107=item B<R>
108
109Rewind or rebase existing ref (commit loss).
110
111=back
112
113=item I<REF>
114
115Affected ref, relative to the git B<refs/> directory. If it begins with
116a caret (B<^>), it is treated as a Perl regular expression (with the B<^>
117being its part). If it ends with a B</>, it is treated as a prefix match,
118so, e.g., B<heads/baz/> matches B<refs/heads/baz> and anything below.
119Otherwise, it must match exactly the affected ref.
120
121=back
122
123=head1 RULE MATCHING
124
125The rule applies only if its I<PROJECT> and I<USER> parts match the project
126which is being updated and the user who requests the update, its I<OP>
127contains the opcode of the requested operation and I<REF> matches the affected
128ref. Missing I<REF> and/or I<OP> are treated as a match.
73 129
74If no rule applies, the operation is allowed. 130If no rule applies, the operation is allowed.
75 131
76For example, assume you have the following ACL file: 132For example, assume you have the following ACL file:
77 133
78allow myprog %devel U heads/master 134 allow myprog %devel U heads/master
79allow myprog %pm CDUR heads/ 135 allow myprog %pm CDUR heads/
80allow myprog %pm C ^heads/tags/v\\d+$ 136 allow myprog %pm C ^heads/tags/v\\d+$
81allow myprog admin CDUR 137 allow myprog admin CDUR
82deny myprog all 138 deny myprog all
83 139
84Then the users from the 'devel' group will be able to push updates to 140Then the users from the B<devel> group will be able to push updates to
85refs/heads/master, the users from the 'pm' group will be allowed to do 141B<refs/heads/master>, the users from the B<pm> group will be allowed to do
86anything with refs under refs/heads and to create tags with names beginning 142anything with refs under B<refs/heads> and to create tags with names beginning
87with 'v' and containing only digits afterwards, and the user 'admin' will 143with B<v> and containing only digits afterwards, and the user B<admin> will
88be allowed to do anything he pleases. No other users will be allowed to 144be allowed to do anything he pleases. No other users will be allowed to
89update that repository. 145update that repository.
90 146
91Configuration settings: 147=head1 CONFIGURATION SETTINGS
148
149=over 4
150
151=item B<hooks.aclfile> STRING
152
153Name of the ACL file.
154
155=item B<hooks.acllog> STRING
156
157Send log info to this file.
158
159=item B<hooks.acldebug> BOOL
92 160
93hooks.aclfile STRING Name of the ACL file 161Enable debugging.
94hooks.acllog STRING Send log info to this file
95hooks.acldebug BOOL Enable debugging
96hooks.aclquiet BOOL Suppress diagnostics on stderr
97 162
163=item B<hooks.aclquiet> BOOL
164
165Suppress diagnostics on stderr.
166
167=item B<hooks.httpd-user> STRING
168
169Name of the user httpd runs as. Define it if the repository can be
170accessed via HTTP(S). If B<gitaclhook> is run as this user, it will
171get the name of the user on behalf of which the update is performed
172from the environment variable B<REMOTE_USER>.
173
174=back
175
176=head1 SEE ALSO
177
178B<git-receive-pack>(1).
179
180=head1 AUTHOR
181
182Sergey Poznyakoff, <gray@gno.org>
183
98=cut 184=cut
99 185
100my $debug = $ENV{GIT_UPDATE_DEBUG} > 0; 186my $debug = $ENV{GIT_UPDATE_DEBUG} > 0;
@@ -131,7 +217,7 @@ sub logmsg($$;$) {
131 close($fd); 217 close($fd);
132} 218}
133 219
134sub deny ($;$) { 220sub deny($;$) {
135 my $msg = shift; 221 my $msg = shift;
136 my $loc = shift; 222 my $loc = shift;
137 223
@@ -144,7 +230,7 @@ sub deny ($;$) {
144 exit 1; 230 exit 1;
145} 231}
146 232
147sub allow ($) { 233sub allow($) {
148 logmsg("ALLOW", 234 logmsg("ALLOW",
149 "$project_name:$user_name:$opstr{$op}:$ref:$old:$new", 235 "$project_name:$user_name:$opstr{$op}:$ref:$old:$new",
150 $_[0]); 236 $_[0]);
@@ -152,12 +238,12 @@ sub allow ($) {
152 exit 0; 238 exit 0;
153} 239}
154 240
155sub info ($) { 241sub info($) {
156 logmsg("INFO", $_[0]); 242 logmsg("INFO", $_[0]);
157 print STDERR "info: $_[0]\n" if $debug; 243 print STDERR "info: $_[0]\n" if $debug;
158} 244}
159 245
160sub git_value (@) { 246sub git_value(@) {
161 my $fd; 247 my $fd;
162 248
163 open($fd,'-|','git',@_); 249 open($fd,'-|','git',@_);
@@ -217,7 +303,7 @@ sub check_acl($$$) {
217 deny("malformed line", "$filename:$line") 303 deny("malformed line", "$filename:$line")
218 unless $#x >= 2; 304 unless $#x >= 2;
219 305
220 next if ($x[1] ne $project); 306 next if ($x[1] ne "*" and $x[1] ne $project);
221 next unless match_user($x[2]); 307 next unless match_user($x[2]);
222 next if ($#x >= 3 && index(uc $x[3], $op) == -1); 308 next if ($#x >= 3 && index(uc $x[3], $op) == -1);
223 next if ($#x == 4 && !match_ref($x[4])); 309 next if ($#x == 4 && !match_ref($x[4]));
@@ -233,7 +319,10 @@ sub check_acl($$$) {
233#### 319####
234 320
235# Sanity checks 321# Sanity checks
236deny "don't run this script from the command line" unless ($git_dir); 322unless ($git_dir) {
323 pod2usage(-exitstatus => 0, -verbose => 2) if ($ref eq "--help");
324 deny "try \"$0 --help\" for fore info"
325}
237 326
238$debug = git_value('config', '--bool', 'hooks.acldebug') unless ($debug); 327$debug = git_value('config', '--bool', 'hooks.acldebug') unless ($debug);
239$logfile = git_value('config', 'hooks.acllog'); 328$logfile = git_value('config', 'hooks.acllog');
@@ -242,6 +331,12 @@ if ($logfile && $logfile !~ /[>|]/) {
242} 331}
243$quiet = git_value('config', 'hooks.aclquiet') unless ($debug); 332$quiet = git_value('config', 'hooks.aclquiet') unless ($debug);
244 333
334my $httpdusr = git_value('config', 'hooks.httpd-user');
335if (defined($httpdusr) and $user_name eq $httpdusr) {
336 deny "need authenticated user" unless defined($ENV{AUTH_TYPE});
337 $user_name = $ENV{REMOTE_USER};
338}
339
245deny "need a ref name" unless $ref; 340deny "need a ref name" unless $ref;
246deny "bogus ref $ref" unless $ref =~ s,^refs/,,; 341deny "bogus ref $ref" unless $ref =~ s,^refs/,,;
247deny "bad old value $old" unless $old =~ /^[a-z0-9]{40}$/; 342deny "bad old value $old" unless $old =~ /^[a-z0-9]{40}$/;

Return to:

Send suggestions and report system problems to the System administrator.