/breezy/unstable

To get this branch, use:
bzr branch https://code.breezy-vcs.org/breezy/unstable

« back to all changes in this revision

Viewing changes to breezy/transport/ssh.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-24 01:39:33 UTC
  • mfrom: (3815.3776.6)
  • Revision ID: jelmer@jelmer.uk-20170524013933-ir4y4tqtrsiz2ka2
New upstream snapshot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
import sys
29
29
from binascii import hexlify
30
30
 
31
 
from bzrlib import (
 
31
from .. import (
32
32
    config,
33
33
    errors,
34
34
    osutils,
38
38
 
39
39
try:
40
40
    import paramiko
41
 
except ImportError, e:
 
41
except ImportError as e:
42
42
    # If we have an ssh subprocess, we don't strictly need paramiko for all ssh
43
43
    # access
44
44
    paramiko = None
47
47
 
48
48
 
49
49
SYSTEM_HOSTKEYS = {}
50
 
BZR_HOSTKEYS = {}
 
50
BRZ_HOSTKEYS = {}
51
51
 
52
52
 
53
53
_paramiko_version = getattr(paramiko, '__version_info__', (0, 0, 0))
63
63
    """Manager for manage SSH vendors."""
64
64
 
65
65
    # Note, although at first sign the class interface seems similar to
66
 
    # bzrlib.registry.Registry it is not possible/convenient to directly use
 
66
    # breezy.registry.Registry it is not possible/convenient to directly use
67
67
    # the Registry because the class just has "get()" interface instead of the
68
68
    # Registry's "get(key)".
69
69
 
85
85
        self._cached_ssh_vendor = None
86
86
 
87
87
    def _get_vendor_by_environment(self, environment=None):
88
 
        """Return the vendor or None based on BZR_SSH environment variable.
 
88
        """Return the vendor or None based on BRZ_SSH environment variable.
89
89
 
90
 
        :raises UnknownSSH: if the BZR_SSH environment variable contains
 
90
        :raises UnknownSSH: if the BRZ_SSH environment variable contains
91
91
                            unknown vendor name
92
92
        """
93
93
        if environment is None:
94
94
            environment = os.environ
95
 
        if 'BZR_SSH' in environment:
96
 
            vendor_name = environment['BZR_SSH']
 
95
        if 'BRZ_SSH' in environment:
 
96
            vendor_name = environment['BRZ_SSH']
97
97
            try:
98
98
                vendor = self._ssh_vendors[vendor_name]
99
99
            except KeyError:
134
134
            vendor = LSHSubprocessVendor()
135
135
        # As plink user prompts are not handled currently, don't auto-detect
136
136
        # it by inspection below, but keep this vendor detection for if a path
137
 
        # is given in BZR_SSH. See https://bugs.launchpad.net/bugs/414743
 
137
        # is given in BRZ_SSH. See https://bugs.launchpad.net/bugs/414743
138
138
        elif 'plink' in version and progname == 'plink':
139
139
            # Checking if "plink" was the executed argument as Windows
140
140
            # sometimes reports 'ssh -V' incorrectly with 'plink' in its
158
158
        """Find out what version of SSH is on the system.
159
159
 
160
160
        :raises SSHVendorNotFound: if no any SSH vendor is found
161
 
        :raises UnknownSSH: if the BZR_SSH environment variable contains
 
161
        :raises UnknownSSH: if the BRZ_SSH environment variable contains
162
162
                            unknown vendor name
163
163
        """
164
164
        if self._cached_ssh_vendor is None:
205
205
    def recv(self, n):
206
206
        try:
207
207
            return self.__socket.recv(n)
208
 
        except socket.error, e:
 
208
        except socket.error as e:
209
209
            if e.args[0] in (errno.EPIPE, errno.ECONNRESET, errno.ECONNABORTED,
210
210
                             errno.EBADF):
211
211
                # Connection has closed.  Paramiko expects an empty string in
267
267
        sock = socket.socket()
268
268
        try:
269
269
            sock.connect((host, port))
270
 
        except socket.error, e:
 
270
        except socket.error as e:
271
271
            self._raise_connection_error(host, port=port, orig_error=e)
272
272
        return SFTPClient(SocketAsChannelAdapter(sock))
273
273
 
281
281
        return hexlify(s).upper()
282
282
 
283
283
    def _connect(self, username, password, host, port):
284
 
        global SYSTEM_HOSTKEYS, BZR_HOSTKEYS
 
284
        global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
285
285
 
286
286
        load_host_keys()
287
287
 
289
289
            t = paramiko.Transport((host, port or 22))
290
290
            t.set_log_channel('bzr.paramiko')
291
291
            t.start_client()
292
 
        except (paramiko.SSHException, socket.error), e:
 
292
        except (paramiko.SSHException, socket.error) as e:
293
293
            self._raise_connection_error(host, port=port, orig_error=e)
294
294
 
295
295
        server_key = t.get_remote_server_key()
298
298
        if host in SYSTEM_HOSTKEYS and keytype in SYSTEM_HOSTKEYS[host]:
299
299
            our_server_key = SYSTEM_HOSTKEYS[host][keytype]
300
300
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
301
 
        elif host in BZR_HOSTKEYS and keytype in BZR_HOSTKEYS[host]:
302
 
            our_server_key = BZR_HOSTKEYS[host][keytype]
 
301
        elif host in BRZ_HOSTKEYS and keytype in BRZ_HOSTKEYS[host]:
 
302
            our_server_key = BRZ_HOSTKEYS[host][keytype]
303
303
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
304
304
        else:
305
305
            trace.warning('Adding %s host key for %s: %s'
306
306
                          % (keytype, host, server_key_hex))
307
 
            add = getattr(BZR_HOSTKEYS, 'add', None)
 
307
            add = getattr(BRZ_HOSTKEYS, 'add', None)
308
308
            if add is not None: # paramiko >= 1.X.X
309
 
                BZR_HOSTKEYS.add(host, keytype, server_key)
 
309
                BRZ_HOSTKEYS.add(host, keytype, server_key)
310
310
            else:
311
 
                BZR_HOSTKEYS.setdefault(host, {})[keytype] = server_key
 
311
                BRZ_HOSTKEYS.setdefault(host, {})[keytype] = server_key
312
312
            our_server_key = server_key
313
313
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
314
314
            save_host_keys()
327
327
        t = self._connect(username, password, host, port)
328
328
        try:
329
329
            return t.open_sftp_client()
330
 
        except paramiko.SSHException, e:
 
330
        except paramiko.SSHException as e:
331
331
            self._raise_connection_error(host, port=port, orig_error=e,
332
332
                                         msg='Unable to start sftp client')
333
333
 
338
338
            cmdline = ' '.join(command)
339
339
            channel.exec_command(cmdline)
340
340
            return _ParamikoSSHConnection(channel)
341
 
        except paramiko.SSHException, e:
 
341
        except paramiko.SSHException as e:
342
342
            self._raise_connection_error(host, port=port, orig_error=e,
343
343
                                         msg='Unable to invoke remote bzr')
344
344
 
388
388
                                                  subsystem='sftp')
389
389
            sock = self._connect(argv)
390
390
            return SFTPClient(SocketAsChannelAdapter(sock))
391
 
        except _ssh_connection_errors, e:
 
391
        except _ssh_connection_errors as e:
392
392
            self._raise_connection_error(host, port=port, orig_error=e)
393
393
 
394
394
    def connect_ssh(self, username, password, host, port, command):
396
396
            argv = self._get_vendor_specific_argv(username, host, port,
397
397
                                                  command=command)
398
398
            return self._connect(argv)
399
 
        except _ssh_connection_errors, e:
 
399
        except _ssh_connection_errors as e:
400
400
            self._raise_connection_error(host, port=port, orig_error=e)
401
401
 
402
402
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
510
510
            try:
511
511
                paramiko_transport.auth_publickey(username, key)
512
512
                return
513
 
            except paramiko.SSHException, e:
 
513
            except paramiko.SSHException as e:
514
514
                pass
515
515
 
516
516
    # okay, try finding id_rsa or id_dss?  (posix only)
532
532
            paramiko_transport.auth_none(username)
533
533
        finally:
534
534
            paramiko_transport.logger.setLevel(old_level)
535
 
    except paramiko.BadAuthenticationType, e:
 
535
    except paramiko.BadAuthenticationType as e:
536
536
        # Supported methods are in the exception
537
537
        supported_auth_types = e.allowed_types
538
 
    except paramiko.SSHException, e:
 
538
    except paramiko.SSHException as e:
539
539
        # Don't know what happened, but just ignore it
540
540
        pass
541
541
    # We treat 'keyboard-interactive' and 'password' auth methods identically,
556
556
        try:
557
557
            paramiko_transport.auth_password(username, password)
558
558
            return
559
 
        except paramiko.SSHException, e:
 
559
        except paramiko.SSHException as e:
560
560
            pass
561
561
 
562
562
    # give up and ask for a password
565
565
    if password is not None:
566
566
        try:
567
567
            paramiko_transport.auth_password(username, password)
568
 
        except paramiko.SSHException, e:
 
568
        except paramiko.SSHException as e:
569
569
            raise errors.ConnectionError(
570
570
                'Unable to authenticate to SSH host as'
571
571
                '\n  %s@%s\n' % (username, host), e)
604
604
    Load system host keys (probably doesn't work on windows) and any
605
605
    "discovered" keys from previous sessions.
606
606
    """
607
 
    global SYSTEM_HOSTKEYS, BZR_HOSTKEYS
 
607
    global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
608
608
    try:
609
609
        SYSTEM_HOSTKEYS = paramiko.util.load_host_keys(
610
610
            os.path.expanduser('~/.ssh/known_hosts'))
611
 
    except IOError, e:
 
611
    except IOError as e:
612
612
        trace.mutter('failed to load system host keys: ' + str(e))
613
 
    bzr_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
 
613
    brz_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
614
614
    try:
615
 
        BZR_HOSTKEYS = paramiko.util.load_host_keys(bzr_hostkey_path)
616
 
    except IOError, e:
617
 
        trace.mutter('failed to load bzr host keys: ' + str(e))
 
615
        BRZ_HOSTKEYS = paramiko.util.load_host_keys(brz_hostkey_path)
 
616
    except IOError as e:
 
617
        trace.mutter('failed to load brz host keys: ' + str(e))
618
618
        save_host_keys()
619
619
 
620
620
 
622
622
    """
623
623
    Save "discovered" host keys in $(config)/ssh_host_keys/.
624
624
    """
625
 
    global SYSTEM_HOSTKEYS, BZR_HOSTKEYS
 
625
    global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
626
626
    bzr_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
627
627
    config.ensure_config_dir_exists()
628
628
 
629
629
    try:
630
630
        f = open(bzr_hostkey_path, 'w')
631
631
        f.write('# SSH host keys collected by bzr\n')
632
 
        for hostname, keys in BZR_HOSTKEYS.iteritems():
 
632
        for hostname, keys in BRZ_HOSTKEYS.iteritems():
633
633
            for keytype, key in keys.iteritems():
634
634
                f.write('%s %s %s\n' % (hostname, keytype, key.get_base64()))
635
635
        f.close()
636
 
    except IOError, e:
 
636
    except IOError as e:
637
637
        trace.mutter('failed to save bzr host keys: ' + str(e))
638
638
 
639
639
 
718
718
 
719
719
        :param proc: a subprocess.Popen
720
720
        :param sock: if proc.stdin/out is a socket from a socketpair, then sock
721
 
            should bzrlib's half of that socketpair.  If not passed, proc's
 
721
            should breezy's half of that socketpair.  If not passed, proc's
722
722
            stdin/out is assumed to be ordinary pipes.
723
723
        """
724
724
        self.proc = proc