diff options
Diffstat (limited to 'git/gitaclhook')
-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 | |||
@@ -13,91 +13,177 @@ | |||
13 | # | 13 | # |
14 | # You should have received a copy of the GNU General Public License | 14 | # You should have received a copy of the GNU General Public License |
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
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> | ||
66 | |||
67 | The name of the project. It is obtained by removing the directory | ||
68 | and suffix parts of the repository pathname. Thus, if the repository | ||
69 | is located in B</var/gitroot/foobar.git>, then the corresponding name of | ||
70 | the project is B<foobar>. | ||
41 | 71 | ||
42 | PROJECT The name of the project. It is obtained by removing the directory | 72 | An 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 | ||
47 | USER 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 | 76 | Name 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, | 77 | matches no one at all. Otherwise, if this part begins with a percent |
51 | the literal match is assumed. | 78 | sign (B<%>), the rest of characters are treated as the name of the UNIX |
79 | group to check and the rule matches any user in that group. Otherwise, | ||
80 | the literal match is assumed. | ||
81 | |||
82 | =back | ||
52 | 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 |
56 | of the following letters (case-insensitive): | 87 | |
57 | 88 | =item I<OP> | |
58 | C: create new ref | 89 | |
59 | D: delete existing ref | 90 | Requested operation codes. It is a string consisting of one or more |
60 | U: fast-forward existing ref (no commit loss) | 91 | of the following letters (case-insensitive): |
61 | R: rewind or rebase existing ref (commit loss) | 92 | |
62 | 93 | =over 8 | |
63 | REF 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. | 97 | Create new ref. |
67 | Otherwise, it must match exactly the affected ref. | 98 | |
68 | 99 | =item B<D> | |
69 | The rule applies only if its PROJECT and USER parts match the project which is | 100 | |
70 | being updated and the user who requests the update, its OP contains the opcode | 101 | Delete existing ref. |
71 | of the requested operation and REF matches the affected ref. Missing REF | 102 | |
72 | and/or OP are treated as a match. | 103 | =item B<U> |
104 | |||
105 | Fast-forward existing ref (no commit loss). | ||
106 | |||
107 | =item B<R> | ||
108 | |||
109 | Rewind or rebase existing ref (commit loss). | ||
110 | |||
111 | =back | ||
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. | ||
119 | Otherwise, it must match exactly the affected ref. | ||
120 | |||
121 | =back | ||
122 | |||
123 | =head1 RULE MATCHING | ||
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 | ||
76 | For example, assume you have the following ACL file: | 132 | For example, assume you have the following ACL file: |
77 | 133 | ||
78 | allow myprog %devel U heads/master | 134 | allow myprog %devel U heads/master |
79 | allow myprog %pm CDUR heads/ | 135 | allow myprog %pm CDUR heads/ |
80 | allow myprog %pm C ^heads/tags/v\\d+$ | 136 | 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 | ||
92 | 160 | ||
93 | hooks.aclfile STRING Name of the ACL file | 161 | Enable debugging. |
94 | hooks.acllog STRING Send log info to this file | ||
95 | hooks.acldebug BOOL Enable debugging | ||
96 | hooks.aclquiet BOOL Suppress diagnostics on stderr | ||
97 | 162 | ||
163 | =item B<hooks.aclquiet> BOOL | ||
164 | |||
165 | 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> | ||
183 | |||
98 | =cut | 184 | =cut |
99 | 185 | ||
100 | my $debug = $ENV{GIT_UPDATE_DEBUG} > 0; | 186 | my $debug = $ENV{GIT_UPDATE_DEBUG} > 0; |
101 | my $logfile; | 187 | my $logfile; |
102 | my $quiet; | 188 | my $quiet; |
103 | my ($user_name) = getpwuid $<; | 189 | my ($user_name) = getpwuid $<; |
@@ -128,39 +214,39 @@ sub logmsg($$;$) { | |||
128 | } else { | 214 | } else { |
129 | print $fd "$status: $message\n"; | 215 | print $fd "$status: $message\n"; |
130 | } | 216 | } |
131 | close($fd); | 217 | close($fd); |
132 | } | 218 | } |
133 | 219 | ||
134 | sub deny ($;$) { | 220 | sub deny($;$) { |
135 | my $msg = shift; | 221 | my $msg = shift; |
136 | my $loc = shift; | 222 | my $loc = shift; |
137 | 223 | ||