summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@redhat.com>2008-11-14 16:34:55 -0500
committerMichael DeHaan <mdehaan@redhat.com>2008-11-14 16:34:55 -0500
commite0dcab7043f8898fb60c3c2b480a3a554f09df5f (patch)
tree1a82d2c29b835227deff5b12b2602ed489d327e8
parentddb71dfd7ff5da0f6ec955eac3f8d6bea6b2a781 (diff)
downloadcobbler-e0dcab7043f8898fb60c3c2b480a3a554f09df5f.tar.gz
cobbler-e0dcab7043f8898fb60c3c2b480a3a554f09df5f.tar.xz
cobbler-e0dcab7043f8898fb60c3c2b480a3a554f09df5f.zip
Two security things -- restrict python imports within cheetah code, allow power-user and power-pass to be specified when running power commands instead of storing them in cobbler.
-rw-r--r--cobbler/action_power.py22
-rw-r--r--cobbler/api.py14
-rw-r--r--cobbler/commands.py6
-rw-r--r--cobbler/modules/cli_system.py4
-rw-r--r--cobbler/templar.py15
5 files changed, 50 insertions, 11 deletions
diff --git a/cobbler/action_power.py b/cobbler/action_power.py
index cf1f1060..39f279fd 100644
--- a/cobbler/action_power.py
+++ b/cobbler/action_power.py
@@ -41,17 +41,24 @@ class PowerTool:
Handles conversion of internal state to the tftpboot tree layout
"""
- def __init__(self,system,api):
+ def __init__(self,system,api,force_user,force_pass):
"""
Power library constructor requires a cobbler system object.
"""
self.system = system
self.api = api
+ self.force_user = force_user
+ self.force_pass = force_pass
def power(self, desired_state):
"""
state is either "on" or "off". Rebooting is implemented at the api.py
level.
+
+ The user and password need not be supplied. If not supplied they
+ will be taken from the environment, COBBLER_POWER_USER and COBBLER_POWER_PASS.
+ If provided, these will override any other data and be used instead. Users
+ interested in maximum security should take that route.
"""
template = self.get_command_template()
@@ -60,6 +67,12 @@ class PowerTool:
meta = utils.blender(self.api, False, self.system)
meta["power_mode"] = desired_state
+ # allow command line overrides of the username/password
+ if self.force_user is not None:
+ meta["power_user"] = self.force_user
+ if self.force_pass is not None:
+ meta["power_pass"] = self.force_pass
+
tmp = templar.Templar(self.api._config)
cmd = tmp.render(template_file, meta, None, self.system)
template_file.close()
@@ -73,6 +86,13 @@ class PowerTool:
print " user : %s" % self.system.power_user
print " id : %s" % self.system.power_id
+ # if no username/password data, check the environment
+
+ if meta.get("power_user","") == "":
+ meta["power_user"] = os.environ.get("COBBLER_POWER_USER","")
+ if meta.get("power_pass","") == "":
+ meta["power_pass"] = os.environ.get("COBBLER_POWER_PASS","")
+
print ""
print "- %s" % cmd
diff --git a/cobbler/api.py b/cobbler/api.py
index 16e02953..d1f75044 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -606,24 +606,24 @@ class BootAPI:
def get_kickstart_templates(self):
return utils.get_kickstar_templates(self)
- def power_on(self, system):
+ def power_on(self, system, user, password):
"""
Powers up a system that has power management configured.
"""
- return action_power.PowerTool(system,self).power("on")
+ return action_power.PowerTool(system,self,user,password).power("on")
- def power_off(self, system):
+ def power_off(self, system, user, password):
"""
Powers down a system that has power management configured.
"""
- return action_power.PowerTool(system,self).power("off")
+ return action_power.PowerTool(system,self,user,password).power("off")
- def reboot(self,system):
+ def reboot(self,system, user, password):
"""
Cycles power on a system that has power management configured.
"""
- self.power_off(system)
+ self.power_off(system, user, password)
time.sleep(1)
- return self.power_on(system)
+ return self.power_on(system, user, password)
diff --git a/cobbler/commands.py b/cobbler/commands.py
index d2da685d..380f374c 100644
--- a/cobbler/commands.py
+++ b/cobbler/commands.py
@@ -276,21 +276,21 @@ class CobblerFunction:
obj = collect_fn().find(self.options.name)
if obj is None:
raise CX(_("object not found"))
- self.api.power_on(obj)
+ self.api.power_on(obj,self.options.power_user,self.options.power_pass)
return None
if "poweroff" in self.args:
obj = collect_fn().find(self.options.name)
if obj is None:
raise CX(_("object not found"))
- self.api.power_off(obj)
+ self.api.power_off(obj,self.options.power_user,self.options.power_pass)
return None
if "reboot" in self.args:
obj = collect_fn().find(self.options.name)
if obj is None:
raise CX(_("object not found"))
- self.api.reboot(obj)
+ self.api.reboot(obj,self.options.power_user,self.options.power_pass)
return None
if "remove" in self.args:
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index ec3797bc..6673c15c 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -94,11 +94,15 @@ class SystemFunction(commands.CobblerFunction):
p.add_option("--power-address", dest="power_address", help="address of power mgmt device, if required")
p.add_option("--power-id", dest="power_id", help="plug-number or blade name, if required")
+ if not self.matches_args(args,["dumpvars","remove","report","getks","list"]):
p.add_option("--power-pass", dest="power_pass", help="password for power management interface")
+ if not self.matches_args(args,["dumpvars","poweron","poweroff","reboot","remove","report","getks","list"]):
p.add_option("--power-type", dest="power_type", help="one of: none, apc_snmp, bullpap, drac, ether-wake, ilo, ipmilan, ipmitool, wti")
+ if not self.matches_args(args,["dumpvars","remove","report","getks","list"]):
p.add_option("--power-user", dest="power_user", help="username for power management interface, if required")
+ if not self.matches_args(args,["dumpvars","poweron","poweroff","reboot","remove","report","getks","list"]):
p.add_option("--profile", dest="profile", help="name of cobbler profile (REQUIRED)")
p.add_option("--server-override", dest="server_override", help="overrides server value in settings file")
p.add_option("--static", dest="static", help="specifies this interface does (0) or does not use DHCP (1), default 0")
diff --git a/cobbler/templar.py b/cobbler/templar.py
index b68af380..bea9f440 100644
--- a/cobbler/templar.py
+++ b/cobbler/templar.py
@@ -40,6 +40,19 @@ class Templar:
self.api = config.api
self.settings = config.settings()
+ def check_for_invalid_imports(self,data):
+ """
+ Ensure that Cheetah code is not importing Python modules
+ that may allow for advanced priveledges by ensuring we whitelist
+ the imports that we allow
+ """
+ lines = data.split("\n")
+ for line in lines:
+ if line.find("#import") != -1:
+ rest=line.replace("#import","").replace(" ","").strip()
+ if rest not in [ "time", "random" ]:
+ raise CX("potentially insecure import in template: %s" % rest)
+
def render(self, data_input, search_table, out_path, subject=None):
"""
Render data_input back into a file.
@@ -55,6 +68,8 @@ class Templar:
else:
raw_data = data_input
+ self.check_for_invalid_imports(raw_data)
+
# backward support for Cobbler's legacy (and slightly more readable)
# template syntax.
raw_data = raw_data.replace("TEMPLATE::","$")