diff --git a/mitogen/parent.py b/mitogen/parent.py index 024f5c14..6ca6369a 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -1461,37 +1461,12 @@ class Connection(object): by returning a 1-element list containing :attr:`python_path` + codecs This allows emulation of existing tools where the Python invocation may - be set to e.g. `['/usr/bin/env', 'python']` or - `['source', '/opt/rh/rh-python36/enable, '&&', 'python']` + be set to e.g. `['/usr/bin/env', 'python']` """ - # if isinstance(self.options.python_path, list): - # python_path = " ".join(self.options.python_path) - # else: - # python_path = self.options.python_path - - # quoting the entire command necessary to invoke python supports - # complex python_paths - # return ["'" + python_path, '-c', - # 'import codecs,os,sys;_=codecs.decode;' - # 'exec(_(_("%s".encode(),"base64"),"zip"))\'' % (encoded.decode(),) - # ] - if isinstance(self.options.python_path, list): return self.options.python_path return [self.options.python_path] - """ - return self.get_python_argv() + [ -- '-c', -- 'import codecs,os,sys;_=codecs.decode;' -- 'exec(_(_("%s".encode(),"base64"),"zip"))' % (encoded.decode(),) -- ] - - if isinstance(self.options.python_path, list): -- return self.options.python_path -- return [self.options.python_path] - """ - def get_boot_command(self): source = inspect.getsource(self._first_stage) source = textwrap.dedent('\n'.join(source.strip().split('\n')[2:])) @@ -1507,7 +1482,6 @@ class Connection(object): # codecs.decode() requires a bytes object. Since we must be compatible # with 2.4 (no bytes literal), an extra .encode() either returns the # same str (2.x) or an equivalent bytes (3.x). - # return self.get_python_cmd(encoded) return self.get_python_argv() + [ '-c', 'import codecs,os,sys;_=codecs.decode;' @@ -1549,8 +1523,6 @@ class Connection(object): def start_child(self): args = self.get_boot_command() - LOG.debug('%s', args) - LOG.debug('walrus') LOG.debug('command line for %r: %s', self, Argv(args)) try: return self.create_child(args=args, **self.create_child_args) diff --git a/mitogen/ssh.py b/mitogen/ssh.py index 602581cf..244766c5 100644 --- a/mitogen/ssh.py +++ b/mitogen/ssh.py @@ -298,12 +298,10 @@ class Connection(mitogen.parent.Connection): if self.options.ssh_args: bits += self.options.ssh_args bits.append(self.options.hostname) - # import pdb - # pdb.set_trace() base = super(Connection, self).get_boot_command() + base_parts = [] for s in base: val = s if s in self.SHLEX_IGNORE else shlex_quote(s).strip() base_parts.append(val) return bits + base_parts - # return bits + [shlex_quote(s).strip() for s in base] diff --git a/mitogen/sudo.py b/mitogen/sudo.py index ea07d0c1..75396fe4 100644 --- a/mitogen/sudo.py +++ b/mitogen/sudo.py @@ -114,10 +114,10 @@ SUDO_OPTIONS = [ #(False, 'bool', '--background', '-b') #(False, 'str', '--close-from', '-C') #(False, 'str', '--login-class', 'c') - (True, 'bool', '--preserve-env', '-E'), + (True, 'bool', '--preserve-env', '-E'), #(False, 'bool', '--edit', '-e') #(False, 'str', '--group', '-g') - (True, 'bool', '--set-home', '-H'), + (True, 'bool', '--set-home', '-H'), #(False, 'str', '--host', '-h') (False, 'bool', '--login', '-i'), #(False, 'bool', '--remove-timestamp', '-K') @@ -146,8 +146,10 @@ SUDO_OPTIONS = [ class OptionParser(optparse.OptionParser): def help(self): self.exit() + def error(self, msg): self.exit(msg=msg) + def exit(self, status=0, msg=None): msg = 'sudo: ' + (msg or 'unsupported option') raise mitogen.core.StreamError(msg) @@ -167,7 +169,7 @@ def parse_sudo_flags(args): parser = make_sudo_parser() opts, args = parser.parse_args(args) if len(args): - raise mitogen.core.StreamError('unsupported sudo arguments:'+str(args)) + raise mitogen.core.StreamError('unsupported sudo arguments:' + str(args)) return opts @@ -249,6 +251,12 @@ class Connection(mitogen.parent.Connection): } child_is_immediate_subprocess = False + # sudo can't run bash builtins; if a supported builtin is detected + # append `-s` to the sudo command to start a shell as the desired user + SUPPORTED_BASH_BUILTINS = [ + "source" + ] + def _get_name(self): return u'sudo.' + mitogen.core.to_text(self.options.username) @@ -256,6 +264,8 @@ class Connection(mitogen.parent.Connection): # Note: sudo did not introduce long-format option processing until July # 2013, so even though we parse long-format options, supply short-form # to the sudo command. + boot_cmd = super(Connection, self).get_boot_command() + bits = [self.options.sudo_path, '-u', self.options.username] if self.options.preserve_env: bits += ['-E'] @@ -267,5 +277,9 @@ class Connection(mitogen.parent.Connection): bits += ['-r', self.options.selinux_role] if self.options.selinux_type: bits += ['-t', self.options.selinux_type] + for builtin in self.SUPPORTED_BASH_BUILTINS: + if builtin in boot_cmd: + bits += ['-s'] + break - return bits + ['--'] + super(Connection, self).get_boot_command() + return bits + ['--'] + boot_cmd