summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Kosek <mkosek@redhat.com>2014-01-16 14:10:42 +0100
committerPetr Viktorin <pviktori@redhat.com>2014-01-22 10:14:05 +0100
commit252ad0b8c150954e773c7739994d1d4d9c5dc927 (patch)
treebe86045d30f82aa7dd01ff9f4b3ae445be99b55a
parentc29211671cfd7d7734b932c8d6d70c94c849b5d1 (diff)
downloadfreeipa-252ad0b8c150954e773c7739994d1d4d9c5dc927.tar.gz
freeipa-252ad0b8c150954e773c7739994d1d4d9c5dc927.tar.xz
freeipa-252ad0b8c150954e773c7739994d1d4d9c5dc927.zip
Add runas option to run function
Run function can now run the specified command as different user by setting the both real and effective UID and GID for executed process. Add both the missing run function attribute doc strings as well as a doc string for the runas attribute.
-rw-r--r--ipapython/ipautil.py59
1 files changed, 38 insertions, 21 deletions
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index a25dc358b..ce4c97838 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -42,6 +42,7 @@ import datetime
import netaddr
import time
import krbV
+import pwd
from dns import resolver, rdatatype
from dns.exception import DNSException
@@ -246,29 +247,35 @@ def shell_quote(string):
return "'" + string.replace("'", "'\\''") + "'"
def run(args, stdin=None, raiseonerr=True,
- nolog=(), env=None, capture_output=True, skip_output=False, cwd=None):
+ nolog=(), env=None, capture_output=True, skip_output=False, cwd=None,
+ runas=None):
"""
Execute a command and return stdin, stdout and the process return code.
- args is a list of arguments for the command
-
- stdin is used if you want to pass input to the command
-
- raiseonerr raises an exception if the return code is not zero
-
- nolog is a tuple of strings that shouldn't be logged, like passwords.
- Each tuple consists of a string to be replaced by XXXXXXXX.
-
- For example, the command ['/usr/bin/setpasswd', '--password', 'Secret123', 'someuser']
-
- We don't want to log the password so nolog would be set to:
- ('Secret123',)
-
- The resulting log output would be:
-
- /usr/bin/setpasswd --password XXXXXXXX someuser
-
- If an value isn't found in the list it is silently ignored.
+ :param args: List of arguments for the command
+ :param stdin: Optional input to the command
+ :param raiseonerr: If True, raises an exception if the return code is
+ not zero
+ :param nolog: Tuple of strings that shouldn't be logged, like passwords.
+ Each tuple consists of a string to be replaced by XXXXXXXX.
+
+ Example:
+ We have a command
+ ['/usr/bin/setpasswd', '--password', 'Secret123', 'someuser']
+ and we don't want to log the password so nolog would be set to:
+ ('Secret123',)
+ The resulting log output would be:
+
+ /usr/bin/setpasswd --password XXXXXXXX someuser
+
+ If a value isn't found in the list it is silently ignored.
+ :param env: Dictionary of environment variables passed to the command.
+ When None, current environment is copied
+ :param capture_output: Capture stderr and stdout
+ :param skip_output: Redirect the output to /dev/null and do not capture it
+ :param cwd: Current working directory
+ :param runas: Name of a user that the command shold be run as. The spawned
+ process will have both real and effective UID and GID set.
"""
p_in = None
p_out = None
@@ -298,9 +305,19 @@ def run(args, stdin=None, raiseonerr=True,
root_logger.debug('Starting external process')
root_logger.debug('args=%s' % arg_string)
+ preexec_fn = None
+ if runas is not None:
+ pent = pwd.getpwnam(runas)
+ root_logger.debug('runas=%s (UID %d, GID %s)', runas,
+ pent.pw_uid, pent.pw_gid)
+
+ preexec_fn = lambda: (os.setregid(pent.pw_gid, pent.pw_gid),
+ os.setreuid(pent.pw_uid, pent.pw_uid))
+
try:
p = subprocess.Popen(args, stdin=p_in, stdout=p_out, stderr=p_err,
- close_fds=True, env=env, cwd=cwd)
+ close_fds=True, env=env, cwd=cwd,
+ preexec_fn=preexec_fn)
stdout,stderr = p.communicate(stdin)
stdout,stderr = str(stdout), str(stderr) # Make pylint happy
except KeyboardInterrupt: