Source code for insights.parsers.krb5

"""
Krb5Configuration - files ``/etc/krb5.conf`` and ``/etc/krb5.conf.d/*``
=======================================================================

krb5 Configuration are ``/etc/krb5.conf`` and ``/etc/krb5.conf.d/*``,
and the content format is similar to ``INI config``, but they include
values that span multiple lines. Multi-line values start with a '{'
and end with a '}', and we join them together by setting the `is_squ`
variable to True while in a multi-line value.

Example:
    >>> krb5_content = '''
    [realms]
     dns_lookup_realm = false
     ticket_lifetime = 24h
     default_ccache_name = KEYRING:persistent:%{uid}
     EXAMPLE.COM = {
      kdc = kerberos.example.com
      admin_server = kerberos.example.com
     }
     pam = {
      debug = false
      krb4_convert = false
      ticket_lifetime = 36000
     }
     [libdefaults]
      dns_lookup_realm = false
      ticket_lifetime = 24h
      EXAMPLE.COM = {
       kdc = kerberos2.example.com
       admin_server = kerberos2.example.com
     }
    # renew_lifetime = 7d
    # forwardable = true
    # rdns = false
    '''.strip()

    >>> from insights.tests import context_wrap
    >>> shared = {Krb5Configuration: Krb5Configuration(context_wrap(krb5_content))}
    >>> krb5_info = shared[Krb5Configuration]
    >>> krb5_info["libdefaults"]["dnsdsd"]
    "false"
    >>> krb5_info["realms"]["EXAMPLE.COM"]["kdc"]
    "kerberos.example.com"
    >>> krb5_info.sections()
    ["libdefaults","realms"]
    >>> krb5_info.has_section("realms")
    True
    >>> krb5_info.has_option("realms", "nosuchoption")
    False
    >>> krb5_info.options("libdefaults")
    ["dns_lookup_realm","ticket_lifetime","EXAMPLE.COM"]
"""


from .. import parser, Parser, get_active_lines, LegacyItemAccess
from insights.specs import Specs


PREFIX_FOR_LIST = ("includedir", "include", "module")


def _handle_key_value(t_dict, key, value):
    """
    Function to handle key has multi value, and return the values as list.
    """
    if key in t_dict:
        val = t_dict[key]
        if isinstance(val, str):
            val = [val]
        val.append(value)
        return val
    return value


def _handle_krb5_bool(value):
    """
    Convert krb5.conf boolean
    """
    # see lib/krb5/krb/libdef_parse.c _krb5_conf_boolean()
    if value in set(["y", "yes", "true", "t", "1", "on"]):
        return True
    elif value in set(["n", "no", "false", "nil", "0", "off"]):
        return False
    else:
        # _krb5_conf_boolean() treats any other value as "False". Return
        # "None" so caller can identify this case.
        return None


[docs] @parser(Specs.krb5) class Krb5Configuration(Parser, LegacyItemAccess): """ Class for ``krb5.conf`` and ``krb5.conf.d`` configuration files. The Kerberos .ini format is like an ordinary .ini file except that values can include a multiple line key-value pair 'relation' that starts with a '{' and end with a '}' on a trailing line. So we track whether we're in curly braces by setting `is_squ` when we enter a relation, and clearing it when we leave. Please fill in the remainder of the logic here. Attributes: includedir (list): The directory list that `krb5.conf` includes via `includedir` directive include (list): The configuration file list that `krb5.conf` includes via `include` directive module (list): The module list that `krb5.conf` specifed via `module` directive """
[docs] def parse_content(self, content): dict_all = {} is_squ = False section_name = "" squ_value = {} squ_section_name = "" section_value = {} self.includedir = [] self.include = [] self.module = [] unchangeable_tags = [] for line in get_active_lines(content): line = line.strip() if line.startswith(PREFIX_FOR_LIST): key, value = [i.strip() for i in line.split(None, 1)] getattr(self, key).append(value) if key in PREFIX_FOR_LIST else None continue if is_squ: # If in {} sub_section, get the key_value pair if "=" in line: key, value = [i.strip() for i in line.split('=', 1)] if key not in unchangeable_tags: value = value.split()[0].strip() squ_value[key] = _handle_key_value(squ_value, key, value) if line.endswith("*"): unchangeable_tags.append(key) # The {} sub_section should end with }, # if it is, set the whole value to the sub_section name, # and clean the flag else: section_value[squ_section_name] = squ_value is_squ = False squ_section_name = "" squ_value = {} else: # [XXX] means a section, get the section name and the value # format is dict. if line.startswith("[") and line.endswith("]"): # If first section, just get the section name, # if not, set the value to the former section and # get the section name section_name = line.strip("[]") section_value = {} if section_name: dict_all[section_name] = section_value # key value format is XXX = YYY, store as dict elif "=" in line and not line.endswith("{"): key, value = [i.strip() for i in line.split('=', 1)] if key not in unchangeable_tags: value = value.split()[0].strip() section_value[key] = _handle_key_value(section_value, key, value) if line.endswith("*"): unchangeable_tags.append(key) # The {} sub_section should start with format XXX = { else: is_squ = True squ_section_name = line.split("=")[0].strip() self.data = dict_all
[docs] def sections(self): """ Return a list of section names. """ return self.data.keys()
[docs] def has_section(self, section): """ Indicate whether the named section is present in the configuration. Return True if the given section is present, and False if not present. """ return section in self.data
[docs] def options(self, section): """ Return a list of option names for the given section name. """ return self.data[section].keys() if self.has_section(section) else []
[docs] def has_option(self, section, option): """ Check for the existence of a given option in a given section. Return True if the given option is present, and False if not present. """ if section not in self.data: return False return option in self.data[section]
[docs] def getboolean(self, section, option): """Parse option as bool Returns None is not a krb5.conf boolean string. """ value = self.data[section][option] return _handle_krb5_bool(value)