ezcert.git: update to more recent version
[girocco.git] / bin / git-http-backend-verify
blobe5e633e79720bf860763025f0d85eac4494dbaf4
1 #!/bin/sh
3 # Abort any push early if the pushing user doesn't have any push permissions
4 # at all. This avoids unnecessary traffic and unpacked object pollution.
6 # Set GIT_HTTP_BACKEND_BIN to change the default http-backend binary from
7 # the default of Config.pm $git_http_backend_bin (which itself has a default
8 # of "/usr/lib/git-core/git-http-backend")
10 # Note that GIT_PROJECT_ROOT is automatically set to $cfg_reporoot and exported
11 # any incoming value for it will be ignored.
13 # Also prevents standard error output from git-http-backend cluttering up the
14 # server's log unless GIT_HTTP_BACKEND_SHOW_ERRORS is set to a non-empty value.
16 set -e
18 . @basedir@/shlib.sh
20 unset GIT_USER_AGENT
21 unset GIT_HTTP_USER_AGENT
22 if [ -n "$defined_cfg_git_server_ua" ]; then
23 GIT_USER_AGENT="$cfg_git_server_ua"
24 export GIT_USER_AGENT
25 GIT_HTTP_USER_AGENT="$cfg_git_server_ua"
26 export GIT_HTTP_USER_AGENT
29 [ -z "$GIT_HTTP_BACKEND_BIN" ] || cfg_git_http_backend_bin="$GIT_HTTP_BACKEND_BIN"
30 [ -n "$cfg_git_http_backend_bin" ] ||
31 cfg_git_http_backend_bin="$($cfg_git_bin --exec-path)/git-http-backend"
33 GIT_PROJECT_ROOT="$cfg_reporoot"
34 export GIT_PROJECT_ROOT
36 # This script is called for both fetch and push.
37 # Only the following conditions trigger a push permissions check:
39 # 1. REQUEST_METHOD=GET
40 # and PATH_INFO ends with "/info/refs"
41 # and QUERY_STRING has "service=git-receive-pack"
43 # 2. REQUEST_METHOD=POST
44 # and PATH_INFO ends with "/git-receive-pack"
46 # Note that there is no check for PATH_INFO being under a certain root as
47 # GIT_PROJECT_ROOT will be exported and set so all PATH_INFO values are
48 # effectively forced under the desired root.
50 # The REQUEST_METHOD is validated. For smart HTTP requests only the project
51 # name is extracted and validated and the corresponding project directory must
52 # exist under $cfg_reporoot. Non-smart HTTP fetch requests (GET or HEAD) are
53 # passed on unchanged and unchecked.
55 errorhdrs()
57 printf '%s\r\n' "Status: $1 $2"
58 printf '%s\r\n' "Expires: Fri, 01 Jan 1980 00:00:00 GMT"
59 printf '%s\r\n' "Pragma: no-cache"
60 printf '%s\r\n' "Cache-Control: no-cache, max-age=0, must-revalidate"
61 [ -z "$3" ] || printf '%s\r\n' "$3"
62 printf '%s\r\n' "Content-Type: text/plain"
63 printf '\r\n'
66 msglines()
68 while [ $# -gt 0 ]; do
69 printf '%s\n' "$1"
70 shift
71 done
74 internalerr()
76 errorhdrs 500 "Internal Server Error"
77 if [ $# -eq 0 ]; then
78 msglines "Internal Server Error"
79 echo "Internal Server Error" >&2
80 else
81 msglines "$@"
82 while [ $# -gt 0 ]; do
83 printf '%s\n' "$1" >&2
84 shift
85 done
87 exit 0
90 methodnotallowed()
92 errorhdrs 405 "Method Not Allowed" "Allow: GET, HEAD, POST"
93 if [ $# -eq 0 ]; then
94 msglines "Method Not Allowed"
95 else
96 msglines "$@"
98 exit 0
101 forbidden()
103 errorhdrs 403 Forbidden
104 if [ $# -eq 0 ]; then
105 msglines "Forbidden"
106 else
107 msglines "$@"
109 exit 0
112 needsauth()
114 errorhdrs 401 "Authorization Required"
115 if [ $# -eq 0 ]; then
116 msglines "Authorization Required"
117 else
118 msglines "$@"
120 exit 0
123 # A quick sanity check
124 if [ -z "$cfg_git_http_backend_bin" ] || ! [ -x "$cfg_git_http_backend_bin" ]; then
125 internalerr "bad cfg_git_http_backend_bin: $cfg_git_http_backend_bin"
126 exit 1
128 case "$cfg_reporoot" in /?*) :;; *)
129 internalerr "bad reporoot: $cfg_reporoot"
130 exit 1
131 esac
132 [ -n "$GIT_PROJECT_ROOT" ] || { internalerr 'GIT_PROJECT_ROOT must be set'; exit 1; }
134 PATH="$(dirname "$cfg_git_http_backend_bin"):$PATH"
135 export PATH
137 proj=
138 smart=
139 suffix=
140 needsauthcheck=
141 pathcheck="${PATH_INFO#/}"
142 if [ "$REQUEST_METHOD" = "GET" -o "$REQUEST_METHOD" = "HEAD" ]; then
143 # We do not currently validate non-smart GET/HEAD requests.
144 # There are only 8 possible suffix values that need to be allowed for
145 # non-smart HTTP GET/HEAD fetches (see http-backend.c):
146 # /HEAD
147 # /info/refs
148 # /objects/info/alternates
149 # /objects/info/http-alternates
150 # /objects/info/packs
151 # /objects/[0-9a-f]{2}/[0-9a-f]{38}
152 # /objects/pack/pack-[0-9a-f]{40}.idx
153 # /objects/pack/pack-[0-9a-f]{40}.pack
154 case "$pathcheck" in *"/info/refs")
155 proj="${pathcheck%/info/refs}"
156 case "&$QUERY_STRING&" in
157 *"&service=git-receive-pack&"*)
158 smart=1
159 needsauthcheck=1
160 suffix=info/refs
162 *"&service=git-upload-pack&"*)
163 smart=1
164 suffix=info/refs
166 esac
167 esac
168 elif [ "$REQUEST_METHOD" = "POST" ]; then
169 case "$pathcheck" in
170 *"/git-receive-pack")
171 smart=1
172 needsauthcheck=1
173 proj="${pathcheck%/git-receive-pack}"
174 suffix=git-receive-pack
176 *"/git-upload-pack")
177 smart=1
178 proj="${pathcheck%/git-upload-pack}"
179 suffix=git-upload-pack
182 forbidden
183 exit 1
185 esac
186 else
187 methodnotallowed
188 exit 1
191 # Reject any project names that start with _
192 case "$pathcheck" in _*)
193 forbidden
194 esac
196 if [ -n "$smart" ]; then
197 # add a missing trailing .git
198 case "$proj" in
199 *.git) :;;
201 proj="$proj.git"
202 esac
204 reporoot="$cfg_reporoot"
205 dir="$reporoot/$proj"
207 # Valid project names never end in .git (we add that automagically), so a valid
208 # fork can never have .git at the end of any path component except the last.
209 # We check this to avoid a situation where a certain collection of pushed refs
210 # could be mistaken for a GIT_DIR. Git would ultimately complain, but some
211 # undesirable things could happen along the way.
213 # Remove the leading $reporoot and trailing .git to get a test string
214 testpath="${dir#$reporoot/}"
215 testpath="${testpath%.git}"
216 case "$testpath/" in *.[Gg][Ii][Tt]/*|_*)
217 forbidden
218 exit 1
219 esac
221 if ! [ -d "$dir" ] || ! [ -f "$dir/HEAD" ] || ! [ -d "$dir/objects" ]; then
222 forbidden
223 exit 1
227 if [ -z "$needsauthcheck" ] || [ -z "$smart" ]; then
228 if [ -n "$GIT_HTTP_BACKEND_SHOW_ERRORS" ]; then
229 exec "$cfg_git_http_backend_bin" "$@"
230 else
231 exec "$cfg_git_http_backend_bin" "$@" 2>/dev/null
233 internalerr "exec failed: $cfg_git_http_backend_bin"
234 exit 1
237 projbare="${proj%.git}"
239 if ! [ -f "$dir/.nofetch" ]; then
240 forbidden "The $proj project is a mirror and may not be pushed to, sorry"
241 exit 1
244 authuser="${REMOTE_USER#/UID=}"
245 authuuid="${authuser}"
246 authuser="${authuser%/dnQualifier=*}"
247 authuuid="${authuuid#$authuser}"
248 authuuid="${authuuid#/dnQualifier=}"
249 if [ -z "$authuser" ]; then
250 needsauth "Only authenticated users may push, sorry"
251 exit 1
253 if [ "$authuser" != "mob" -o "$cfg_mob" != "mob" ]; then
254 if ! useruuid="$("$cfg_basedir/bin/get_user_uuid" "$authuser")" || [ "$useruuid" != "$authuuid" ]; then
255 forbidden "The user '$authuser' certificate being used is no longer valid." \
256 "You may download a new user certificate at $cfg_webadmurl/edituser.cgi"
257 exit 1
261 if ! "$cfg_basedir/bin/can_user_push_http" "$projbare" "$authuser"; then
262 # If mob is enabled and mob has push permissions and
263 # the current user is not the mob then it's a personal mob push
264 # presuming the special mob directory has been set up
265 if [ "$cfg_mob" = "mob" -a "$authuser" != "mob" -a -d "$cfg_reporoot/$proj/mob" ] &&
266 "$cfg_basedir/bin/can_user_push_http" "$projbare" "mob"; then
268 umask 113
269 > "$cfg_chroot/etc/sshactive/${authuser},"
270 mv -f "$cfg_chroot/etc/sshactive/${authuser}," "$cfg_chroot/etc/sshactive/${authuser}"
272 export PATH_INFO="/$proj/mob/$suffix"
273 if [ -n "$GIT_HTTP_BACKEND_SHOW_ERRORS" ]; then
274 exec "$cfg_git_http_backend_bin" "$@"
275 else
276 exec "$cfg_git_http_backend_bin" "$@" 2>/dev/null
278 internalerr "exec failed: $cfg_git_http_backend_bin"
279 exit 1
281 forbidden "The user '$authuser' does not have push permissions for project '$proj'." \
282 "You may adjust push permissions at $cfg_webadmurl/editproj.cgi?name=$proj"
283 exit 1
287 umask 113
288 > "$cfg_chroot/etc/sshactive/${authuser},"
289 mv -f "$cfg_chroot/etc/sshactive/${authuser}," "$cfg_chroot/etc/sshactive/${authuser}"
291 if [ -n "$GIT_HTTP_BACKEND_SHOW_ERRORS" ]; then
292 exec "$cfg_git_http_backend_bin" "$@"
293 else
294 exec "$cfg_git_http_backend_bin" "$@" 2>/dev/null
296 internalerr "exec failed: $cfg_git_http_backend_bin"
297 exit 1