<def-group>
    <definition class="compliance" id="{{{ rule_id }}}" version="1">
        {{{ oval_metadata("If inbound SSH access is needed, the firewall should allow access to
        the SSH service.") }}}
        <criteria operator="AND">
            <criteria operator="OR">
                <criteria operator="AND">
                    <criterion
                        comment="Ensure default file zones have SSH service defined"
                        test_ref="test_firewalld_sshd_port_enabled_zone_ssh_enabled_usr"/>
                    <criterion
                        comment="Ensure default files from active zones were not overridden"
                        test_ref="test_firewalld_sshd_port_enabled_usr_zones_not_overridden"/>
                </criteria>
                <criterion
                    comment="Ensure custom files from active zones have SSH service defined"
                    test_ref="test_firewalld_sshd_port_enabled_zone_ssh_enabled_etc"/>
            </criteria>
            <criteria operator="AND">
                <criterion
                    comment="Ensure default file for SSH service is correct"
                    test_ref="test_firewalld_sshd_port_enabled_ssh_service_usr"/>
                <criterion
                    comment="Ensure the modified firewalld SSH port is correct"
                    test_ref="test_firewalld_sshd_port_enabled_ssh_service_etc"/>
            </criteria>
        </criteria>
    </definition>

    <!-- zones allow SSH -->
    <!-- Except to the block and drop zones, which have a clear purpose suggested by their
         respective names, all other zones delivered in the firewalld package allow SSH
         out-of-box. This test ensure these files are indeed allowing SSH in case a NIC is
         assigned to any of these existing zones. -->
    <ind:xmlfilecontent_test id="test_firewalld_sshd_port_enabled_zone_ssh_enabled_usr"
        check="all" check_existence="at_least_one_exists" version="1"
        comment="SSH service is defined in all zones delivered in the firewalld package">
      <ind:object object_ref="object_firewalld_sshd_port_enabled_zone_files_usr"/>
    </ind:xmlfilecontent_test>

    <ind:xmlfilecontent_object id="object_firewalld_sshd_port_enabled_zone_files_usr"
      version="1">
      <ind:path>/usr/lib/firewalld/zones</ind:path>
      <ind:filename operation="pattern match" var_check="all"
          var_ref="var_firewalld_sshd_port_enabled_default_zones"/>
      <ind:xpath>/zone/service[@name='ssh']</ind:xpath>
    </ind:xmlfilecontent_object>

    <!-- Once the default firewalld zone files are confirmed to be allowing ssh, it is necessary
         to confirm they are indeed in use by not having an equivalent file in /etc/firewalld/zones
         dir. Otherwise, it is not possible to rely only on default files and the /etc dir should
         also be checked. -->
    <unix:file_test id="test_firewalld_sshd_port_enabled_usr_zones_not_overridden" version="1"
        check="all" check_existence="none_exist"
        comment="there is no equivalent zone file defined by the administrator in /etc dir">
      <unix:object object_ref="object_firewalld_sshd_port_enabled_customized_zone_files"/>
    </unix:file_test>

    <unix:file_object id="object_firewalld_sshd_port_enabled_customized_zone_files" version="1">
      <unix:behaviors recurse="directories" recurse_direction="down" max_depth="1"
          recurse_file_system="all"/>
      <unix:path>/etc/firewalld/zones</unix:path>
      <unix:filename operation="pattern match" var_check="at least one"
          var_ref="var_firewalld_sshd_port_enabled_default_zones"/>
    </unix:file_object>

    <!-- During the refactoring of this file, it was tried many techniques to use the available
         OVAL resources in order to detect and assess only active zone, which are zones with at
         least one NIC assigned to it. Since it was possible to easily have the list of active
         zones, it was cumbersome to use that list in other OVAL objects without introduce a high
         level of complexity to ensure proper assessment in environments where multiple NICs and
         multiple zones are in use. So, in favor of simplicity and readbility it was decided to
         work with a static list. It means that, in the future, it is possible this list needs to
         be updated. -->
    <local_variable id="var_firewalld_sshd_port_enabled_default_zones" version="1"
        datatype="string"
        comment="Regex containing the list of zones files delivered in the firewalld package">
        <literal_component>^(dmz|external|home|internal|public|trusted|work)\.xml$</literal_component>
    </local_variable>

    <!-- If any default zone is modified by the administrator, the respective zone file is placed
         in the /etc/firewalld/zones dir in order to override the default zone settings. The same
         directory is applicable for new zones created by the administrator. Therefore, all files
         in this directory should also allow SSH.
         This test was updated in a reaction to https://github.com/OpenSCAP/openscap/issues/1923,
         which changed the behaviour of xmlfilecontent probe in OpenSCAP 1.3.7. Currently, a
         variable test is the simplest way to check if all custom zones are allowing ssh, but have
         an impact in transparency since the objects are not shown in reports. The transparency
         impact can be workarounded by using other OVAL objects, but this would impact in
         readability and would increase complexity. This solution is in favor of simplicity. -->
    <ind:variable_test id="test_firewalld_sshd_port_enabled_zone_ssh_enabled_etc"
        check="all" check_existence="at_least_one_exists" version="1"
        comment="SSH service is defined in all zones created or modified by the administrator">
        <ind:object
            object_ref="object_firewalld_sshd_port_enabled_custom_zone_files_with_ssh_count"/>
        <ind:state state_ref="state_firewalld_sshd_port_enabled_custom_zone_files_count"/>
    </ind:variable_test>

    <ind:variable_object id="object_firewalld_sshd_port_enabled_custom_zone_files_with_ssh_count"
        version="1">
      <ind:var_ref>var_firewalld_sshd_port_enabled_custom_zone_files_with_ssh_count</ind:var_ref>
    </ind:variable_object>

    <local_variable id="var_firewalld_sshd_port_enabled_custom_zone_files_with_ssh_count"
        datatype="int" version="1"
        comment="Variable including number of custom zone files allowing ssh">
        <count>
            <object_component item_field="filepath"
                object_ref="object_firewalld_sshd_port_enabled_zone_files_etc"/>
        </count>
    </local_variable>

    <ind:xmlfilecontent_object id="object_firewalld_sshd_port_enabled_zone_files_etc" version="1">
        <ind:path>/etc/firewalld/zones</ind:path>
        <ind:filename operation="pattern match">^.*\.xml$</ind:filename>
        <ind:xpath>/zone/service[@name='ssh']</ind:xpath>
    </ind:xmlfilecontent_object>

    <ind:variable_state id="state_firewalld_sshd_port_enabled_custom_zone_files_count"
        version="1">
        <ind:value datatype="int" operation="equals" var_check="at least one"
            var_ref="var_firewalld_sshd_port_enabled_custom_zone_files_count"/>
    </ind:variable_state>

    <local_variable id="var_firewalld_sshd_port_enabled_custom_zone_files_count"
        datatype="int" version="1"
        comment="Variable including number of custom zone files present in /etc/firewalld/zones">
        <count>
            <object_component item_field="filepath"
                object_ref="object_firewalld_sshd_port_enabled_custom_zone_files"/>
        </count>
    </local_variable>

    <unix:file_object id="object_firewalld_sshd_port_enabled_custom_zone_files" version="1">
        <unix:behaviors recurse="directories" recurse_direction="down" max_depth="1"
            recurse_file_system="local"/>
        <unix:path>/etc/firewalld/zones</unix:path>
        <unix:filename operation="pattern match">^.*\.xml$</unix:filename>
    </unix:file_object>

    <!-- SSH service is configured as expected -->
    <!-- The firewalld package brings many services already defined out-of-box, including SSH.
         SSH port is defined as 22/tcp by default. However, there are possible cases where the
         admin wants, for whatever reason, to change this default port. The proper way to do this
         is overriding the respectice SSH service file by populating the /etc/firewalld/services
         directory with a file with the same name. So, its necessary to ensure the file delivered
         by the package, in the /usr/lib/firewalld/services directory, was not changed. However,
         if the file is changed, there is necessary to ensure there is a customized service
         properly configured by the administrator. -->
    <ind:xmlfilecontent_test id="test_firewalld_sshd_port_enabled_ssh_service_usr"
        check="all" check_existence="all_exist" version="1"
        comment="SSH service is interger in the /usr/lib/firewalld/services dir">
      <ind:object object_ref="object_firewalld_sshd_port_enabled_ssh_service_file_usr"/>
    </ind:xmlfilecontent_test>

    <ind:xmlfilecontent_object id="object_firewalld_sshd_port_enabled_ssh_service_file_usr"
      version="1">
      <ind:filepath>/usr/lib/firewalld/services/ssh.xml</ind:filepath>
      <ind:xpath>/service/port[@port='22']</ind:xpath>
    </ind:xmlfilecontent_object>

    <!-- If, for whatever reason, the administrator decides to change the SSH default port, the
         modified ssh.xml file is placed in the /etc/firewalld/services directory with the proper
         port defined. -->
    <ind:textfilecontent54_test id="test_firewalld_sshd_port_enabled_ssh_service_etc"
        check="all" check_existence="any_exist" version="1"
        comment="SSH service is properly configured in /etc/firewalld/services dir">
        <ind:object object_ref="object_firewalld_sshd_port_enabled_ssh_service_file_etc"/>
        <ind:state state_ref="state_firewalld_sshd_port_enabled_ssh_service_file_etc"/>
    </ind:textfilecontent54_test>

    <ind:textfilecontent54_object id="object_firewalld_sshd_port_enabled_ssh_service_file_etc"
        version="1">
        <ind:filepath>/etc/firewalld/services/ssh.xml</ind:filepath>
        <ind:pattern operation="pattern match">&lt;port.*port="(\d+)"</ind:pattern>
        <ind:instance datatype="int" operation="equals">1</ind:instance>
    </ind:textfilecontent54_object>

    <ind:textfilecontent54_state id="state_firewalld_sshd_port_enabled_ssh_service_file_etc"
        comment="expected SSH port as defined by external variable" version="1">
      <ind:subexpression datatype="int" operation="equals" var_ref="sshd_listening_port"/>
    </ind:textfilecontent54_state>

    <external_variable id="sshd_listening_port" datatype="int" version="1"
        comment="external variable containing the expected SSH port"/>
</def-group>
