Remember time of last user push activity
[girocco.git] / bin / git-shell-verify
blob351fde703b200420040853044a309c2cc3baa1ef
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 if ! [ -x /usr/bin/perl ]; then
12 # We are INSIDE the chroot
13 reporoot=/@jailreporoot@
14 else
15 # We are NOT INSIDE the chroot
16 reporoot=@reporoot@
18 mob=@mob@
19 webadmurl=@webadmurl@
21 # Only the following commands are allowed:
23 # git-shell -c "git-receive-pack 'dir'"
24 # git-shell -c "git receive-pack 'dir'"
25 # git-shell -c "git-upload-pack 'dir'"
26 # git-shell -c "git upload-pack 'dir'"
27 # git-shell -c "git-upload-archive 'dir'"
28 # git-shell -c "git upload-archive 'dir'"
30 # where dir must start with $reporoot/ but a leading/trailing '/' is optional
31 # as well as the final .git however if $dir does not start with $reporoot but
32 # adding a $reporoot prefix makes it work then the $reporoot prefix will be
33 # silently added.
35 if [ "$1" != "-c" ]; then
36 echo forbidden >&2
37 exit 1
40 dir="$2"
41 type=''
42 case "$2" in
43 "git-receive-pack "*) type='receive-pack'; dir="${dir#git-receive-pack }";;
44 "git receive-pack "*) type='receive-pack'; dir="${dir#git receive-pack }";;
45 "git-upload-pack "*) type='upload-pack'; dir="${dir#git-upload-pack }";;
46 "git upload-pack "*) type='upload-pack'; dir="${dir#git upload-pack }";;
47 "git-upload-archive "*) type='upload-archive'; dir="${dir#git-upload-archive }";;
48 "git upload-archive "*) type='upload-archive'; dir="${dir#git upload-archive }";;
50 echo forbidden >&2
51 exit 1
52 esac
54 # valid project names only allow 0-9A-Za-z._+- plus the / separator and they
55 # are always single quoted so the only valid directory names will always start
56 # with a single quote and end with a single quote and not contain any internal
57 # character that needs to be escaped.
59 case "$dir" in
60 "'"*) :;;
62 echo forbidden >&2
63 exit 1
64 esac
65 case "$dir" in
66 *"'") :;;
68 echo forbidden >&2
69 exit 1
70 esac
72 # Some shells do not properly handle quoting after # or % so we cannot
73 # put an explicit ' there in a way that works for all shells. Instead
74 # just remove a single character since we've already verified it's a '.
75 dir="${dir#?}"; dir="${dir%?}"
77 # add a missing leading /
78 case "$dir" in
79 /*) :;;
81 dir="/$dir"
82 esac
84 # remove a trailing /
85 case "$dir" in
86 *?/)
87 dir="${dir%/}"
88 esac
90 # add a missing trailing .git
91 case "$dir" in
92 *.git) :;;
94 dir="$dir.git"
95 esac
97 case "$dir" in
98 "$reporoot/"*) :;;
100 # Allow it if prefixing with $reporoot matches an existing directory
101 if [ -d "$reporoot$dir" ]; then
102 dir="$reporoot$dir"
103 else
104 echo forbidden >&2
105 exit 1
107 esac
109 # Valid project names never end in .git (we add that automagically), so a valid
110 # fork can never have .git at the end of any path component except the last.
111 # We check this to avoid a situation where a certain collection of pushed refs
112 # could be mistaken for a GIT_DIR. Git would ultimately complain, but some
113 # undesirable things could happen along the way.
115 # Remove the leading $reporoot and trailing .git to get a test string
116 testpath="${dir#$reporoot/}"
117 testpath="${testpath%.git}"
118 case "$testpath/" in *.[Gg][Ii][Tt]/*)
119 echo forbidden >&2
120 exit 1
121 esac
123 if ! [ -d "$dir" ] || ! [ -f "$dir/HEAD" ] || ! [ -d "$dir/objects" ]; then
124 echo forbidden >&2
125 exit 1
128 proj="${dir#$reporoot/}"; projbare="${proj%.git}"
130 if [ "$type" = 'receive-pack' ] && ! [ -f "$dir/.nofetch" ]; then
131 echo "The $proj project is a mirror and may not be pushed to, sorry" >&2
132 exit 3
135 if ! [ -x /usr/bin/perl ] && [ "$type" = 'receive-pack' ]; then
136 # We are INSIDE the chroot trying to push
138 if ! can_user_push "$projbare"; then
139 # If mob is enabled and mob has push permissions and
140 # the current user is not the mob then it's a personal mob push
141 # presuming the special mob directory has been set up
142 if [ "$mob" = "mob" -a "$LOGNAME" != "mob" -a -d "$reporoot/$proj/mob" ] &&
143 can_user_push "$projbare" mob; then
144 (umask 113; > "/etc/sshactive/$LOGNAME")
145 exec git-shell -c "git-receive-pack '$reporoot/$proj/mob'"
146 exit 1
148 echo "The user '$LOGNAME' does not have push permissions for project '$proj'" >&2
149 echo "You may adjust push permissions at $webadmurl/editproj.cgi?name=$proj" >&2
150 exit 3
152 (umask 113; > "/etc/sshactive/$LOGNAME")
155 exec git-shell -c "git-$type '$dir'"
156 exit 1