~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/ssh.py

  • Committer: Kit Randel
  • Date: 2014-12-15 20:24:42 UTC
  • mto: This revision was merged to the branch mainline in revision 6602.
  • Revision ID: kit.randel@canonical.com-20141215202442-usf2ixhypqg8yh6q
added a note for bug-1400567 to the 2.7b release notes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Robey Pointer <robey@lag.net>
 
1
# Copyright (C) 2006-2011 Robey Pointer <robey@lag.net>
2
2
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
17
17
 
18
18
"""Foundation SSH support for SFTP and smart server."""
19
19
 
 
20
from __future__ import absolute_import
 
21
 
20
22
import errno
21
23
import getpass
22
24
import logging
126
128
        elif 'SSH Secure Shell' in version:
127
129
            trace.mutter('ssh implementation is SSH Corp.')
128
130
            vendor = SSHCorpSubprocessVendor()
 
131
        elif 'lsh' in version:
 
132
            trace.mutter('ssh implementation is GNU lsh.')
 
133
            vendor = LSHSubprocessVendor()
129
134
        # As plink user prompts are not handled currently, don't auto-detect
130
135
        # it by inspection below, but keep this vendor detection for if a path
131
136
        # is given in BZR_SSH. See https://bugs.launchpad.net/bugs/414743
349
354
class SubprocessVendor(SSHVendor):
350
355
    """Abstract base class for vendors that use pipes to a subprocess."""
351
356
 
 
357
    # In general stderr should be inherited from the parent process so prompts
 
358
    # are visible on the terminal. This can be overriden to another file for
 
359
    # tests, but beware of using PIPE which may hang due to not being read.
 
360
    _stderr_target = None
 
361
 
352
362
    def _connect(self, argv):
353
363
        # Attempt to make a socketpair to use as stdin/stdout for the SSH
354
364
        # subprocess.  We prefer sockets to pipes because they support
356
366
        # whatever) chunks.
357
367
        try:
358
368
            my_sock, subproc_sock = socket.socketpair()
 
369
            osutils.set_fd_cloexec(my_sock)
359
370
        except (AttributeError, socket.error):
360
371
            # This platform doesn't support socketpair(), so just use ordinary
361
372
            # pipes instead.
362
373
            stdin = stdout = subprocess.PIPE
363
 
            sock = None
 
374
            my_sock, subproc_sock = None, None
364
375
        else:
365
376
            stdin = stdout = subproc_sock
366
 
            sock = my_sock
367
377
        proc = subprocess.Popen(argv, stdin=stdin, stdout=stdout,
 
378
                                stderr=self._stderr_target,
368
379
                                **os_specific_subprocess_params())
369
 
        return SSHSubprocessConnection(proc, sock=sock)
 
380
        if subproc_sock is not None:
 
381
            subproc_sock.close()
 
382
        return SSHSubprocessConnection(proc, sock=my_sock)
370
383
 
371
384
    def connect_sftp(self, username, password, host, port):
372
385
        try:
403
416
                                  command=None):
404
417
        args = [self.executable_path,
405
418
                '-oForwardX11=no', '-oForwardAgent=no',
406
 
                '-oClearAllForwardings=yes', '-oProtocol=2',
 
419
                '-oClearAllForwardings=yes',
407
420
                '-oNoHostAuthenticationForLocalhost=yes']
408
421
        if port is not None:
409
422
            args.extend(['-p', str(port)])
439
452
register_ssh_vendor('sshcorp', SSHCorpSubprocessVendor())
440
453
 
441
454
 
 
455
class LSHSubprocessVendor(SubprocessVendor):
 
456
    """SSH vendor that uses the 'lsh' executable from GNU"""
 
457
 
 
458
    executable_path = 'lsh'
 
459
 
 
460
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
 
461
                                  command=None):
 
462
        args = [self.executable_path]
 
463
        if port is not None:
 
464
            args.extend(['-p', str(port)])
 
465
        if username is not None:
 
466
            args.extend(['-l', username])
 
467
        if subsystem is not None:
 
468
            args.extend(['--subsystem', subsystem, host])
 
469
        else:
 
470
            args.extend([host] + command)
 
471
        return args
 
472
 
 
473
register_ssh_vendor('lsh', LSHSubprocessVendor())
 
474
 
 
475
 
442
476
class PLinkSubprocessVendor(SubprocessVendor):
443
477
    """SSH vendor that uses the 'plink' executable from Putty."""
444
478
 
547
581
        return True
548
582
    except paramiko.PasswordRequiredException:
549
583
        password = ui.ui_factory.get_password(
550
 
            prompt='SSH %(filename)s password', filename=filename)
 
584
            prompt=u'SSH %(filename)s password',
 
585
            filename=filename.decode(osutils._fs_enc))
551
586
        try:
552
587
            key = pkey_class.from_private_key_file(filename, password)
553
588
            paramiko_transport.auth_publickey(username, key)
629
664
import weakref
630
665
_subproc_weakrefs = set()
631
666
 
632
 
def _close_ssh_proc(proc):
 
667
def _close_ssh_proc(proc, sock):
633
668
    """Carefully close stdin/stdout and reap the SSH process.
634
669
 
635
670
    If the pipes are already closed and/or the process has already been
636
671
    wait()ed on, that's ok, and no error is raised.  The goal is to do our best
637
672
    to clean up (whether or not a clean up was already tried).
638
673
    """
639
 
    dotted_names = ['stdin.close', 'stdout.close', 'wait']
640
 
    for dotted_name in dotted_names:
641
 
        attrs = dotted_name.split('.')
642
 
        try:
643
 
            obj = proc
644
 
            for attr in attrs:
645
 
                obj = getattr(obj, attr)
646
 
        except AttributeError:
647
 
            # It's ok for proc.stdin or proc.stdout to be None.
648
 
            continue
649
 
        try:
650
 
            obj()
 
674
    funcs = []
 
675
    for closeable in (proc.stdin, proc.stdout, sock):
 
676
        # We expect that either proc (a subprocess.Popen) will have stdin and
 
677
        # stdout streams to close, or that we will have been passed a socket to
 
678
        # close, with the option not in use being None.
 
679
        if closeable is not None:
 
680
            funcs.append(closeable.close)
 
681
    funcs.append(proc.wait)
 
682
    for func in funcs:
 
683
        try:
 
684
            func()
651
685
        except OSError:
652
686
            # It's ok for the pipe to already be closed, or the process to
653
687
            # already be finished.
692
726
        # to avoid leaving processes lingering indefinitely.
693
727
        def terminate(ref):
694
728
            _subproc_weakrefs.remove(ref)
695
 
            _close_ssh_proc(proc)
 
729
            _close_ssh_proc(proc, sock)
696
730
        _subproc_weakrefs.add(weakref.ref(self, terminate))
697
731
 
698
732
    def send(self, data):
708
742
            return os.read(self.proc.stdout.fileno(), count)
709
743
 
710
744
    def close(self):
711
 
        _close_ssh_proc(self.proc)
 
745
        _close_ssh_proc(self.proc, self._sock)
712
746
 
713
747
    def get_sock_or_pipes(self):
714
748
        if self._sock is not None: