File security_fix_xmlrpc_command_injection.diff of Package cobbler

Index: cobbler-2.2.2/cobbler/action_power.py
===================================================================
--- cobbler-2.2.2.orig/cobbler/action_power.py
+++ cobbler-2.2.2/cobbler/action_power.py
@@ -69,8 +69,9 @@ class PowerTool:
         interested in maximum security should take that route.
         """
 
-        template = self.get_command_template()
-        template_file = open(template, "r")
+        power_command = utils.get_power(self.system.power_type)
+        if not power_command:
+            utils.die(self.logger,"no power type set for system")
 
         meta = utils.blender(self.api, False, self.system)
         meta["power_mode"] = desired_state
@@ -81,43 +82,34 @@ class PowerTool:
         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()
-
-        cmd = cmd.strip()
-
         self.logger.info("cobbler power configuration is:")
-
         self.logger.info("      type   : %s" % self.system.power_type)
         self.logger.info("      address: %s" % self.system.power_address)
         self.logger.info("      user   : %s" % self.system.power_user)
         self.logger.info("      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","")
 
-        self.logger.info("- %s" % cmd)
-
-        # use shell so we can have mutliple power commands chained together
-        cmd = ['/bin/sh','-c', cmd]
+        template = utils.get_power_template(self.system.power_type)
+        tmp = templar.Templar(self.api._config)
+        template_data = tmp.render(template, meta, None, self.system)
 
         # Try the power command 5 times before giving up.
         # Some power switches are flakey
         for x in range(0,5):
-            output, rc = utils.subprocess_sp(self.logger, cmd, shell=False)
+            output, rc = utils.subprocess_sp(self.logger, power_command, shell=False, input=template_data)
             if rc == 0:
                 # If the desired state is actually a query for the status
                 # return different information than command return code
                 if desired_state == 'status':
-                    match = re.match('(^Status:\s)(ON|OFF)', output)
+                    match = re.match('(^Status:\s)(on|off)', output, re.IGNORECASE)
                     if match:
                         power_status = match.groups()[1]
-                        if power_status == 'ON':
+                        if power_status.lower() == 'on':
                             return True
                         else:
                             return False
@@ -132,19 +124,3 @@ class PowerTool:
 
         return rc
 
-    def get_command_template(self):
-
-        """
-        In case the user wants to customize the power management commands, 
-        we source the code for each command from /etc/cobbler and run
-        them through Cheetah.
-        """
-
-        if self.system.power_type in [ "", "none" ]:
-            utils.die(self.logger,"Power management is not enabled for this system")
-
-        result = utils.get_power(self.system.power_type)
-        if not result:
-            utils.die(self.logger, "Invalid power management type for this system (%s, %s)" % (self.system.power_type, self.system.name))
-        return result
-
Index: cobbler-2.2.2/cobbler/item_system.py
===================================================================
--- cobbler-2.2.2.orig/cobbler/item_system.py
+++ cobbler-2.2.2/cobbler/item_system.py
@@ -53,11 +53,11 @@ FIELDS = [
   ["virt_auto_boot","<<inherit>>",0,"Virt Auto Boot",True,"Auto boot this VM?",0,"bool"],
   ["ctime",0,0,"",False,"",0,"float"],
   ["mtime",0,0,"",False,"",0,"float"],
-  ["power_type","SETTINGS:power_management_default_type",0,"Power Management Type",True,"",utils.get_power_types(),"str"],
+  ["power_type","SETTINGS:power_management_default_type",0,"Power Management Type",True,"Power management script to use",utils.get_power_types(),"str"],
   ["power_address","",0,"Power Management Address",True,"Ex: power-device.example.org",0,"str"],
-  ["power_user","",0,"Power Username ",True,"",0,"str"],
-  ["power_pass","",0,"Power Password",True,"",0,"str"],
-  ["power_id","",0,"Power ID",True,"Usually a plug number or blade name, if power type requires it",0,"str"],
+  ["power_user","",0,"Power Management Username ",True,"",0,"str"],
+  ["power_pass","",0,"Power Management Password",True,"",0,"str"],
+  ["power_id","",0,"Power Management ID",True,"Usually a plug number or blade name, if power type requires it",0,"str"],
   ["hostname","",0,"Hostname",True,"",0,"str"],
   ["gateway","",0,"Gateway",True,"",0,"str"],
   ["name_servers",[],0,"Name Servers",True,"space delimited",0,"list"],
Index: cobbler-2.2.2/cobbler/utils.py
===================================================================
--- cobbler-2.2.2.orig/cobbler/utils.py
+++ cobbler-2.2.2/cobbler/utils.py
@@ -1676,29 +1676,34 @@ def is_remote_file(file):
     else:
        return False
 
-def subprocess_sp(logger, cmd, shell=True):
+def subprocess_sp(logger, cmd, shell=True, input=None):
     if logger is not None:
         logger.info("running: %s" % cmd)
+
+    stdin = None
+    if input:
+        stdin = sub_process.PIPE
+
     try:
-        sp = sub_process.Popen(cmd, shell=shell, stdout=sub_process.PIPE, stderr=sub_process.PIPE, close_fds=True)
+        sp = sub_process.Popen(cmd, shell=shell, stdin=stdin, stdout=sub_process.PIPE, stderr=sub_process.PIPE, close_fds=True)
     except OSError:
         if logger is not None:
             log_exc(logger)
         die(logger, "OS Error, command not found?  While running: %s" % cmd)
 
-    (out,err) = sp.communicate()
+    (out,err) = sp.communicate(input)
     rc = sp.returncode
     if logger is not None:
         logger.info("received on stdout: %s" % out)
         logger.debug("received on stderr: %s" % err)
     return out, rc
 
-def subprocess_call(logger, cmd, shell=True):
-    data, rc = subprocess_sp(logger, cmd, shell=shell)
+def subprocess_call(logger, cmd, shell=True, input=None):
+    data, rc = subprocess_sp(logger, cmd, shell=shell, input=input)
     return rc
 
-def subprocess_get(logger, cmd, shell=True):
-    data, rc = subprocess_sp(logger, cmd, shell=shell)
+def subprocess_get(logger, cmd, shell=True, input=None):
+    data, rc = subprocess_sp(logger, cmd, shell=shell, input=input)
     return data
 
 def popen2(args, **kwargs):
@@ -1960,8 +1965,8 @@ def get_power_types():
     Return all possible power types
     """
     power_types = []
