Config file validation
======================

Related ticket(s):

-  `https://pagure.io/SSSD/sssd/issue/2269 <https://pagure.io/SSSD/sssd/issue/2269>`__
-  `https://pagure.io/SSSD/sssd/issue/133 <https://pagure.io/SSSD/sssd/issue/133>`__

Problem statement
~~~~~~~~~~~~~~~~~

Typos in option names are not detected. If conflicting options are used
or required options are missing, SSSD should produce easy to understand
error/debug message so that administrators can fix the problem easier.

Overview of the solution
~~~~~~~~~~~~~~~~~~~~~~~~

Application developers that use libini from Ding libs will be able to
specify constraints that the configuration must respect. These
constraints will be written using INI format in form of rules. Each rule
will use one validator. The validator can be internal (provided by
libini) or external (provided by applications). The rules will be
written in a separate file and their usage will be optional. Validators
will generate errors in form of strings that should be readable for
users. Applications that use libini will then be able to write these
strings somewhere appropriate (for example log files or stderr).

Format of rules
~~~~~~~~~~~~~~~

::

    [rule/NAME]
    validator = validator_name
    validator_specific_parameter1 = ...
    validator_specific_parameter2 = ...
    .
    .
    .
    validator_specific_parameterN = ...

Each rule needs to specify validator that will be used, other parameters
depend on the validator. Some validators may not require any additional
parameters.

Using the rules
~~~~~~~~~~~~~~~

The rules are used from applications in the following way:

#. rules are loaded from file using the function
   ``int ini_read_rules_from_file(const char *filename, struct ini_cfgobj **_rules_obj);``
#. rules and configuration are passed as two fist parameters to the
   function ::

       int ini_rules_check(struct ini_cfgobj *rules_obj,
                              struct ini_cfgobj *config_obj,
                              struct ini_validator *extra_validators,
                              int num_extra_validators,
                              struct ini_errobj *errobj);

The last parameter is special structure used to hold all errors
generated by the validators. libini will provide API to create, destroy,
read errors from and write errors into this structure. The
extra\_validators and num\_extra validators are used to specify external
validators (see section 'External validators' below).

Internal validators
~~~~~~~~~~~~~~~~~~~

Internal validators will be simple validators that may be used by
projects outside SSSD. More complicated and application specific
validators will be written as external validators. First two internal
validators will be ini\_allowed\_options and ini\_allowed\_sections.

Validator ini\_allowed\_options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Example: ::

    [rule/allowed_options_for_section_foo]
    validator = ini_allowed_options
    section_re = ^foo$
    option = foo
    option = bar
    option = baz

The rule above uses the ini\_allowed\_option validator and enumerates
all allowed options for sections with names that match regular
expression :sup:\`foo$. The options allowed here are foo, bar and baz.
Config file like this: ::

    [foo]
    bar = 1
    baz = 1
    foo = 1

will generate no errors, because all options in section foo are allowed.
Config file ::

    [foo]
    baaaar = 1
    baz = 1
    foo = 1

will result in errors being generated because there is an unknown option
baaaar used in section foo.

The ini\_allowed\_options validator controls only sections that match
regular expression specified in section\_re. Other sections are ignored
by the validator.

Validator ini\_allowed\_sections
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This validator is used to enumerate all allowed sections. The format is
following. ::

    [rule/enumerate_sections]
    validator = ini_allowed_sections
    section_re = regex1
    section_re = regex2
    .
    .
    .

    section_re = regexN

The validator will generate error if the config file contains section
that is not matched by any of the regular expressions specified by one
of the section\_re parameters.

External validators
~~~~~~~~~~~~~~~~~~~

External validators are specified using following structures: ::

    struct ini_validator {
         const char *name;
         ini_validator_func *func;
    };

The name attribute is sting that is used inside rules in the validator
parameter. The func attribute is pointer to function of type
ini\_validator\_func which is defined using typedef as following: ::

    typedef int (ini_validator_func)(const char *rule_name,
                                     struct ini_cfgobj *rules_obj,
                                     struct ini_cfgobj *config_obj,
                                     struct ini_errobj *errobj);

This function has following parameters:

-  rule\_name - this is name of rule that uses this validator (for
   example "rule/myrule")
-  rules\_obj - this is config object with all the rules
-  config\_obj - this is config object with the actual configuration
   that is being checked by the rules
-  errobj - this ini\_errobj structure used to propagate errors

Users of libini can specify array of struct ini\_validator structures
and pass them to ini\_rules\_check() function. After this they can be
used in the same way as internal validators.

Configuration changes
~~~~~~~~~~~~~~~~~~~~~

In order to take advantage of this feature in SSSD the constraint file
will have to be created.

How To Test
~~~~~~~~~~~

Unit tests in Ding libs. Integration and unit tests for SSSD.

Authors
~~~~~~~

Michal Židek `mzidek@redhat.com <mailto:mzidek@redhat.com>`__