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
|
import os, errno, re
import logging
log = logging.getLogger('gitosis.ssh')
_ACCEPTABLE_USER_RE = re.compile(r'^[a-z][a-z0-9_.-]*(@[a-z][a-z0-9.-]*)?$')
def isSafeUsername(user):
match = _ACCEPTABLE_USER_RE.match(user)
return (match is not None)
def readKeys(keydir):
"""
Read SSH public keys from ``keydir/*.pub``
"""
for filename in os.listdir(keydir):
if filename.startswith('.'):
continue
basename, ext = os.path.splitext(filename)
if ext != '.pub':
continue
if not isSafeUsername(basename):
log.warn('Unsafe SSH username in keyfile: %r', filename)
continue
path = os.path.join(keydir, filename)
f = file(path)
for line in f:
line = line.rstrip('\n')
yield (basename, line)
f.close()
COMMENT = '### autogenerated by gitosis, DO NOT EDIT'
def generateAuthorizedKeys(keys):
TEMPLATE=('command="gitosis-serve %(user)s",no-port-forwarding,'
+'no-X11-forwarding,no-agent-forwarding,no-pty %(key)s')
yield COMMENT
for (user, key) in keys:
yield TEMPLATE % dict(user=user, key=key)
_COMMAND_RE = re.compile('^command="(/[^ "]+/)?gitosis-serve [^"]+",no-port-forw'
+'arding,no-X11-forwarding,no-agent-forwardi'
+'ng,no-pty .*')
def filterAuthorizedKeys(fp):
"""
Read lines from ``fp``, filter out autogenerated ones.
Note removes newlines.
"""
for line in fp:
line = line.rstrip('\n')
if line == COMMENT:
continue
if _COMMAND_RE.match(line):
continue
yield line
def writeAuthorizedKeys(path, keydir):
tmp = '%s.%d.tmp' % (path, os.getpid())
try:
in_ = file(path)
except IOError, e:
if e.errno == errno.ENOENT:
in_ = None
else:
raise
try:
out = file(tmp, 'w')
try:
if in_ is not None:
for line in filterAuthorizedKeys(in_):
print >>out, line
keygen = readKeys(keydir)
for line in generateAuthorizedKeys(keygen):
print >>out, line
os.fsync(out)
finally:
out.close()
finally:
if in_ is not None:
in_.close()
os.rename(tmp, path)
|