ssh: enable fetches using "git" user
[girocco.git] / bin / git-shell-verify
blob91815acb547150160cfa4cfa358d0a8be4463b8f
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 # This script is intended for use from within the chroot jail and may or may
7 # not work properly outside it.
9 set -e
11 # git_add_config "some.var=value"
12 # every ' in value must be replaced with the 4-character sequence '\'' before
13 # calling this function or Git will barf. Will not be effective unless running
14 # Git version 1.7.3 or later.
15 git_add_config() {
16 GIT_CONFIG_PARAMETERS="${GIT_CONFIG_PARAMETERS:+$GIT_CONFIG_PARAMETERS }'$1'"
17 export GIT_CONFIG_PARAMETERS
20 GIT_CONFIG_NOSYSTEM=1
21 GIT_ATTR_NOSYSTEM=1
22 GIT_NO_REPLACE_OBJECTS=1
23 GIT_TERMINAL_PROMPT=0
25 if ! [ -x @perlbin@ ]; then
26 # We are INSIDE the chroot
27 reporoot=/@jailreporoot@
28 XDG_CONFIG_HOME=/var/empty
29 HOME=/etc/girocco
30 GIT_ASKPASS=/bin/git-askpass-password
31 else
32 # We are NOT INSIDE the chroot
33 reporoot=@reporoot@
34 XDG_CONFIG_HOME=@chroot@/var/empty
35 HOME=@chroot@/etc/girocco
36 GIT_ASKPASS=@basedir@/bin/git-askpass-password
38 mob=@mob@
39 webadmurl=@webadmurl@
40 ua=@git_server_ua@
41 defined_ua=@defined_git_server_ua@
42 cfg_git_no_mmap=@git_no_mmap@
43 var_big_file_threshold=@big_file_threshold@
44 var_upload_window=@upload_pack_window@
46 export XDG_CONFIG_HOME
47 export HOME
48 export GIT_CONFIG_NOSYSTEM
49 export GIT_ATTR_NOSYSTEM
50 export GIT_NO_REPLACE_OBJECTS
51 export GIT_TERMINAL_PROMPT
52 export GIT_ASKPASS
53 unset GIT_USER_AGENT
54 unset GIT_HTTP_USER_AGENT
55 if [ -n "$defined_ua" ]; then
56 GIT_USER_AGENT="$ua"
57 export GIT_USER_AGENT
58 GIT_HTTP_USER_AGENT="$ua"
59 export GIT_HTTP_USER_AGENT
61 unset GIT_CONFIG_PARAMETERS
62 git_add_config "core.ignoreCase=false"
63 if [ -n "$cfg_git_no_mmap" ]; then
64 # Just like compiling with NO_MMAP
65 git_add_config "core.packedGitWindowSize=1m"
66 else
67 # Always use the 32-bit default (32m) even on 64-bit to avoid memory blowout
68 git_add_config "core.packedGitWindowSize=32m"
70 [ -z "$var_big_file_threshold" ] ||
71 git_add_config "core.bigFileThreshold=$var_big_file_threshold"
73 # Only the following commands are allowed:
75 # git-shell -c "git-receive-pack 'dir'"
76 # git-shell -c "git receive-pack 'dir'"
77 # git-shell -c "git-upload-pack 'dir'"
78 # git-shell -c "git upload-pack 'dir'"
79 # git-shell -c "git-upload-archive 'dir'"
80 # git-shell -c "git upload-archive 'dir'"
82 # where dir must start with $reporoot/ but a leading/trailing '/' is optional
83 # as well as the final .git however if $dir does not start with $reporoot but
84 # adding a $reporoot prefix makes it work then the $reporoot prefix will be
85 # silently added.
87 if [ "$1" != "-c" ]; then
88 echo forbidden >&2
89 exit 1
92 dir="$2"
93 type=''
94 case "$2" in
95 "git-receive-pack "*) type='receive-pack'; dir="${dir#git-receive-pack }";;
96 "git receive-pack "*) type='receive-pack'; dir="${dir#git receive-pack }";;
97 "git-upload-pack "*) type='upload-pack'; dir="${dir#git-upload-pack }";;
98 "git upload-pack "*) type='upload-pack'; dir="${dir#git upload-pack }";;
99 "git-upload-archive "*) type='upload-archive'; dir="${dir#git-upload-archive }";;
100 "git upload-archive "*) type='upload-archive'; dir="${dir#git upload-archive }";;
102 echo forbidden >&2
103 exit 1
104 esac
106 # valid project names only allow 0-9A-Za-z._+- plus the / separator and they
107 # are always single quoted so the only valid directory names will always start
108 # with a single quote and end with a single quote and not contain any internal
109 # character that needs to be escaped.
111 case "$dir" in
112 "'"*) :;;
114 echo forbidden >&2
115 exit 1
116 esac
117 case "$dir" in
118 *"'") :;;
120 echo forbidden >&2
121 exit 1
122 esac
124 # Some shells do not properly handle quoting after # or % so we cannot
125 # put an explicit ' there in a way that works for all shells. Instead
126 # just remove a single character since we've already verified it's a '.
127 dir="${dir#?}"; dir="${dir%?}"
129 # add a missing leading /
130 case "$dir" in
131 /*) :;;
133 dir="/$dir"
134 esac
136 # remove a trailing /
137 case "$dir" in
138 *?/)
139 dir="${dir%/}"
140 esac
142 # add a missing trailing .git
143 case "$dir" in
144 *.git) :;;
146 dir="$dir.git"
147 esac
149 # do not allow any .. sequence
150 case "$dir" in *..*)
151 echo forbidden >&2
152 exit 1
153 esac
155 case "$dir" in
156 "$reporoot/"*) :;;
158 # Allow it if prefixing with $reporoot matches an existing directory
159 if [ -d "$reporoot$dir" ]; then
160 dir="$reporoot$dir"
161 else
162 echo forbidden >&2
163 exit 1
165 esac
167 # Valid project names never end in .git (we add that automagically), so a valid
168 # fork can never have .git at the end of any path component except the last.
169 # We check this to avoid a situation where a certain collection of pushed refs
170 # could be mistaken for a GIT_DIR. Git would ultimately complain, but some
171 # undesirable things could happen along the way.
173 # Remove the leading $reporoot and trailing .git to get a test string
174 testpath="${dir#$reporoot/}"
175 testpath="${testpath%.git}"
176 case "$testpath/" in *.[Gg][Ii][Tt]/*|_*)
177 echo forbidden >&2
178 exit 1
179 esac
181 if ! [ -d "$dir" ] || ! [ -f "$dir/HEAD" ] || ! [ -d "$dir/objects" ]; then
182 echo forbidden >&2
183 exit 1
186 proj="${dir#$reporoot/}"; projbare="${proj%.git}"
188 if [ "$type" = 'receive-pack' ] && [ "$LOGNAME" = 'git' ]; then
189 echo "The user '$LOGNAME' may only be used for fetches, sorry" >&2
190 exit 3
193 if [ "$type" = 'receive-pack' ] && ! [ -f "$dir/.nofetch" ]; then
194 echo "The $proj project is a mirror and may not be pushed to, sorry" >&2
195 exit 3
198 if [ "$type" = 'receive-pack' ]; then
199 git_add_config 'receive.unpackLimit=1'
200 # Note the git config documentation is wrong
201 # transfer.unpackLimit, if set, overrides receive.unpackLimit
202 git_add_config 'transfer.unpackLimit=1'
205 if ! [ -x @perlbin@ ] && [ "$type" = 'receive-pack' ]; then
206 # We are INSIDE the chroot trying to push
208 if ! can_user_push "$projbare"; then
209 # If mob is enabled and mob has push permissions and
210 # the current user is not the mob then it's a personal mob push
211 # presuming the special mob directory has been set up
212 if [ "$mob" = "mob" -a "$LOGNAME" != "mob" -a -d "$reporoot/$proj/mob" ] &&
213 can_user_push "$projbare" mob; then
215 umask 113
216 > "/etc/sshactive/${LOGNAME},"
217 mv -f "/etc/sshactive/${LOGNAME}," "/etc/sshactive/${LOGNAME}"
218 ! [ -e "$dir/.delaygc" ] || > "$dir/.allowgc" || :
220 exec git-shell -c "git-receive-pack '$reporoot/$proj/mob'"
221 exit 1
223 echo "The user '$LOGNAME' does not have push permissions for project '$proj'" >&2
224 echo "You may adjust push permissions at $webadmurl/editproj.cgi?name=$proj" >&2
225 exit 3
228 umask 113
229 > "/etc/sshactive/${LOGNAME},"
230 mv -f "/etc/sshactive/${LOGNAME}," "/etc/sshactive/${LOGNAME}"
231 ! [ -e "$dir/.delaygc" ] || > "$dir/.allowgc" || :
235 [ -z "$var_upload_window" ] || [ "$type" != "upload-pack" ] || \
236 git_add_config "pack.window=$var_upload_window"
238 exec git-shell -c "git-$type '$dir'"
239 exit 1