~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/ssh.py

  • Committer: Ian Clatworthy
  • Date: 2008-04-01 04:19:06 UTC
  • mfrom: (3302.6.1 xma-mailmode)
  • mto: This revision was merged to the branch mainline in revision 3323.
  • Revision ID: ian.clatworthy@canonical.com-20080401041906-s7ekpfpo0tnyfkbz
Add mail-mode GNU Emacs mail package as a mail client option (Xavier Maillard)

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
18
"""Foundation SSH support for SFTP and smart server."""
19
19
 
172
172
    signal.signal(signal.SIGINT, signal.SIG_IGN)
173
173
 
174
174
 
175
 
class SocketAsChannelAdapter(object):
 
175
class LoopbackSFTP(object):
176
176
    """Simple wrapper for a socket that pretends to be a paramiko Channel."""
177
177
 
178
178
    def __init__(self, sock):
179
179
        self.__socket = sock
180
180
 
181
 
    def get_name(self):
182
 
        return "bzr SocketAsChannelAdapter"
183
 
 
184
181
    def send(self, data):
185
182
        return self.__socket.send(data)
186
183
 
187
184
    def recv(self, n):
188
 
        try:
189
 
            return self.__socket.recv(n)
190
 
        except socket.error, e:
191
 
            if e.args[0] in (errno.EPIPE, errno.ECONNRESET, errno.ECONNABORTED,
192
 
                             errno.EBADF):
193
 
                # Connection has closed.  Paramiko expects an empty string in
194
 
                # this case, not an exception.
195
 
                return ''
196
 
            raise
 
185
        return self.__socket.recv(n)
197
186
 
198
187
    def recv_ready(self):
199
 
        # TODO: jam 20051215 this function is necessary to support the
200
 
        # pipelined() function. In reality, it probably should use
201
 
        # poll() or select() to actually return if there is data
202
 
        # available, otherwise we probably don't get any benefit
203
188
        return True
204
189
 
205
190
    def close(self):
211
196
 
212
197
    def connect_sftp(self, username, password, host, port):
213
198
        """Make an SSH connection, and return an SFTPClient.
214
 
 
 
199
        
215
200
        :param username: an ascii string
216
201
        :param password: an ascii string
217
202
        :param host: a host name as an ascii string
226
211
 
227
212
    def connect_ssh(self, username, password, host, port, command):
228
213
        """Make an SSH connection.
229
 
 
 
214
        
230
215
        :returns: something with a `close` method, and a `get_filelike_channels`
231
216
            method that returns a pair of (read, write) filelike objects.
232
217
        """
252
237
            sock.connect((host, port))
253
238
        except socket.error, e:
254
239
            self._raise_connection_error(host, port=port, orig_error=e)
255
 
        return SFTPClient(SocketAsChannelAdapter(sock))
 
240
        return SFTPClient(LoopbackSFTP(sock))
256
241
 
257
242
register_ssh_vendor('loopback', LoopbackVendor())
258
243
 
362
347
            argv = self._get_vendor_specific_argv(username, host, port,
363
348
                                                  subsystem='sftp')
364
349
            sock = self._connect(argv)
365
 
            return SFTPClient(SocketAsChannelAdapter(sock))
 
350
            return SFTPClient(sock)
366
351
        except _sftp_connection_errors, e:
367
352
            self._raise_connection_error(host, port=port, orig_error=e)
368
353
        except (OSError, IOError), e:
391
376
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
392
377
                                  command=None):
393
378
        """Returns the argument list to run the subprocess with.
394
 
 
 
379
        
395
380
        Exactly one of 'subsystem' and 'command' must be specified.
