/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5594.1.1 by Vincent Ladeuil
Fix socketpair-based SSH transport leaking socket into other child processes
1
# Copyright (C) 2006-2011 Robey Pointer <robey@lag.net>
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
2
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
17
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
18
"""Foundation SSH support for SFTP and smart server."""
19
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
20
import errno
4304.2.1 by Vincent Ladeuil
Fix bug #367726 by reverting some default user handling introduced
21
import getpass
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
22
import logging
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
23
import os
24
import socket
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
25
import subprocess
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
26
import sys
6603.3.1 by Andrew Starr-Bochicchio
Use hexlify() from binascii directly as paramiko removed hexify().
27
from binascii import hexlify
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
28
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
29
from .. import (
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
30
    config,
7336.2.1 by Martin
Split non-ini config methods to bedding
31
    bedding,
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
32
    errors,
33
    osutils,
34
    trace,
35
    ui,
36
    )
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
37
38
try:
39
    import paramiko
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
40
except ImportError as e:
2104.5.1 by John Arbash Meinel
Remove the strict dependency on paramiko for ssh access
41
    # If we have an ssh subprocess, we don't strictly need paramiko for all ssh
42
    # access
43
    paramiko = None
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
44
else:
45
    from paramiko.sftp_client import SFTPClient
46
47
6753.1.1 by Jelmer Vernooij
Refuse to connect to ssh hostnames starting with a dash. Fixes LP:1710979
48
class StrangeHostname(errors.BzrError):
49
    _fmt = "Refusing to connect to strange SSH hostname %(hostname)s"
50
51
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
52
SYSTEM_HOSTKEYS = {}
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
53
BRZ_HOSTKEYS = {}
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
54
55
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
56
class SSHVendorManager(object):
57
    """Manager for manage SSH vendors."""
58
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
59
    # Note, although at first sign the class interface seems similar to
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
60
    # breezy.registry.Registry it is not possible/convenient to directly use
2221.5.22 by Dmitry Vasiliev
Updated note about registry.Registry
61
    # the Registry because the class just has "get()" interface instead of the
62
    # Registry's "get(key)".
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
63
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
64
    def __init__(self):
65
        self._ssh_vendors = {}
2221.5.8 by Dmitry Vasiliev
Added SSHVendorManager.clear_cache() method
66
        self._cached_ssh_vendor = None
2221.5.5 by Dmitry Vasiliev
Added 'register_default_vendor' method to the SSHVendorManager
67
        self._default_ssh_vendor = None
68
69
    def register_default_vendor(self, vendor):
70
        """Register default SSH vendor."""
71
        self._default_ssh_vendor = vendor
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
72
73
    def register_vendor(self, name, vendor):
2221.5.5 by Dmitry Vasiliev
Added 'register_default_vendor' method to the SSHVendorManager
74
        """Register new SSH vendor by name."""
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
75
        self._ssh_vendors[name] = vendor
76
2221.5.8 by Dmitry Vasiliev
Added SSHVendorManager.clear_cache() method
77
    def clear_cache(self):
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
78
        """Clear previously cached lookup result."""
2221.5.8 by Dmitry Vasiliev
Added SSHVendorManager.clear_cache() method
79
        self._cached_ssh_vendor = None
80
7358.9.1 by Jelmer Vernooij
Allow setting the ssh vendor in configuration.
81
    def _get_vendor_by_config(self):
82
        vendor_name = config.GlobalStack().get('ssh')
83
        if vendor_name is not None:
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
84
            try:
85
                vendor = self._ssh_vendors[vendor_name]
86
            except KeyError:
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
87
                vendor = self._get_vendor_from_path(vendor_name)
88
                if vendor is None:
89
                    raise errors.UnknownSSH(vendor_name)
90
                vendor.executable_path = vendor_name
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
91
            return vendor
92
        return None
93
94
    def _get_ssh_version_string(self, args):
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
95
        """Return SSH version string from the subprocess."""
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
96
        try:
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
97
            p = subprocess.Popen(args,
98
                                 stdout=subprocess.PIPE,
99
                                 stderr=subprocess.PIPE,
6973.7.3 by Jelmer Vernooij
Fix some more tests.
100
                                 bufsize=0,
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
101
                                 **os_specific_subprocess_params())
102
            stdout, stderr = p.communicate()
103
        except OSError:
6973.6.1 by Jelmer Vernooij
More bees.
104
            stdout = stderr = b''
7045.1.2 by Jelmer Vernooij
Fix some SSH version tests.
105
        return (stdout + stderr).decode(osutils.get_terminal_encoding())
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
106
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
107
    def _get_vendor_by_version_string(self, version, progname):
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
108
        """Return the vendor or None based on output from the subprocess.
109
110
        :param version: The output of 'ssh -V' like command.
2772.3.1 by Martin Pool
Fix detection of ssh implementation on Windows
111
        :param args: Command line that was run.
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
112
        """
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
113
        vendor = None
114
        if 'OpenSSH' in version:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
115
            trace.mutter('ssh implementation is OpenSSH')
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
116
            vendor = OpenSSHSubprocessVendor()
117
        elif 'SSH Secure Shell' in version:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
118
            trace.mutter('ssh implementation is SSH Corp.')
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
119
            vendor = SSHCorpSubprocessVendor()
5444.2.3 by Matthew Gordon
Added missing check for GNU lsh in _get_vendor_by_version_string().
120
        elif 'lsh' in version:
121
            trace.mutter('ssh implementation is GNU lsh.')
122
            vendor = LSHSubprocessVendor()
