58
59
# connect to an agent if we are on win32 and using Paramiko older than 1.6
59
60
_use_ssh_agent = (sys.platform != 'win32' or _paramiko_version >= (1, 6, 0))
63
def register_ssh_vendor(name, vendor):
64
"""Register SSH vendor."""
65
_ssh_vendors[name] = vendor
69
def _get_ssh_vendor():
70
"""Find out what version of SSH is on the system."""
72
if _ssh_vendor is not None:
75
if 'BZR_SSH' in os.environ:
76
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."""
78
_ssh_vendor = _ssh_vendors[vendor_name]
80
raise UnknownSSH(vendor_name)
84
p = subprocess.Popen(['ssh', '-V'],
85
stdin=subprocess.PIPE,
86
stdout=subprocess.PIPE,
87
stderr=subprocess.PIPE,
88
**os_specific_subprocess_params())
89
returncode = p.returncode
90
stdout, stderr = p.communicate()
94
if 'OpenSSH' in stderr:
95
mutter('ssh implementation is OpenSSH')
96
_ssh_vendor = OpenSSHSubprocessVendor()
97
elif 'SSH Secure Shell' in stderr:
98
mutter('ssh implementation is SSH Corp.')
99
_ssh_vendor = SSHCorpSubprocessVendor()
101
if _ssh_vendor is not None:
104
# XXX: 20051123 jamesh
105
# A check for putty's plink or lsh would go here.
107
mutter('falling back to paramiko implementation')
108
_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
112
168
def _ignore_sigint():
369
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())
372
453
def _paramiko_auth(username, password, host, paramiko_transport):
373
454
# paramiko requires a username, but it might be none if nothing was supplied
374
455
# use the local username, just in case.