various: add read-only mode support
[girocco.git] / bin / git-daemon-verify
blobecff6a41eb1b67383db421e349825cda909db956
1 #!/bin/sh
3 # Abort any fetch early if the fetch is invalid or times out.
4 # This avoids unnecessary traffic and unpacked object pollution.
6 # This script is called for fetch, archive and push.
7 # Push requests are outright rejected and so are paths starting with ~.
9 set -e
11 . @basedir@/shlib.sh
13 unset GIT_USER_AGENT
14 unset GIT_HTTP_USER_AGENT
15 if [ -n "$defined_cfg_git_server_ua" ]; then
16 GIT_USER_AGENT="$cfg_git_server_ua"
17 export GIT_USER_AGENT
20 [ -z "$GIT_DAEMON_BIN" ] || cfg_git_daemon_bin="$GIT_DAEMON_BIN"
21 [ -n "$cfg_git_daemon_bin" ] ||
22 cfg_git_daemon_bin="$var_git_exec_path/git-daemon"
24 fromip=
25 logmsg()
27 [ "${cfg_suppress_git_ssh_logging:-0}" = "0" ] || return 0
28 _msg="$(LC_ALL=C tr -c '\040-\176' '[?*]' <<EOT
29 $fromip$*
30 EOT
31 )" && _msg="${_msg%[?]}" &&
32 logger -t "${0##*/}[$$]" <<EOT
33 $_msg
34 EOT
37 errormsg()
39 _l="$*"
40 printf '%04xERR %s' $(( 8 + ${#_l} )) "$_l"
43 invalbaderr()
45 errormsg "invalid or incomplete request"
48 invalerr()
50 errormsg "invalid or unsupported request"
53 denied()
55 errormsg "access denied or no such repository"
58 internalerr()
60 printf '%s\n' "git-daemon-verify: $*" >&2
61 errormsg "internal server error"
64 # A quick sanity check
65 if [ -z "$cfg_git_daemon_bin" ] || ! [ -x "$cfg_git_daemon_bin" ]; then
66 internalerr "bad cfg_git_daemon_bin: $cfg_git_daemon_bin"
67 exit 1
69 case "$cfg_reporoot" in /?*) :;; *)
70 internalerr "bad reporoot: $cfg_reporoot"
71 exit 1
72 esac
74 PATH="$(dirname "$cfg_git_daemon_bin"):$PATH"
75 export PATH
77 if ! request="$("$cfg_basedir/bin/peek_packet")" || [ -z "$request" ]; then
78 invalbaderr
79 exit 1
82 _IFS="$IFS"
83 IFS='
85 set -- $request
86 IFS="$_IFS"
87 [ $# -ge 1 ] || { invalidbaderr; exit 1; }
88 request="$1"
89 shift
91 # Extract host and port now
92 REMOTE_ADDR=
93 REMOTE_PORT=
94 SERVER_ADDR=
95 SERVER_PORT=
96 [ "${hnam+set}" != "set" ] || unset hnam
97 [ "${pnum+set}" != "set" ] || unset pnum
98 [ "${hostport+set}" != "set" ] || unset hostport
99 for extra in "$@"; do
100 case "$extra" in
101 "host="*) hnam="${extra#host=}";;
102 "port="*) pnum="${extra#port=}";;
103 "server_addr="*) SERVER_ADDR="${extra#server_addr=}";;
104 "server_port="*) SERVER_PORT="${extra#server_port=}";;
105 "remote_addr="*) REMOTE_ADDR="${extra#remote_addr=}";;
106 "remote_port="*) REMOTE_PORT="${extra#remote_port=}";;
107 esac
108 done
109 # Make nice hostport variable for later use
110 fromip="$REMOTE_ADDR"
111 fromip="${fromip:+$fromip }"
112 if [ "${hnam+set}" = "set" ]; then
113 case "$hnam" in
114 *":"*) hostport="[$hnam]";;
115 *) hostport="$hnam";;
116 esac
117 [ "${pnum+set}" != "set" ] || hostport="$hostport:$pnum"
120 # Validate the host name if requested
121 if [ -z "$cfg_git_daemon_any_host" ] && [ -n "$cfg_git_daemon_host_list" ]; then
122 case " $cfg_git_daemon_host_list " in *" $hnam "*);;*)
123 logmsg "denied ${request#git-}${hostport+ host=$hostport}"
124 denied
125 exit 1
126 esac
129 # The request should look like one of the following
131 # git-upload-pack /dir
132 # git-upload-pack ~name/dir
133 # git-upload-archive /dir
134 # git-upload-archive ~name/dir
135 # git-receive-pack /dir
136 # git-receive-pack ~name/dir
138 # Where the '~' forms are relative to a user's home directory.
139 # A trailing '/' is optional as well as a final '.git'.
140 # git-receive-pack and paths starting with '~' are rejected outright.
142 type=
143 dir=
144 case "$request" in
145 "git-upload-pack "*) type='upload-pack'; dir="${request#git-upload-pack }";;
146 "git-upload-archive "*) type='upload-archive'; dir="${request#git-upload-archive }";;
147 "git-receive-pack "*) type='receive-pack'; dir="${request#git-receive-pack }";;
149 invalerr
150 exit 1
151 esac
152 if [ "$type" = 'receive-pack' ]; then
153 logmsg "denied $type $dir${hostport+ host=$hostport}"
154 invalerr
155 exit 1
157 case "$dir" in /*) :;; *)
158 logmsg "denied $type $dir${hostport+ host=$hostport}"
159 invalerr
160 exit 1
161 esac
163 # remove extraneous '/' chars
164 proj="${dir#/}"
165 proj="${proj%/}"
166 # add a missing .git
167 case "$proj" in
168 *.git) :;;
170 proj="$proj.git"
171 esac
173 # Reject any project names that start with _ or contain ..
174 case "$proj" in _*|*..*)
175 logmsg "denied $type $dir${hostport+ host=$hostport}"
176 denied
177 exit 1
178 esac
180 odir="$dir"
181 reporoot="$cfg_reporoot"
182 dir="$reporoot/$proj"
184 # Valid project names never end in .git (we add that automagically), so a valid
185 # fork can never have .git at the end of any path component except the last.
186 # We check this to avoid a situation where a certain collection of pushed refs
187 # could be mistaken for a GIT_DIR. Git would ultimately complain, but some
188 # undesirable things could happen along the way.
190 # Remove the leading $reporoot and trailing .git to get a test string
191 testpath="${dir#$reporoot/}"
192 testpath="${testpath%.git}"
193 case "$testpath/" in *.[Gg][Ii][Tt]/*|_*)
194 logmsg "denied $type $odir${hostport+ host=$hostport}"
195 denied
196 exit 1
197 esac
199 if ! [ -d "$dir" ] || ! [ -f "$dir/HEAD" ] || ! [ -d "$dir/objects" ]; then
200 logmsg "denied $type $odir${hostport+ host=$hostport}"
201 denied
202 exit 1
205 [ -z "$var_upload_window" ] || [ "$type" != "upload-pack" ] ||
206 git_add_config "pack.window=$var_upload_window"
208 if [ "${cfg_fetch_stash_refs:-0}" = "0" ]; then
209 git_add_config "uploadpack.hiderefs=refs/stash"
210 git_add_config "uploadpack.hiderefs=refs/tgstash"
213 logmsg "accepted $type $odir${hostport+ host=$hostport}"
214 exec "$cfg_git_daemon_bin" --inetd --verbose --export-all --enable=upload-archive --base-path="$cfg_reporoot"
215 internalerr "exec failed: $cfg_git_daemon_bin"
216 exit 1