Skip to content

Commit

Permalink
Fix Paramiko command quoting (for Unicode->bytes and inclusion of quo…
Browse files Browse the repository at this point in the history
…tes)
  • Loading branch information
inducer committed Sep 14, 2015
1 parent 97ce263 commit 6e855f6
Showing 1 changed file with 45 additions and 1 deletion.
46 changes: 45 additions & 1 deletion dulwich/contrib/paramiko_vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,40 @@ def close(self):
self.stop_monitoring()


# {{{ shell quoting

# Adapted from
# https://github.com/python/cpython/blob/8cd133c63f156451eb3388b9308734f699f4f1af/Lib/shlex.py#L278

def is_shell_safe(s):
import re
import sys

flags = 0
if sys.version_info >= (3,):
flags = re.ASCII

unsafe_re = re.compile(br'[^\w@%+=:,./-]', flags)

return unsafe_re.search(s) is None


def shell_quote(s):
"""Return a shell-escaped version of the byte string *s*."""

# Unconditionally quotes because that's apparently git's behavior, too,
# and some code hosting sites (notably Bitbucket) appear to rely on that.

if not s:
return b"''"

# use single quotes, and put single quotes into double quotes
# the string $'b is then quoted as '$'"'"'b'
return b"'" + s.replace(b"'", b"'\"'\"'") + b"'"

# }}}


class ParamikoSSHVendor(object):

def __init__(self):
Expand All @@ -132,8 +166,18 @@ def run_command(self, host, command, username=None, port=None,
# Open SSH session
channel = client.get_transport().open_session()

# Quote command
assert command
assert is_shell_safe(command[0])

quoted_command = (
command[0]
+ b' '
+ b' '.join(
shell_quote(c) for c in command[1:]))

# Run commands
channel.exec_command(subprocess.list2cmdline(command))
channel.exec_command(quoted_command)

return _ParamikoWrapper(
client, channel, progress_stderr=progress_stderr)

0 comments on commit 6e855f6

Please sign in to comment.