diff options
author | Sol Jerome <sol.jerome@gmail.com> | 2012-12-03 08:45:48 -0600 |
---|---|---|
committer | Sol Jerome <sol.jerome@gmail.com> | 2012-12-03 08:45:48 -0600 |
commit | 41d1d29b8b545e0f636ebf26795eecd1a46bc9fb (patch) | |
tree | ffed75712d123ef83c37484b618dbe4ff3171b34 | |
parent | 10f815f1af1935bd76b7f75c5577c6f6197d706e (diff) | |
download | bcfg2-41d1d29b8b545e0f636ebf26795eecd1a46bc9fb.tar.gz bcfg2-41d1d29b8b545e0f636ebf26795eecd1a46bc9fb.tar.bz2 bcfg2-41d1d29b8b545e0f636ebf26795eecd1a46bc9fb.zip |
SELinux: Split up selinux entries
This commit splits up the all-in-one SELinux tag into various entries
(formerly done using a type attribute). This helps prevent ambiguation
when entries of different SELinux types have the same name.
Note that there is still some ambiguation for File Context entries since
there can be duplicates involved.
Signed-off-by: Sol Jerome <sol.jerome@gmail.com>
-rw-r--r-- | doc/server/plugins/generators/rules.txt | 56 | ||||
-rw-r--r-- | doc/server/selinux.txt | 39 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/SELinux.py | 117 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/SEModules.py | 6 |
4 files changed, 91 insertions, 127 deletions
diff --git a/doc/server/plugins/generators/rules.txt b/doc/server/plugins/generators/rules.txt index 542b38f01..65eb0c5d9 100644 --- a/doc/server/plugins/generators/rules.txt +++ b/doc/server/plugins/generators/rules.txt @@ -394,14 +394,12 @@ the permissions to ``0674``. When this happens, Bcfg2 will change the permissions and set the ACLs on every run and the entry will be eternally marked as bad. -SELinux Tag ------------ +SELinux Entries +--------------- -The SELinux tag has different values depending on the *type* attribute -of the SELinux entry specified in your configuration. Below is a set -of tables which describe the attributes available for various SELinux -types. The types (except for ``module``) correspond to ``semanage`` -subcommands. +Below is a set of tables which describe the attributes available +for various SELinux types. The entry types (except for ``module``) +correspond to ``semanage`` subcommands. Note that the ``selinuxtype`` attribute takes only an SELinux type, not a full context; e.g., "``etc_t``", not @@ -411,18 +409,10 @@ As it can be very tedious to create a baseline of all existing SELinux entries, you can use ``selinux_baseline.py`` located in the ``tools/`` directory to do that for you. -In certain cases, it may be necessary to create multiple SELinux -entries with the same name. For instance, "root" is both an SELinux -user and an SELinux login record; or a given fcontext may need two -different SELinux types depending on whether it's a symlink or a plain -file. In these (few) cases, it is necessary to create BoundSELinux -entries directly in Bundler rather than using abstract SELinux entries -in Bundler and binding them with Rules. - See :ref:`server-selinux` for more information. -boolean -^^^^^^^ +SEBoolean Tag +^^^^^^^^^^^^^ +-------+----------------------+---------+----------+ | Name | Description | Values | Required | @@ -432,8 +422,8 @@ boolean | value | Value of the boolean | on|off | Yes | +-------+----------------------+---------+----------+ -port -^^^^ +SEPort Tag +^^^^^^^^^^ +-------------+------------------------+---------------------------+----------+ | Name | Description | Values | Required | @@ -445,8 +435,8 @@ port | | to this port | | | +-------------+------------------------+---------------------------+----------+ -fcontext -^^^^^^^^ +SEFcontext Tag +^^^^^^^^^^^^^^ +-------------+-------------------------+---------------------+----------+ | Name | Description | Values | Required | @@ -462,8 +452,8 @@ fcontext | | | socket|block|char) | | +-------------+-------------------------+---------------------+----------+ -node -^^^^ +SENode Tag +^^^^^^^^^^ +-------------+------------------------------------+------------------+----------+ | Name | Description | Values | Required | @@ -477,8 +467,8 @@ node | proto | Protocol | (ipv4|ipv6) | Yes | +-------------+------------------------------------+------------------+----------+ -login -^^^^^ +SELogin Tag +^^^^^^^^^^^ +-------------+-------------------------------+-----------+----------+ | Name | Description | Values | Required | @@ -488,8 +478,8 @@ login | selinuxuser | SELinux username | String | Yes | +-------------+-------------------------------+-----------+----------+ -user -^^^^ +SEUser Tag +^^^^^^^^^^ +-------------+-------------------------------+-----------+----------+ | Name | Description | Values | Required | @@ -501,8 +491,8 @@ user | prefix | Home directory context prefix | String | Yes | +-------------+-------------------------------+-----------+----------+ -interface -^^^^^^^^^ +SEInterface Tag +^^^^^^^^^^^^^^^ +-------------+-------------------------+-------------+----------+ | Name | Description | Values | Required | @@ -513,8 +503,8 @@ interface | | to this interface | | | +-------------+-------------------------+-------------+----------+ -permissive -^^^^^^^^^^ +SEPermissive Tag +^^^^^^^^^^^^^^^^ +-------------+------------------------------------+-------------+----------+ | Name | Description | Values | Required | @@ -522,8 +512,8 @@ permissive | name | SELinux type to make permissive | String | Yes | +-------------+------------------------------------+-------------+----------+ -module -^^^^^^ +SEModule Tag +^^^^^^^^^^^^ See :ref:`server-plugins-generators-semodules` diff --git a/doc/server/selinux.txt b/doc/server/selinux.txt index e61a09002..9f54b0d68 100644 --- a/doc/server/selinux.txt +++ b/doc/server/selinux.txt @@ -135,47 +135,16 @@ will be considered extra, making ``selinux_baseline.py`` quite necessary. ``selinux_baseline.py`` writes a bundle to stdout that contains -``BoundSELinux`` entries for the appropriate SELinux entities. It -does this rather than separate Bundle/Rules files because of the -:ref:`server-selinux-duplicate-entries` problem. +``BoundSELinux`` entries for the appropriate SELinux entities. .. _server-selinux-duplicate-entries: Duplicate Entries ----------------- -In certain cases, it may be necessary to create multiple SELinux -entries with the same name. For instance, "root" is both an SELinux -user and an SELinux login record, so to manage both, you would have -the following in Bundler: - -.. code-block:: xml - - <SELinux name="root"/> - <SELinux name="root"/> - -And in Rules: - -.. code-block:: xml - - <SELinux type="login" selinuxuser="root" name="root"/> - <SELinux type="user" prefix="user" name="root" - roles="system_r sysadm_r user_r"/> - -But Rules has no way to tell which "root" is which, and you will get -errors. In these cases, it is necessary to use ``BoundSELinux`` tags -directly in Bundler. (See :ref:`boundentries` for more details on -bound entries.) For instance: - -.. code-block:: xml - - <BoundSELinux type="login" selinuxuser="root" name="root"/> - <BoundSELinux type="user" prefix="user" name="root" - roles="system_r sysadm_r user_r"/> - -It may also be necessary to use ``BoundSELinux`` tags if a single -fcontext needs two different SELinux types depending on whether it's a -symlink or a plain file. For instance: +It may be necessary to use `BoundSELinux` tags if a single fcontext +needs two different SELinux types depending on whether it's a symlink +or a plain file. For instance: .. code-block:: xml diff --git a/src/lib/Bcfg2/Client/Tools/SELinux.py b/src/lib/Bcfg2/Client/Tools/SELinux.py index fc47883c9..7aa0e8a20 100644 --- a/src/lib/Bcfg2/Client/Tools/SELinux.py +++ b/src/lib/Bcfg2/Client/Tools/SELinux.py @@ -58,36 +58,44 @@ def netmask_itoa(netmask, proto="ipv4"): class SELinux(Bcfg2.Client.Tools.Tool): """ SELinux entry support """ name = 'SELinux' - __handles__ = [('SELinux', 'boolean'), - ('SELinux', 'port'), - ('SELinux', 'fcontext'), - ('SELinux', 'node'), - ('SELinux', 'login'), - ('SELinux', 'user'), - ('SELinux', 'interface'), - ('SELinux', 'permissive'), - ('SELinux', 'module')] - __req__ = dict(SELinux=dict(boolean=['name', 'value'], - module=['name'], - port=['name', 'selinuxtype'], - fcontext=['name', 'selinuxtype'], - node=['name', 'selinuxtype', 'proto'], - login=['name', 'selinuxuser'], - user=['name', 'roles', 'prefix'], - interface=['name', 'selinuxtype'], - permissive=['name'])) + __handles__ = [('SEBoolean', None), + ('SEFcontext', None), + ('SEInterface', None), + ('SELogin', None), + ('SEModule', None), + ('SENode', None), + ('SEPermissive', None), + ('SEPort', None), + ('SEUser', None)] + __req__ = dict(SEBoolean=['name', 'value'], + SEFcontext=['name', 'selinuxtype'], + SEInterface=['name', 'selinuxtype'], + SELogin=['name', 'selinuxuser'], + SEModule=['name'], + SENode=['name', 'selinuxtype', 'proto'], + SEPermissive=['name'], + SEPort=['name', 'selinuxtype'], + SEUser=['name', 'roles', 'prefix']) def __init__(self, logger, setup, config): Bcfg2.Client.Tools.Tool.__init__(self, logger, setup, config) self.handlers = {} - for handles in self.__handles__: - etype = handles[1] + for handler in self.__handles__: + etype = handler[0] self.handlers[etype] = \ globals()["SELinux%sHandler" % etype.title()](self, logger, setup, config) self.txn = False self.post_txn_queue = [] + def __getattr__(self, attr): + if attr.startswith("VerifySE"): + return self.GenericSEVerify + elif attr.startswith("InstallSE"): + return self.GenericSEInstall + else: + return object.__getattr__(self, attr) + def BundleUpdated(self, _, states): for handler in self.handlers.values(): handler.BundleUpdated(states) @@ -100,12 +108,12 @@ class SELinux(Bcfg2.Client.Tools.Tool): def canInstall(self, entry): return (Bcfg2.Client.Tools.Tool.canInstall(self, entry) and - self.handlers[entry.get('type')].canInstall(entry)) + self.handlers[entry.tag].canInstall(entry)) def primarykey(self, entry): """ return a string that should be unique amongst all entries in the specification """ - return self.handlers[entry.get('type')].primarykey(entry) + return self.handlers[entry.tag].primarykey(entry) def Install(self, entries, states): # start a transaction @@ -125,32 +133,32 @@ class SELinux(Bcfg2.Client.Tools.Tool): for func, arg, kwargs in self.post_txn_queue: states[arg] = func(*arg, **kwargs) - def InstallSELinux(self, entry): - """Dispatch install to the proper method according to type""" - return self.handlers[entry.get('type')].Install(entry) + def GenericSEInstall(self, entry): + """Dispatch install to the proper method according to entry tag""" + return self.handlers[entry.tag].Install(entry) - def VerifySELinux(self, entry, _): - """Dispatch verify to the proper method according to type""" - rv = self.handlers[entry.get('type')].Verify(entry) + def GenericSEVerify(self, entry, _): + """Dispatch verify to the proper method according to entry tag""" + rv = self.handlers[entry.tag].Verify(entry) if entry.get('qtext') and self.setup['interactive']: entry.set('qtext', - '%s\nInstall SELinux %s %s: (y/N) ' % + '%s\nInstall %s: (y/N) ' % (entry.get('qtext'), - entry.get('type'), - self.handlers[entry.get('type')].tostring(entry))) + self.handlers[entry.tag].tostring(entry))) return rv def Remove(self, entries): - """Dispatch verify to the proper removal method according to type""" + """Dispatch verify to the proper removal + method according to entry tag""" # sort by type types = list() for entry in entries: - if entry.get('type') not in types: - types.append(entry.get('type')) + if entry.tag not in types: + types.append(entry.tag) for etype in types: self.handlers[etype].Remove([e for e in entries - if e.get('type') == etype]) + if e.tag == etype]) class SELinuxEntryHandler(object): @@ -253,8 +261,7 @@ class SELinuxEntryHandler(object): def key2entry(self, key): """ Generate an XML entry from an SELinux record key """ attrs = self._key2attrs(key) - attrs["type"] = self.etype - return Bcfg2.Client.XML.Element("SELinux", **attrs) + return Bcfg2.Client.XML.Element(self.etype, **attrs) def _args(self, entry, method): """ Get the argument list for invoking _modify or _add, or @@ -279,7 +286,7 @@ class SELinuxEntryHandler(object): """ return a string that should be unique amongst all entries in the specification. some entry types are not universally disambiguated by tag:type:name alone """ - return ":".join([entry.tag, entry.get("type"), entry.get("name")]) + return ":".join([entry.tag, entry.get("name")]) def exists(self, entry): """ return True if the entry already exists in the record list """ @@ -303,8 +310,8 @@ class SELinuxEntryHandler(object): continue if current_attrs[attr] != desired_attrs[attr]: entry.set('current_%s' % attr, current_attrs[attr]) - errors.append("SELinux %s %s has wrong %s: %s, should be %s" % - (self.etype, self.tostring(entry), attr, + errors.append("%s %s has wrong %s: %s, should be %s" % + (entry.tag, entry.get('name'), attr, current_attrs[attr], desired_attrs[attr])) if errors: @@ -331,8 +338,8 @@ class SELinuxEntryHandler(object): return True except ValueError: err = sys.exc_info()[1] - self.logger.debug("Failed to %s SELinux %s %s: %s" % - (method, self.etype, self.tostring(entry), err)) + self.logger.info("Failed to %s SELinux %s %s: %s" % + (method, self.etype, self.tostring(entry), err)) return False def Remove(self, entries): @@ -365,7 +372,7 @@ class SELinuxEntryHandler(object): pass -class SELinuxBooleanHandler(SELinuxEntryHandler): +class SELinuxSebooleanHandler(SELinuxEntryHandler): """ handle SELinux boolean entries """ etype = "boolean" value_format = ("value",) @@ -414,7 +421,7 @@ class SELinuxBooleanHandler(SELinuxEntryHandler): SELinuxEntryHandler.canInstall(self, entry)) -class SELinuxPortHandler(SELinuxEntryHandler): +class SELinuxSeportHandler(SELinuxEntryHandler): """ handle SELinux port entries """ etype = "port" value_format = ('selinuxtype', None) @@ -486,7 +493,7 @@ class SELinuxPortHandler(SELinuxEntryHandler): return tuple(entry.get("name").split("/")) -class SELinuxFcontextHandler(SELinuxEntryHandler): +class SELinuxSefcontextHandler(SELinuxEntryHandler): """ handle SELinux file context entries """ etype = "fcontext" @@ -556,11 +563,11 @@ class SELinuxFcontextHandler(SELinuxEntryHandler): '', '') def primarykey(self, entry): - return ":".join([entry.tag, entry.get("type"), entry.get("name"), + return ":".join([entry.tag, entry.get("name"), entry.get("filetype", "all")]) -class SELinuxNodeHandler(SELinuxEntryHandler): +class SELinuxSenodeHandler(SELinuxEntryHandler): """ handle SELinux node entries """ etype = "node" @@ -592,7 +599,7 @@ class SELinuxNodeHandler(SELinuxEntryHandler): entry.get("selinuxtype")) -class SELinuxLoginHandler(SELinuxEntryHandler): +class SELinuxSeloginHandler(SELinuxEntryHandler): """ handle SELinux login entries """ etype = "login" @@ -603,7 +610,7 @@ class SELinuxLoginHandler(SELinuxEntryHandler): return (entry.get("name"), entry.get("selinuxuser"), "") -class SELinuxUserHandler(SELinuxEntryHandler): +class SELinuxSeuserHandler(SELinuxEntryHandler): """ handle SELinux user entries """ etype = "user" @@ -652,7 +659,7 @@ class SELinuxUserHandler(SELinuxEntryHandler): return tuple(rv) -class SELinuxInterfaceHandler(SELinuxEntryHandler): +class SELinuxSeinterfaceHandler(SELinuxEntryHandler): """ handle SELinux interface entries """ etype = "interface" @@ -663,7 +670,7 @@ class SELinuxInterfaceHandler(SELinuxEntryHandler): return (entry.get("name"), '', entry.get("selinuxtype")) -class SELinuxPermissiveHandler(SELinuxEntryHandler): +class SELinuxSepermissiveHandler(SELinuxEntryHandler): """ handle SELinux permissive domain entries """ etype = "permissive" @@ -695,7 +702,7 @@ class SELinuxPermissiveHandler(SELinuxEntryHandler): return (entry.get("name"),) -class SELinuxModuleHandler(SELinuxEntryHandler): +class SELinuxSemoduleHandler(SELinuxEntryHandler): """ handle SELinux module entries """ etype = "module" @@ -808,10 +815,9 @@ class SELinuxModuleHandler(SELinuxEntryHandler): def Install(self, entry, _=None): if not self.filetool.install(self._pathentry(entry)): return False - if hasattr(self, 'records'): + if hasattr(seobject, 'moduleRecords'): # if seobject has the moduleRecords attribute, install the # module using the seobject library - self.records # pylint: disable=W0104 return self._install_seobject(entry) else: # seobject doesn't have the moduleRecords attribute, so @@ -891,8 +897,7 @@ class SELinuxModuleHandler(SELinuxEntryHandler): def FindExtra(self): specified = [self._key(e) - for e in self.tool.getSupportedEntries() - if e.get("type") == self.etype] + for e in self.tool.getSupportedEntries()] rv = [] for module in self._all_records_from_filesystem().keys(): if module not in specified: diff --git a/src/lib/Bcfg2/Server/Plugins/SEModules.py b/src/lib/Bcfg2/Server/Plugins/SEModules.py index 3edfb72a3..fa47f9496 100644 --- a/src/lib/Bcfg2/Server/Plugins/SEModules.py +++ b/src/lib/Bcfg2/Server/Plugins/SEModules.py @@ -40,8 +40,8 @@ class SEModules(Bcfg2.Server.Plugin.GroupSpool): #: objects as its EntrySet children. es_child_cls = SEModuleData - #: SEModules manages ``SELinux`` entries - entry_type = 'SELinux' + #: SEModules manages ``SEModule`` entries + entry_type = 'SEModule' #: The SEModules plugin is experimental experimental = True @@ -68,7 +68,7 @@ class SEModules(Bcfg2.Server.Plugin.GroupSpool): return name.lstrip("/") def HandlesEntry(self, entry, metadata): - if entry.tag in self.Entries and entry.get('type') == 'module': + if entry.tag in self.Entries: return self._get_module_filename(entry) in self.Entries[entry.tag] return Bcfg2.Server.Plugin.GroupSpool.HandlesEntry(self, entry, metadata) |