# 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
import os
import os.path
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)
def readfile(self, fn):
try:
f = open(fn)
try:
for l in f:
l = l.strip()
if len(l) == 0 or l.startswith("#"):
continue
l = l.split()
self.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
def rules_from_env():
res = Ruleset()
for f in os.environ['HG_ACCESS_RULES_PATH'].split(os.pathsep):
if os.path.isfile(f):
res.readfile(f)
return res