3
# Copyright 2008-2009 LShift Ltd
4
# Copyright 2005-2007 by Intevation GmbH <intevation@intevation.de>
6
# Paul Crowley <paul@lshift.net>
7
# Thomas Arendsen Hein <thomas@intevation.de>
8
# with ideas from Mathieu PASQUET <kiorky@cryptelium.net>
10
# This software may be used and distributed according to the terms
11
# of the GNU General Public License, incorporated herein by reference.
14
hg-ssh - limit access to hg repositories reached via ssh. Part of
17
This script is called by hg-ssh-wrapper with no arguments - everything
18
should be in enviroment variables:
20
HG_ACCESS_RULES_PATH identifies the paths to the rule files
21
REMOTE_USER the remote user (which is the key used by ssh)
22
SSH_ORIGINAL_COMMAND the command the user was trying to run
24
It uses SSH_ORIGINAL_COMMAND to determine what the user was trying to
25
do and to what repository, and then checks each rule in the rule file
26
in turn for a matching rule which decides what to do, defaulting to
27
disallowing the action.
31
# enable importing on demand to reduce startup time
32
from mercurial import demandimport; demandimport.enable()
34
from mercurial import dispatch
36
import sys, os, os.path
38
from mercurialserver import ruleset, paths
41
sys.stderr.write("mercurial-server: %s\n" % message)
45
head, tail = os.path.split(path)
46
if tail.startswith("."):
47
fail("paths cannot contain dot file components")
51
def checkParents(path):
52
path = os.path.dirname(path)
55
if os.path.exists(path + "/.hg"):
56
fail("Cannot create repo under existing repo")
59
def getrepo(op, repo):
60
# First canonicalise, then check the string, then the rules
61
# and finally the filesystem.
62
repo = repo.rstrip("/")
64
fail("path to repository seems to be empty")
65
if repo.startswith("/"):
66
fail("absolute paths are not supported")
68
ruleset.rules.set(repo=repo)
69
if not ruleset.rules.allow(op, branch=None, file=None):
76
if len(sys.argv) == 3 and sys.argv[1] == "--base64":
77
ruleset.rules.set(user = base64.b64decode(sys.argv[2]))
78
elif len(sys.argv) == 2:
79
ruleset.rules.set(user = sys.argv[1])
81
fail("hg-ssh wrongly called, is authorized_keys corrupt? (%s)"
84
# Use a different hgrc for remote pulls - this way you can set
85
# up access.py for everything at once without affecting local operations
87
os.environ['HGRCPATH'] = paths.getHgrcPaths()
89
os.chdir(paths.getReposPath())
91
for f in paths.getAccessPaths():
93
ruleset.rules.readfile(f)
95
cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None)
97
fail("direct logins on the hg account prohibited")
98
elif cmd.startswith('hg -R ') and cmd.endswith(' serve --stdio'):
99
repo = getrepo("read", cmd[6:-14])
100
if not os.path.isdir(repo + "/.hg"):
101
fail("no such repository %s" % repo)
102
dispatch.dispatch(['-R', repo, 'serve', '--stdio'])
103
elif cmd.startswith('hg init '):
104
repo = getrepo("init", cmd[8:])
105
if os.path.exists(repo):
106
fail("%s exists" % repo)
107
d = os.path.dirname(repo)
108
if d != "" and not os.path.isdir(d):
110
dispatch.dispatch(['init', repo])
112
fail("illegal command %r" % cmd)