4595.17.2 by Martin
Merge bzr.dev 4789 to resolve conflict from the disabling of plink auto-detection, and relocate NEWS
123
        # As plink user prompts are not handled currently, don't auto-detect
124
        # it by inspection below, but keep this vendor detection for if a path
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
125
        # is given in BRZ_SSH. See https://bugs.launchpad.net/bugs/414743
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
126
        elif 'plink' in version and progname == 'plink':
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
127
            # Checking if "plink" was the executed argument as Windows
5448.2.1 by Martin
Fix some "its" vs. "it's" spelling confusion in bzrlib code... also, ahem, a name in the NEWS file
128
            # sometimes reports 'ssh -V' incorrectly with 'plink' in its
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
129
            # version.  See https://bugs.launchpad.net/bzr/+bug/107155
130
            trace.mutter("ssh implementation is Putty's plink.")
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
131
            vendor = PLinkSubprocessVendor()
132
        return vendor
133
134
    def _get_vendor_by_inspection(self):
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
135
        """Return the vendor or None by checking for known SSH implementations."""
4595.17.2 by Martin
Merge bzr.dev 4789 to resolve conflict from the disabling of plink auto-detection, and relocate NEWS
136
        version = self._get_ssh_version_string(['ssh', '-V'])
137
        return self._get_vendor_by_version_string(version, "ssh")
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
138
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
139
    def _get_vendor_from_path(self, path):
140
        """Return the vendor or None using the program at the given path"""
141
        version = self._get_ssh_version_string([path, '-V'])
7143.15.2 by Jelmer Vernooij
Run autopep8.
142
        return self._get_vendor_by_version_string(version,
143
                                                  os.path.splitext(os.path.basename(path))[0])
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
144
7358.9.2 by Jelmer Vernooij
Add test.
145
    def get_vendor(self):
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
146
        """Find out what version of SSH is on the system.
147
148
        :raises SSHVendorNotFound: if no any SSH vendor is found
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
149
        :raises UnknownSSH: if the BRZ_SSH environment variable contains
2221.5.15 by Dmitry Vasiliev
Added docstrings for all SSHVendorManager's methods
150
                            unknown vendor name
151
        """
2221.5.8 by Dmitry Vasiliev
Added SSHVendorManager.clear_cache() method
152
        if self._cached_ssh_vendor is None:
7358.9.2 by Jelmer Vernooij
Add test.
153
            vendor = self._get_vendor_by_config()
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
154
            if vendor is None:
7358.9.2 by Jelmer Vernooij
Add test.
155
                vendor = self._get_vendor_by_inspection()
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
156
                if vendor is None:
7358.9.2 by Jelmer Vernooij
Add test.
157
                    trace.mutter('falling back to default implementation')
158
                    vendor = self._default_ssh_vendor
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
159
                    if vendor is None:
7358.9.2 by Jelmer Vernooij
Add test.
160
                        raise errors.SSHVendorNotFound()
2221.5.8 by Dmitry Vasiliev
Added SSHVendorManager.clear_cache() method
161
            self._cached_ssh_vendor = vendor
162
        return self._cached_ssh_vendor
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
163
7143.15.2 by Jelmer Vernooij
Run autopep8.
164
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
165
_ssh_vendor_manager = SSHVendorManager()
166
_get_ssh_vendor = _ssh_vendor_manager.get_vendor
2221.5.5 by Dmitry Vasiliev
Added 'register_default_vendor' method to the SSHVendorManager
167
register_default_ssh_vendor = _ssh_vendor_manager.register_default_vendor
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
168
register_ssh_vendor = _ssh_vendor_manager.register_vendor
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
169
170
5050.2.1 by Martin
Drive-by fix for breakin killing off ssh child processes
171
def _ignore_signals():
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
172
    # TODO: This should possibly ignore SIGHUP as well, but bzr currently
173
    # doesn't handle it itself.
174
    # <https://launchpad.net/products/bzr/+bug/41433/+index>
175
    import signal
176
    signal.signal(signal.SIGINT, signal.SIG_IGN)
5050.2.1 by Martin
Drive-by fix for breakin killing off ssh child processes
177
    # GZ 2010-02-19: Perhaps make this check if breakin is installed instead
178
    if signal.getsignal(signal.SIGQUIT) != signal.SIG_DFL:
179
        signal.signal(signal.SIGQUIT, signal.SIG_IGN)
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
180
181
3353.1.3 by Andrew Bennetts
Always adapt sockets to look like paramiko Channels before passing them to paramiko's SFTPClient.
182
class SocketAsChannelAdapter(object):
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
183
    """Simple wrapper for a socket that pretends to be a paramiko Channel."""
184
185
    def __init__(self, sock):
186
        self.__socket = sock
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
187
3353.1.2 by Andrew Bennetts
Add get_name to LoopbackSFTP. Makes the current tests pass with current paramiko.
188
    def get_name(self):
3353.1.3 by Andrew Bennetts
Always adapt sockets to look like paramiko Channels before passing them to paramiko's SFTPClient.
189
        return "bzr SocketAsChannelAdapter"
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
190
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
191
    def send(self, data):
192
        return self.__socket.send(data)
193
194
    def recv(self, n):
3353.1.3 by Andrew Bennetts
Always adapt sockets to look like paramiko Channels before passing them to paramiko's SFTPClient.
195
        try:
196
            return self.__socket.recv(n)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
197
        except socket.error as e:
3353.1.3 by Andrew Bennetts
Always adapt sockets to look like paramiko Channels before passing them to paramiko's SFTPClient.
198
            if e.args[0] in (errno.EPIPE, errno.ECONNRESET, errno.ECONNABORTED,
199
                             errno.EBADF):
