moved stuff into subdirectories
authorPaul Crowley <paul@lshift.net>
Mon, 16 Jun 2008 17:12:20 +0100
changeset 33 18e93dbdaf12
parent 32 4059dbe9f26a
child 34 4b5ca59fe3b7
moved stuff into subdirectories
access.py
hg-ssh
hginit
install
refresh-auth
remote-hgrc
ruleset.py
src/access.py
src/hg-ssh
src/init/conf/remote-hgrc
src/init/hginit
src/refresh-auth
src/ruleset.py
--- a/access.py	Thu Jun 05 16:53:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-# Copyright 2008 LShift Ltd
-# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
-#
-# Authors:
-# Paul Crowley <paul@lshift.net>
-# Vadim Gelfer <vadim.gelfer@gmail.com>
-#
-# This software may be used and distributed according to the terms
-# of the GNU General Public License, incorporated herein by reference.
-
-from mercurial.i18n import _
-from mercurial.node import *
-from mercurial import util
-
-import os
-import ruleset
-
-class Checker(object):
-    '''acl checker.'''
-
-    def __init__(self, ui, repo):
-        self.ui = ui
-        self.repo = repo
-        self.rules = ruleset.Ruleset.readfile(os.environ['HG_ACCESS_RULES_FILE'])
-        self.rules.set(user = os.environ['REMOTE_USER'])
-        self.rules.set(repo = os.environ['HG_REPO_PATH'])
-
-    def allow(self, node):
-        '''return if access allowed, raise exception if not.'''
-        ctx = self.repo.changectx(node)
-        branch = ctx.branch()
-        if not self.rules.allow("write", branch=branch, file=None):
-            return False
-        for f in ctx.files():
-            if not self.rules.allow("write", branch=branch, file=f):
-                return False
-        self.ui.debug(_('%s: allowing changeset %s\n') % (__name__, short(node)))
-        return True
-
-    def check(self, node):
-        if not self.allow(node):
-            raise util.Abort(_('%s: access denied for changeset %s') %
-                (__name__, short(node)))
-
-        
-def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
-    if hooktype != 'pretxnchangegroup':
-        raise util.Abort(_('config error - hook type "%s" cannot stop '
-                           'incoming changesets') % hooktype)
-    c = Checker(ui, repo)
-    start = repo.changelog.rev(bin(node))
-    end = repo.changelog.count()
-    for rev in xrange(start, end):
-        c.check(repo.changelog.node(rev))
-
--- a/hg-ssh	Thu Jun 05 16:53:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2008 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
-hg-admin-tools.
-
-This script is called by hg-ssh-wrapper with no arguments - everything
-should be in enviroment variables:
-
-HG_ACCESS_RULES_FILE identifies the path to the rules file
-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
-import ruleset
-
-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 get_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
-            return ['-R', repo, 'serve', '--stdio']
-    elif cmd.startswith('hg init '):
-        repo = getpath(cmd[8:])
-        if rules.allow("init", repo=repo):
-            os.environ["HG_REPO_PATH"] = repo
-            return ['init', repo]
-    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) != 1:
-    fail("hg-ssh must have no arguments (%s)" 
-        % sys.argv)
-
-rules = ruleset.Ruleset.readfile(os.environ['HG_ACCESS_RULES_FILE'])
-rules.set(user = getpath(os.environ['REMOTE_USER']))
-rules.set(branch = None, file = None)
-todispatch = get_cmd(rules, 
-    os.environ.get('SSH_ORIGINAL_COMMAND', '?'))
-dispatch.dispatch(todispatch)
-
--- a/hginit	Thu Jun 05 16:53:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-set -e
-
-cd ~hg
-mkdir -p repos/hgadmin .ssh
-cd repos/hgadmin
-hg init .
-cp /usr/local/lib/hg-admin-tools/hgadmin-hgrc .hg/hgrc
-
--- a/install	Thu Jun 05 16:53:57 2008 +0100
+++ b/install	Mon Jun 16 17:12:20 2008 +0100
@@ -4,7 +4,21 @@
 
 install -o root -g root -d /usr/local/lib/hg-admin-tools
 install -o root -g root -t /usr/local/lib/hg-admin-tools \
-    access.py hg-ssh refresh-auth ruleset.py hgadmin-hgrc create-breakin-repository ssh-replacement as-if-by-ssh break-in
+    src/access.py \
+    src/hg-ssh \
+    src/refresh-auth \
+    src/ruleset.py
+install -o root -g root -d /usr/local/lib/hg-admin-tools/init
+install -o root -g root -t /usr/local/lib/hg-admin-tools/init \
+    src/init/hgadmin-hgrc
+install -o root -g root -d /usr/local/lib/hg-admin-tools/init/break-in
+install -o root -g root -t /usr/local/lib/hg-admin-tools/init/break-in \
+    src/init/break-in/create-breakin-repository \
+    src/init/break-in/ssh-replacement
+    src/init/break-in/as-if-by-ssh
+    src/init/break-in/break-in
 install -o root -g root -d /etc/hg-admin-tools
