/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 bzrlib/transport/ssh.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

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 .. import (
 
31
from bzrlib import (
32
32
    config,
33
33
    errors,
34
34
    osutils,
38
38
 
39
39
try:
40
40
    import paramiko
41
 
except ImportError as e:
 
41
except ImportError, 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
46
46
    from paramiko.sftp_client import SFTPClient
47
47
 
48
48
 
49
 
class StrangeHostname(errors.BzrError):
50
 
    _fmt = "Refusing to connect to strange SSH hostname %(hostname)s"
51
 
 
52
 
 
53
49
SYSTEM_HOSTKEYS = {}
54
 
BRZ_HOSTKEYS = {}
 
50
BZR_HOSTKEYS = {}
55
51
 
56
52
 
57
53
_paramiko_version = getattr(paramiko, '__version_info__', (0, 0, 0))
67
63
    """Manager for manage SSH vendors."""
68
64
 
69
65
    # Note, although at first sign the class interface seems similar to
70
 
    # breezy.registry.Registry it is not possible/convenient to directly use
 
66
    # bzrlib.registry.Registry it is not possible/convenient to directly use
71
67
    # the Registry because the class just has "get()" interface instead of the
72
68
    # Registry's "get(key)".
73
69
 
89
85
        self._cached_ssh_vendor = None
90
86
 
91
87
    def _get_vendor_by_environment(self, environment=None):
92
 
        """Return the vendor or None based on BRZ_SSH environment variable.
 
88
        """Return the vendor or None based on BZR_SSH environment variable.
93
89
 
94
 
        :raises UnknownSSH: if the BRZ_SSH environment variable contains
 
90
        :raises UnknownSSH: if the BZR_SSH environment variable contains
95
91
                            unknown vendor name
96
92
        """
97
93
        if environment is None:
98
94
            environment = os.environ
99
 
        if 'BRZ_SSH' in environment:
100
 
            vendor_name = environment['BRZ_SSH']
 
95
        if 'BZR_SSH' in environment:
 
96
            vendor_name = environment['BZR_SSH']
101
97
            try:
102
98
                vendor = self._ssh_vendors[vendor_name]
103
99
            except KeyError:
138
134
            vendor = LSHSubprocessVendor()
139
135
        # As plink user prompts are not handled currently, don't auto-detect
140
136
        # it by inspection below, but keep this vendor detection for if a path
141
 
        # is given in BRZ_SSH. See https://bugs.launchpad.net/bugs/414743
 
137
        # is given in BZR_SSH. See https://bugs.launchpad.net/bugs/414743
142
138
        elif 'plink' in version and progname == 'plink':
143
139
            # Checking if "plink" was the executed argument as Windows
144
140
            # sometimes reports 'ssh -V' incorrectly with 'plink' in its
162
158
        """Find out what version of SSH is on the system.
163
159
 
164
160
        :raises SSHVendorNotFound: if no any SSH vendor is found
165
 
        :raises UnknownSSH: if the BRZ_SSH environment variable contains
 
161
        :raises UnknownSSH: if the BZR_SSH environment variable contains
166
162
                            unknown vendor name
167
163
        """
168
164
        if self._cached_ssh_vendor is None:
209
205
    def recv(self, n):
210
206
        try:
211
207
            return self.__socket.recv(n)
212
 
        except socket.error as e:
 
208
        except socket.error, e:
213
209
            if e.args[0] in (errno.EPIPE, errno.ECONNRESET, errno.ECONNABORTED,
214
210
                             errno.EBADF):
215
211
                # Connection has closed.  Paramiko expects an empty string in
271
267
        sock = socket.socket()
272
268
        try:
273
269
            sock.connect((host, port))
274
 
        except socket.error as e:
 
270
        except socket.error, e:
275
271
            self._raise_connection_error(host, port=port, orig_error=e)
276
272
        return SFTPClient(SocketAsChannelAdapter(sock))
277
273
 
285
281
        return hexlify(s).upper()
286
282
 
287
283
    def _connect(self, username, password, host, port):
288
 
        global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
 
284
        global SYSTEM_HOSTKEYS, BZR_HOSTKEYS
289
285
 
290
286
        load_host_keys()
291
287
 
293
289
            t = paramiko.Transport((host, port or 22))
294
290
            t.set_log_channel('bzr.paramiko')
295
291
            t.start_client()
296
 
        except (paramiko.SSHException, socket.error) as e:
 
292
        except (paramiko.SSHException, socket.error), e:
297
293
            self._raise_connection_error(host, port=port, orig_error=e)
298
294
 
299
295
        server_key = t.get_remote_server_key()
302
298
        if host in SYSTEM_HOSTKEYS and keytype in SYSTEM_HOSTKEYS[host]:
303
299
            our_server_key = SYSTEM_HOSTKEYS[host][keytype]
304
300
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
305
 
        elif host in BRZ_HOSTKEYS and keytype in BRZ_HOSTKEYS[host]:
306
 
            our_server_key = BRZ_HOSTKEYS[host][keytype]
 
301
        elif host in BZR_HOSTKEYS and keytype in BZR_HOSTKEYS[host]:
 
302
            our_server_key = BZR_HOSTKEYS[host][keytype]
307
303
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
308
304
        else:
309
305
            trace.warning('Adding %s host key for %s: %s'
310
306
                          % (keytype, host, server_key_hex))
311
 
            add = getattr(BRZ_HOSTKEYS, 'add', None)
 
307
            add = getattr(BZR_HOSTKEYS, 'add', None)
312
308
            if add is not None: # paramiko >= 1.X.X
313
 
                BRZ_HOSTKEYS.add(host, keytype, server_key)
 
309
                BZR_HOSTKEYS.add(host, keytype, server_key)
314
310
            else:
315
 
                BRZ_HOSTKEYS.setdefault(host, {})[keytype] = server_key
 
311
                BZR_HOSTKEYS.setdefault(host, {})[keytype] = server_key
316
312
            our_server_key = server_key
317
313
            our_server_key_hex = self._hexify(our_server_key.get_fingerprint())
318
314
            save_host_keys()
331
327
        t = self._connect(username, password, host, port)
332
328
        try:
333
329
            return t.open_sftp_client()
334
 
        except paramiko.SSHException as e:
 
330
        except paramiko.SSHException, e:
335
331
            self._raise_connection_error(host, port=port, orig_error=e,
336
332
                                         msg='Unable to start sftp client')
337
333
 
342
338
            cmdline = ' '.join(command)
343
339
            channel.exec_command(cmdline)
344
340
            return _ParamikoSSHConnection(channel)
345
 
        except paramiko.SSHException as e:
 
341
        except paramiko.SSHException, e:
346
342
            self._raise_connection_error(host, port=port, orig_error=e,
347
343
                                         msg='Unable to invoke remote bzr')
348
344
 
364
360
    # tests, but beware of using PIPE which may hang due to not being read.
365
361
    _stderr_target = None
366
362
 
367
 
    @staticmethod
368
 
    def _check_hostname(arg):
369
 
        if arg.startswith('-'):
370
 
            raise StrangeHostname(hostname=arg)
371
 
 
372
363
    def _connect(self, argv):
373
364
        # Attempt to make a socketpair to use as stdin/stdout for the SSH
374
365
        # subprocess.  We prefer sockets to pipes because they support
397
388
                                                  subsystem='sftp')
398
389
            sock = self._connect(argv)
399
390
            return SFTPClient(SocketAsChannelAdapter(sock))
400
 
        except _ssh_connection_errors as e:
 
391
        except _ssh_connection_errors, e:
401
392
            self._raise_connection_error(host, port=port, orig_error=e)
402
393
 
403
394
    def connect_ssh(self, username, password, host, port, command):
405
396
            argv = self._get_vendor_specific_argv(username, host, port,
406
397
                                                  command=command)
407
398
            return self._connect(argv)
408
 
        except _ssh_connection_errors as e:
 
399
        except _ssh_connection_errors, e:
409
400
            self._raise_connection_error(host, port=port, orig_error=e)
410
401
 
411
402
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
433
424
        if username is not None:
434
425
            args.extend(['-l', username])
435
426
        if subsystem is not None:
436
 
            args.extend(['-s', '--', host, subsystem])
 
427
            args.extend(['-s', host, subsystem])
437
428
        else:
438
 
            args.extend(['--', host] + command)
 
429
            args.extend([host] + command)
439
430
        return args
440
431
 
441
432
register_ssh_vendor('openssh', OpenSSHSubprocessVendor())
448
439
 
449
440
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
450
441
                                  command=None):
451
 
        self._check_hostname(host)
452
442
        args = [self.executable_path, '-x']
453
443
        if port is not None:
454
444
            args.extend(['-p', str(port)])
470
460
 
471
461
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
472
462
                                  command=None):
473
 
        self._check_hostname(host)
474
463
        args = [self.executable_path]
475
464
        if port is not None:
476
465
            args.extend(['-p', str(port)])
492
481
 
493
482
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
494
483
                                  command=None):
495
 
        self._check_hostname(host)
496
484
        args = [self.executable_path, '-x', '-a', '-ssh', '-2', '-batch']
497
485
        if port is not None:
498
486
            args.extend(['-P', str(port)])
522
510
            try:
523
511
                paramiko_transport.auth_publickey(username, key)
524
512
                return
525
 
            except paramiko.SSHException as e:
 
513
            except paramiko.SSHException, e:
526
514
                pass
527
515
 
528
516
    # okay, try finding id_rsa or id_dss?  (posix only)
544
532
            paramiko_transport.auth_none(username)
545
533
        finally:
546
534
            paramiko_transport.logger.setLevel(old_level)
547
 
    except paramiko.BadAuthenticationType as e:
 
535
    except paramiko.BadAuthenticationType, e:
548
536
        # Supported methods are in the exception
549
537
        supported_auth_types = e.allowed_types
550
 
    except paramiko.SSHException as e:
 
538
    except paramiko.SSHException, e:
551
539
        # Don't know what happened, but just ignore it
552
540
        pass
553
541
    # We treat 'keyboard-interactive' and 'password' auth methods identically,
568
556
        try:
569
557
            paramiko_transport.auth_password(username, password)
570
558
            return
571
 
        except paramiko.SSHException as e:
 
559
        except paramiko.SSHException, e:
572
560
            pass
573
561
 
574
562
    # give up and ask for a password
577
565
    if password is not None:
578
566
        try:
579
567
            paramiko_transport.auth_password(username, password)
580
 
        except paramiko.SSHException as e:
 
568
        except paramiko.SSHException, e:
581
569
            raise errors.ConnectionError(
582
570
                'Unable to authenticate to SSH host as'
583
571
                '\n  %s@%s\n' % (username, host), e)
616
604
    Load system host keys (probably doesn't work on windows) and any
617
605
    "discovered" keys from previous sessions.
618
606
    """
619
 
    global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
 
607
    global SYSTEM_HOSTKEYS, BZR_HOSTKEYS
620
608
    try:
621
609
        SYSTEM_HOSTKEYS = paramiko.util.load_host_keys(
622
610
            os.path.expanduser('~/.ssh/known_hosts'))
623
 
    except IOError as e:
 
611
    except IOError, e:
624
612
        trace.mutter('failed to load system host keys: ' + str(e))
625
 
    brz_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
 
613
    bzr_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
626
614
    try:
627
 
        BRZ_HOSTKEYS = paramiko.util.load_host_keys(brz_hostkey_path)
628
 
    except IOError as e:
629
 
        trace.mutter('failed to load brz host keys: ' + str(e))
 
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))
630
618
        save_host_keys()