200
                # Connection has closed.  Paramiko expects an empty string in
201
                # this case, not an exception.
202
                return ''
203
            raise
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
204
205
    def recv_ready(self):
3353.1.3 by Andrew Bennetts
Always adapt sockets to look like paramiko Channels before passing them to paramiko's SFTPClient.
206
        # TODO: jam 20051215 this function is necessary to support the
207
        # pipelined() function. In reality, it probably should use
208
        # poll() or select() to actually return if there is data
209
        # available, otherwise we probably don't get any benefit
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
210
        return True
211
212
    def close(self):
213
        self.__socket.close()
214
215
216
class SSHVendor(object):
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
217
    """Abstract base class for SSH vendor implementations."""
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
218
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
219
    def connect_sftp(self, username, password, host, port):
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
220
        """Make an SSH connection, and return an SFTPClient.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
221
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
222
        :param username: an ascii string
223
        :param password: an ascii string
224
        :param host: a host name as an ascii string
225
        :param port: a port number
226
        :type port: int
227
228
        :raises: ConnectionError if it cannot connect.
229
230
        :rtype: paramiko.sftp_client.SFTPClient
231
        """
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
232
        raise NotImplementedError(self.connect_sftp)
233
234
    def connect_ssh(self, username, password, host, port, command):
2018.1.9 by Andrew Bennetts
Implement ParamikoVendor.connect_ssh
235
        """Make an SSH connection.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
236
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
237
        :returns: an SSHConnection.
1951.1.12 by Andrew Bennetts
Cosmetic tweaks.
238
        """
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
239
        raise NotImplementedError(self.connect_ssh)
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
240
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
241
    def _raise_connection_error(self, host, port=None, orig_error=None,
2052.4.4 by John Arbash Meinel
Create a SocketConnectionError to make creating nice errors easier
242
                                msg='Unable to connect to SSH host'):
243
        """Raise a SocketConnectionError with properly formatted host.
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
244
245
        This just unifies all the locations that try to raise ConnectionError,
246
        so that they format things properly.
247
        """
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
248
        raise errors.SocketConnectionError(host=host, port=port, msg=msg,
249
                                           orig_error=orig_error)
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
250
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
251
252
class LoopbackVendor(SSHVendor):
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
253
    """SSH "vendor" that connects over a plain TCP socket, not SSH."""
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
254
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
255
    def connect_sftp(self, username, password, host, port):
256
        sock = socket.socket()
257
        try:
258
            sock.connect((host, port))
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
259
        except socket.error as e:
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
260
            self._raise_connection_error(host, port=port, orig_error=e)
3353.1.3 by Andrew Bennetts
Always adapt sockets to look like paramiko Channels before passing them to paramiko's SFTPClient.
261
        return SFTPClient(SocketAsChannelAdapter(sock))
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
262
7143.15.2 by Jelmer Vernooij
Run autopep8.
263
1951.1.11 by Andrew Bennetts
Change register_ssh_vendor to take an instance rather than a class.
264
register_ssh_vendor('loopback', LoopbackVendor())
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
265
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
266
267
class ParamikoVendor(SSHVendor):
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
268
    """Vendor that uses paramiko."""
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
269
6603.3.1 by Andrew Starr-Bochicchio
Use hexlify() from binascii directly as paramiko removed hexify().
270
    def _hexify(self, s):
271
        return hexlify(s).upper()
272
2018.1.9 by Andrew Bennetts
Implement ParamikoVendor.connect_ssh
273
    def _connect(self, username, password, host, port):
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
274
        global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
2900.2.8 by Vincent Ladeuil
Make sftp and bzr+ssh aware of authentication config.
275
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
276
        load_host_keys()
277
278
        try:
279
            t = paramiko.Transport((host, port or 22))
280
            t.set_log_channel('bzr.paramiko')
281
            t.start_client()
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
282
        except (paramiko.SSHException, socket.error) as e:
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
283
            self._raise_connection_error(host, port=port, orig_error=e)
2900.2.8 by Vincent Ladeuil
Make sftp and bzr+ssh aware of authentication config.
284
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
285
        server_key = t.get_remote_server_key()
6603.3.1 by Andrew Starr-Bochicchio
Use hexlify() from binascii directly as paramiko removed hexify().
286
        server_key_hex = self._hexify(server_key.get_fingerprint())
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
287
        keytype = server_key.get_name()
1711.9.10 by John Arbash Meinel
Update transport/ssh.py to remove has_key usage
288
        if host in SYSTEM_HOSTKEYS and keytype in SYSTEM_HOSTKEYS[host]:
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
289
            our_server_key = SYSTEM_HOSTKEYS[host][keytype]
6603.3.1 by Andrew Starr-Bochicchio
Use hexlify() from binascii directly as paramiko removed hexify().
290
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
291
        elif host in BRZ_HOSTKEYS and keytype in BRZ_HOSTKEYS[host]:
292
            our_server_key = BRZ_HOSTKEYS[host][keytype]
6603.3.1 by Andrew Starr-Bochicchio
Use hexlify() from binascii directly as paramiko removed hexify().
293
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
294
        else:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
295
            trace.warning('Adding %s host key for %s: %s'
296
                          % (keytype, host, server_key_hex))
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
297
            add = getattr(BRZ_HOSTKEYS, 'add', None)
7143.15.2 by Jelmer Vernooij
Run autopep8.
298
            if add is not None:  # paramiko >= 1.X.X
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
299
                BRZ_HOSTKEYS.add(host, keytype, server_key)
