Source code for insights.parsers.sudoers

"""
Sudoers - files ``/etc/sudoers`` and ``/etc/sudoers.d/*``
=========================================================

Module for processing each of the ``/etc/sudoers`` and ``/etc/sudoers.d/*`` files.

.. note::
    These files is filtered to skip the sensitive information.

.. note::
    Please use the :py:class:`insigths.combiners.suoders.Sudoers` for global
    checking.

"""
from insights.core import Parser
from insights.core.exceptions import SkipComponent
from insights.core.filters import add_filter
from insights.core.plugins import parser
from insights.parsers import get_active_lines
from insights.specs import Specs

add_filter(Specs.sudoers, "#includedir")
"""The "#includedir" is the line that should be always collected. """


[docs] class SudoersBase(object): """ Base class for parsing the files ``/etc/sudoers`` or ``/etc/sudoers.d/*``, it provides the following two helper functions ``get`` and ``last``. """
[docs] def get(self, s, check=all): """ Returns all lines that contain `s` anywhere and return the list of RAW line directly. `s` can be either a single string or a string list. For list, all keywords in the list must be found in each line. Parameters: s(str or list): one or more strings to search for check(func): built-in function ``all`` or ``any`` applied to each line Returns: (list): list of lines that contain the `s`. Raises: TypeError: When `s` is not a string or a list of strings, or `num` is not an integer. """ def _valid_search(s, check=all): if isinstance(s, str): return lambda l: s in l elif (isinstance(s, (tuple, list)) and len(s) > 0 and all(isinstance(w, str) for w in s)): return lambda l: check(w in l for w in s) raise TypeError('"s" must be given as a string or a list of strings') search_by_expression = _valid_search(s, check) ret = [] for _l in self.lines: if search_by_expression(_l): ret.append(_l) return ret
[docs] def last(self, s, check=all): """ Returns the last line that contain `s` anywhere and return the RAW line directly. `s` can be either a single string or a string list. For list, all keywords in the list must be found in each line. Parameters: s(str or list): one or more strings to search for check(func): built-in function ``all`` or ``any`` applied to each line Returns: (str): The line that contains the `s`. None by default. Raises: TypeError: When `s` is not a string or a list of strings, or `num` is not an integer. """ ret = self.get(s, check) return ret[-1] if ret else None
[docs] @parser(Specs.sudoers) class EtcSudoers(Parser, SudoersBase): """ Class to parse the files ``/etc/sudoers`` or ``/etc/sudoers.d/*`` Typical content of the ``/etc/sudoers`` and ``/etc/sudoers.d/*`` is:: ## Allows people in group wheel to run all commands %wheel ALL=(ALL) ALL ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) #includedir /etc/sudoers.d Attributes: lines(list): The list of RAW lines of the file. .. note:: The super-class :class:`SudoersBase` providers two helper functions: :func:`SudoersBase.get()` and :func:`SudoersBase.last()`. Examples: >>> type(sudo) <class 'insights.parsers.sudoers.EtcSudoers'> >>> len(sudo.lines) 2 >>> sudo.get(['wheel', 'ALL=(ALL)', 'ALL']) ['%wheel ALL=(ALL) ALL'] >>> sudo.last("#includedir") '#includedir /etc/sudoers.d' """
[docs] def parse_content(self, content): self.lines = get_active_lines(content, comment_char="##") if not self.lines: raise SkipComponent