src/hg-ssh
branchdebian
changeset 115 731a72b742db
parent 110 69596fffcf7d
child 117 b6b8a5daf0f4
equal deleted inserted replaced
99:e99262dfa950 115:731a72b742db
    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