/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/transport/ssh.py

  • Committer: Jelmer Vernooij
  • Date: 2018-05-06 11:48:54 UTC
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180506114854-h4qd9ojaqy8wxjsd
Move .mailmap to root.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
 
31
31
from .. import (
32
32
    config,
33
 
    bedding,
34
33
    errors,
35
34
    osutils,
36
35
    trace,
55
54
BRZ_HOSTKEYS = {}
56
55
 
57
56
 
 
57
_paramiko_version = getattr(paramiko, '__version_info__', (0, 0, 0))
 
58
 
 
59
# Paramiko 1.5 tries to open a socket.AF_UNIX in order to connect
 
60
# to ssh-agent. That attribute doesn't exist on win32 (it does in cygwin)
 
61
# so we get an AttributeError exception. So we will not try to
 
62
# connect to an agent if we are on win32 and using Paramiko older than 1.6
 
63
_use_ssh_agent = (sys.platform != 'win32' or _paramiko_version >= (1, 6, 0))
 
64
 
 
65
 
58
66
class SSHVendorManager(object):
59
67
    """Manager for manage SSH vendors."""
60
68
 
80
88
        """Clear previously cached lookup result."""
81
89
        self._cached_ssh_vendor = None
82
90
 
83
 
    def _get_vendor_by_config(self):
84
 
        vendor_name = config.GlobalStack().get('ssh')
85
 
        if vendor_name is not None:
 
91
    def _get_vendor_by_environment(self, environment=None):
 
92
        """Return the vendor or None based on BRZ_SSH environment variable.
 
93
 
 
94
        :raises UnknownSSH: if the BRZ_SSH environment variable contains
 
95
                            unknown vendor name
 
96
        """
 
97
        if environment is None:
 
98
            environment = os.environ
 
99
        if 'BRZ_SSH' in environment:
 
100
            vendor_name = environment['BRZ_SSH']
86
101
            try:
87
102
                vendor = self._ssh_vendors[vendor_name]
88
103
            except KeyError:
99
114
            p = subprocess.Popen(args,
100
115
                                 stdout=subprocess.PIPE,
101
116
                                 stderr=subprocess.PIPE,
102
 
                                 bufsize=0,
103
117
                                 **os_specific_subprocess_params())
104
118
            stdout, stderr = p.communicate()
105
119
        except OSError:
106
 
            stdout = stderr = b''
107
 
        return (stdout + stderr).decode(osutils.get_terminal_encoding())
 
120
            stdout = stderr = ''
 
121
        return stdout + stderr
108
122
 
109
123
    def _get_vendor_by_version_string(self, version, progname):
110
124
        """Return the vendor or None based on output from the subprocess.
141
155
    def _get_vendor_from_path(self, path):
142
156
        """Return the vendor or None using the program at the given path"""
143
157
        version = self._get_ssh_version_string([path, '-V'])
144
 
        return self._get_vendor_by_version_string(version,
145
 
                                                  os.path.splitext(os.path.basename(path))[0])
 
158
        return self._get_vendor_by_version_string(version, 
 
159
            os.path.splitext(os.path.basename(path))[0])
146
160
 
147
 
    def get_vendor(self):
 
161
    def get_vendor(self, environment=None):
148
162
        """Find out what version of SSH is on the system.
149
163
 
150
164
        :raises SSHVendorNotFound: if no any SSH vendor is found
152
166
                            unknown vendor name
153
167
        """
154
168
        if self._cached_ssh_vendor is None:
155
 
            vendor = self._get_vendor_by_config()
 
169
            vendor = self._get_vendor_by_environment(environment)
156
170
            if vendor is None:
157
171
                vendor = self._get_vendor_by_inspection()
158
172
                if vendor is None:
163
177
            self._cached_ssh_vendor = vendor
164
178
        return self._cached_ssh_vendor
165
179
 
166
 
 
167
180
_ssh_vendor_manager = SSHVendorManager()
168
181
_get_ssh_vendor = _ssh_vendor_manager.get_vendor
169
182
register_default_ssh_vendor = _ssh_vendor_manager.register_default_vendor
262
275
            self._raise_connection_error(host, port=port, orig_error=e)
263
276
        return SFTPClient(SocketAsChannelAdapter(sock))
264
277
 
265
 
 
266
278
register_ssh_vendor('loopback', LoopbackVendor())
267
279
 
268
280
 
297
309
            trace.warning('Adding %s host key for %s: %s'
298
310
                          % (keytype, host, server_key_hex))
299
311
            add = getattr(BRZ_HOSTKEYS, 'add', None)
300
 
            if add is not None:  # paramiko >= 1.X.X
 
312
            if add is not None: # paramiko >= 1.X.X
301
313
                BRZ_HOSTKEYS.add(host, keytype, server_key)
302
314
            else:
303
315
                BRZ_HOSTKEYS.setdefault(host, {})[keytype] = server_key
306
318
            save_host_keys()
307
319
        if server_key != our_server_key:
308
320
            filename1 = os.path.expanduser('~/.ssh/known_hosts')
309
 
            filename2 = _ssh_host_keys_config_dir()
 
321
            filename2 = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
310
322
            raise errors.TransportError(
311
323
                'Host keys for %s do not match!  %s != %s' %
312
324
                (host, our_server_key_hex, server_key_hex),
334
346
            self._raise_connection_error(host, port=port, orig_error=e,
335
347
                                         msg='Unable to invoke remote bzr')
336
348
 
337
 
 
338
349
_ssh_connection_errors = (EOFError, OSError, IOError, socket.error)
339
350
if paramiko is not None:
340
351
    vendor = ParamikoVendor()
375
386
            stdin = stdout = subproc_sock
376
387
        proc = subprocess.Popen(argv, stdin=stdin, stdout=stdout,
377
388
                                stderr=self._stderr_target,
378
 
                                bufsize=0,
379
389
                                **os_specific_subprocess_params())
380
390
        if subproc_sock is not None:
381
391
            subproc_sock.close()
428
438
            args.extend(['--', host] + command)
429
439
        return args
430
440
 
431
 
 
432
441
register_ssh_vendor('openssh', OpenSSHSubprocessVendor())
433
442
 
434
443
 
451
460
            args.extend([host] + command)
452
461
        return args
453
462
 
454
 
 
455
463
register_ssh_vendor('sshcorp', SSHCorpSubprocessVendor())
456
464
 
457
465
 
474
482
            args.extend([host] + command)
475
483
        return args
476
484
 
477
 
 
478
485
register_ssh_vendor('lsh', LSHSubprocessVendor())
479
486
 
480
487
 
497
504
            args.extend([host] + command)
498
505
        return args
499
506
 
500
 
 
501
507
register_ssh_vendor('plink', PLinkSubprocessVendor())
502
508
 
503
509
 
508
514
    if username is None:
509
515
        username = auth.get_user('ssh', host, port=port,
510
516
                                 default=getpass.getuser())
511
 
    agent = paramiko.Agent()
512
 
    for key in agent.get_keys():
513
 
        trace.mutter('Trying SSH agent key %s'
514
 
                     % hexlify(key.get_fingerprint()).upper())
515
 
        try:
516
 
            paramiko_transport.auth_publickey(username, key)
517
 
            return
518
 
        except paramiko.SSHException as e:
519
 
            pass
 
517
    if _use_ssh_agent:
 
518
        agent = paramiko.Agent()
 
519
        for key in agent.get_keys():
 
520
            trace.mutter('Trying SSH agent key %s'
 
521
                         % self._hexify(key.get_fingerprint()))
 
522
            try:
 
523
                paramiko_transport.auth_publickey(username, key)
 
524
                return
 
525
            except paramiko.SSHException as e:
 
526
                pass
520
527
 
521
528
    # okay, try finding id_rsa or id_dss?  (posix only)
522
529
    if _try_pkey_auth(paramiko_transport, paramiko.RSAKey, username, 'id_rsa'):
552
559
    # requires something other than a single password, but we currently don't
553
560
    # support that.
554
561
    if ('password' not in supported_auth_types and
555
 
            'keyboard-interactive' not in supported_auth_types):
 
562
        'keyboard-interactive' not in supported_auth_types):
556
563
        raise errors.ConnectionError('Unable to authenticate to SSH host as'
557
 
                                     '\n  %s@%s\nsupported auth types: %s'
558
 
                                     % (username, host, supported_auth_types))
 
564
            '\n  %s@%s\nsupported auth types: %s'
 
565
            % (username, host, supported_auth_types))
559
566
 
560
567
    if password:
561
568
        try:
604
611
    return False
605
612
 
606
613
 
607
 
def _ssh_host_keys_config_dir():
608
 
    return osutils.pathjoin(bedding.config_dir(), 'ssh_host_keys')
609
 
 
610
 
 
611
614
def load_host_keys():
612
615
    """
613
616
    Load system host keys (probably doesn't work on windows) and any
619
622
            os.path.expanduser('~/.ssh/known_hosts'))
620
623
    except IOError as e:
621
624
        trace.mutter('failed to load system host keys: ' + str(e))
622
 
    brz_hostkey_path = _ssh_host_keys_config_dir()
 
625
    brz_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
623
626
    try:
624
627
        BRZ_HOSTKEYS = paramiko.util.load_host_keys(brz_hostkey_path)
625
628
    except IOError as e:
632
635
    Save "discovered" host keys in $(config)/ssh_host_keys/.
633
636
    """
634
637
    global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
635
 
    bzr_hostkey_path = _ssh_host_keys_config_dir()
636
 
    bedding.ensure_config_dir_exists()
 
638
    bzr_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
 
639
    config.ensure_config_dir_exists()
637
640
 
638
641
    try:
639
642
        with open(bzr_hostkey_path, 'w') as f:
640
643
            f.write('# SSH host keys collected by bzr\n')
641
644
            for hostname, keys in BRZ_HOSTKEYS.items():
642
645
                for keytype, key in keys.items():
643
 
                    f.write('%s %s %s\n' %
644
 
                            (hostname, keytype, key.get_base64()))
 
646
                    f.write('%s %s %s\n' % (hostname, keytype, key.get_base64()))
645
647
    except IOError as e:
646
648
        trace.mutter('failed to save bzr host keys: ' + str(e))
647
649
 
671
673
                'close_fds': True,
672
674
                }
673
675
 
674
 
 
675
676
import weakref
676
677
_subproc_weakrefs = set()
677
678
 
678
 
 
679
679
def _close_ssh_proc(proc, sock):
680
680
    """Carefully close stdin/stdout and reap the SSH process.
681
681
 
736
736
        self._sock = sock
737
737
        # Add a weakref to proc that will attempt to do the same as self.close
738
738
        # to avoid leaving processes lingering indefinitely.
739
 
 
740
739
        def terminate(ref):
741
740
            _subproc_weakrefs.remove(ref)
742
741
            _close_ssh_proc(proc, sock)
775
774
 
776
775
    def close(self):
777
776
        return self.channel.close()
 
777
 
 
778