-install -o root -g root -t /etc/hg-admin-tools hg-ssh-wrapper remote-hgrc
+install -o root -g root -t /etc/hg-admin-tools \
+    src/init/conf/hg-ssh-wrapper \
+    src/init/conf/remote-hgrc
 
--- a/refresh-auth	Thu Jun 05 16:53:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-#!/usr/bin/env python
-
-# WARNING
-# This script completely destroys your ~/.ssh/authorized_keys
-# file every time it is run
-# WARNING
-
-import sys
-import os
-import os.path
-import ruleset
-import subprocess
-
-if len(sys.argv) != 3:
-    sys.stderr.write("refresh-auth: wrong number of arguments (%s)\n" % sys.argv)
-    sys.exit(-1)
-
-akeyfile = sys.argv[1]
-wrappercommand = sys.argv[2]
-prefix='no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command='
-
-if os.path.exists(akeyfile):
-    f = open(akeyfile)
-    try:
-        for l in f:
-            if not l.startswith(prefix):
-                raise Exception("Safety check failed, delete %s to continue" % akeyfile)
-    finally:
-        f.close()
-
-akeys = open(akeyfile + "_new", "w")
-for root, dirs, files in os.walk("keys"):
-    for fn in files:
-        ffn = os.path.join(root, fn)
-        if not ruleset.goodpath(ffn):
-            # ignore any path that contains dodgy characters
-            continue
-        keyname = ffn[5:]
-        if keyname == "root":
-            # No key can claim root privileges
-            continue
-        p = subprocess.Popen(("ssh-keygen", "-i", "-f", ffn), 
-            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        newkey = p.communicate()[0]
-        if p.wait() == 0:
-            klines = [l.strip() for l in newkey.split("\n")]
-        else:
-            # Conversion failed, read it directly.
-            kf = open(ffn)
-            try:
-                klines = [l.strip() for l in kf]
-            finally:
-                kf.close()
-        for l in klines:
-            if len(l):
-                akeys.write('%s"%s %s" %s\n' % (prefix, wrappercommand, keyname, l))
-
-akeys.close()
-
-os.rename(akeyfile + "_new", akeyfile)
-
--- a/remote-hgrc	Thu Jun 05 16:53:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-# hgrc to use for all remote users
-
-[extensions]
-access = /usr/local/lib/hg-admin-tools/access.py
-
-[hooks]
-pretxnchangegroup.access = python:access.hook
--- a/ruleset.py	Thu Jun 05 16:53:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-# Copyright 2008 LShift Ltd
-# Author(s):
-# Paul Crowley <paul@lshift.net>
-#
-# This software may be used and distributed according to the terms
-# of the GNU General Public License, incorporated herein by reference.
-
-import sys
-import re
-
-allowedchars = "A-Za-z0-9_-"
-
-goodpathre = re.compile("([%s]+/)*[%s]+$" % (allowedchars, allowedchars))
-def goodpath(path):
-    return goodpathre.match(path) is not None
-
-goodglobre = re.compile("[*/%s]+$" % allowedchars)
-
-def goodglob(pattern):
-    return goodglobre.match(pattern) is not None
-
-# Don't put anything except *A-Za-z0-9_- in rule globs or   
-# it will match nothing.  No regexp metachars, not even .
-# We may fix this later.
-def globmatcher(pattern):
-    if not goodglob(pattern):
-        #fail("Bad glob pattern in auth config: %s" % pattern)
-        # FIXME: report it somehow
-        return lambda x: False
-    # Substitution cunning so ** can be different from *
-    pattern = pattern.replace("*", "[]")
-    pattern = pattern.replace("[][]", "[/%s]*" % allowedchars)
-    pattern = pattern.replace("[]", "[%s]*" % allowedchars)
-    rex = re.compile(pattern + "$")
-    # None matches everything
-    return lambda x: x is None or rex.match(x) is not None
-
-def rule(pairs):
-    matchers = [(k, globmatcher(v)) for k, v in pairs]
-    def c(**kw):
-        for k, m in matchers:
-            if k not in kw or not m(kw[k]):
-                return False
-        return True
-    return c
-
-class Ruleset(object):
-    '''Class representing the rules in a rule file'''
-    
-    levels = ["init", "write", "read", "deny"]
-
-    def __init__(self):
-        # The user called "root" automatically has the highest
-        # privilege
-        self.rules = [(self.levels[0], rule([('user', 'root')]))]
-        self.preset = {}
-
-    def add(self, action, conditions):
-        self.rules.append((action, conditions))
-
-
-    def set(self, **kw):
-        self.preset.update(kw)
-        
-    def matchrule(self, **kw):
-        d = self.preset.copy()
-        d.update(**kw)
-        for a, c in self.rules:
-            if c(**d):
-                return a
-        return None
-
-    def allow(self, level, **kw):
-        a = self.matchrule(**kw)
-        return a in self.levels and self.levels.index(a) <= self.levels.index(level)
-    
-    @classmethod
-    def readfile(cls, fn):
-        res = cls()
-        try:
-            f = open(fn)
-            try:
-                for l in f:
-                    l = l.strip()
-                    if len(l) == 0 or l.startswith("#"):
-                        continue
-                    l = l.split()
-                    res.add(l[0], rule([c.split("=", 1) for c in l[1:]]))
-            finally:
-                f.close()
-        except Exception, e:
-            print >> sys.stderr, "Failure reading rules file:", e
-            return cls()
-        return res
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/access.py	Mon Jun 16 17:12:20 2008 +0100
@@ -0,0 +1,55 @@
+# Copyright 2008 LShift Ltd
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# Authors:
+# Paul Crowley <paul@lshift.net>
+# Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from mercurial.i18n import _
+from mercurial.node import *
+from mercurial import util
+
+import os
+import ruleset
+
+class Checker(object):
+    '''acl checker.'''
+
+    def __init__(self, ui, repo):
+        self.ui = ui
+        self.repo = repo
+        self.rules = ruleset.Ruleset.readfile(os.environ['HG_ACCESS_RULES_FILE'])
+        self.rules.set(user = os.environ['REMOTE_USER'])
+        self.rules.set(repo = os.environ['HG_REPO_PATH'])
+
+    def allow(self, node):
+        '''return if access allowed, raise exception if not.'''
+        ctx = self.repo.changectx(node)
+        branch = ctx.branch()
+        if not self.rules.allow("write", branch=branch, file=None):
+            return False
+        for f in ctx.files():
+            if not self.rules.allow("write", branch=branch, file=f):
+                return False
+        self.ui.debug(_('%s: allowing changeset %s\n') % (__name__, short(node)))
+        return True
+
+    def check(self, node):
+        if not self.allow(node):
+            raise util.Abort(_('%s: access denied for changeset %s') %
+                (__name__, short(node)))
+
+        
+def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
+    if hooktype != 'pretxnchangegroup':
+        raise util.Abort(_('config error - hook type "%s" cannot stop '
+                           'incoming changesets') % hooktype)
+    c = Checker(ui, repo)
+    start = repo.changelog.rev(bin(node))
+    end = repo.changelog.count()
+    for rev in xrange(start, end):
+        c.check(repo.changelog.node(rev))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hg-ssh	Mon Jun 16 17:12:20 2008 +0100
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 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
+hg-admin-tools.
+
+This script is called by hg-ssh-wrapper with no arguments - everything
+should be in enviroment variables:
+
+HG_ACCESS_RULES_FILE identifies the path to the rules file
+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
+import ruleset
+
+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 get_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
+            return ['-R', repo, 'serve', '--stdio']
+    elif cmd.startswith('hg init '):
+        repo = getpath(cmd[8:])
+        if rules.allow("init", repo=repo):
+            os.environ["HG_REPO_PATH"] = repo
+            return ['init', repo]
+    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) != 1:
+    fail("hg-ssh must have no arguments (%s)" 
+        % sys.argv)
+
+rules = ruleset.Ruleset.readfile(os.environ['HG_ACCESS_RULES_FILE'])
+rules.set(user = getpath(os.environ['REMOTE_USER']))
+rules.set(branch = None, file = None)
+todispatch = get_cmd(rules, 
+    os.environ.get('SSH_ORIGINAL_COMMAND', '?'))
+dispatch.dispatch(todispatch)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/init/conf/remote-hgrc	Mon Jun 16 17:12:20 2008 +0100
@@ -0,0 +1,7 @@
+# hgrc to use for all remote users
+
+[extensions]
+access = /usr/local/lib/hg-admin-tools/access.py
+
+[hooks]
+pretxnchangegroup.access = python:access.hook
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/init/hginit	Mon Jun 16 17:12:20 2008 +0100
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+cd ~hg
+mkdir -p repos/hgadmin .ssh
+cd repos/hgadmin
+hg init .
+cp /usr/local/lib/hg-admin-tools/hgadmin-hgrc .hg/hgrc
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/refresh-auth	Mon Jun 16 17:12:20 2008 +0100
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+# WARNING
+# This script completely destroys your ~/.ssh/authorized_keys
+# file every time it is run
+# WARNING
+
+import sys
+import os
+import os.path
+import ruleset
+import subprocess
+
+if len(sys.argv) != 3:
+    sys.stderr.write("refresh-auth: wrong number of arguments (%s)\n" % sys.argv)
+    sys.exit(-1)
+
+akeyfile = sys.argv[1]
+wrappercommand = sys.argv[2]
+prefix='no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command='
+
+if os.path.exists(akeyfile):
+    f = open(akeyfile)
+    try:
+        for l in f:
+            if not l.startswith(prefix):
+                raise Exception("Safety check failed, delete %s to continue" % akeyfile)
+    finally:
+        f.close()
+
+akeys = open(akeyfile + "_new", "w")
+for root, dirs, files in os.walk("keys"):
+    for fn in files:
+        ffn = os.path.join(root, fn)
+        if not ruleset.goodpath(ffn):
+            # ignore any path that contains dodgy characters
+            continue
+        keyname = ffn[5:]
+        if keyname == "root":
+            # No key can claim root privileges
+            continue
+        p = subprocess.Popen(("ssh-keygen", "-i", "-f", ffn), 
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        newkey = p.communicate()[0]
+        if p.wait() == 0:
+            klines = [l.strip() for l in newkey.split("\n")]
+        else:
+            # Conversion failed, read it directly.
+            kf = open(ffn)
+            try:
+                klines = [l.strip() for l in kf]
+            finally:
+                kf.close()
+        for l in klines:
+            if len(l):
+                akeys.write('%s"%s %s" %s\n' % (prefix, wrappercommand, keyname, l))
+
+akeys.close()
+
+os.rename(akeyfile + "_new", akeyfile)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ruleset.py	Mon Jun 16 17:12:20 2008 +0100
@@ -0,0 +1,95 @@
+# Copyright 2008 LShift Ltd
+# Author(s):
+# Paul Crowley <paul@lshift.net>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import sys
+import re
+
+allowedchars = "A-Za-z0-9_-"
+
+goodpathre = re.compile("([%s]+/)*[%s]+$" % (allowedchars, allowedchars))
+def goodpath(path):
+    return goodpathre.match(path) is not None
+
+goodglobre = re.compile("[*/%s]+$" % allowedchars)
+
+def goodglob(pattern):
+    return goodglobre.match(pattern) is not None
+
+# Don't put anything except *A-Za-z0-9_- in rule globs or   
+# it will match nothing.  No regexp metachars, not even .
+# We may fix this later.
+def globmatcher(pattern):
+    if not goodglob(pattern):
+        #fail("Bad glob pattern in auth config: %s" % pattern)
+        # FIXME: report it somehow
+        return lambda x: False
+    # Substitution cunning so ** can be different from *
+    pattern = pattern.replace("*", "[]")
+    pattern = pattern.replace("[][]", "[/%s]*" % allowedchars)
+    pattern = pattern.replace("[]", "[%s]*" % allowedchars)
+    rex = re.compile(pattern + "$")
+    # None matches everything
+    return lambda x: x is None or rex.match(x) is not None
+
+def rule(pairs):
+    matchers = [(k, globmatcher(v)) for k, v in pairs]
+    def c(**kw):
+        for k, m in matchers:
+            if k not in kw or not m(kw[k]):
+                return False
+        return True
+    return c
+
+class Ruleset(object):
+    '''Class representing the rules in a rule file'''
+    
+    levels = ["init", "write", "read", "deny"]
+
+    def __init__(self):
+        # The user called "root" automatically has the highest
+        # privilege
+        self.rules = [(self.levels[0], rule([('user', 'root')]))]
+        self.preset = {}
+
+    def add(self, action, conditions):
+        self.rules.append((action, conditions))
+
+
+    def set(self, **kw):
+        self.preset.update(kw)
+        
+    def matchrule(self, **kw):
+        d = self.preset.copy()
+        d.update(**kw)
+        for a, c in self.rules:
+            if c(**d):
+                return a
+        return None
+
+    def allow(self, level, **kw):
+        a = self.matchrule(**kw)
+        return a in self.levels and self.levels.index(a) <= self.levels.index(level)
+    
+    @classmethod
+    def readfile(cls, fn):
+        res = cls()
+        try:
+            f = open(fn)
+            try:
+                for l in f:
+                    l = l.strip()
+                    if len(l) == 0 or l.startswith("#"):
+                        continue
+                    l = l.split()
+                    res.add(l[0], rule([c.split("=", 1) for c in l[1:]]))
+            finally:
+                f.close()
+        except Exception, e:
+            print >> sys.stderr, "Failure reading rules file:", e
+            return cls()
+        return res
+