Add support for personal mob.user branches
[girocco.git] / bin / git-http-backend-verify
blobc31a8b116664210d67a4226ced4c15590d0c4c48
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 must be set to use this script.
12 # Also prevent standard error output from git-http-backend cluttering up the
13 # server's log unless GIT_HTTP_BACKEND_SHOW_ERRORS is set to a non-empty value.
15 set -e
17 . @basedir@/shlib.sh
19 [ -z "$GIT_HTTP_BACKEND_BIN" ] || cfg_git_http_backend_bin="$GIT_HTTP_BACKEND_BIN"
20 [ -n "$cfg_git_http_backend_bin" ] ||
21 cfg_git_http_backend_bin=/usr/lib/git-core/git-http-backend
23 # This script is called for both fetch and push.
24 # Only the following conditions trigger a push permissions check:
26 # 1. REQUEST_METHOD=GET
27 # and PATH_INFO ends with "/info/refs"
28 # and QUERY_STRING has "service=git-receive-pack"
30 # 2. REQUEST_METHOD=POST
31 # and PATH_INFO ends with "/git-receive-pack"
33 # Note that there is no check for PATH_INFO being under a certain root as
34 # it's presumed that GIT_PROJECT_ROOT has been set and so all PATH_INFO
35 # values are effectively forced under the desired root.
36 # The project name is, however, extracted and the project directory must exist
37 # under $cfg_reporoot.
39 errorhdrs()
41 # A single CR (0x0d) is between the quotes
42 cr=" "
43 echo "Status: $1 $2$cr"
44 echo "Expires: Fri, 01 Jan 1980 00:00:00 GMT$cr"
45 echo "Pragma: no-cache$cr"
46 echo "Cache-Control: no-cache, max-age=0, must-revalidate$cr"
47 echo "Content-Type: text/plain$cr"
48 echo "$cr"
51 msglines()
53 while [ $# -gt 0 ]; do
54 echo "$1"
55 shift
56 done
59 internalerr()
61 errorhdrs 500 "Internal Server Error"
62 if [ $# -eq 0 ]; then
63 msglines "Internal Server Error"
64 echo "Internal Server Error" >&2
65 else
66 msglines "$@"
67 while [ $# -gt 0 ]; do
68 echo "$1" >&2
69 shift
70 done
72 exit 0
75 forbidden()
77 errorhdrs 403 Forbidden
78 if [ $# -eq 0 ]; then
79 msglines "Forbidden"
80 else
81 msglines "$@"
83 exit 0
86 needsauth()
88 errorhdrs 401 "Authorization Required"
89 if [ $# -eq 0 ]; then
90 msglines "Authorization Required"
91 else
92 msglines "$@"
94 exit 0
97 [ -n "$GIT_PROJECT_ROOT" ] || { internalerr 'GIT_PROJECT_ROOT must be set'; exit 1; }
99 proj=
100 suffix=
101 needscheck=
102 pathcheck="${PATH_INFO#/}"
103 if [ "$REQUEST_METHOD" = "GET" -o "$REQUEST_METHOD" = "HEAD" ]; then
104 case "$pathcheck" in *"/info/refs")
105 case "&$QUERY_STRING&" in *"&service=git-receive-pack&"*)
106 needscheck=1
107 proj="${pathcheck%/info/refs}"
108 suffix=info/refs
109 esac
110 esac
111 elif [ "$REQUEST_METHOD" = "POST" ]; then
112 case "$pathcheck" in *"/git-receive-pack")
113 needscheck=1
114 proj="${pathcheck%/git-receive-pack}"
115 suffix=git-receive-pack
116 esac
119 if [ -z "$needscheck" ]; then
120 if [ -n "$GIT_HTTP_BACKEND_SHOW_ERRORS" ]; then
121 exec "$cfg_git_http_backend_bin" "$@"
122 else
123 exec "$cfg_git_http_backend_bin" "$@" 2>/dev/null
125 internalerr "exec failed: $cfg_git_http_backend_bin"
126 exit 1
129 # add a missing trailing .git
130 case "$proj" in
131 *.git) :;;
133 proj="$proj.git"
134 esac
136 dir="$cfg_reporoot/$proj"
137 if ! [ -d "$dir" ] || ! [ -f "$dir/HEAD" ] || ! [ -d "$dir/objects" ]; then
138 forbidden
139 exit 1
142 projbare="${proj%.git}"
144 if ! [ -f "$dir/.nofetch" ]; then
145 forbidden "The $proj project is a mirror and may not be pushed to, sorry"
146 exit 1
149 authuser="${REMOTE_USER#/UID=}"
150 authuuid="${authuser}"
151 authuser="${authuser%/dnQualifier=*}"
152 authuuid="${authuuid#$authuser}"
153 authuuid="${authuuid#/dnQualifier=}"
154 if [ -z "$authuser" ]; then
155 needsauth "Only authenticated users may push, sorry"
156 exit 1
159 if perl -I@basedir@ -MGirocco::Project -MGirocco::User <<EOT; then :; else
160 my \$p = Girocco::Project->load('$projbare');
161 exit 1 unless \$p && \$p->can_user_push('$authuser');
162 exit 0 if \$Girocco::Config::mob eq 'mob' && '$authuser' eq 'mob';
163 my \$u = Girocco::User->load('$authuser');
164 exit 2 unless \$u && \$u->{uuid} eq '$authuuid';
165 exit 0
167 if [ $? -eq 2 ]; then
168 forbidden "The user '$authuser' certificate being used is no longer valid." \
169 "You may download a new user certificate at $cfg_webadmurl/edituser.cgi"
170 else
171 # If mob is enabled and mob has push permissions and
172 # the current user is not the mob then it's a personal mob push
173 # presuming the special mob directory has been set up
174 if [ "$cfg_mob" = "mob" -a "$authuser" != "mob" -a -d "$cfg_reporoot/$proj/mob" ] &&
175 perl -I@basedir@ -MGirocco::Project -e 'exit(1) unless Girocco::Project->load("'$projbare'")->can_user_push("'mob'")'; then
176 export PATH_INFO="/$proj/mob/$suffix"
177 exec "$cfg_git_http_backend_bin" "$@"
178 internalerr "exec failed: $cfg_git_http_backend_bin"
179 exit 1
181 forbidden "The user '$authuser' does not have push permissions for project '$proj'." \
182 "You may adjust push permissions at $cfg_webadmurl/editproj.cgi?name=$proj"
184 exit 1
187 if [ -n "$GIT_HTTP_BACKEND_SHOW_ERRORS" ]; then
188 exec "$cfg_git_http_backend_bin" "$@"
189 else
190 exec "$cfg_git_http_backend_bin" "$@" 2>/dev/null
192 internalerr "exec failed: $cfg_git_http_backend_bin"
193 exit 1