31 # enable importing on demand to reduce startup time |
31 # enable importing on demand to reduce startup time |
32 from mercurial import demandimport; demandimport.enable() |
32 from mercurial import demandimport; demandimport.enable() |
33 |
33 |
34 from mercurial import dispatch |
34 from mercurial import dispatch |
35 |
35 |
36 import sys, os |
36 import sys, os, os.path |
|
37 import base64 |
37 from mercurialserver import ruleset, paths |
38 from mercurialserver import ruleset, paths |
38 |
39 |
39 def fail(message): |
40 def fail(message): |
40 #logfile.write("Fail: %s\n" % message) |
41 sys.stderr.write("mercurial-server: %s\n" % message) |
41 sys.stderr.write(message + "\n") |
|
42 sys.exit(-1) |
42 sys.exit(-1) |
43 |
43 |
44 def getpath(path): |
44 def checkDots(path): |
45 if path.endswith("/"): |
45 head, tail = os.path.split(path) |
46 path = path[:-1] |
46 if tail.startswith("."): |
47 if not ruleset.goodpath(path): |
47 fail("paths cannot contain dot file components") |
48 fail("Disallowing path: %s" % path) |
48 if head: |
49 return path |
49 checkDots(head) |
50 |
50 |
51 def try_cmd(cmd): |
51 def checkParents(path): |
52 if cmd.startswith('hg -R ') and cmd.endswith(' serve --stdio'): |
52 path = os.path.dirname(path) |
53 repo = getpath(cmd[6:-14]) |
53 if path == "": |
54 ruleset.rules.set(repo=repo) |
54 return |
55 if ruleset.rules.allow("read", branch=None, file=None): |
55 if os.path.exists(path + "/.hg"): |
56 dispatch.dispatch(['-R', repo, 'serve', '--stdio']) |
56 fail("Cannot create repo under existing repo") |
57 return |
57 checkParents(path) |
58 elif cmd.startswith('hg init '): |
|
59 repo = getpath(cmd[8:]) |
|
60 ruleset.rules.set(repo=repo) |
|
61 if ruleset.rules.allow("init", branch=None, file=None): |
|
62 dispatch.dispatch(['init', repo]) |
|
63 return |
|
64 fail("Illegal command %r" % cmd) |
|
65 |
58 |
66 #logfile = open("/tmp/hg-ssh.%d.txt" % os.getpid(), "w") |
59 def getrepo(op, repo): |
67 #logfile.write("Started: %s\n" % sys.argv) |
60 # First canonicalise, then check the string, then the rules |
68 |
61 # and finally the filesystem. |
69 if len(sys.argv) != 2: |
62 repo = repo.rstrip("/") |
70 fail("hg-ssh must have exactly one argument (%s)" |
63 if len(repo) == 0: |
71 % sys.argv) |
64 fail("path to repository seems to be empty") |
|
65 if repo.startswith("/"): |
|
66 fail("absolute paths are not supported") |
|
67 checkDots(path) |
|
68 ruleset.rules.set(repo=repo) |
|
69 if not ruleset.rules.allow(op, branch=None, file=None): |
|
70 fail("access denied") |
|
71 checkParents(repo) |
|
72 return repo |
72 |
73 |
73 paths.setExePath() |
74 paths.setExePath() |
74 ruleset.rules.set(user = sys.argv[1]) |
75 |
|
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]) |
|
80 else: |
|
81 fail("hg-ssh wrongly called, is authorized_keys corrupt? (%s)" |
|
82 % sys.argv) |
75 |
83 |
76 # Use a different hgrc for remote pulls - this way you can set |
84 # Use a different hgrc for remote pulls - this way you can set |
77 # up access.py for everything at once without affecting local operations |
85 # up access.py for everything at once without affecting local operations |
78 |
86 |
79 os.environ['HGRCPATH'] = paths.getEtcPath() + "/remote-hgrc" |
87 os.environ['HGRCPATH'] = paths.getEtcPath() + "/remote-hgrc" |
84 paths.getEtcPath() + "/access.conf", |
92 paths.getEtcPath() + "/access.conf", |
85 os.getcwd() + "/hgadmin/access.conf"]: |
93 os.getcwd() + "/hgadmin/access.conf"]: |
86 if os.path.isfile(f): |
94 if os.path.isfile(f): |
87 ruleset.rules.readfile(f) |
95 ruleset.rules.readfile(f) |
88 |
96 |
89 try_cmd(os.environ.get('SSH_ORIGINAL_COMMAND', '?')) |
97 cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None) |
|
98 if cmd is None: |
|
99 fail("direct logins on the hg account prohibited") |
|
100 elif cmd.startswith('hg -R ') and cmd.endswith(' serve --stdio'): |
|
101 repo = getrepo("read", cmd[6:-14]) |
|
102 if not os.path.isdir(repo + "/.hg"): |
|
103 fail("no such repository %s" % repo) |
|
104 dispatch.dispatch(['-R', repo, 'serve', '--stdio']) |
|
105 elif cmd.startswith('hg init '): |
|
106 repo = getrepo("init", cmd[8:]) |
|
107 if os.path.exists(repo): |
|
108 fail("%s exists" % repo) |
|
109 d = os.path.dirname(repo) |
|
110 if d != "" and not os.path.isdir(d): |
|
111 os.makedirs(d) |
|
112 dispatch.dispatch(['init', repo]) |
|
113 else: |
|
114 fail("illegal command %r" % cmd) |
|
115 |