|
1 #!/usr/bin/env python |
|
2 # |
|
3 # Copyright 2008 LShift Ltd |
|
4 # Copyright 2005-2007 by Intevation GmbH <intevation@intevation.de> |
|
5 # Authors: |
|
6 # Paul Crowley <paul@lshift.net> |
|
7 # Thomas Arendsen Hein <thomas@intevation.de> |
|
8 # with ideas from Mathieu PASQUET <kiorky@cryptelium.net> |
|
9 # |
|
10 # This software may be used and distributed according to the terms |
|
11 # of the GNU General Public License, incorporated herein by reference. |
|
12 |
|
13 """ |
|
14 hg-ssh - limit access to hg repositories reached via ssh. Part of |
|
15 hg-admin-tools. |
|
16 |
|
17 This script is called by hg-ssh-wrapper with no arguments - everything |
|
18 should be in enviroment variables: |
|
19 |
|
20 HG_ACCESS_RULES_FILE identifies the path to the rules file |
|
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 |
|
23 |
|
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. |
|
28 |
|
29 """ |
|
30 |
|
31 # enable importing on demand to reduce startup time |
|
32 from mercurial import demandimport; demandimport.enable() |
|
33 |
|
34 from mercurial import dispatch |
|
35 |
|
36 import sys, os |
|
37 import ruleset |
|
38 |
|
39 def fail(message): |
|
40 #logfile.write("Fail: %s\n" % message) |
|
41 sys.stderr.write(message + "\n") |
|
42 sys.exit(-1) |
|
43 |
|
44 def getpath(path): |
|
45 if path.endswith("/"): |
|
46 path = path[:-1] |
|
47 if not ruleset.goodpath(path): |
|
48 fail("Disallowing path: %s" % path) |
|
49 return path |
|
50 |
|
51 def get_cmd(rules, cmd): |
|
52 if cmd.startswith('hg -R ') and cmd.endswith(' serve --stdio'): |
|
53 repo = getpath(cmd[6:-14]) |
|
54 if rules.allow("read", repo=repo): |
|
55 os.environ["HG_REPO_PATH"] = repo |
|
56 return ['-R', repo, 'serve', '--stdio'] |
|
57 elif cmd.startswith('hg init '): |
|
58 repo = getpath(cmd[8:]) |
|
59 if rules.allow("init", repo=repo): |
|
60 os.environ["HG_REPO_PATH"] = repo |
|
61 return ['init', repo] |
|
62 fail("Illegal command %r" % cmd) |
|
63 |
|
64 #logfile = open("/tmp/hg-ssh.%d.txt" % os.getpid(), "w") |
|
65 #logfile.write("Started: %s\n" % sys.argv) |
|
66 |
|
67 if len(sys.argv) != 1: |
|
68 fail("hg-ssh must have no arguments (%s)" |
|
69 % sys.argv) |
|
70 |
|
71 rules = ruleset.Ruleset.readfile(os.environ['HG_ACCESS_RULES_FILE']) |
|
72 rules.set(user = getpath(os.environ['REMOTE_USER'])) |
|
73 rules.set(branch = None, file = None) |
|
74 todispatch = get_cmd(rules, |
|
75 os.environ.get('SSH_ORIGINAL_COMMAND', '?')) |
|
76 dispatch.dispatch(todispatch) |
|
77 |