diff options
Diffstat (limited to 'git/gitaclhook')
-rwxr-xr-x | git/gitaclhook | 169 |
1 files changed, 132 insertions, 37 deletions
diff --git a/git/gitaclhook b/git/gitaclhook index f9b3d3a..dd31dd8 100755 --- a/git/gitaclhook +++ b/git/gitaclhook | |||
@@ -16,60 +16,116 @@ | |||
16 | 16 | ||
17 | use strict; | 17 | use strict; |
18 | use File::Spec; | 18 | use File::Spec; |
19 | use Pod::Man; | ||
20 | use Pod::Usage; | ||
19 | 21 | ||
20 | =doc | 22 | =head1 NAME |
21 | This hook is intended to be run as an "update" hook by git. | ||
22 | It is called by git-receive-pack with arguments: refname old-sha1 new-sha1. | ||
23 | 23 | ||
24 | If the hooks.aclfile keyword is defined in the repository's config file, | 24 | gitaclhook - control access to git repositories |
25 | |||
26 | =head1 SYNOPSIS | ||
27 | |||
28 | B<gitaclhook> I<refname> I<old-sha1> I<new-sha1> | ||
29 | |||
30 | B<gitaclhook --help> | ||
31 | |||
32 | =head1 DESCRIPTION | ||
33 | |||
34 | This program is intended to be run as an "update" hook by git. | ||
35 | It is called by B<git-receive-pack> with arguments: | ||
36 | I<refname> I<old-sha1> I<new-sha1>. | ||
37 | |||
38 | If the B<hooks.aclfile> keyword is defined in the repository's config file, | ||
25 | this hook will parse the file and allow or deny update depending on | 39 | this hook will parse the file and allow or deny update depending on |
26 | its settings. If hooks.aclfile is not defined, update is allowed | 40 | its settings. If B<hooks.aclfile> is not defined, update is allowed |
27 | unconditionally. | 41 | unconditionally. |
28 | 42 | ||
43 | =head1 ACL FILE | ||
44 | |||
29 | The ACL file has the usual line-oriented syntax. Comments are introduced | 45 | The ACL file has the usual line-oriented syntax. Comments are introduced |
30 | by the # sign and extend to the end of the physical line. Comments and | 46 | by the # sign and extend to the end of the physical line. Comments and |
31 | empty lines are ignored. | 47 | empty lines are ignored. |
32 | 48 | ||
33 | Non-empty lines introduce ACL rules. The syntax is: | 49 | Non-empty lines introduce ACL rules. The syntax is: |
34 | 50 | ||
35 | VERB PROJECT USER [OP REF] | 51 | =over 4 |
52 | |||
53 | I<VERB> I<PROJECT> I<USER> [I<OP> I<REF>] | ||
54 | |||
55 | =back | ||
36 | 56 | ||
37 | where brackets denote optional parts. The parts of an ACL are: | 57 | where brackets denote optional parts. The parts of an ACL are: |
38 | 58 | ||
39 | VERB Either 'allow' or 'deny', to allow or deny the operation, | 59 | =over 4 |
40 | correspondingly. | 60 | |
61 | =item I<VERB> | ||
62 | |||
63 | Either B<allow> or B<deny>, to allow or deny the operation, correspondingly. | ||
64 | |||
65 | =item I<PROJECT> | ||
41 | 66 | ||
42 | PROJECT The name of the project. It is obtained by removing the directory | 67 | The name of the project. It is obtained by removing the directory |
43 | and suffix parts of the repository pathname. Thus, if the repository | 68 | and suffix parts of the repository pathname. Thus, if the repository |
44 | is located in /var/gitroot/foobar.git, then the corresponding name of | 69 | is located in B</var/gitroot/foobar.git>, then the corresponding name of |
45 | the project is 'foobar'. | 70 | the project is B<foobar>. |
46 | 71 | ||
47 | USER Name of the user. The word 'all' stands for any user, the word 'none' | 72 | An asterisk matches any project name. |
73 | |||
74 | =item I<USER> | ||
75 | |||
76 | Name of the user. The word B<all> stands for any user, the word B<none> | ||
48 | matches no one at all. Otherwise, if this part begins with a percent | 77 | matches no one at all. Otherwise, if this part begins with a percent |
49 | sign (%), the rest of characters aretreated as the name of the UNIX | 78 | sign (B<%>), the rest of characters are treated as the name of the UNIX |
50 | group to check and the rule matches any user in that group. Otherwise, | 79 | group to check and the rule matches any user in that group. Otherwise, |
51 | the literal match is assumed. | 80 | the literal match is assumed. |
52 | 81 | ||
82 | =back | ||
83 | |||
53 | The optional parts are: | 84 | The optional parts are: |
54 | 85 | ||
55 | OP Requested operation codes. It is a string consisting of one or more | 86 | =over 4 |
87 | |||
88 | =item I<OP> | ||
89 | |||
90 | Requested operation codes. It is a string consisting of one or more | ||
56 | of the following letters (case-insensitive): | 91 | of the following letters (case-insensitive): |
57 | 92 | ||
58 | C: create new ref | 93 | =over 8 |
59 | D: delete existing ref | 94 | |
60 | U: fast-forward existing ref (no commit loss) | 95 | =item B<C> |
61 | R: rewind or rebase existing ref (commit loss) | 96 | |
97 | Create new ref. | ||
98 | |||
99 | =item B<D> | ||
100 | |||
101 | Delete existing ref. | ||
102 | |||
103 | =item B<U> | ||
104 | |||
105 | Fast-forward existing ref (no commit loss). | ||
106 | |||
107 | =item B<R> | ||
62 | 108 | ||
63 | REF Affected ref, relative to the git refs/ directory. If it begins with | 109 | Rewind or rebase existing ref (commit loss). |
64 | a caret (^), it is treated as a Perl regular expression (with the ^ | 110 | |
65 | being its part). If it ends with a /, it is treated as a prefix match, | 111 | =back |
66 | so, e.g., "heads/baz/" matches "refs/heads/baz" and anything below. | 112 | |
113 | =item I<REF> | ||
114 | |||
115 | Affected ref, relative to the git B<refs/> directory. If it begins with | ||
116 | a caret (B<^>), it is treated as a Perl regular expression (with the B<^> | ||
117 | being its part). If it ends with a B</>, it is treated as a prefix match, | ||
118 | so, e.g., B<heads/baz/> matches B<refs/heads/baz> and anything below. | ||
67 | Otherwise, it must match exactly the affected ref. | 119 | Otherwise, it must match exactly the affected ref. |
68 | 120 | ||
69 | The rule applies only if its PROJECT and USER parts match the project which is | 121 | =back |
70 | being updated and the user who requests the update, its OP contains the opcode | 122 | |
71 | of the requested operation and REF matches the affected ref. Missing REF | 123 | =head1 RULE MATCHING |
72 | and/or OP are treated as a match. | 124 | |
125 | The rule applies only if its I<PROJECT> and I<USER> parts match the project | ||
126 | which is being updated and the user who requests the update, its I<OP> | ||
127 | contains the opcode of the requested operation and I<REF> matches the affected | ||
128 | ref. Missing I<REF> and/or I<OP> are treated as a match. | ||
73 | 129 | ||
74 | If no rule applies, the operation is allowed. | 130 | If no rule applies, the operation is allowed. |
75 | 131 | ||
@@ -81,19 +137,49 @@ allow myprog %pm C ^heads/tags/v\\d+$ | |||
81 | allow myprog admin CDUR | 137 | allow myprog admin CDUR |
82 | deny myprog all | 138 | deny myprog all |
83 | 139 | ||
84 | Then the users from the 'devel' group will be able to push updates to | 140 | Then the users from the B<devel> group will be able to push updates to |
85 | refs/heads/master, the users from the 'pm' group will be allowed to do | 141 | B<refs/heads/master>, the users from the B<pm> group will be allowed to do |
86 | anything with refs under refs/heads and to create tags with names beginning | 142 | anything with refs under B<refs/heads> and to create tags with names beginning |
87 | with 'v' and containing only digits afterwards, and the user 'admin' will | 143 | with B<v> and containing only digits afterwards, and the user B<admin> will |
88 | be allowed to do anything he pleases. No other users will be allowed to | 144 | be allowed to do anything he pleases. No other users will be allowed to |
89 | update that repository. | 145 | update that repository. |
90 | 146 | ||
91 | Configuration settings: | 147 | =head1 CONFIGURATION SETTINGS |
148 | |||
149 | =over 4 | ||
150 | |||
151 | =item B<hooks.aclfile> STRING | ||
152 | |||
153 | Name of the ACL file. | ||
154 | |||
155 | =item B<hooks.acllog> STRING | ||
156 | |||
157 | Send log info to this file. | ||
158 | |||
159 | =item B<hooks.acldebug> BOOL | ||
160 | |||
161 | Enable debugging. | ||
92 | 162 | ||
93 | hooks.aclfile STRING Name of the ACL file | 163 | =item B<hooks.aclquiet> BOOL |
94 | hooks.acllog STRING Send log info to this file | 164 | |
95 | hooks.acldebug BOOL Enable debugging | 165 | Suppress diagnostics on stderr. |
96 | hooks.aclquiet BOOL Suppress diagnostics on stderr | 166 | |
167 | =item B<hooks.httpd-user> STRING | ||
168 | |||
169 | Name of the user httpd runs as. Define it if the repository can be | ||
170 | accessed via HTTP(S). If B<gitaclhook> is run as this user, it will | ||
171 | get the name of the user on behalf of which the update is performed | ||
172 | from the environment variable B<REMOTE_USER>. | ||
173 | |||
174 | =back | ||
175 | |||
176 | =head1 SEE ALSO | ||
177 | |||
178 | B<git-receive-pack>(1). | ||
179 | |||
180 | =head1 AUTHOR | ||
181 | |||
182 | Sergey Poznyakoff, <gray@gno.org> | ||
97 | 183 | ||
98 | =cut | 184 | =cut |
99 | 185 | ||
@@ -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 |
236 | deny "don't run this script from the command line" unless ($git_dir); | 322 | unless ($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 | ||
334 | my $httpdusr = git_value('config', 'hooks.httpd-user'); | ||
335 | if (defined($httpdusr) and $user_name eq $httpdusr) { | ||
336 | deny "need authenticated user" unless defined($ENV{AUTH_TYPE}); | ||