summaryrefslogtreecommitdiff
path: root/heat_cfntools/cfntools/cfn_helper.py
diff options
context:
space:
mode:
Diffstat (limited to 'heat_cfntools/cfntools/cfn_helper.py')
-rw-r--r--heat_cfntools/cfntools/cfn_helper.py62
1 files changed, 53 insertions, 9 deletions
diff --git a/heat_cfntools/cfntools/cfn_helper.py b/heat_cfntools/cfntools/cfn_helper.py
index 7e75cf9..b285d24 100644
--- a/heat_cfntools/cfntools/cfn_helper.py
+++ b/heat_cfntools/cfntools/cfn_helper.py
@@ -1,4 +1,4 @@
-#
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
@@ -19,6 +19,7 @@ Not implemented yet:
- placeholders are ignored
"""
import atexit
+import contextlib
import errno
import functools
import grp
@@ -40,6 +41,7 @@ import six.moves.configparser as ConfigParser
import subprocess
import tempfile
+
# Override BOTO_CONFIG, which makes boto look only at the specified
# config file, instead of the default locations
os.environ['BOTO_CONFIG'] = '/var/lib/heat-cfntools/cfn-boto-cfg'
@@ -152,6 +154,33 @@ class Hook(object):
self.action)
+class ControlledPrivilegesFailureException(Exception):
+ pass
+
+
+@contextlib.contextmanager
+def controlled_privileges(user):
+ orig_euid = None
+ try:
+ real = pwd.getpwnam(user)
+ if os.geteuid() != real.pw_uid:
+ orig_euid = os.geteuid()
+ os.seteuid(real.pw_uid)
+ LOG.debug("Privileges set for user %s" % user)
+ except Exception as e:
+ raise ControlledPrivilegesFailureException(e)
+
+ try:
+ yield
+ finally:
+ if orig_euid is not None:
+ try:
+ os.seteuid(orig_euid)
+ LOG.debug("Original privileges restored.")
+ except Exception as e:
+ LOG.error("Error restoring privileges %s" % e)
+
+
class CommandRunner(object):
"""Helper class to run a command and store the output."""
@@ -180,19 +209,34 @@ class CommandRunner(object):
self
"""
LOG.debug("Running command: %s" % self._command)
- cmd = ['su', user, '-c', self._command]
- subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, cwd=cwd, env=env)
- output = subproc.communicate()
-
- self._status = subproc.returncode
- self._stdout = output[0]
- self._stderr = output[1]
+
+ cmd = self._command
+
+ # Ensure commands are passed as strings only as we run them
+ # using shell
+ assert isinstance(cmd, six.string_types)
+
+ try:
+ with controlled_privileges(user):
+ subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, cwd=cwd,
+ env=env, shell=True)
+ output = subproc.communicate()
+ self._status = subproc.returncode
+ self._stdout = output[0]
+ self._stderr = output[1]
+ except ControlledPrivilegesFailureException as e:
+ LOG.error("Error setting privileges for user '%s': %s"
+ % (user, e))
+ self._status = 126
+ self._stderr = six.text_type(e)
+
if self._status:
LOG.debug("Return code of %d after executing: '%s'\n"
"stdout: '%s'\n"
"stderr: '%s'" % (self._status, cmd, self._stdout,
self._stderr))
+
if self._next:
self._next.run()
return self