summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2013-01-18 11:05:37 -0500
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2013-01-18 11:05:37 -0500
commit84b9fabb4895b38eeddefdcc417301e8ae1befc4 (patch)
treea409a3e9ac6eac1f30f562a8cae27e4571807032 /src
parent661d1f6d2789e855eff4fca38e6f4a0a564da728 (diff)
parent3d78a3a1c00035c9d8c49b949b63e8f05f31c7a1 (diff)
downloadbcfg2-84b9fabb4895b38eeddefdcc417301e8ae1befc4.tar.gz
bcfg2-84b9fabb4895b38eeddefdcc417301e8ae1befc4.tar.bz2
bcfg2-84b9fabb4895b38eeddefdcc417301e8ae1befc4.zip
Merge branch 'master' into 1.3.1
Conflicts: src/lib/Bcfg2/Server/Plugins/Properties.py
Diffstat (limited to 'src')
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIXUsers.py97
-rw-r--r--src/lib/Bcfg2/Options.py26
-rw-r--r--src/lib/Bcfg2/Server/Plugins/GroupPatterns.py7
3 files changed, 118 insertions, 12 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
index 78734f5c2..7c8a4d578 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
@@ -4,9 +4,45 @@ and groupadd/mod/del """
import sys
import pwd
import grp
-import Bcfg2.Client.XML
import subprocess
+import Bcfg2.Client.XML
import Bcfg2.Client.Tools
+from Bcfg2.Compat import any # pylint: disable=W0622
+
+
+class IDRangeSet(object):
+ """ Representation of a set of integer ranges. Used to describe
+ which UID/GID ranges are managed or unmanaged. """
+
+ def __init__(self, *ranges):
+ self.ranges = []
+ self.ints = []
+ self.str = ",".join(str(r) for r in ranges)
+ for item in ranges:
+ item = str(item).strip()
+ if item.endswith("-"):
+ self.ranges.append((int(item[:-1]), None))
+ elif '-' in str(item):
+ self.ranges.append(tuple(int(x) for x in item.split('-')))
+ else:
+ self.ints.append(int(item))
+
+ def __contains__(self, other):
+ other = int(other)
+ if other in self.ints:
+ return True
+ return any((end is None and other >= start) or
+ (end is not None and other >= start and other <= end)
+ for start, end in self.ranges)
+
+ def __repr__(self):
+ return "%s:%s" % (self.__class__.__name__, str(self))
+
+ def __str__(self):
+ return "[%s]" % self.str
+
+ def __len__(self):
+ return len(self.ranges) + len(self.ints)
class ExecutionError(Exception):
@@ -68,18 +104,36 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool):
POSIXGroup=['name'])
experimental = True
- # A mapping of XML entry attributes to the indexes of
- # corresponding values in the get*ent data structures
+ #: A mapping of XML entry attributes to the indexes of
+ #: corresponding values in the get{pw|gr}all data structures
attr_mapping = dict(POSIXUser=dict(name=0, uid=2, gecos=4, home=5,
shell=6),
POSIXGroup=dict(name=0, gid=2))
+ #: A mapping that describes the attribute name of the id of a given
+ #: user or group
+ id_mapping = dict(POSIXUser="uid", POSIXGroup="gid")
+
def __init__(self, logger, setup, config):
Bcfg2.Client.Tools.Tool.__init__(self, logger, setup, config)
self.set_defaults = dict(POSIXUser=self.populate_user_entry,
POSIXGroup=lambda g: g)
self.cmd = Executor(logger)
self._existing = None
+ self._whitelist = dict(POSIXUser=None, POSIXGroup=None)
+ self._blacklist = dict(POSIXUser=None, POSIXGroup=None)
+ if self.setup['posix_uid_whitelist']:
+ self._whitelist['POSIXUser'] = \
+ IDRangeSet(*self.setup['posix_uid_whitelist'])
+ else:
+ self._blacklist['POSIXUser'] = \
+ IDRangeSet(*self.setup['posix_uid_blacklist'])
+ if self.setup['posix_gid_whitelist']:
+ self._whitelist['POSIXGroup'] = \
+ IDRangeSet(*self.setup['posix_gid_whitelist'])
+ else:
+ self._blacklist['POSIXGroup'] = \
+ IDRangeSet(*self.setup['posix_gid_blacklist'])
@property
def existing(self):
@@ -91,6 +145,33 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool):
for g in grp.getgrall()]))
return self._existing
+ def _in_managed_range(self, tag, eid):
+ """ Check if the given uid or gid is in the appropriate
+ managed range. This means that either a) a whitelist is
+ defined, and the uid/gid is in that whitelist; or b) no
+ whitelist is defined, and the uid/gid is not in the
+ blacklist. """
+ if self._whitelist[tag] is None:
+ return eid not in self._blacklist[tag]
+ else:
+ return eid in self._whitelist[tag]
+
+ def canInstall(self, entry):
+ if not Bcfg2.Client.Tools.Tool.canInstall(self, entry):
+ return False
+ eid = entry.get(self.id_mapping[entry.tag])
+ if eid is not None and not self._in_managed_range(entry.tag, eid):
+ if self._whitelist[entry.tag] is not None:
+ err = "not in whitelist"
+ else: # blacklisted
+ err = "in blacklist"
+ self.logger.debug("%s: %s %s %s: %s" %
+ (self.primarykey(entry), err,
+ self.id_mapping[entry.tag], eid,
+ self._blacklist[entry.tag]))
+ return False
+ return True
+
def Inventory(self, states, structures=None):
if not structures:
structures = self.config.getchildren()
@@ -121,9 +202,11 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool):
for entry in self.getSupportedEntries():
if entry.tag == tag:
specified.append(entry.get("name"))
- extra.extend([Bcfg2.Client.XML.Element(tag, name=e)
- for e in self.existing[tag].keys()
- if e not in specified])
+ for name, data in self.existing[tag].items():
+ eid = data[self.attr_mapping[tag][self.id_mapping[tag]]]
+ if name not in specified and self._in_managed_range(tag, eid):
+ extra.append(Bcfg2.Client.XML.Element(tag, name=name))
+
return extra
def populate_user_entry(self, entry):
@@ -201,7 +284,7 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool):
errors.append("%s for %s %s is incorrect. Current %s is "
"%s, but should be %s" %
(attr.title(), entry.tag, entry.get("name"),
- attr, entry.get(attr), val))
+ attr, val, entry.get(attr)))
if errors:
for error in errors:
diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py
index 4818c67f9..11c61a634 100644
--- a/src/lib/Bcfg2/Options.py
+++ b/src/lib/Bcfg2/Options.py
@@ -989,6 +989,26 @@ CLIENT_YUM_VERIFY_FLAGS = \
cf=('YUM', 'verify_flags'),
deprecated_cf=('YUMng', 'verify_flags'),
cook=list_split)
+CLIENT_POSIX_UID_WHITELIST = \
+ Option("UID ranges the POSIXUsers tool will manage",
+ default=[],
+ cf=('POSIXUsers', 'uid_whitelist'),
+ cook=list_split)
+CLIENT_POSIX_GID_WHITELIST = \
+ Option("GID ranges the POSIXUsers tool will manage",
+ default=[],
+ cf=('POSIXUsers', 'gid_whitelist'),
+ cook=list_split)
+CLIENT_POSIX_UID_BLACKLIST = \
+ Option("UID ranges the POSIXUsers tool will not manage",
+ default=[],
+ cf=('POSIXUsers', 'uid_blacklist'),
+ cook=list_split)
+CLIENT_POSIX_GID_BLACKLIST = \
+ Option("GID ranges the POSIXUsers tool will not manage",
+ default=[],
+ cf=('POSIXUsers', 'gid_blacklist'),
+ cook=list_split)
# Logging options
LOGGING_FILE_PATH = \
@@ -1141,7 +1161,11 @@ DRIVER_OPTIONS = \
yum_installed_action=CLIENT_YUM_INSTALLED_ACTION,
yum_version_fail_action=CLIENT_YUM_VERSION_FAIL_ACTION,
yum_verify_fail_action=CLIENT_YUM_VERIFY_FAIL_ACTION,
- yum_verify_flags=CLIENT_YUM_VERIFY_FLAGS)
+ yum_verify_flags=CLIENT_YUM_VERIFY_FLAGS,
+ posix_uid_whitelist=CLIENT_POSIX_UID_WHITELIST,
+ posix_gid_whitelist=CLIENT_POSIX_UID_WHITELIST,
+ posix_uid_blacklist=CLIENT_POSIX_UID_BLACKLIST,
+ posix_gid_blacklist=CLIENT_POSIX_UID_BLACKLIST)
CLIENT_COMMON_OPTIONS = \
dict(extra=CLIENT_EXTRA_DISPLAY,
diff --git a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
index 2e8c56b4e..1b12e590a 100644
--- a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
+++ b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
@@ -6,6 +6,7 @@ import sys
import logging
import Bcfg2.Server.Lint
import Bcfg2.Server.Plugin
+from Bcfg2.Compat import any # pylint: disable=W0622
class PackedDigitRange(object):
@@ -25,10 +26,8 @@ class PackedDigitRange(object):
iother = int(other)
if iother in self.sparse:
return True
- for (start, end) in self.ranges:
- if iother in range(start, end + 1):
- return True
- return False
+ return any(iother in range(start, end + 1)
+ for start, end in self.ranges)
class PatternMap(object):