2127.3.1 by Alexander Belchenko
Use BZR_HOSTKEYS.add instead of deprecated dict-like paramiko interface
300
            else:
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
301
                BRZ_HOSTKEYS.setdefault(host, {})[keytype] = server_key
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
302
            our_server_key = server_key
6603.3.1 by Andrew Starr-Bochicchio
Use hexlify() from binascii directly as paramiko removed hexify().
303
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
304
            save_host_keys()
305
        if server_key != our_server_key:
306
            filename1 = os.path.expanduser('~/.ssh/known_hosts')
7336.2.1 by Martin
Split non-ini config methods to bedding
307
            filename2 = _ssh_host_keys_config_dir()
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
308
            raise errors.TransportError(
309
                'Host keys for %s do not match!  %s != %s' %
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
310
                (host, our_server_key_hex, server_key_hex),
311
                ['Try editing %s or %s' % (filename1, filename2)])
312
2900.2.8 by Vincent Ladeuil
Make sftp and bzr+ssh aware of authentication config.
313
        _paramiko_auth(username, password, host, port, t)
2018.1.9 by Andrew Bennetts
Implement ParamikoVendor.connect_ssh
314
        return t
2900.2.8 by Vincent Ladeuil
Make sftp and bzr+ssh aware of authentication config.
315
2018.1.9 by Andrew Bennetts
Implement ParamikoVendor.connect_ssh
316
    def connect_sftp(self, username, password, host, port):
317
        t = self._connect(username, password, host, port)
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
318
        try:
2018.1.9 by Andrew Bennetts
Implement ParamikoVendor.connect_ssh
319
            return t.open_sftp_client()
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
320
        except paramiko.SSHException as e:
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
321
            self._raise_connection_error(host, port=port, orig_error=e,
2052.4.4 by John Arbash Meinel
Create a SocketConnectionError to make creating nice errors easier
322
                                         msg='Unable to start sftp client')
2018.1.9 by Andrew Bennetts
Implement ParamikoVendor.connect_ssh
323
324
    def connect_ssh(self, username, password, host, port, command):
325
        t = self._connect(username, password, host, port)
326
        try:
327
            channel = t.open_session()
328
            cmdline = ' '.join(command)
329
            channel.exec_command(cmdline)
330
            return _ParamikoSSHConnection(channel)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
331
        except paramiko.SSHException as e:
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
332
            self._raise_connection_error(host, port=port, orig_error=e,
2052.4.4 by John Arbash Meinel
Create a SocketConnectionError to make creating nice errors easier
333
                                         msg='Unable to invoke remote bzr')
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
334
7143.15.2 by Jelmer Vernooij
Run autopep8.
335
5430.6.1 by Andrew Bennetts
Simplify connect_sftp/ssh error handling, hopefully resolving intermittent test failure in test_bad_connection_ssh.
336
_ssh_connection_errors = (EOFError, OSError, IOError, socket.error)
2104.5.1 by John Arbash Meinel
Remove the strict dependency on paramiko for ssh access
337
if paramiko is not None:
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
338
    vendor = ParamikoVendor()
339
    register_ssh_vendor('paramiko', vendor)
340
    register_ssh_vendor('none', vendor)
2221.5.5 by Dmitry Vasiliev
Added 'register_default_vendor' method to the SSHVendorManager
341
    register_default_ssh_vendor(vendor)
5430.6.1 by Andrew Bennetts
Simplify connect_sftp/ssh error handling, hopefully resolving intermittent test failure in test_bad_connection_ssh.
342
    _ssh_connection_errors += (paramiko.SSHException,)
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
343
    del vendor
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
344
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
345
346
class SubprocessVendor(SSHVendor):
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
347
    """Abstract base class for vendors that use pipes to a subprocess."""
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
348
6331.5.1 by Martin Packman
Stop requiring a bzr subprocess in bt.test_sftp_transport for ssh connection error test
349
    # In general stderr should be inherited from the parent process so prompts
350
    # are visible on the terminal. This can be overriden to another file for
351
    # tests, but beware of using PIPE which may hang due to not being read.
352
    _stderr_target = None
353
6753.1.2 by Jelmer Vernooij
use staticmethod rather than classmethod
354
    @staticmethod
355
    def _check_hostname(arg):
6753.1.1 by Jelmer Vernooij
Refuse to connect to ssh hostnames starting with a dash. Fixes LP:1710979
356
        if arg.startswith('-'):
357
            raise StrangeHostname(hostname=arg)
358
2018.1.6 by Andrew Bennetts
Remove a little bit of duplication in ssh.py
359
    def _connect(self, argv):
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
360
        # Attempt to make a socketpair to use as stdin/stdout for the SSH
361
        # subprocess.  We prefer sockets to pipes because they support
362
        # non-blocking short reads, allowing us to optimistically read 64k (or
363
        # whatever) chunks.
364
        try:
365
            my_sock, subproc_sock = socket.socketpair()
5582.6.1 by Max Bowsher
Fix socketpair-based SSH transport leaking socket into other child processes.
366
            osutils.set_fd_cloexec(my_sock)
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
367
        except (AttributeError, socket.error):
368
            # This platform doesn't support socketpair(), so just use ordinary
369
            # pipes instead.
370
            stdin = stdout = subprocess.PIPE
5050.54.3 by Max Bowsher
Also close the subprocess side of the socketpair within bzrlib.
371
            my_sock, subproc_sock = None, None
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
372
        else:
373
            stdin = stdout = subproc_sock
