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 from mercurialserver import ruleset, paths |
37 from mercurialserver import ruleset, paths |
38 |
38 |
39 def fail(message): |
39 def fail(message): |
40 #logfile.write("Fail: %s\n" % message) |
40 sys.stderr.write("mercurial-server: %s\n" % message) |
41 sys.stderr.write(message + "\n") |
|
42 sys.exit(-1) |
41 sys.exit(-1) |
43 |
42 |
44 def getpath(path): |
43 def checkpath(path) |
45 path = path.rstrip("/") |
44 path = os.path.dirname(path) |
46 if not ruleset.goodpath(path): |
45 if path == "": |
47 fail("Disallowing path: %s" % path) |
46 return |
48 return path |
47 if os.path.exists(path + "/.hg"): |
|
48 raise ruleset.AccessException() |
|
49 checkpath(path) |
49 |
50 |
50 def try_cmd(cmd): |
51 def getrepo(op, repo): |
51 if cmd.startswith('hg -R ') and cmd.endswith(' serve --stdio'): |
52 repo = os.path.normcase(os.path.normpath(repo.rstrip("/"))) |
52 repo = getpath(cmd[6:-14]) |
53 if len(repo) == 0: |
53 ruleset.rules.set(repo=repo) |
54 fail("path to repository seems to be empty") |
54 if ruleset.rules.allow("read", branch=None, file=None): |
55 if repo.startswith("/"): |
55 dispatch.dispatch(['-R', repo, 'serve', '--stdio']) |
56 fail("absolute paths are not supported") |
56 return |
57 for component in repo.split("/"): |
57 elif cmd.startswith('hg init '): |
58 if component.startswith("."): |
58 repo = getpath(cmd[8:]) |
59 fail("paths cannot contain dot file components") |
59 ruleset.rules.set(repo=repo) |
60 ruleset.rules.set(repo=repo) |
60 if ruleset.rules.allow("init", branch=None, file=None): |
61 ruleset.rules.check(op, branch=None, file=None) |
61 dispatch.dispatch(['init', repo]) |
62 checkpath(repo) |
62 return |
63 return repo |
63 fail("Illegal command %r" % cmd) |
|
64 |
64 |
65 #logfile = open("/tmp/hg-ssh.%d.txt" % os.getpid(), "w") |
65 #logfile = open("/tmp/hg-ssh.%d.txt" % os.getpid(), "w") |
66 #logfile.write("Started: %s\n" % sys.argv) |
66 #logfile.write("Started: %s\n" % sys.argv) |
67 |
67 |
68 if len(sys.argv) != 2: |
68 if len(sys.argv) != 2: |
69 fail("hg-ssh must have exactly one argument (%s)" |
69 fail("hg-ssh wrongly called, is authorized_keys corrupt? (%s)" |
70 % sys.argv) |
70 % sys.argv) |
71 |
71 |
72 paths.setExePath() |
72 paths.setExePath() |
73 ruleset.rules.set(user = sys.argv[1]) |
73 ruleset.rules.set(user = sys.argv[1]) |
74 |
74 |
83 paths.getEtcPath() + "/access.conf", |
83 paths.getEtcPath() + "/access.conf", |
84 os.getcwd() + "/hgadmin/access.conf"]: |
84 os.getcwd() + "/hgadmin/access.conf"]: |
85 if os.path.isfile(f): |
85 if os.path.isfile(f): |
86 ruleset.rules.readfile(f) |
86 ruleset.rules.readfile(f) |
87 |
87 |
88 try_cmd(os.environ.get('SSH_ORIGINAL_COMMAND', '?')) |
88 cmd = os.environ.get('SSH_ORIGINAL_COMMAND', '') |
|
89 try: |
|
90 if cmd.startswith('hg -R ') and cmd.endswith(' serve --stdio'): |
|
91 repo = getrepo("read", cmd[6:-14]) |
|
92 if not os.path.isdir(repo + "/.hg") |
|
93 fail("no such repository %s" % repo) |
|
94 dispatch.dispatch(['-R', repo, 'serve', '--stdio']) |
|
95 elif cmd.startswith('hg init '): |
|
96 repo = getrepo("init", cmd[8:]) |
|
97 if os.path.exists(repo): |
|
98 fail("%s exists" % repo) |
|
99 d = os.path.dirname(repo) |
|
100 if d != "" and not os.path.isdir(d): |
|
101 os.makedirs(d) |
|
102 dispatch.dispatch(['init', repo]) |
|
103 elif cmd == "": |
|
104 fail("direct logins on the hg account prohibited ") |
|
105 else: |
|
106 fail("illegal command %r" % cmd) |
|
107 except ruleset.AccessException: |
|
108 fail("access denied") |
|
109 |