~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/ssh.py

  • Committer: Jelmer Vernooij
  • Date: 2011-12-16 19:18:39 UTC
  • mto: This revision was merged to the branch mainline in revision 6391.
  • Revision ID: jelmer@samba.org-20111216191839-eg681lxqibi1qxu1
Fix remaining tests.

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