-    power_template = re.compile(r'power_(.*).template')
-    for x in glob.glob("/etc/cobbler/power/power_*.template"):
+    power_template = re.compile(r'fence_(.*)')
+    for x in glob.glob("/usr/sbin/fence_*"):
         power_types.append(power_template.search(x).group(1))
     return power_types
 
@@ -1970,11 +1975,25 @@ def get_power(powertype=None):
     Return power command for type
     """
     if powertype:
-        powerpath = "/etc/cobbler/power/power_%s.template" % powertype
-        if os.path.isfile(powerpath):
+        powerpath = "/usr/sbin/fence_%s" % powertype
+        if os.path.isfile(powerpath) and os.access(powerpath, os.X_OK):
             return powerpath
     return None
 
+def get_power_template(powertype=None):
+    """
+    Return power template for type
+    """
+    if powertype:
+        powertemplate = "/etc/cobbler/power/fence_%s.template" % powertype
+        if os.path.isfile(powertemplate):
+            f = open(powertemplate)
+            template = f.read()
+            f.close()
+            return template
+    # return a generic template if a specific one wasn't found
+    return "action=$power_mode\nlogin=$power_user\npasswd=$power_pass\nipaddr=$power_address\nport=$power_id"
+
 def get_shared_secret():
     """
     The 'web.ss' file is regenerated each time cobblerd restarts and is
openSUSE Build Service is sponsored by