55
59
# connect to an agent if we are on win32 and using Paramiko older than 1.6
56
60
_use_ssh_agent = (sys.platform != 'win32' or _paramiko_version >= (1, 6, 0))
60
def register_ssh_vendor(name, vendor):
61
"""Register SSH vendor."""
62
_ssh_vendors[name] = vendor
66
def _get_ssh_vendor():
67
"""Find out what version of SSH is on the system."""
69
if _ssh_vendor is not None:
72
if 'BZR_SSH' in os.environ:
73
vendor_name = os.environ['BZR_SSH']
63
class SSHVendorManager(object):
64
"""Manager for manage SSH vendors."""
66
# Note, although at first sign the class interface seems similar to
67
# bzrlib.registry.Registry it is not possible/convenient to directly use
68
# the Registry because the class just has "get()" interface instead of the
69
# Registry's "get(key)".
72
self._ssh_vendors = {}
73
self._cached_ssh_vendor = None
74
self._default_ssh_vendor = None
76
def register_default_vendor(self, vendor):
77
"""Register default SSH vendor."""
78
self._default_ssh_vendor = vendor
80
def register_vendor(self, name, vendor):
81
"""Register new SSH vendor by name."""
82
self._ssh_vendors[name] = vendor
84
def clear_cache(self):
85
"""Clear previously cached lookup result."""
86
self._cached_ssh_vendor = None
88
def _get_vendor_by_environment(self, environment=None):
89
"""Return the vendor or None based on BZR_SSH environment variable.
91
:raises UnknownSSH: if the BZR_SSH environment variable contains
94
if environment is None:
95
environment = os.environ
96
if 'BZR_SSH' in environment:
97
vendor_name = environment['BZR_SSH']
99
vendor = self._ssh_vendors[vendor_name]
101
raise UnknownSSH(vendor_name)
105
def _get_ssh_version_string(self, args):
106
"""Return SSH version string from the subprocess."""
75
_ssh_vendor = _ssh_vendors[vendor_name]
77
raise UnknownSSH(vendor_name)
81
p = subprocess.Popen(['ssh', '-V'],
82
stdin=subprocess.PIPE,
83
stdout=subprocess.PIPE,
84
stderr=subprocess.PIPE,
85
**os_specific_subprocess_params())
86
returncode = p.returncode
87
stdout, stderr = p.communicate()
91
if 'OpenSSH' in stderr:
92
mutter('ssh implementation is OpenSSH')
93
_ssh_vendor = OpenSSHSubprocessVendor()
94
elif 'SSH Secure Shell' in stderr:
95
mutter('ssh implementation is SSH Corp.')
96
_ssh_vendor = SSHCorpSubprocessVendor()
98
if _ssh_vendor is not None:
101
# XXX: 20051123 jamesh
102
# A check for putty's plink or lsh would go here.
104
mutter('falling back to paramiko implementation')
105
_ssh_vendor = ParamikoVendor()
108
p = subprocess.Popen(args,
109
stdout=subprocess.PIPE,
110
stderr=subprocess.PIPE,
111
**os_specific_subprocess_params())
112
stdout, stderr = p.communicate()
115
return stdout + stderr
117
def _get_vendor_by_version_string(self, version):
118
"""Return the vendor or None based on output from the subprocess.
120
:param version: The output of 'ssh -V' like command.
123
if 'OpenSSH' in version:
124
mutter('ssh implementation is OpenSSH')
125
vendor = OpenSSHSubprocessVendor()
126
elif 'SSH Secure Shell' in version:
127
mutter('ssh implementation is SSH Corp.')
128
vendor = SSHCorpSubprocessVendor()
129
elif 'plink' in version:
130
mutter("ssh implementation is Putty's plink.")
131
vendor = PLinkSubprocessVendor()
134
def _get_vendor_by_inspection(self):
135
"""Return the vendor or None by checking for known SSH implementations."""
136
for args in [['ssh', '-V'], ['plink', '-V']]:
137
version = self._get_ssh_version_string(args)
138
vendor = self._get_vendor_by_version_string(version)
139
if vendor is not None:
143
def get_vendor(self, environment=None):
144
"""Find out what version of SSH is on the system.
146
:raises SSHVendorNotFound: if no any SSH vendor is found
147
:raises UnknownSSH: if the BZR_SSH environment variable contains
150
if self._cached_ssh_vendor is None:
151
vendor = self._get_vendor_by_environment(environment)
153
vendor = self._get_vendor_by_inspection()
155
mutter('falling back to default implementation')
156
vendor = self._default_ssh_vendor
158
raise SSHVendorNotFound()
159
self._cached_ssh_vendor = vendor
160
return self._cached_ssh_vendor
162
_ssh_vendor_manager = SSHVendorManager()
163
_get_ssh_vendor = _ssh_vendor_manager.get_vendor
164
register_default_ssh_vendor = _ssh_vendor_manager.register_default_vendor
165
register_ssh_vendor = _ssh_vendor_manager.register_vendor
110
168
def _ignore_sigint():
247
314
channel.exec_command(cmdline)
248
315
return _ParamikoSSHConnection(channel)
249
316
except paramiko.SSHException, e:
250
raise ConnectionError('Unable to invoke remote bzr %s:%d' %
317
self._raise_connection_error(host, port=port, orig_error=e,
318
msg='Unable to invoke remote bzr')
253
register_ssh_vendor('paramiko', ParamikoVendor())
320
if paramiko is not None:
321
vendor = ParamikoVendor()
322
register_ssh_vendor('paramiko', vendor)
323
register_ssh_vendor('none', vendor)
324
register_default_ssh_vendor(vendor)
256
328
class SubprocessVendor(SSHVendor):
270
342
sock = self._connect(argv)
271
343
return SFTPClient(sock)
272
344
except (EOFError, paramiko.SSHException), e:
273
raise ConnectionError('Unable to connect to SSH host %s:%s: %s'
345
self._raise_connection_error(host, port=port, orig_error=e)
275
346
except (OSError, IOError), e:
276
347
# If the machine is fast enough, ssh can actually exit
277
348
# before we try and send it the sftp request, which
278
349
# raises a Broken Pipe
279
350
if e.errno not in (errno.EPIPE,):
281
raise ConnectionError('Unable to connect to SSH host %s:%s: %s'
352
self._raise_connection_error(host, port=port, orig_error=e)
284
354
def connect_ssh(self, username, password, host, port, command):
288
358
return self._connect(argv)
289
359
except (EOFError), e:
290
raise ConnectionError('Unable to connect to SSH host %s:%s: %s'
360
self._raise_connection_error(host, port=port, orig_error=e)
292
361
except (OSError, IOError), e:
293
362
# If the machine is fast enough, ssh can actually exit
294
363
# before we try and send it the sftp request, which
295
364
# raises a Broken Pipe
296
365
if e.errno not in (errno.EPIPE,):
298
raise ConnectionError('Unable to connect to SSH host %s:%s: %s'
367
self._raise_connection_error(host, port=port, orig_error=e)
301
369
def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
360
426
register_ssh_vendor('ssh', SSHCorpSubprocessVendor())
429
class PLinkSubprocessVendor(SubprocessVendor):
430
"""SSH vendor that uses the 'plink' executable from Putty."""
432
def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
434
assert subsystem is not None or command is not None, (
435
'Must specify a command or subsystem')
436
if subsystem is not None:
437
assert command is None, (
438
'subsystem and command are mutually exclusive')
439
args = ['plink', '-x', '-a', '-ssh', '-2']
441
args.extend(['-P', str(port)])
442
if username is not None:
443
args.extend(['-l', username])
444
if subsystem is not None:
445
args.extend(['-s', host, subsystem])
447
args.extend([host] + command)
450
register_ssh_vendor('plink', PLinkSubprocessVendor())
363
453
def _paramiko_auth(username, password, host, paramiko_transport):
364
454
# paramiko requires a username, but it might be none if nothing was supplied
365
455
# use the local username, just in case.