374
        proc = subprocess.Popen(argv, stdin=stdin, stdout=stdout,
6331.5.1 by Martin Packman
Stop requiring a bzr subprocess in bt.test_sftp_transport for ssh connection error test
375
                                stderr=self._stderr_target,
6973.7.3 by Jelmer Vernooij
Fix some more tests.
376
                                bufsize=0,
2018.1.6 by Andrew Bennetts
Remove a little bit of duplication in ssh.py
377
                                **os_specific_subprocess_params())
5050.54.3 by Max Bowsher
Also close the subprocess side of the socketpair within bzrlib.
378
        if subproc_sock is not None:
379
            subproc_sock.close()
380
        return SSHSubprocessConnection(proc, sock=my_sock)
2018.1.6 by Andrew Bennetts
Remove a little bit of duplication in ssh.py
381
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
382
    def connect_sftp(self, username, password, host, port):
383
        try:
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
384
            argv = self._get_vendor_specific_argv(username, host, port,
385
                                                  subsystem='sftp')
2018.1.6 by Andrew Bennetts
Remove a little bit of duplication in ssh.py
386
            sock = self._connect(argv)
3353.1.3 by Andrew Bennetts
Always adapt sockets to look like paramiko Channels before passing them to paramiko's SFTPClient.
387
            return SFTPClient(SocketAsChannelAdapter(sock))
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
388
        except _ssh_connection_errors as e:
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
389
            self._raise_connection_error(host, port=port, orig_error=e)
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
390
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
391
    def connect_ssh(self, username, password, host, port, command):
392
        try:
393
            argv = self._get_vendor_specific_argv(username, host, port,
394
                                                  command=command)
2018.1.6 by Andrew Bennetts
Remove a little bit of duplication in ssh.py
395
            return self._connect(argv)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
396
        except _ssh_connection_errors as e:
2052.4.2 by John Arbash Meinel
Refactor all 'raise ConnectionError' into a helper function
397
            self._raise_connection_error(host, port=port, orig_error=e)
2018.1.1 by Andrew Bennetts
Make bzr+ssh:// actually work (at least with absolute paths).
398
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
399
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
400
                                  command=None):
401
        """Returns the argument list to run the subprocess with.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
402
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
403
        Exactly one of 'subsystem' and 'command' must be specified.
404
        """
405
        raise NotImplementedError(self._get_vendor_specific_argv)
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
406
407
408
class OpenSSHSubprocessVendor(SubprocessVendor):
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
409
    """SSH vendor that uses the 'ssh' executable from OpenSSH."""
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
410
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
411
    executable_path = 'ssh'
412
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
413
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
414
                                  command=None):
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
415
        args = [self.executable_path,
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
416
                '-oForwardX11=no', '-oForwardAgent=no',
5459.4.1 by Neil Martinsen-Burrell
dont force openssh to use protocol=2
417
                '-oClearAllForwardings=yes',
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
418
                '-oNoHostAuthenticationForLocalhost=yes']
419
        if port is not None:
420
            args.extend(['-p', str(port)])
421
        if username is not None:
422
            args.extend(['-l', username])
423
        if subsystem is not None:
6753.1.1 by Jelmer Vernooij
Refuse to connect to ssh hostnames starting with a dash. Fixes LP:1710979
424
            args.extend(['-s', '--', host, subsystem])
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
425
        else:
6753.1.1 by Jelmer Vernooij
Refuse to connect to ssh hostnames starting with a dash. Fixes LP:1710979
426
            args.extend(['--', host] + command)
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
427
        return args
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
428
7143.15.2 by Jelmer Vernooij
Run autopep8.
429
1951.1.11 by Andrew Bennetts
Change register_ssh_vendor to take an instance rather than a class.
430
register_ssh_vendor('openssh', OpenSSHSubprocessVendor())
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
431
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
432
433
class SSHCorpSubprocessVendor(SubprocessVendor):
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
434
    """SSH vendor that uses the 'ssh' executable from SSH Corporation."""
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
435
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
436
    executable_path = 'ssh'
437
1951.1.9 by Andrew Bennetts
Add docstrings and tweak method names in ssh.py
438
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
439
                                  command=None):
6753.1.1 by Jelmer Vernooij
Refuse to connect to ssh hostnames starting with a dash. Fixes LP:1710979
440
        self._check_hostname(host)
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
441
        args = [self.executable_path, '-x']
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
442
        if port is not None:
443
            args.extend(['-p', str(port)])
444
        if username is not None:
445
            args.extend(['-l', username])
446
        if subsystem is not None:
447
            args.extend(['-s', subsystem, host])
448
        else:
449
            args.extend([host] + command)
450
        return args
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
451
7143.15.2 by Jelmer Vernooij
Run autopep8.
452
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
453
register_ssh_vendor('sshcorp', SSHCorpSubprocessVendor())
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
454
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
455
5444.2.1 by Matthew Gordon
Added GNU lsh support to supported SSH vendors.
456
class LSHSubprocessVendor(SubprocessVendor):
457
    """SSH vendor that uses the 'lsh' executable from GNU"""
458
459
    executable_path = 'lsh'
460
461
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
462
                                  command=None):
6753.1.1 by Jelmer Vernooij
Refuse to connect to ssh hostnames starting with a dash. Fixes LP:1710979
463
        self._check_hostname(host)
5444.2.1 by Matthew Gordon
Added GNU lsh support to supported SSH vendors.
464
        args = [self.executable_path]
465
        if port is not None:
466
            args.extend(['-p', str(port)])
467
        if username is not None:
468
            args.extend(['-l', username])
469
        if subsystem is not None:
470
            args.extend(['--subsystem', subsystem, host])
471
        else:
472
            args.extend([host] + command)
473
        return args
474
7143.15.2 by Jelmer Vernooij
Run autopep8.
475
5444.2.1 by Matthew Gordon
Added GNU lsh support to supported SSH vendors.
476
register_ssh_vendor('lsh', LSHSubprocessVendor())
477
478
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
479
class PLinkSubprocessVendor(SubprocessVendor):
480
    """SSH vendor that uses the 'plink' executable from Putty."""
481
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
482
    executable_path = 'plink'
483
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
484
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
485
                                  command=None):
6753.1.1 by Jelmer Vernooij
Refuse to connect to ssh hostnames starting with a dash. Fixes LP:1710979
486
        self._check_hostname(host)
4595.17.1 by Martin
Add ability to give a path to a particular ssh client in BZR_SSH envvar
487
        args = [self.executable_path, '-x', '-a', '-ssh', '-2', '-batch']
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
488
        if port is not None:
489
            args.extend(['-P', str(port)])
490
        if username is not None:
491
            args.extend(['-l', username])
492
        if subsystem is not None:
2221.5.3 by Dmitry Vasiliev
Fixed plink's arguments order. Added tests for such a case.
493
            args.extend(['-s', host, subsystem])
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
494
        else:
495
            args.extend([host] + command)
496
        return args
497
7143.15.2 by Jelmer Vernooij
Run autopep8.
498
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
499
register_ssh_vendor('plink', PLinkSubprocessVendor())
500
501
2900.2.8 by Vincent Ladeuil
Make sftp and bzr+ssh aware of authentication config.
502
def _paramiko_auth(username, password, host, port, paramiko_transport):
4222.3.4 by Jelmer Vernooij
Default to getpass.getuser() in AuthenticationConfig.get_user(), but allow
503
    auth = config.AuthenticationConfig()
3777.1.5 by Aaron Bentley
Remove AuthenticationConfig handling from Paramiko SSHVendor
504
    # paramiko requires a username, but it might be none if nothing was
505
    # supplied.  If so, use the local username.
2900.2.15 by Vincent Ladeuil
AuthenticationConfig can be queried for logins too (first step).
506
    if username is None:
4304.2.1 by Vincent Ladeuil
Fix bug #367726 by reverting some default user handling introduced
507
        username = auth.get_user('ssh', host, port=port,
508
                                 default=getpass.getuser())
6973.7.4 by Jelmer Vernooij
Fix some more tests.
509
    agent = paramiko.Agent()
510
    for key in agent.get_keys():
511
        trace.mutter('Trying SSH agent key %s'
7290.22.1 by Jelmer Vernooij
Fix syntax error - avoid using self in non-class function.
512
                     % hexlify(key.get_fingerprint()).upper())
6973.7.4 by Jelmer Vernooij
Fix some more tests.
513
        try:
514
            paramiko_transport.auth_publickey(username, key)
515
            return
516
        except paramiko.SSHException as e:
517
            pass
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
518
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
519
    # okay, try finding id_rsa or id_dss?  (posix only)
520
    if _try_pkey_auth(paramiko_transport, paramiko.RSAKey, username, 'id_rsa'):
521
        return
522
    if _try_pkey_auth(paramiko_transport, paramiko.DSSKey, username, 'id_dsa'):
523
        return
524
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
525
    # If we have gotten this far, we are about to try for passwords, do an
526
    # auth_none check to see if it is even supported.
527
    supported_auth_types = []
528
    try:
529
        # Note that with paramiko <1.7.5 this logs an INFO message:
530
        #    Authentication type (none) not permitted.
531
        # So we explicitly disable the logging level for this action
532
        old_level = paramiko_transport.logger.level
533
        paramiko_transport.logger.setLevel(logging.WARNING)
534
        try:
535
            paramiko_transport.auth_none(username)
536
        finally:
537
            paramiko_transport.logger.setLevel(old_level)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
538
    except paramiko.BadAuthenticationType as e:
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
539
        # Supported methods are in the exception
540
        supported_auth_types = e.allowed_types
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
541
    except paramiko.SSHException as e:
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
542
        # Don't know what happened, but just ignore it
543
        pass
4634.56.1 by Andrew Bennetts
Try paramiko's auth_password if the server supports 'keyboard-interactive' auth, even if it doesn't support 'password'.
544
    # We treat 'keyboard-interactive' and 'password' auth methods identically,
545
    # because Paramiko's auth_password method will automatically try
546
    # 'keyboard-interactive' auth (using the password as the response) if
547
    # 'password' auth is not available.  Apparently some Debian and Gentoo
548
    # OpenSSH servers require this.
549
    # XXX: It's possible for a server to require keyboard-interactive auth that
550
    # requires something other than a single password, but we currently don't
551
    # support that.
552
    if ('password' not in supported_auth_types and
7143.15.2 by Jelmer Vernooij
Run autopep8.
553
            'keyboard-interactive' not in supported_auth_types):
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
554
        raise errors.ConnectionError('Unable to authenticate to SSH host as'
7143.15.2 by Jelmer Vernooij
Run autopep8.
555
                                     '\n  %s@%s\nsupported auth types: %s'
556
                                     % (username, host, supported_auth_types))
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
557
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
558
    if password:
559
        try:
560
            paramiko_transport.auth_password(username, password)
561
            return
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
562
        except paramiko.SSHException as e:
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
563
            pass
564
565
    # give up and ask for a password