631
619
 
632
620
 
634
622
    """
635
623
    Save "discovered" host keys in $(config)/ssh_host_keys/.
636
624
    """
637
 
    global SYSTEM_HOSTKEYS, BRZ_HOSTKEYS
 
625
    global SYSTEM_HOSTKEYS, BZR_HOSTKEYS
638
626
    bzr_hostkey_path = osutils.pathjoin(config.config_dir(), 'ssh_host_keys')
639
627
    config.ensure_config_dir_exists()
640
628
 
641
629
    try:
642
 
        with open(bzr_hostkey_path, 'w') as f:
643
 
            f.write('# SSH host keys collected by bzr\n')
644
 
            for hostname, keys in BRZ_HOSTKEYS.items():
645
 
                for keytype, key in keys.items():
646
 
                    f.write('%s %s %s\n' % (hostname, keytype, key.get_base64()))
647
 
    except IOError as e:
 
630
        f = open(bzr_hostkey_path, 'w')
 
631
        f.write('# SSH host keys collected by bzr\n')
 
632
        for hostname, keys in BZR_HOSTKEYS.iteritems():
 
633
            for keytype, key in keys.iteritems():
 
634
                f.write('%s %s %s\n' % (hostname, keytype, key.get_base64()))
 
635
        f.close()
 
636
    except IOError, e:
648
637
        trace.mutter('failed to save bzr host keys: ' + str(e))
649
638
 
650
639
 
729
718
 
730
719
        :param proc: a subprocess.Popen
731
720
        :param sock: if proc.stdin/out is a socket from a socketpair, then sock
732
 
            should breezy's half of that socketpair.  If not passed, proc's
 
721
            should bzrlib's half of that socketpair.  If not passed, proc's
733
722
            stdin/out is assumed to be ordinary pipes.
734
723
        """
735
724
        self.proc = proc