File feature-upstream-new-check-config-2.patch of Package firewalld.24166

From 4e8710b0df4c1ae4625c612ffa560219fed9f709 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Thu, 11 Nov 2021 16:04:26 -0500
Subject: [PATCH] chore(io): check_config() now takes all_io_objects

The intent is to allow cross object configuration checks. e.g. is the
service used in the zone actually defined?
---
 src/firewall/core/fw_config.py             | 62 +++++++++++++---------
 src/firewall/core/io/direct.py             |  4 +-
 src/firewall/core/io/helper.py             |  2 +-
 src/firewall/core/io/icmptype.py           |  2 +-
 src/firewall/core/io/io_object.py          | 18 +++----
 src/firewall/core/io/ipset.py              |  6 +--
 src/firewall/core/io/lockdown_whitelist.py |  4 +-
 src/firewall/core/io/policy.py             |  6 +--
 src/firewall/core/io/service.py            |  2 +-
 src/firewall/core/io/zone.py               |  4 +-
 src/firewall/server/config.py              |  4 +-
 11 files changed, 64 insertions(+), 50 deletions(-)

Index: firewalld-0.9.3/src/firewall/core/fw_config.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/fw_config.py
+++ firewalld-0.9.3/src/firewall/core/fw_config.py
@@ -120,6 +120,20 @@ class FirewallConfig(object):
             self._direct = None
 
         self.__init_vars()
+    
+    def get_all_io_objects_dict(self):
+        """
+        Returns a dict of dicts of all permanent config objects.
+        """
+        conf_dict = {}
+        conf_dict["ipsets"] = {ipset: self.get_ipset(ipset) for ipset in self.get_ipsets()}
+        conf_dict["helpers"] = {helper: self.get_helper(helper) for helper in self.get_helpers()}
+        conf_dict["icmptypes"] = {icmptype: self.get_icmptype(icmptype) for icmptype in self.get_icmptypes()}
+        conf_dict["services"] = {service: self.get_service(service) for service in self.get_services()}
+        conf_dict["zones"] = {zone: self.get_zone(zone) for zone in self.get_zones()}
+        conf_dict["policies"] = {policy: self.get_policy_object(policy) for policy in self.get_policy_objects()}
+
+        return conf_dict
 
     # access check
 
@@ -208,7 +222,7 @@ class FirewallConfig(object):
     def set_ipset_config(self, obj, conf):
         if obj.builtin:
             x = copy.copy(obj)
