#!/usr/bin/env python
#
# Copyright 2008-2009 LShift Ltd
# Copyright 2005-2007 by Intevation GmbH <intevation@intevation.de>
# Authors:
# Paul Crowley <paul@lshift.net>
# Thomas Arendsen Hein <thomas@intevation.de>
# with ideas from Mathieu PASQUET <kiorky@cryptelium.net>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
"""
hg-ssh - limit access to hg repositories reached via ssh. Part of
mercurial-server.
This script is called by hg-ssh-wrapper with no arguments - everything
should be in enviroment variables:
HG_ACCESS_RULES_PATH identifies the paths to the rule files
REMOTE_USER the remote user (which is the key used by ssh)
SSH_ORIGINAL_COMMAND the command the user was trying to run
It uses SSH_ORIGINAL_COMMAND to determine what the user was trying to
do and to what repository, and then checks each rule in the rule file
in turn for a matching rule which decides what to do, defaulting to
disallowing the action.
"""
# enable importing on demand to reduce startup time
from mercurial import demandimport; demandimport.enable()
from mercurial import dispatch
import sys, os
from mercurialserver import ruleset, paths
def fail(message):
#logfile.write("Fail: %s\n" % message)
sys.stderr.write(message + "\n")
sys.exit(-1)
def getpath(path):
if path.endswith("/"):
path = path[:-1]
if not ruleset.goodpath(path):
fail("Disallowing path: %s" % path)
return path
def try_cmd(rules, cmd):
if cmd.startswith('hg -R ') and cmd.endswith(' serve --stdio'):
repo = getpath(cmd[6:-14])
if rules.allow("read", repo=repo):
os.environ["HG_REPO_PATH"] = repo
dispatch.dispatch(['-R', repo, 'serve', '--stdio'])
return
elif cmd.startswith('hg init '):
repo = getpath(cmd[8:])
if rules.allow("init", repo=repo):
os.environ["HG_REPO_PATH"] = repo
dispatch.dispatch(['init', repo])
return
fail("Illegal command %r" % cmd)
#logfile = open("/tmp/hg-ssh.%d.txt" % os.getpid(), "w")
#logfile.write("Started: %s\n" % sys.argv)
if len(sys.argv) != 2:
fail("hg-ssh must have exactly one argument (%s)"
% sys.argv)
remote_user = sys.argv[1]
os.environ['REMOTE_USER'] = remote_user
# Use a different hgrc for remote pulls - this way you can set
# up access.py for everything at once without affecting local operations
os.environ['HGRCPATH'] = paths.getEtcPath() + "/remote-hgrc"
os.chdir('repos')
os.environ['HG_ACCESS_RULES_PATH'] = (
paths.getEtcPath() + "/access.conf" + ":" +
os.getcwd() + "/hgadmin/access.conf")
rules = ruleset.rules_from_env()
rules.set(user = getpath(remote_user))
rules.set(branch = None, file = None)
try_cmd(rules, os.environ.get('SSH_ORIGINAL_COMMAND', '?'))