Search the pam.d configuration file by keyword.  This is provided by
        the :func:`insights.parsers.keyword_search` function - see its
        documentation for more information.

        Searching on the list of PAM configuration entries is exactly like
        they were dictionaries instead of objects with properties.  In
        addition, the 'control_flags' property becomes a dictionary of
        keywords and values, so that 'control_flags__contains' allows
        searching for a particular control flag.

        Returns:
            (list): A list of PamConfEntry objects that match the given
            search criteria.

def search(self, **kwargs):
        """
        Search the pam.d configuration file by keyword.  This is provided by
        the :func:`insights.parsers.keyword_search` function - see its
        documentation for more information.

        Searching on the list of PAM configuration entries is exactly like
        they were dictionaries instead of objects with properties.  In
        addition, the 'control_flags' property becomes a dictionary of
        keywords and values, so that 'control_flags__contains' allows
        searching for a particular control flag.

        Returns:
            (list): A list of PamConfEntry objects that match the given
            search criteria.
        """
        # Because keyword_search takes dicts, and we have objects with complex
        # properties, we convert them to a list of dicts.
        # First, store the things we're going to convert.
        prop_keys = ('service', 'interface', 'module_name', 'module_args')
        search = []
        # Can't find a neat way to do this as a comprehension, so it's back
        # to loops.
        for obj in self.data:
            row = {'entry_obj': obj}
            for key in prop_keys:
                row[key] = getattr(obj, key)
            # For hysterical reasons, module_args can contain None if not
            # defined, but that's non-iterable: replace with ''
            if row['module_args'] is None:
                row['module_args'] = ''
            # Convert control_flags down to key/value dictionary
            flags = {}
            for cf in obj.control_flags:
                flags[cf.flag] = cf.value
            row['control_flags'] = flags
            search.append(row)
        # Now get the result, and just return the entry objects
        found = []
        for r in keyword_search(search, **kwargs):
            found.append(r['entry_obj'])
        return found