-            x.import_config(conf)
+            x.import_config(conf, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_IPSETS
             x.builtin = False
             if obj.path != x.path:
@@ -217,7 +231,7 @@ class FirewallConfig(object):
             ipset_writer(x)
             return x
         else:
-            obj.import_config(conf)
+            obj.import_config(conf, self.get_all_io_objects_dict())
             ipset_writer(obj)
             return obj
 
@@ -228,7 +242,7 @@ class FirewallConfig(object):
 
         x = IPSet()
         x.check_name(name)
-        x.import_config(conf)
+        x.import_config(conf, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_IPSETS
@@ -381,7 +395,7 @@ class FirewallConfig(object):
     def set_icmptype_config(self, obj, conf):
         if obj.builtin:
             x = copy.copy(obj)
-            x.import_config(conf)
+            x.import_config(conf, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_ICMPTYPES
             x.builtin = False
             if obj.path != x.path:
@@ -390,7 +404,7 @@ class FirewallConfig(object):
             icmptype_writer(x)
             return x
         else:
-            obj.import_config(conf)
+            obj.import_config(conf, self.get_all_io_objects_dict())
             icmptype_writer(obj)
             return obj
 
@@ -401,7 +415,7 @@ class FirewallConfig(object):
 
         x = IcmpType()
         x.check_name(name)
-        x.import_config(conf)
+        x.import_config(conf, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_ICMPTYPES
@@ -570,7 +584,7 @@ class FirewallConfig(object):
 
         if obj.builtin:
             x = copy.copy(obj)
-            x.import_config_dict(conf_dict)
+            x.import_config_dict(conf_dict, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_SERVICES
             x.builtin = False
             if obj.path != x.path:
@@ -579,14 +593,14 @@ class FirewallConfig(object):
             service_writer(x)
             return x
         else:
-            obj.import_config_dict(conf_dict)
+            obj.import_config_dict(conf_dict, self.get_all_io_objects_dict())
             service_writer(obj)
             return obj
 
     def set_service_config_dict(self, obj, conf):
         if obj.builtin:
             x = copy.copy(obj)
-            x.import_config_dict(conf)
+            x.import_config_dict(conf, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_SERVICES
             x.builtin = False
             if obj.path != x.path:
@@ -595,7 +609,7 @@ class FirewallConfig(object):
             service_writer(x)
             return x
         else:
-            obj.import_config_dict(conf)
+            obj.import_config_dict(conf, self.get_all_io_objects_dict())
             service_writer(obj)
             return obj
 
@@ -610,7 +624,7 @@ class FirewallConfig(object):
 
         x = Service()
         x.check_name(name)
-        x.import_config_dict(conf_dict)
+        x.import_config_dict(conf_dict, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_SERVICES
@@ -629,7 +643,7 @@ class FirewallConfig(object):
 
         x = Service()
         x.check_name(name)
-        x.import_config_dict(conf)
+        x.import_config_dict(conf, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_SERVICES
@@ -805,7 +819,7 @@ class FirewallConfig(object):
         if obj.builtin:
             x = copy.copy(obj)
             x.fw_config = self
-            x.import_config_dict(conf_dict)
+            x.import_config_dict(conf_dict, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_ZONES
             x.builtin = False
             if obj.path != x.path:
@@ -815,7 +829,7 @@ class FirewallConfig(object):
             return x
         else:
             obj.fw_config = self
-            obj.import_config_dict(conf_dict)
+            obj.import_config_dict(conf_dict, self.get_all_io_objects_dict())
             zone_writer(obj)
             return obj
 
@@ -823,7 +837,7 @@ class FirewallConfig(object):
         if obj.builtin:
             x = copy.copy(obj)
             x.fw_config = self
-            x.import_config_dict(conf)
+            x.import_config_dict(conf, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_ZONES
             x.builtin = False
             if obj.path != x.path:
@@ -833,7 +847,7 @@ class FirewallConfig(object):
             return x
         else:
             obj.fw_config = self
-            obj.import_config_dict(conf)
+            obj.import_config_dict(conf, self.get_all_io_objects_dict())
             zone_writer(obj)
             return obj
 
@@ -848,7 +862,7 @@ class FirewallConfig(object):
         x = Zone()
         x.fw_config = self
         x.check_name(name)
-        x.import_config_dict(conf_dict)
+        x.import_config_dict(conf_dict, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_ZONES
@@ -867,7 +881,7 @@ class FirewallConfig(object):
         x = Zone()
         x.fw_config = self
         x.check_name(name)
-        x.import_config_dict(conf)
+        x.import_config_dict(conf, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_ZONES
@@ -1029,7 +1043,7 @@ class FirewallConfig(object):
         if obj.builtin:
             x = copy.copy(obj)
             x.fw_config = self
-            x.import_config_dict(conf)
+            x.import_config_dict(conf, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_POLICIES
             x.builtin = False
             if obj.path != x.path:
@@ -1039,7 +1053,7 @@ class FirewallConfig(object):
             return x
         else:
             obj.fw_config = self
-            obj.import_config_dict(conf)
+            obj.import_config_dict(conf, self.get_all_io_objects_dict())
             policy_writer(obj)
             return obj
 
@@ -1050,7 +1064,7 @@ class FirewallConfig(object):
         x = Policy()
         x.fw_config = self
         x.check_name(name)
-        x.import_config_dict(conf)
+        x.import_config_dict(conf, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_POLICIES
@@ -1211,7 +1225,7 @@ class FirewallConfig(object):
     def set_helper_config(self, obj, conf):
         if obj.builtin:
             x = copy.copy(obj)
-            x.import_config(conf)
+            x.import_config(conf, self.get_all_io_objects_dict())
             x.path = config.ETC_FIREWALLD_HELPERS
             x.builtin = False
             if obj.path != x.path:
@@ -1220,7 +1234,7 @@ class FirewallConfig(object):
             helper_writer(x)
             return x
         else:
-            obj.import_config(conf)
+            obj.import_config(conf, self.get_all_io_objects_dict())
             helper_writer(obj)
             return obj
 
@@ -1231,7 +1245,7 @@ class FirewallConfig(object):
 
         x = Helper()
         x.check_name(name)
-        x.import_config(conf)
+        x.import_config(conf, self.get_all_io_objects_dict())
         x.name = name
         x.filename = "%s.xml" % name
         x.path = config.ETC_FIREWALLD_HELPERS
Index: firewalld-0.9.3/src/firewall/core/io/direct.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/direct.py
+++ firewalld-0.9.3/src/firewall/core/io/direct.py
@@ -142,7 +142,7 @@ class Direct(IO_Object):
         self.rules = LastUpdatedOrderedDict()
         self.passthroughs = LastUpdatedOrderedDict()
 
-    def _check_config(self, conf, item, all_conf):
+    def _check_config(self, conf, item, all_conf, all_io_objects):
         pass
         # check arg lists
 
@@ -166,7 +166,7 @@ class Direct(IO_Object):
         ret.append(x)
         return tuple(ret)
 
-    def import_config(self, conf):
+    def import_config(self, conf, all_io_objects):
         self.cleanup()
         self.check_config(conf)
         for i,(element,dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
Index: firewalld-0.9.3/src/firewall/core/io/helper.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/helper.py
+++ firewalld-0.9.3/src/firewall/core/io/helper.py
@@ -90,7 +90,7 @@ class Helper(IO_Object):
             raise FirewallError(errors.INVALID_IPV,
                                 "'%s' not in '%s'" % (ipv, ipvs))
 
-    def _check_config(self, config, item, all_config):
+    def _check_config(self, config, item, all_config, all_io_objects):
         if item == "ports":
             for port in config:
                 check_port(port[0])
Index: firewalld-0.9.3/src/firewall/core/io/icmptype.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/icmptype.py
+++ firewalld-0.9.3/src/firewall/core/io/icmptype.py
@@ -75,7 +75,7 @@ class IcmpType(IO_Object):
         self.description = u2b_if_py2(self.description)
         self.destination = [u2b_if_py2(m) for m in self.destination]
 
-    def _check_config(self, config, item, all_config):
+    def _check_config(self, config, item, all_config, all_io_objects):
         if item == "destination":
             for destination in config:
                 if destination not in [ "ipv4", "ipv6" ]:
Index: firewalld-0.9.3/src/firewall/core/io/io_object.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/io_object.py
+++ firewalld-0.9.3/src/firewall/core/io/io_object.py
@@ -68,8 +68,8 @@ class IO_Object(object):
                 conf[key] = copy.deepcopy(getattr(self, key))
         return conf
 
-    def import_config(self, conf):
-        self.check_config(conf)
+    def import_config(self, conf, all_io_objects):
+        self.check_config(conf, all_io_objects)
         for i,(element,dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
             if isinstance(conf[i], list):
                 # remove duplicates without changing the order
@@ -84,8 +84,8 @@ class IO_Object(object):
             else:
                 setattr(self, element, copy.deepcopy(conf[i]))
 
-    def import_config_dict(self, conf):
-        self.check_config_dict(conf)
+    def import_config_dict(self, conf, all_io_objects):
+        self.check_config_dict(conf, all_io_objects)
 
         for key in conf:
             if not hasattr(self, key):
@@ -109,7 +109,7 @@ class IO_Object(object):
                     errors.INVALID_NAME,
                     "'%s' is not allowed in '%s'" % ((char, name)))
 
-    def check_config(self, conf):
+    def check_config(self, conf, all_io_objects={}):
         if len(conf) != len(self.IMPORT_EXPORT_STRUCTURE):
             raise FirewallError(
                 errors.INVALID_TYPE,
@@ -118,17 +118,17 @@ class IO_Object(object):
         conf_dict = {}
         for i,(x,y) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
             conf_dict[x] = conf[i]
-        self.check_config_dict(conf_dict)
+        self.check_config_dict(conf_dict, all_io_objects)
 
-    def check_config_dict(self, conf):
+    def check_config_dict(self, conf, all_io_objects):
         type_formats = dict([(x[0], x[1]) for x in self.IMPORT_EXPORT_STRUCTURE])
         for key in conf:
             if key not in [x for (x,y) in self.IMPORT_EXPORT_STRUCTURE]:
                 raise FirewallError(errors.INVALID_OPTION, "option '{}' is not valid".format(key))
             self._check_config_structure(conf[key], type_formats[key])
-            self._check_config(conf[key], key, conf)
+            self._check_config(conf[key], key, conf, all_io_objects)
 
-    def _check_config(self, dummy1, dummy2, dummy3):
+    def _check_config(self, dummy1, dummy2, dummy3, dummy4):
         # to be overloaded by sub classes
         return
 
Index: firewalld-0.9.3/src/firewall/core/io/ipset.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/ipset.py
+++ firewalld-0.9.3/src/firewall/core/io/ipset.py
@@ -277,7 +277,7 @@ class IPSet(IO_Object):
                 raise FirewallError(errors.INVALID_IPSET,
                                     "ipset type '%s' not usable" % ipset_type)
 
-    def _check_config(self, config, item, all_config):
+    def _check_config(self, config, item, all_config, all_io_objects):
         if item == "type":
             if config not in IPSET_TYPES:
                 raise FirewallError(errors.INVALID_TYPE,
@@ -304,13 +304,13 @@ class IPSet(IO_Object):
                      config[key] not in [ "inet", "inet6" ]:
                     raise FirewallError(errors.INVALID_FAMILY, config[key])
 
-    def import_config(self, config):
+    def import_config(self, config, all_io_objects):
         if "timeout" in config[4] and config[4]["timeout"] != "0":
             if len(config[5]) != 0:
                 raise FirewallError(errors.IPSET_WITH_TIMEOUT)
         for entry in config[5]:
             IPSet.check_entry(entry, config[4], config[3])
-        super(IPSet, self).import_config(config)
+        super(IPSet, self).import_config(config, all_io_objects)
 
 # PARSER
 
Index: firewalld-0.9.3/src/firewall/core/io/lockdown_whitelist.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/lockdown_whitelist.py
+++ firewalld-0.9.3/src/firewall/core/io/lockdown_whitelist.py
@@ -118,10 +118,10 @@ class LockdownWhitelist(IO_Object):
 #        self.gids = [ ]
 #        self.groups = [ ]
 
-    def _check_config(self, config, item, all_config):
+    def _check_config(self, config, item, all_config, all_io_objects):
         if item in [ "commands", "contexts", "users", "uids" ]:
             for x in config:
-                self._check_config(x, item[:-1], all_config)
+                self._check_config(x, item[:-1], all_config, all_io_objects)
         elif item == "command":
             if not checkCommand(config):
                 raise FirewallError(errors.INVALID_COMMAND, config)
Index: firewalld-0.9.3/src/firewall/core/io/policy.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/policy.py
+++ firewalld-0.9.3/src/firewall/core/io/policy.py
@@ -296,7 +296,7 @@ def common_endElement(obj, name):
     elif name in [ "accept", "reject", "drop", "mark", "log", "audit" ]:
         obj._limit_ok = None
 
-def common_check_config(obj, config, item, all_config):
+def common_check_config(obj, config, item, all_config, all_io_objects):
     if item == "services" and obj.fw_config:
         existing_services = obj.fw_config.get_services()
         for service in config:
@@ -686,8 +686,8 @@ class Policy(IO_Object):
         else:
             super(Policy, self).__setattr__(name, value)
 
-    def _check_config(self, config, item, all_config):
-        common_check_config(self, config, item, all_config)
+    def _check_config(self, config, item, all_config, all_io_objects):
+        common_check_config(self, config, item, all_config, all_io_objects)
 
         if item == "target":
             if config not in POLICY_TARGETS:
Index: firewalld-0.9.3/src/firewall/core/io/service.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/service.py
+++ firewalld-0.9.3/src/firewall/core/io/service.py
@@ -106,7 +106,7 @@ class Service(IO_Object):
         self.includes = [u2b_if_py2(s) for s in self.includes]
         self.helpers = [u2b_if_py2(s) for s in self.helpers]
 
-    def _check_config(self, config, item, all_config):
+    def _check_config(self, config, item, all_config, all_io_objects):
         if item == "ports":
             for port in config:
                 if port[0] != "":
Index: firewalld-0.9.3/src/firewall/core/io/zone.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/core/io/zone.py
+++ firewalld-0.9.3/src/firewall/core/io/zone.py
@@ -183,8 +183,8 @@ class Zone(IO_Object):
         del conf["UNUSED"]
         return conf
 
-    def _check_config(self, config, item, all_config):
-        common_check_config(self, config, item, all_config)
+    def _check_config(self, config, item, all_config, all_io_objects):
+        common_check_config(self, config, item, all_config, all_io_objects)
 
         if item == "target":
             if config not in ZONE_TARGETS:
Index: firewalld-0.9.3/src/firewall/server/config.py
===================================================================
--- firewalld-0.9.3.orig/src/firewall/server/config.py
+++ firewalld-0.9.3/src/firewall/server/config.py
@@ -815,7 +815,7 @@ class FirewallDConfig(slip.dbus.service.
     def setLockdownWhitelist(self, settings, sender=None): # pylint: disable=W0613
         log.debug1("config.policies.setLockdownWhitelist(...)")
         settings = dbus_to_python(settings)
-        self.config.get_policies().lockdown_whitelist.import_config(settings)
+        self.config.get_policies().lockdown_whitelist.import_config(settings, {})
         self.config.get_policies().lockdown_whitelist.write()
         self.LockdownWhitelistUpdated()
 
@@ -1425,7 +1425,7 @@ class FirewallDConfig(slip.dbus.service.
         # returns list ipv, table, list of chains
         log.debug1("config.direct.update()")
         settings = dbus_to_python(settings)
-        self.config.get_direct().import_config(settings)
+        self.config.get_direct().import_config(settings, {})
         self.config.get_direct().write()
         self.Updated()
 
openSUSE Build Service is sponsored by