2900.2.12 by Vincent Ladeuil
Since all schemes query AuthenticationConfig then prompt user, make that
566
    password = auth.get_password('ssh', host, username, port=port)
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
567
    # get_password can still return None, which means we should not prompt
568
    if password is not None:
569
        try:
570
            paramiko_transport.auth_password(username, password)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
571
        except paramiko.SSHException as e:
4555.1.3 by John Arbash Meinel
Reformat the errors so they aren't so long.
572
            raise errors.ConnectionError(
573
                'Unable to authenticate to SSH host as'
574
                '\n  %s@%s\n' % (username, host), e)
4555.1.1 by John Arbash Meinel
Fix bug #375867, check if password is a supported auth type
575
    else:
4555.1.3 by John Arbash Meinel
Reformat the errors so they aren't so long.
576
        raise errors.ConnectionError('Unable to authenticate to SSH host as'
577
                                     '  %s@%s' % (username, host))
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
578
579
580
def _try_pkey_auth(paramiko_transport, pkey_class, username, filename):
581
    filename = os.path.expanduser('~/.ssh/' + filename)
582
    try:
583
        key = pkey_class.from_private_key_file(filename)
584
        paramiko_transport.auth_publickey(username, key)
585
        return True
586
    except paramiko.PasswordRequiredException:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
587
        password = ui.ui_factory.get_password(
5863.6.1 by Jelmer Vernooij
Require a unicode prompt to be passed into all methods that prompt.
588
            prompt=u'SSH %(filename)s password',
589
            filename=filename.decode(osutils._fs_enc))
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
590
        try:
591
            key = pkey_class.from_private_key_file(filename, password)
592
            paramiko_transport.auth_publickey(username, key)
593
            return True
594
        except paramiko.SSHException:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
595
            trace.mutter('SSH authentication via %s key failed.'
596
                         % (os.path.basename(filename),))
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
597
    except paramiko.SSHException:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
598
        trace.mutter('SSH authentication via %s key failed.'
599
                     % (os.path.basename(filename),))
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
600
    except IOError:
601
        pass
602
    return False
603
604
7336.2.1 by Martin
Split non-ini config methods to bedding
605
def _ssh_host_keys_config_dir():
606
    return osutils.pathjoin(bedding.config_dir(), 'ssh_host_keys')
607
608
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
609
def load_host_keys():
610
    """
611
    Load system host keys (probably doesn't work on windows) and any
612
    "discovered" keys from previous sessions.
613
    """
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
614
    global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
615
    try:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
616
        SYSTEM_HOSTKEYS = paramiko.util.load_host_keys(
617
            os.path.expanduser('~/.ssh/known_hosts'))
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
618
    except IOError as e:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
619
        trace.mutter('failed to load system host keys: ' + str(e))
7336.2.1 by Martin
Split non-ini config methods to bedding
620
    brz_hostkey_path = _ssh_host_keys_config_dir()
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
621
    try:
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
622
        BRZ_HOSTKEYS = paramiko.util.load_host_keys(brz_hostkey_path)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
623
    except IOError as e:
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
624
        trace.mutter('failed to load brz host keys: ' + str(e))
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
625
        save_host_keys()
626
627
628
def save_host_keys():
629
    """
630
    Save "discovered" host keys in $(config)/ssh_host_keys/.
631
    """
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
632
    global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
7336.2.1 by Martin
Split non-ini config methods to bedding
633
    bzr_hostkey_path = _ssh_host_keys_config_dir()
634
    bedding.ensure_config_dir_exists()
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
635
636
    try:
6855.4.5 by Jelmer Vernooij
Fix more bees, use with rather than try/finally for some files.
637
        with open(bzr_hostkey_path, 'w') as f:
638
            f.write('# SSH host keys collected by bzr\n')
639
            for hostname, keys in BRZ_HOSTKEYS.items():
640
                for keytype, key in keys.items():
7143.15.2 by Jelmer Vernooij
Run autopep8.
641
                    f.write('%s %s %s\n' %
642
                            (hostname, keytype, key.get_base64()))
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
643
    except IOError as e:
2900.2.18 by Vincent Ladeuil
Previous commits didn't check the test suite enough.
644
        trace.mutter('failed to save bzr host keys: ' + str(e))
1951.1.4 by Andrew Bennetts
Start moving SSH connection code into bzrlib/transport/ssh.py
645
646
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
647
def os_specific_subprocess_params():
648
    """Get O/S specific subprocess parameters."""
649
    if sys.platform == 'win32':
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
650
        # setting the process group and closing fds is not supported on
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
651
        # win32
652
        return {}
653
    else:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
654
        # We close fds other than the pipes as the child process does not need
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
655
        # them to be open.
656
        #
657
        # We also set the child process to ignore SIGINT.  Normally the signal
658
        # would be sent to every process in the foreground process group, but
659
        # this causes it to be seen only by bzr and not by ssh.  Python will
660
        # generate a KeyboardInterrupt in bzr, and we will then have a chance
661
        # to release locks or do other cleanup over ssh before the connection
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
662
        # goes away.
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
663
        # <https://launchpad.net/products/bzr/+bug/5987>
664
        #
665
        # Running it in a separate process group is not good because then it
666
        # can't get non-echoed input of a password or passphrase.
667
        # <https://launchpad.net/products/bzr/+bug/40508>
5050.2.1 by Martin
Drive-by fix for breakin killing off ssh child processes
668
        return {'preexec_fn': _ignore_signals,
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
669
                'close_fds': True,
670
                }
