forked from nodester/nodester
-
Notifications
You must be signed in to change notification settings - Fork 0
/
git-shell-enforce-directory
executable file
·91 lines (74 loc) · 2.83 KB
/
git-shell-enforce-directory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/python
# Copyright (c) 2007 Tommi Virtanen <tv@eagain.net>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Enforce git-shell to only serve repositories
# in the given directory. The client should refer
# to them without any directory prefix.
# Repository names are forced to match ALLOW.
import sys, os, optparse, re
def die(msg):
print >>sys.stderr, '%s: %s' % (sys.argv[0], msg)
sys.exit(1)
def getParser():
parser = optparse.OptionParser(
usage='%prog [OPTIONS] DIR',
description='Allow restricted git operations under DIR',
)
parser.add_option('--read-only',
help='disable write operations',
action='store_true',
default=False,
)
return parser
ALLOW_RE = re.compile("^(?P<command>git-(?:receive|upload)-pack) '[a-zA-Z0-9@._-]*(/[a-zA-Z0-9@._-]*)*'$")
COMMANDS_READONLY = [
'git-upload-pack',
]
COMMANDS_WRITE = [
'git-receive-pack',
]
def main(args):
os.umask(0022)
parser = getParser()
(options, args) = parser.parse_args()
try:
(path,) = args
except ValueError:
parser.error('Missing argument DIR.')
os.chdir(path)
cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None)
if cmd is None:
die("Need SSH_ORIGINAL_COMMAND in environment.")
if '\n' in cmd:
die("Command may not contain newlines.")
match = ALLOW_RE.match(cmd)
if match is None:
die("Command to run looks dangerous")
allowed = list(COMMANDS_READONLY)
if not options.read_only:
allowed.extend(COMMANDS_WRITE)
if match.group('command') not in allowed:
die("Command not allowed")
os.execve('/usr/bin/git-shell', ['git-shell', '-c', cmd], {})
die("Cannot execute git-shell.")
if __name__ == '__main__':
main(args=sys.argv[1:])