summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishwanatha Subbanna <vishwa@linux.vnet.ibm.com>2016-09-21 15:49:26 +0530
committerPatrick Williams <patrick@stwcx.xyz>2016-09-27 18:42:55 +0000
commit5b090c61086f196fbaa9279ae7728d3680f52e43 (patch)
tree60e7a49d53e282c9a84b1f25397a1c240bc69050
parentd5b7e9385bd62dddaf765810c16f68ea2a1c6324 (diff)
downloadphosphor-settingsd-5b090c61086f196fbaa9279ae7728d3680f52e43.tar.gz
phosphor-settingsd-5b090c61086f196fbaa9279ae7728d3680f52e43.zip
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>
-rw-r--r--settings.yaml29
-rw-r--r--settings_file.py91
-rw-r--r--settings_manager.py101
3 files changed, 185 insertions, 36 deletions
diff --git a/settings.yaml b/settings.yaml
index 9e08e29..ca26840 100644
--- a/settings.yaml
+++ b/settings.yaml
@@ -1,6 +1,6 @@
---
# Settings Config File
-host:
+org.openbmc.settings.Host:
powercap:
name: power_cap
type: i
@@ -8,39 +8,66 @@ host:
min: 0
max: 1000
unit: watts
+ validation: range
bootflags:
name: boot_flags
type: s
default: "default"
+ validation: list
+ allowed: ["Network", "Disk", "Safe", "CDROM", "Setup", "default"]
sysstate:
name: system_state
type: s
default: ""
+ validation: None
powerpolicy:
name: power_policy
type: s
default: "RESTORE_LAST_STATE"
+ validation: list
+ allowed: ["ALWAYS_POWER_ON", "RESTORE_LAST_STATE", "LEAVE_OFF"]
restrictedmode:
name: restricted_mode
type: b
default: false
+ min: 0
+ max: 1
+ validation: range
bootpolicy:
name: boot_policy
type: s
default: "ONETIME"
+ validation: list
+ allowed: ["ONETIME", "PERMANENT"]
networkconfig:
name: network_config
type: s
default: "ipaddress=,prefix=,gateway=,mac=,addr_type="
+ validation: custom
+ method: validate_net_config
TimeMode:
name: time_mode
type: s
default: "NTP"
+ validation: list
+ allowed: ["NTP", "MANUAL"]
TimeOwner:
name: time_owner
type: s
default: "BMC"
+ validation: list
+ allowed: ["BMC", "HOST", "SPLIT", "BOTH"]
UseDhcpNtp:
name: use_dhcp_ntp
type: s
default: "yes"
+ validation: list
+ allowed: ["yes", "no"]
+
+# Example of using regex
+# macaddress:
+# name: mac_address
+# type: s
+# default: "aa:bb:cc:dd:ee:ff"
+# validation: regex
+# regex: '([a-fA-F0-9]{2}[:|\-]?){6}'
diff --git a/settings_file.py b/settings_file.py
index ced0d5e..f0c6d13 100644
--- a/settings_file.py
+++ b/settings_file.py
@@ -1,30 +1,65 @@
#!/usr/bin/python -u
SETTINGS=\
-{'host': {'TimeMode': {'default': 'NTP', 'name': 'time_mode', 'type': 's'},
- 'TimeOwner': {'default': 'BMC', 'name': 'time_owner', 'type': 's'},
- 'UseDhcpNtp': {'default': 'yes',
- 'name': 'use_dhcp_ntp',
- 'type': 's'},
- 'bootflags': {'default': 'default',
- 'name': 'boot_flags',
- 'type': 's'},
- 'bootpolicy': {'default': 'ONETIME',
- 'name': 'boot_policy',
- 'type': 's'},
- 'networkconfig': {'default':
- 'ipaddress=,prefix=,gateway=,mac=,addr_type=',
- 'name': 'network_config',
- 'type': 's'},
- 'powercap': {'default': 0,
- 'max': 1000,
- 'min': 0,
- 'name': 'power_cap',
- 'type': 'i',
- 'unit': 'watts'},
- 'powerpolicy': {'default': 'RESTORE_LAST_STATE',
- 'name': 'power_policy',
- 'type': 's'},
- 'restrictedmode': {'default': False,
- 'name': 'restricted_mode',
- 'type': 'b'},
- 'sysstate': {'default': '', 'name': 'system_state', 'type': 's'}}}
+{'org.openbmc.settings.Host': {'TimeMode': {'allowed': ['NTP', 'MANUAL'],
+ 'default': 'NTP',
+ 'name': 'time_mode',
+ 'type': 's',
+ 'validation': 'list'},
+ 'TimeOwner': {'allowed': ['BMC',
+ 'HOST',
+ 'SPLIT',
+ 'BOTH'],
+ 'default': 'BMC',
+ 'name': 'time_owner',
+ 'type': 's',
+ 'validation': 'list'},
+ 'UseDhcpNtp': {'allowed': ['yes', 'no'],
+ 'default': 'yes',
+ 'name': 'use_dhcp_ntp',
+ 'type': 's',
+ 'validation': 'list'},
+ 'bootflags': {'allowed': ['Network',
+ 'Disk',
+ 'Safe',
+ 'CDROM',
+ 'Setup',
+ 'default'],
+ 'default': 'default',
+ 'name': 'boot_flags',
+ 'type': 's',
+ 'validation': 'list'},
+ 'bootpolicy': {'allowed': ['ONETIME',
+ 'PERMANENT'],
+ 'default': 'ONETIME',
+ 'name': 'boot_policy',
+ 'type': 's',
+ 'validation': 'list'},
+ 'networkconfig': {'default': 'ipaddress=,prefix=,gateway=,mac=,addr_type=',
+ 'method': 'validate_net_config',
+ 'name': 'network_config',
+ 'type': 's',
+ 'validation': 'custom'},
+ 'powercap': {'default': 0,
+ 'max': 1000,
+ 'min': 0,
+ 'name': 'power_cap',
+ 'type': 'i',
+ 'unit': 'watts',
+ 'validation': 'range'},
+ 'powerpolicy': {'allowed': ['ALWAYS_POWER_ON',
+ 'RESTORE_LAST_STATE',
+ 'LEAVE_OFF'],
+ 'default': 'RESTORE_LAST_STATE',
+ 'name': 'power_policy',
+ 'type': 's',
+ 'validation': 'list'},
+ 'restrictedmode': {'default': False,
+ 'max': 1,
+ 'min': 0,
+ 'name': 'restricted_mode',
+ 'type': 'b',
+ 'validation': 'range'},
+ 'sysstate': {'default': '',
+ 'name': 'system_state',
+ 'type': 's',
+ 'validation': 'None'}}}
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
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 @@ CONTROL_INTF = 'org.openbmc.Settings'
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 @@ class HostSettingsObject(DbusProperties):
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 @@ class HostSettingsObject(DbusProperties):
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 @@ class HostSettingsObject(DbusProperties):
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)
OpenPOWER on IntegriCloud