671
7143.15.2 by Jelmer Vernooij
Run autopep8.
672
4824.1.1 by Andrew Bennetts
Terminate SSHSubprocesses when no refs to them are left, in case .close is never called.
673
import weakref
674
_subproc_weakrefs = set()
675
7143.15.2 by Jelmer Vernooij
Run autopep8.
676
5050.54.1 by Max Bowsher
Do close the socket used for stdin/out to a ssh subprocess.
677
def _close_ssh_proc(proc, sock):
5050.30.1 by Andrew Bennetts
Fix AttributeError in _close_ssh_proc.
678
    """Carefully close stdin/stdout and reap the SSH process.
679
680
    If the pipes are already closed and/or the process has already been
681
    wait()ed on, that's ok, and no error is raised.  The goal is to do our best
682
    to clean up (whether or not a clean up was already tried).
683
    """
5050.54.1 by Max Bowsher
Do close the socket used for stdin/out to a ssh subprocess.
684
    funcs = []
685
    for closeable in (proc.stdin, proc.stdout, sock):
686
        # We expect that either proc (a subprocess.Popen) will have stdin and
687
        # stdout streams to close, or that we will have been passed a socket to
688
        # close, with the option not in use being None.
689
        if closeable is not None:
690
            funcs.append(closeable.close)
691
    funcs.append(proc.wait)
692
    for func in funcs:
693
        try:
694
            func()
4824.1.1 by Andrew Bennetts
Terminate SSHSubprocesses when no refs to them are left, in case .close is never called.
695
        except OSError:
5050.30.1 by Andrew Bennetts
Fix AttributeError in _close_ssh_proc.
696
            # It's ok for the pipe to already be closed, or the process to
697
            # already be finished.
698
            continue
4824.1.1 by Andrew Bennetts
Terminate SSHSubprocesses when no refs to them are left, in case .close is never called.
699
1951.1.12 by Andrew Bennetts
Cosmetic tweaks.
700
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
701
class SSHConnection(object):
702
    """Abstract base class for SSH connections."""
703
704
    def get_sock_or_pipes(self):
705
        """Returns a (kind, io_object) pair.
706
707
        If kind == 'socket', then io_object is a socket.
708
709
        If kind == 'pipes', then io_object is a pair of file-like objects
710
        (read_from, write_to).
711
        """
712
        raise NotImplementedError(self.get_sock_or_pipes)
713
714
    def close(self):
715
        raise NotImplementedError(self.close)
716
717
718
class SSHSubprocessConnection(SSHConnection):
5284.5.3 by Andrew Bennetts
Docstring tweaks.
719
    """A connection to an ssh subprocess via pipes or a socket.
720
721
    This class is also socket-like enough to be used with
722
    SocketAsChannelAdapter (it has 'send' and 'recv' methods).
723
    """
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
724
725
    def __init__(self, proc, sock=None):
726
        """Constructor.
727
728
        :param proc: a subprocess.Popen
729
        :param sock: if proc.stdin/out is a socket from a socketpair, then sock
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
730
            should breezy's half of that socketpair.  If not passed, proc's
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
731
            stdin/out is assumed to be ordinary pipes.
732
        """
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
733
        self.proc = proc
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
734
        self._sock = sock
4824.1.1 by Andrew Bennetts
Terminate SSHSubprocesses when no refs to them are left, in case .close is never called.
735
        # Add a weakref to proc that will attempt to do the same as self.close
736
        # to avoid leaving processes lingering indefinitely.
7143.15.2 by Jelmer Vernooij
Run autopep8.
737
4824.1.1 by Andrew Bennetts
Terminate SSHSubprocesses when no refs to them are left, in case .close is never called.
738
        def terminate(ref):
739
            _subproc_weakrefs.remove(ref)
5050.54.1 by Max Bowsher
Do close the socket used for stdin/out to a ssh subprocess.
740
            _close_ssh_proc(proc, sock)
4824.1.1 by Andrew Bennetts
Terminate SSHSubprocesses when no refs to them are left, in case .close is never called.
741
        _subproc_weakrefs.add(weakref.ref(self, terminate))
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
742
743
    def send(self, data):
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
744
        if self._sock is not None:
745
            return self._sock.send(data)
746
        else:
747
            return os.write(self.proc.stdin.fileno(), data)
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
748
749
    def recv(self, count):
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
750
        if self._sock is not None:
5303.1.1 by Vincent Ladeuil
Fix typo: recv() on sockets, read() on files ;)
751
            return self._sock.recv(count)
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
752
        else:
753
            return os.read(self.proc.stdout.fileno(), count)
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
754
755
    def close(self):
5050.54.1 by Max Bowsher
Do close the socket used for stdin/out to a ssh subprocess.
756
        _close_ssh_proc(self.proc, self._sock)
1951.1.7 by Andrew Bennetts
Move more generic SSH code from sftp.py into ssh.py, and start unifying the connection establishing logic.
757
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
758
    def get_sock_or_pipes(self):
759
        if self._sock is not None:
760
            return 'socket', self._sock
761
        else:
762
            return 'pipes', (self.proc.stdout, self.proc.stdin)
763
764
765
class _ParamikoSSHConnection(SSHConnection):
5284.5.3 by Andrew Bennetts
Docstring tweaks.
766
    """An SSH connection via paramiko."""
767
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
768
    def __init__(self, channel):
769
        self.channel = channel
770
771
    def get_sock_or_pipes(self):
5284.5.2 by Andrew Bennetts
Use the socket-medium with paramiko connections as well as socketpair-to-subprocess connections, as quick inspection of the paramiko source suggests it handles EINTR ok.
772
        return ('socket', self.channel)
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
773
774
    def close(self):
775
        return self.channel.close()