Validate user inputs in settings daemon
Currently, the properties defined under /org/openbmc/settings/host0 can take any
value and it is upto the consumer daemons to act only if the valid data was
given.
This patch will provide a validation logic for all the properties and will raise
an exception in the case of invalid inputs. Only on a valid input, will the data
gets written and saved.
Validation methods and types per property are provided in the configuration file
and used by the manager whenever a particular property is changed.
Change-Id: I0731ce6e00ab3cb4e11deb98c03fda8d5adad913
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
diff --git a/settings_manager.py b/settings_manager.py
index 864ee9d..997c56f 100644
--- a/settings_manager.py
+++ b/settings_manager.py
@@ -8,10 +8,12 @@
import os.path as path
import sys
from obmc.dbuslib.bindings import DbusProperties, get_dbus
+from IPy import IP
settings_file_path = os.path.join(sys.prefix, 'share/obmc-phosphor-settings')
sys.path.insert(1, settings_file_path)
import settings_file as s
+import re
DBUS_NAME = 'org.openbmc.settings.Host'
OBJ_NAME = '/org/openbmc/settings/host0'
@@ -20,10 +22,14 @@
class HostSettingsObject(DbusProperties):
def __init__(self, bus, name, settings, path):
- DbusProperties.__init__(self)
- dbus.service.Object.__init__(self, bus, name)
-
+ super(HostSettingsObject, self).__init__(conn=bus, object_path=name,
+ validator=self.input_validator)
+ self.bus = bus
self.path = path
+ # Needed to ignore the validation on default networkconfig values as
+ # opposed to user giving the same.
+ self.adminmode = True
+
if not os.path.exists(path):
os.mkdir(path)
@@ -35,11 +41,13 @@
path="/org/openbmc/settings/host0")
# Create the dbus properties
- for i in settings['host'].iterkeys():
- shk = settings['host'][i]
+ for i in settings[DBUS_NAME].iterkeys():
+ shk = settings[DBUS_NAME][i]
self.set_settings_property(shk['name'],
shk['type'],
shk['default'])
+ # Done with consuming factory settings.
+ self.adminmode = False
def get_bmc_value(self, name):
try:
@@ -58,11 +66,11 @@
if bmcv:
value = bmcv
if type == "i":
- self.Set(DBUS_NAME, name, value)
+ self.Set(DBUS_NAME, name, int(value))
elif type == "s":
self.Set(DBUS_NAME, name, str(value))
elif type == "b":
- self.Set(DBUS_NAME, name, value)
+ self.Set(DBUS_NAME, name, bool(value))
# Save the settings to the BMC. This will write the settings value in
# individual files named by the property name to the BMC.
@@ -85,6 +93,85 @@
def SettingsUpdated(self, sname):
pass
+ def validate_regex(self, regex, value):
+ if not re.compile(regex).search(value):
+ raise ValueError, "Invalid input. Data does not satisfy regex"
+
+ def validate_range(self, min, max, value):
+ if value not in range(min, max):
+ raise ValueError, "Invalid input. Data not in allowed range"
+
+ def validate_list_ignore_case(self, lst, value):
+ if value.lower() not in map(lambda val: val.lower(), lst):
+ raise ValueError, "Invalid input. Data not in allowed values"
+
+ # validate host network configuration
+ # need "ipaddress=,prefix=,gateway=,mac=,addr_type="
+ # Must be able to handle any order
+ def validate_net_config(self, value):
+ if self.adminmode:
+ return
+
+ # Need all of these to be given by the user.
+ user_config = []
+ all_config = ['ipaddress', 'prefix', 'gateway', 'mac', 'addr_type']
+
+ # This has a hard data format mentioned above so no blanks allowed.
+ if value.count(" ") or value.count("=") != 5:
+ raise ValueError, "Invalid Network Data. No white spaces allowed"
+
+ config = value.split(',')
+ for key_value in config:
+ key , value = key_value.split('=')
+ if not key or not value:
+ raise ValueError, "Invalid key or Data"
+
+ # Add the current key seen so we can compare at the end to see
+ # if all values have been given
+ user_config.append(key.lower())
+
+ if key.lower() == 'ipaddress' or key.lower() == 'gateway':
+ IP(value)
+
+ elif key.lower() == 'mac':
+ regex = '([a-fA-F0-9]{2}[:|\-]?){6}'
+ self.validate_regex(regex, value)
+
+ elif key.lower() == 'prefix':
+ self.validate_range(0, 33, int(value))
+
+ elif key.lower() == 'addr_type':
+ allowed = ["STATIC", "DYNAMIC"]
+ self.validate_list_ignore_case(allowed, value)
+
+ # Did user pass everything ??
+ if set(all_config) - set(user_config):
+ raise ValueError, "Invalid Network Data. All information is mandatory"
+
+ # Validate to see if the changes are in order
+ def input_validator(self, iface, proprty, value):
+ settings = s.SETTINGS
+ shk = {}
+ for key in settings[iface].iterkeys():
+ if proprty == settings[iface][key]['name']:
+ shk = settings[iface][key]
+ break
+
+ # User entered key is not present
+ if not shk: raise KeyError, "Invalid Property"
+
+ if shk['validation'] == 'list':
+ self.validate_list_ignore_case(shk['allowed'], value)
+
+ elif shk['validation'] == 'range':
+ self.validate_range(shk['min'], shk['max']+1, value)
+
+ elif shk['validation'] == 'regex':
+ self.validate_regex(shk['regex'], value)
+
+ elif shk['validation'] == 'custom':
+ getattr(self, shk['method'])(value)
+
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)