396
381
        """
397
382
        raise NotImplementedError(self._get_vendor_specific_argv)
402
387
 
403
388
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
404
389
                                  command=None):
 
390
        assert subsystem is not None or command is not None, (
 
391
            'Must specify a command or subsystem')
 
392
        if subsystem is not None:
 
393
            assert command is None, (
 
394
                'subsystem and command are mutually exclusive')
405
395
        args = ['ssh',
406
396
                '-oForwardX11=no', '-oForwardAgent=no',
407
397
                '-oClearAllForwardings=yes', '-oProtocol=2',
424
414
 
425
415
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
426
416
                                  command=None):
 
417
        assert subsystem is not None or command is not None, (
 
418
            'Must specify a command or subsystem')
 
419
        if subsystem is not None:
 
420
            assert command is None, (
 
421
                'subsystem and command are mutually exclusive')
427
422
        args = ['ssh', '-x']
428
423
        if port is not None:
429
424
            args.extend(['-p', str(port)])
443
438
 
444
439
    def _get_vendor_specific_argv(self, username, host, port, subsystem=None,
445
440
                                  command=None):
 
441
        assert subsystem is not None or command is not None, (
 
442
            'Must specify a command or subsystem')
 
443
        if subsystem is not None:
 
444
            assert command is None, (
 
445
                'subsystem and command are mutually exclusive')
446
446
        args = ['plink', '-x', '-a', '-ssh', '-2', '-batch']
447
447
        if port is not None:
448
448
            args.extend(['-P', str(port)])
458
458
 
459
459
 
460
460
def _paramiko_auth(username, password, host, port, paramiko_transport):
461
 
    # paramiko requires a username, but it might be none if nothing was
462
 
    # supplied.  If so, use the local username.
 
461
    # paramiko requires a username, but it might be none if nothing was supplied
 
462
    # use the local username, just in case.
 
463
    # We don't override username, because if we aren't using paramiko,
 
464
    # the username might be specified in ~/.ssh/config and we don't want to
 
465
    # force it to something else
 
466
    # Also, it would mess up the self.relpath() functionality
 
467
    auth = config.AuthenticationConfig()
463
468
    if username is None:
464
 
        username = getpass.getuser()
 
469
        username = auth.get_user('ssh', host, port=port)
 
470
        if username is None:
 
471
            # Default to local user
 
472
            username = getpass.getuser()
465
473
 
466
474
    if _use_ssh_agent:
467
475
        agent = paramiko.Agent()
488
496
            pass
489
497
 
490
498
    # give up and ask for a password
491
 
    auth = config.AuthenticationConfig()
492
499
    password = auth.get_password('ssh', host, username, port=port)
493
500
    try:
494
501
        paramiko_transport.auth_password(username, password)
562
569
def os_specific_subprocess_params():
563
570
    """Get O/S specific subprocess parameters."""
564
571
    if sys.platform == 'win32':
565
 
        # setting the process group and closing fds is not supported on
 
572
        # setting the process group and closing fds is not supported on 
566
573
        # win32
567
574
        return {}
568
575
    else:
569
 
        # We close fds other than the pipes as the child process does not need
 
576
        # We close fds other than the pipes as the child process does not need 
570
577
        # them to be open.
571
578
        #
572
579
        # We also set the child process to ignore SIGINT.  Normally the signal
574
581
        # this causes it to be seen only by bzr and not by ssh.  Python will
575
582
        # generate a KeyboardInterrupt in bzr, and we will then have a chance
576
583
        # to release locks or do other cleanup over ssh before the connection
577
 
        # goes away.
 
584
        # goes away.  
578
585
        # <https://launchpad.net/products/bzr/+bug/5987>
579
586
        #
580
587
        # Running it in a separate process group is not good because then it
594
601
    def send(self, data):
595
602
        return os.write(self.proc.stdin.fileno(), data)
596
603
 
 
604
    def recv_ready(self):
 
605
        # TODO: jam 20051215 this function is necessary to support the
 
606
        # pipelined() function. In reality, it probably should use
 
607
        # poll() or select() to actually return if there is data
 
608
        # available, otherwise we probably don't get any benefit
 
609
        return True
 
610
 
597
611
    def recv(self, count):
598
612
        return os.read(self.proc.stdout.fileno(), count)
599
613