paramiko.transport

Package paramiko :: Module transport |
[frames] | no frames]

# Source Code for Module paramiko.transport

       1  # Copyright (C) 2003-2007  Robey Pointer <robey@lag.net>
       2  #
       3  # This file is part of paramiko.
       4  #
       5  # Paramiko is free software; you can redistribute it and/or modify it under the
       6  # terms of the GNU Lesser General Public License as published by the Free
       7  # Software Foundation; either version 2.1 of the License, or (at your option)
       8  # any later version.
       9  #
      10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
      11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13  # details.
      14  #
      15  # You should have received a copy of the GNU Lesser General Public License
      16  # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
      17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
      18
      19  """
      20  L{Transport} handles the core SSH2 protocol.
      21  """
      22
      23  import os
      24  import socket
      25  import string
      26  import struct
      27  import sys
      28  import threading
      29  import time
      30  import weakref
      31
      32  from paramiko import util
      33  from paramiko.auth_handler import AuthHandler
      34  from paramiko.channel import Channel
      35  from paramiko.common import *
      36  from paramiko.compress import ZlibCompressor, ZlibDecompressor
      37  from paramiko.dsskey import DSSKey
      38  from paramiko.kex_gex import KexGex
      39  from paramiko.kex_group1 import KexGroup1
      40  from paramiko.message import Message
      41  from paramiko.packet import Packetizer, NeedRekeyException
      42  from paramiko.primes import ModulusPack
      43  from paramiko.rsakey import RSAKey
      44  from paramiko.server import ServerInterface
      45  from paramiko.sftp_client import SFTPClient
      46  from paramiko.ssh_exception import SSHException, BadAuthenticationType, ChannelException
      47
      48  # these come from PyCrypt
      49  #     http://www.amk.ca/python/writing/pycrypt/
      50  # i believe this on the standards track.
      51  # PyCrypt compiled for Win32 can be downloaded from the HashTar homepage:
      52  #     http://nitace.bsd.uchicago.edu:8080/hashtar
      53  from Crypto.Cipher import Blowfish, AES, DES3
      54  from Crypto.Hash import SHA, MD5
      55
      56
      57  # for thread cleanup
      58  _active_threads = []
      59 -def _join_lingering_threads():
      60      for thr in _active_threads:
      61          thr.stop_thread()
      62  import atexit
      63  atexit.register(_join_lingering_threads)
      64
      65
      66 -class SecurityOptions (object):
      67      """
      68      Simple object containing the security preferences of an ssh transport.
      69      These are tuples of acceptable ciphers, digests, key types, and key
      70      exchange algorithms, listed in order of preference.
      71
      72      Changing the contents and/or order of these fields affects the underlying
      73      L{Transport} (but only if you change them before starting the session).
      74      If you try to add an algorithm that paramiko doesn't recognize,
      75      C{ValueError} will be raised.  If you try to assign something besides a
      76      tuple to one of the fields, C{TypeError} will be raised.
      77      """
      78      __slots__ = [ 'ciphers', 'digests', 'key_types', 'kex', 'compression', '_transport' ]
      79
      80 -    def __init__(self, transport):
      81          self._transport = transport
      82
      83 -    def __repr__(self):
      84          """
      85          Returns a string representation of this object, for debugging.
      86
      87          @rtype: str
      88          """
      89          return '<paramiko.SecurityOptions for %s>' % repr(self._transport)
      90
      91 -    def _get_ciphers(self):
      92          return self._transport._preferred_ciphers
      93
      94 -    def _get_digests(self):
      95          return self._transport._preferred_macs
      96
      97 -    def _get_key_types(self):
      98          return self._transport._preferred_keys
      99
     100 -    def _get_kex(self):
     101          return self._transport._preferred_kex
     102
     103 -    def _get_compression(self):
     104          return self._transport._preferred_compression
     105
     106 -    def _set(self, name, orig, x):
     107          if type(x) is list:
     108              x = tuple(x)
     109          if type(x) is not tuple:
     110              raise TypeError('expected tuple or list')
     111          possible = getattr(self._transport, orig).keys()
     112          forbidden = filter(lambda n: n not in possible, x)
     113          if len(forbidden) > 0:
     114              raise ValueError('unknown cipher')
     115          setattr(self._transport, name, x)
     116
     117 -    def _set_ciphers(self, x):
     118          self._set('_preferred_ciphers', '_cipher_info', x)
     119
     120 -    def _set_digests(self, x):
     121          self._set('_preferred_macs', '_mac_info', x)
     122
     123 -    def _set_key_types(self, x):
     124          self._set('_preferred_keys', '_key_info', x)
     125
     126 -    def _set_kex(self, x):
     127          self._set('_preferred_kex', '_kex_info', x)
     128
     129 -    def _set_compression(self, x):
     130          self._set('_preferred_compression', '_compression_info', x)
     131
     132      ciphers = property(_get_ciphers, _set_ciphers, None,
     133                         "Symmetric encryption ciphers")
     134      digests = property(_get_digests, _set_digests, None,
     135                         "Digest (one-way hash) algorithms")
     136      key_types = property(_get_key_types, _set_key_types, None,
     137                           "Public-key algorithms")
     138      kex = property(_get_kex, _set_kex, None, "Key exchange algorithms")
     139      compression = property(_get_compression, _set_compression, None,
     140                             "Compression algorithms")
     141
     142
     143 -class ChannelMap (object):
     144 -    def __init__(self):
     145          # (id -> Channel)
     146          self._map = weakref.WeakValueDictionary()
     147          self._lock = threading.Lock()
     148
     149 -    def put(self, chanid, chan):
     150          self._lock.acquire()
     151          try:
     152              self._map[chanid] = chan
     153          finally:
     154              self._lock.release()
     155
     156 -    def get(self, chanid):
     157          self._lock.acquire()
     158          try:
     159              return self._map.get(chanid, None)
     160          finally:
     161              self._lock.release()
     162
     163 -    def delete(self, chanid):
     164          self._lock.acquire()
     165          try:
     166              try:
     167                  del self._map[chanid]
     168              except KeyError:
     169                  pass
     170          finally:
     171              self._lock.release()
     172
     173 -    def values(self):
     174          self._lock.acquire()
     175          try:
     176              return self._map.values()
     177          finally:
     178              self._lock.release()
     179
     180 -    def __len__(self):
     181          self._lock.acquire()
     182          try:
     183              return len(self._map)
     184          finally:
     185              self._lock.release()
     186
     187
     188 -class Transport (threading.Thread):
     189      """
     190      An SSH Transport attaches to a stream (usually a socket), negotiates an
     191      encrypted session, authenticates, and then creates stream tunnels, called
     192      L{Channel}s, across the session.  Multiple channels can be multiplexed
     193      across a single session (and often are, in the case of port forwardings).
     194      """
     195
     196      _PROTO_ID = '2.0'
     197      _CLIENT_ID = 'paramiko_1.7.3'
     198
     199      _preferred_ciphers = ( 'aes128-cbc', 'blowfish-cbc', 'aes256-cbc', '3des-cbc' )
     200      _preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' )
     201      _preferred_keys = ( 'ssh-rsa', 'ssh-dss' )
     202      _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' )
     203      _preferred_compression = ( 'none', )
     204
     205      _cipher_info = {
     206          'blowfish-cbc': { 'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16 },
     207          'aes128-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16 },
     208          'aes256-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32 },
     209          '3des-cbc': { 'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24 },
     210          }
     211
     212      _mac_info = {
     213          'hmac-sha1': { 'class': SHA, 'size': 20 },
     214          'hmac-sha1-96': { 'class': SHA, 'size': 12 },
     215          'hmac-md5': { 'class': MD5, 'size': 16 },
     216          'hmac-md5-96': { 'class': MD5, 'size': 12 },
     217          }
     218
     219      _key_info = {
     220          'ssh-rsa': RSAKey,
     221          'ssh-dss': DSSKey,
     222          }
     223
     224      _kex_info = {
     225          'diffie-hellman-group1-sha1': KexGroup1,
     226          'diffie-hellman-group-exchange-sha1': KexGex,
     227          }
     228
     229      _compression_info = {
     230          # zlib@openssh.com is just zlib, but only turned on after a successful
     231          # authentication.  openssh servers may only offer this type because
     232          # they've had troubles with security holes in zlib in the past.
     233          'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ),
     234          'zlib': ( ZlibCompressor, ZlibDecompressor ),
     235          'none': ( None, None ),
     236      }
     237
     238
     239      _modulus_pack = None
     240
     241 -    def __init__(self, sock):
     242          """
     243          Create a new SSH session over an existing socket, or socket-like
     244          object.  This only creates the Transport object; it doesn't begin the
     245          SSH session yet.  Use L{connect} or L{start_client} to begin a client
     246          session, or L{start_server} to begin a server session.
     247
     248          If the object is not actually a socket, it must have the following
     249          methods:
     250              - C{send(str)}: Writes from 1 to C{len(str)} bytes, and
     251                returns an int representing the number of bytes written.  Returns
     252                0 or raises C{EOFError} if the stream has been closed.
     253              - C{recv(int)}: Reads from 1 to C{int} bytes and returns them as a
     254                string.  Returns 0 or raises C{EOFError} if the stream has been
     255                closed.
     256              - C{close()}: Closes the socket.
     257              - C{settimeout(n)}: Sets a (float) timeout on I/O operations.
     258
     259          For ease of use, you may also pass in an address (as a tuple) or a host
     260          string as the C{sock} argument.  (A host string is a hostname with an
     261          optional port (separated by C{":"}) which will be converted into a
     262          tuple of C{(hostname, port)}.)  A socket will be connected to this
     263          address and used for communication.  Exceptions from the C{socket} call
     264          may be thrown in this case.
     265
     266          @param sock: a socket or socket-like object to create the session over.
     267          @type sock: socket
     268          """
     269          if type(sock) is str:
     270              # convert "host:port" into (host, port)
     271              hl = sock.split(':', 1)
     272              if len(hl) == 1:
     273                  sock = (hl[0], 22)
     274              else:
     275                  sock = (hl[0], int(hl[1]))
     276          if type(sock) is tuple:
     277              # connect to the given (host, port)
     278              hostname, port = sock
     279              sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     280              sock.connect((hostname, port))
     281          # okay, normal socket-ish flow here...
     282          threading.Thread.__init__(self)
     283          self.randpool = randpool
     284          self.sock = sock
     285          # Python < 2.3 doesn't have the settimeout method - RogerB
     286          try:
     287              # we set the timeout so we can check self.active periodically to
     288              # see if we should bail.  socket.timeout exception is never
     289              # propagated.
     290              self.sock.settimeout(0.1)
     291          except AttributeError:
     292              pass
     293
     294          # negotiated crypto parameters
     295          self.packetizer = Packetizer(sock)
     296          self.local_version = 'SSH-' + self._PROTO_ID + '-' + self._CLIENT_ID
     297          self.remote_version = ''
     298          self.local_cipher = self.remote_cipher = ''
     299          self.local_kex_init = self.remote_kex_init = None
     300          self.local_mac = self.remote_mac = None
     301          self.local_compression = self.remote_compression = None
     302          self.session_id = None
     303          self.host_key_type = None
     304          self.host_key = None
     305
     306          # state used during negotiation
     307          self.kex_engine = None
     308          self.H = None
     309          self.K = None
     310
     311          self.active = False
     312          self.initial_kex_done = False
     313          self.in_kex = False
     314          self.authenticated = False
     315          self._expected_packet = tuple()
     316          self.lock = threading.Lock()    # synchronization (always higher level than write_lock)
     317
     318          # tracking open channels
     319          self._channels = ChannelMap()
     320          self.channel_events = { }       # (id -> Event)
     321          self.channels_seen = { }        # (id -> True)
     322          self._channel_counter = 1
     323          self.window_size = 65536
     324          self.max_packet_size = 34816
     325          self._x11_handler = None
     326          self._tcp_handler = None
     327
     328          self.saved_exception = None
     329          self.clear_to_send = threading.Event()
     330          self.clear_to_send_lock = threading.Lock()
     331          self.log_name = 'paramiko.transport'
     332          self.logger = util.get_logger(self.log_name)
     333          self.packetizer.set_log(self.logger)
     334          self.auth_handler = None
     335          self.global_response = None     # response Message from an arbitrary global request
     336          self.completion_event = None    # user-defined event callbacks
     337          self.banner_timeout = 15        # how long (seconds) to wait for the SSH banner
     338
     339          # server mode:
     340          self.server_mode = False
     341          self.server_object = None
     342          self.server_key_dict = { }
     343          self.server_accepts = [ ]
     344          self.server_accept_cv = threading.Condition(self.lock)
     345          self.subsystem_table = { }
     346
     347 -    def __repr__(self):
     348          """
     349          Returns a string representation of this object, for debugging.
     350
     351          @rtype: str
     352          """
     353          out = '<paramiko.Transport at %s' % hex(long(id(self)) & 0xffffffffL)
     354          if not self.active:
     355              out += ' (unconnected)'
     356          else:
     357              if self.local_cipher != '':
     358                  out += ' (cipher %s, %d bits)' % (self.local_cipher,
     359                                                    self._cipher_info[self.local_cipher]['key-size'] * 8)
     360              if self.is_authenticated():
     361                  out += ' (active; %d open channel(s))' % len(self._channels)
     362              elif self.initial_kex_done:
     363                  out += ' (connected; awaiting auth)'
     364              else:
     365                  out += ' (connecting)'
     366          out += '>'
     367          return out
     368
     369 -    def atfork(self):
     370          """
     371          Terminate this Transport without closing the session.  On posix
     372          systems, if a Transport is open during process forking, both parent
     373          and child will share the underlying socket, but only one process can
     374          use the connection (without corrupting the session).  Use this method
     375          to clean up a Transport object without disrupting the other process.
     376
     377          @since: 1.5.3
     378          """
     379          self.sock.close()
     380          self.close()
     381
     382 -    def get_security_options(self):
     383          """
     384          Return a L{SecurityOptions} object which can be used to tweak the
     385          encryption algorithms this transport will permit, and the order of
     386          preference for them.
     387
     388          @return: an object that can be used to change the preferred algorithms
     389              for encryption, digest (hash), public key, and key exchange.
     390          @rtype: L{SecurityOptions}
     391          """
     392          return SecurityOptions(self)
     393
     394 -    def start_client(self, event=None):
     395          """
     396          Negotiate a new SSH2 session as a client.  This is the first step after
     397          creating a new L{Transport}.  A separate thread is created for protocol
     398          negotiation.
     399
     400          If an event is passed in, this method returns immediately.  When
     401          negotiation is done (successful or not), the given C{Event} will
     402          be triggered.  On failure, L{is_active} will return C{False}.
     403
     404          (Since 1.4) If C{event} is C{None}, this method will not return until
     405          negotation is done.  On success, the method returns normally.
     406          Otherwise an SSHException is raised.
     407
     408          After a successful negotiation, you will usually want to authenticate,
     409          calling L{auth_password <Transport.auth_password>} or
     410          L{auth_publickey <Transport.auth_publickey>}.
     411
     412          @note: L{connect} is a simpler method for connecting as a client.
     413
     414          @note: After calling this method (or L{start_server} or L{connect}),
     415              you should no longer directly read from or write to the original
     416              socket object.
     417
     418          @param event: an event to trigger when negotiation is complete
     419              (optional)
     420          @type event: threading.Event
     421
     422          @raise SSHException: if negotiation fails (and no C{event} was passed
     423              in)
     424          """
     425          self.active = True
     426          if event is not None:
     427              # async, return immediately and let the app poll for completion
     428              self.completion_event = event
     429              self.start()
     430              return
     431
     432          # synchronous, wait for a result
     433          self.completion_event = event = threading.Event()
     434          self.start()
     435          while True:
     436              event.wait(0.1)
     437              if not self.active:
     438                  e = self.get_exception()
     439                  if e is not None:
     440                      raise e
     441                  raise SSHException('Negotiation failed.')
     442              if event.isSet():
     443                  break
     444
     445 -    def start_server(self, event=None, server=None):
     446          """
     447          Negotiate a new SSH2 session as a server.  This is the first step after
     448          creating a new L{Transport} and setting up your server host key(s).  A
     449          separate thread is created for protocol negotiation.
     450
     451          If an event is passed in, this method returns immediately.  When
     452          negotiation is done (successful or not), the given C{Event} will
     453          be triggered.  On failure, L{is_active} will return C{False}.
     454
     455          (Since 1.4) If C{event} is C{None}, this method will not return until
     456          negotation is done.  On success, the method returns normally.
     457          Otherwise an SSHException is raised.
     458
     459          After a successful negotiation, the client will need to authenticate.
     460          Override the methods
     461          L{get_allowed_auths <ServerInterface.get_allowed_auths>},
     462          L{check_auth_none <ServerInterface.check_auth_none>},
     463          L{check_auth_password <ServerInterface.check_auth_password>}, and
     464          L{check_auth_publickey <ServerInterface.check_auth_publickey>} in the
     465          given C{server} object to control the authentication process.
     466
     467          After a successful authentication, the client should request to open
     468          a channel.  Override
     469          L{check_channel_request <ServerInterface.check_channel_request>} in the
     470          given C{server} object to allow channels to be opened.
     471
     472          @note: After calling this method (or L{start_client} or L{connect}),
     473              you should no longer directly read from or write to the original
     474              socket object.
     475
     476          @param event: an event to trigger when negotiation is complete.
     477          @type event: threading.Event
     478          @param server: an object used to perform authentication and create
     479              L{Channel}s.
     480          @type server: L{server.ServerInterface}
     481
     482          @raise SSHException: if negotiation fails (and no C{event} was passed
     483              in)
     484          """
     485          if server is None:
     486              server = ServerInterface()
     487          self.server_mode = True
     488          self.server_object = server
     489          self.active = True
     490          if event is not None:
     491              # async, return immediately and let the app poll for completion
     492              self.completion_event = event
     493              self.start()
     494              return
     495
     496          # synchronous, wait for a result
     497          self.completion_event = event = threading.Event()
     498          self.start()
     499          while True:
     500              event.wait(0.1)
     501              if not self.active:
     502                  e = self.get_exception()
     503                  if e is not None:
     504                      raise e
     505                  raise SSHException('Negotiation failed.')
     506              if event.isSet():
     507                  break
     508
     509 -    def add_server_key(self, key):
     510          """
     511          Add a host key to the list of keys used for server mode.  When behaving
     512          as a server, the host key is used to sign certain packets during the
     513          SSH2 negotiation, so that the client can trust that we are who we say
     514          we are.  Because this is used for signing, the key must contain private
     515          key info, not just the public half.  Only one key of each type (RSA or
     516          DSS) is kept.
     517
     518          @param key: the host key to add, usually an L{RSAKey <rsakey.RSAKey>} or
     519              L{DSSKey <dsskey.DSSKey>}.
     520          @type key: L{PKey <pkey.PKey>}
     521          """
     522          self.server_key_dict[key.get_name()] = key
     523
     524 -    def get_server_key(self):
     525          """
     526          Return the active host key, in server mode.  After negotiating with the
     527          client, this method will return the negotiated host key.  If only one
     528          type of host key was set with L{add_server_key}, that's the only key
     529          that will ever be returned.  But in cases where you have set more than
     530          one type of host key (for example, an RSA key and a DSS key), the key
     531          type will be negotiated by the client, and this method will return the
     532          key of the type agreed on.  If the host key has not been negotiated
     533          yet, C{None} is returned.  In client mode, the behavior is undefined.
     534
     535          @return: host key of the type negotiated by the client, or C{None}.
     536          @rtype: L{PKey <pkey.PKey>}
     537          """
     538          try:
     539              return self.server_key_dict[self.host_key_type]
     540          except KeyError:
     541              pass
     542          return None
     543
     544 -    def load_server_moduli(filename=None):
     545          """
     546          I{(optional)}
     547          Load a file of prime moduli for use in doing group-exchange key
     548          negotiation in server mode.  It's a rather obscure option and can be
     549          safely ignored.
     550
     551          In server mode, the remote client may request "group-exchange" key
     552          negotiation, which asks the server to send a random prime number that
     553          fits certain criteria.  These primes are pretty difficult to compute,
     554          so they can't be generated on demand.  But many systems contain a file
     555          of suitable primes (usually named something like C{/etc/ssh/moduli}).
     556          If you call C{load_server_moduli} and it returns C{True}, then this
     557          file of primes has been loaded and we will support "group-exchange" in
     558          server mode.  Otherwise server mode will just claim that it doesn't
     559          support that method of key negotiation.
     560
     561          @param filename: optional path to the moduli file, if you happen to
     562              know that it's not in a standard location.
     563          @type filename: str
     564          @return: True if a moduli file was successfully loaded; False
     565              otherwise.
     566          @rtype: bool
     567
     568          @note: This has no effect when used in client mode.
     569          """
     570          Transport._modulus_pack = ModulusPack(randpool)
     571          # places to look for the openssh "moduli" file
     572          file_list = [ '/etc/ssh/moduli', '/usr/local/etc/moduli' ]
     573          if filename is not None:
     574              file_list.insert(0, filename)
     575          for fn in file_list:
     576              try:
     577                  Transport._modulus_pack.read_file(fn)
     578                  return True
     579              except IOError:
     580                  pass
     581          # none succeeded
     582          Transport._modulus_pack = None
     583          return False
     584      load_server_moduli = staticmethod(load_server_moduli)
     585
     586 -    def close(self):
     587          """
     588          Close this session, and any open channels that are tied to it.
     589          """
     590          if not self.active:
     591              return
     592          self.active = False
     593          self.packetizer.close()
     594          self.join()
     595          for chan in self._channels.values():
     596              chan._unlink()
     597
     598 -    def get_remote_server_key(self):
     599          """
     600          Return the host key of the server (in client mode).
     601
     602          @note: Previously this call returned a tuple of (key type, key string).
     603              You can get the same effect by calling
     604              L{PKey.get_name <pkey.PKey.get_name>} for the key type, and
     605              C{str(key)} for the key string.
     606
     607          @raise SSHException: if no session is currently active.
     608
     609          @return: public key of the remote server
     610          @rtype: L{PKey <pkey.PKey>}
     611          """
     612          if (not self.active) or (not self.initial_kex_done):
     613              raise SSHException('No existing session')
     614          return self.host_key
     615
     616 -    def is_active(self):
     617          """
     618          Return true if this session is active (open).
     619
     620          @return: True if the session is still active (open); False if the
     621              session is closed
     622          @rtype: bool
     623          """
     624          return self.active
     625
     626 -    def open_session(self):
     627          """
     628          Request a new channel to the server, of type C{"session"}.  This
     629          is just an alias for C{open_channel('session')}.
     630
     631          @return: a new L{Channel}
     632          @rtype: L{Channel}
     633
     634          @raise SSHException: if the request is rejected or the session ends
     635              prematurely
     636          """
     637          return self.open_channel('session')
     638
     639 -    def open_x11_channel(self, src_addr=None):
     640          """
     641          Request a new channel to the client, of type C{"x11"}.  This
     642          is just an alias for C{open_channel('x11', src_addr=src_addr)}.
     643
     644          @param src_addr: the source address of the x11 server (port is the
     645              x11 port, ie. 6010)
     646          @type src_addr: (str, int)
     647          @return: a new L{Channel}
     648          @rtype: L{Channel}
     649
     650          @raise SSHException: if the request is rejected or the session ends
     651              prematurely
     652          """
     653          return self.open_channel('x11', src_addr=src_addr)
     654
     655 -    def open_forwarded_tcpip_channel(self, (src_addr, src_port), (dest_addr, dest_port)):
     656          """
     657          Request a new channel back to the client, of type C{"forwarded-tcpip"}.
     658          This is used after a client has requested port forwarding, for sending
     659          incoming connections back to the client.
     660
     661          @param src_addr: originator's address
     662          @param src_port: originator's port
     663          @param dest_addr: local (server) connected address
     664          @param dest_port: local (server) connected port
     665          """
     666          return self.open_channel('forwarded-tcpip', (dest_addr, dest_port), (src_addr, src_port))
     667
     668 -    def open_channel(self, kind, dest_addr=None, src_addr=None):
     669          """
     670          Request a new channel to the server.  L{Channel}s are socket-like
     671          objects used for the actual transfer of data across the session.
     672          You may only request a channel after negotiating encryption (using
     673          L{connect} or L{start_client}) and authenticating.
     674
     675          @param kind: the kind of channel requested (usually C{"session"},
     676              C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"})
     677          @type kind: str
     678          @param dest_addr: the destination address of this port forwarding,
     679              if C{kind} is C{"forwarded-tcpip"} or C{"direct-tcpip"} (ignored
     680              for other channel types)
     681          @type dest_addr: (str, int)
     682          @param src_addr: the source address of this port forwarding, if
     683              C{kind} is C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"}
     684          @type src_addr: (str, int)
     685          @return: a new L{Channel} on success
     686          @rtype: L{Channel}
     687
     688          @raise SSHException: if the request is rejected or the session ends
     689              prematurely
     690          """
     691          chan = None
     692          if not self.active:
     693              # don't bother trying to allocate a channel
     694              return None
     695          self.lock.acquire()
     696          try:
     697              chanid = self._next_channel()
     698              m = Message()
     699              m.add_byte(chr(MSG_CHANNEL_OPEN))
     700              m.add_string(kind)
     701              m.add_int(chanid)
     702              m.add_int(self.window_size)
     703              m.add_int(self.max_packet_size)
     704              if (kind == 'forwarded-tcpip') or (kind == 'direct-tcpip'):
     705                  m.add_string(dest_addr[0])
     706                  m.add_int(dest_addr[1])
     707                  m.add_string(src_addr[0])
     708                  m.add_int(src_addr[1])
     709              elif kind == 'x11':
     710                  m.add_string(src_addr[0])
     711                  m.add_int(src_addr[1])
     712              chan = Channel(chanid)
     713              self._channels.put(chanid, chan)
     714              self.channel_events[chanid] = event = threading.Event()
     715              self.channels_seen[chanid] = True
     716              chan._set_transport(self)
     717              chan._set_window(self.window_size, self.max_packet_size)
     718          finally:
     719              self.lock.release()
     720          self._send_user_message(m)
     721          while True:
     722              event.wait(0.1);
     723              if not self.active:
     724                  e = self.get_exception()
     725                  if e is None:
     726                      e = SSHException('Unable to open channel.')
     727                  raise e
     728              if event.isSet():
     729                  break
     730          chan = self._channels.get(chanid)
     731          if chan is not None:
     732              return chan
     733          e = self.get_exception()
     734          if e is None:
     735              e = SSHException('Unable to open channel.')
     736          raise e
     737
     738 -    def request_port_forward(self, address, port, handler=None):
     739          """
     740          Ask the server to forward TCP connections from a listening port on
     741          the server, across this SSH session.
     742
     743          If a handler is given, that handler is called from a different thread
     744          whenever a forwarded connection arrives.  The handler parameters are::
     745
     746              handler(channel, (origin_addr, origin_port), (server_addr, server_port))
     747
     748          where C{server_addr} and C{server_port} are the address and port that
     749          the server was listening on.
     750
     751          If no handler is set, the default behavior is to send new incoming
     752          forwarded connections into the accept queue, to be picked up via
     753          L{accept}.
     754
     755          @param address: the address to bind when forwarding
     756          @type address: str
     757          @param port: the port to forward, or 0 to ask the server to allocate
     758              any port
     759          @type port: int
     760          @param handler: optional handler for incoming forwarded connections
     761          @type handler: function(Channel, (str, int), (str, int))
     762          @return: the port # allocated by the server
     763          @rtype: int
     764
     765          @raise SSHException: if the server refused the TCP forward request
     766          """
     767          if not self.active:
     768              raise SSHException('SSH session not active')
     769          address = str(address)
     770          port = int(port)
     771          response = self.global_request('tcpip-forward', (address, port), wait=True)
     772          if response is None:
     773              raise SSHException('TCP forwarding request denied')
     774          if port == 0:
     775              port = response.get_int()
     776          if handler is None:
     777              def default_handler(channel, (src_addr, src_port), (dest_addr, dest_port)):
     778                  self._queue_incoming_channel(channel)
     779              handler = default_handler
     780          self._tcp_handler = handler
     781          return port
     782
     783 -    def cancel_port_forward(self, address, port):
     784          """
     785          Ask the server to cancel a previous port-forwarding request.  No more
     786          connections to the given address & port will be forwarded across this
     787          ssh connection.
     788
     789          @param address: the address to stop forwarding
     790          @type address: str
     791          @param port: the port to stop forwarding
     792          @type port: int
     793          """
     794          if not self.active:
     795              return
     796          self._tcp_handler = None
     797          self.global_request('cancel-tcpip-forward', (address, port), wait=True)
     798
     799 -    def open_sftp_client(self):
     800          """
     801          Create an SFTP client channel from an open transport.  On success,
     802          an SFTP session will be opened with the remote host, and a new
     803          SFTPClient object will be returned.
     804
     805          @return: a new L{SFTPClient} object, referring to an sftp session
     806              (channel) across this transport
     807          @rtype: L{SFTPClient}
     808          """
     809          return SFTPClient.from_transport(self)
     810
     811 -    def send_ignore(self, bytes=None):
     812          """
     813          Send a junk packet across the encrypted link.  This is sometimes used
     814          to add "noise" to a connection to confuse would-be attackers.  It can
     815          also be used as a keep-alive for long lived connections traversing
     816          firewalls.
     817
     818          @param bytes: the number of random bytes to send in the payload of the
     819              ignored packet -- defaults to a random number from 10 to 41.
     820          @type bytes: int
     821          """
     822          m = Message()
     823          m.add_byte(chr(MSG_IGNORE))
     824          randpool.stir()
     825          if bytes is None:
     826              bytes = (ord(randpool.get_bytes(1)) % 32) + 10
     827          m.add_bytes(randpool.get_bytes(bytes))
     828          self._send_user_message(m)
     829
     830 -    def renegotiate_keys(self):
     831          """
     832          Force this session to switch to new keys.  Normally this is done
     833          automatically after the session hits a certain number of packets or
     834          bytes sent or received, but this method gives you the option of forcing
     835          new keys whenever you want.  Negotiating new keys causes a pause in
     836          traffic both ways as the two sides swap keys and do computations.  This
     837          method returns when the session has switched to new keys.
     838
     839          @raise SSHException: if the key renegotiation failed (which causes the
     840              session to end)
     841          """
     842          self.completion_event = threading.Event()
     843          self._send_kex_init()
     844          while True:
     845              self.completion_event.wait(0.1)
     846              if not self.active:
     847                  e = self.get_exception()
     848                  if e is not None:
     849                      raise e
     850                  raise SSHException('Negotiation failed.')
     851              if self.completion_event.isSet():
     852                  break
     853          return
     854
     855 -    def set_keepalive(self, interval):
     856          """
     857          Turn on/off keepalive packets (default is off).  If this is set, after
     858          C{interval} seconds without sending any data over the connection, a
     859          "keepalive" packet will be sent (and ignored by the remote host).  This
     860          can be useful to keep connections alive over a NAT, for example.
     861
     862          @param interval: seconds to wait before sending a keepalive packet (or
     863              0 to disable keepalives).
     864          @type interval: int
     865          """
     866          self.packetizer.set_keepalive(interval,
     867              lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False))
     868
     869 -    def global_request(self, kind, data=None, wait=True):
     870          """
     871          Make a global request to the remote host.  These are normally
     872          extensions to the SSH2 protocol.
     873
     874          @param kind: name of the request.
     875          @type kind: str
     876          @param data: an optional tuple containing additional data to attach
     877              to the request.
     878          @type data: tuple
     879          @param wait: C{True} if this method should not return until a response
     880              is received; C{False} otherwise.
     881          @type wait: bool
     882          @return: a L{Message} containing possible additional data if the
     883              request was successful (or an empty L{Message} if C{wait} was
     884              C{False}); C{None} if the request was denied.
     885          @rtype: L{Message}
     886          """
     887          if wait:
     888              self.completion_event = threading.Event()
     889          m = Message()
     890          m.add_byte(chr(MSG_GLOBAL_REQUEST))
     891          m.add_string(kind)
     892          m.add_boolean(wait)
     893          if data is not None:
     894              m.add(*data)
     895          self._log(DEBUG, 'Sending global request "%s"' % kind)
     896          self._send_user_message(m)
     897          if not wait:
     898              return None
     899          while True:
     900              self.completion_event.wait(0.1)
     901              if not self.active:
     902                  return None
     903              if self.completion_event.isSet():
     904                  break
     905          return self.global_response
     906
     907 -    def accept(self, timeout=None):
     908          """
     909          Return the next channel opened by the client over this transport, in
     910          server mode.  If no channel is opened before the given timeout, C{None}
     911          is returned.
     912
     913          @param timeout: seconds to wait for a channel, or C{None} to wait
     914              forever
     915          @type timeout: int
     916          @return: a new Channel opened by the client
     917          @rtype: L{Channel}
     918          """
     919          self.lock.acquire()
     920          try:
     921              if len(self.server_accepts) > 0:
     922                  chan = self.server_accepts.pop(0)
     923              else:
     924                  self.server_accept_cv.wait(timeout)
     925                  if len(self.server_accepts) > 0:
     926                      chan = self.server_accepts.pop(0)
     927                  else:
     928                      # timeout
     929                      chan = None
     930          finally:
     931              self.lock.release()
     932          return chan
     933
     934 -    def connect(self, hostkey=None, username='', password=None, pkey=None):
     935          """
     936          Negotiate an SSH2 session, and optionally verify the server's host key
     937          and authenticate using a password or private key.  This is a shortcut
     938          for L{start_client}, L{get_remote_server_key}, and
     939          L{Transport.auth_password} or L{Transport.auth_publickey}.  Use those
     940          methods if you want more control.
     941
     942          You can use this method immediately after creating a Transport to
     943          negotiate encryption with a server.  If it fails, an exception will be
     944          thrown.  On success, the method will return cleanly, and an encrypted
     945          session exists.  You may immediately call L{open_channel} or
     946          L{open_session} to get a L{Channel} object, which is used for data
     947          transfer.
     948
     949          @note: If you fail to supply a password or private key, this method may
     950          succeed, but a subsequent L{open_channel} or L{open_session} call may
     951          fail because you haven't authenticated yet.
     952
     953          @param hostkey: the host key expected from the server, or C{None} if
     954              you don't want to do host key verification.
     955          @type hostkey: L{PKey<pkey.PKey>}
     956          @param username: the username to authenticate as.
     957          @type username: str
     958          @param password: a password to use for authentication, if you want to
     959              use password authentication; otherwise C{None}.
     960          @type password: str
     961          @param pkey: a private key to use for authentication, if you want to
     962              use private key authentication; otherwise C{None}.
     963          @type pkey: L{PKey<pkey.PKey>}
     964
     965          @raise SSHException: if the SSH2 negotiation fails, the host key
     966              supplied by the server is incorrect, or authentication fails.
     967          """
     968          if hostkey is not None:
     969              self._preferred_keys = [ hostkey.get_name() ]
     970
     971          self.start_client()
     972
     973          # check host key if we were given one
     974          if (hostkey is not None):
     975              key = self.get_remote_server_key()
     976              if (key.get_name() != hostkey.get_name()) or (str(key) != str(hostkey)):
     977                  self._log(DEBUG, 'Bad host key from server')
     978                  self._log(DEBUG, 'Expected: %s: %s' % (hostkey.get_name(), repr(str(hostkey))))
     979                  self._log(DEBUG, 'Got     : %s: %s' % (key.get_name(), repr(str(key))))
     980                  raise SSHException('Bad host key from server')
     981              self._log(DEBUG, 'Host key verified (%s)' % hostkey.get_name())
     982
     983          if (pkey is not None) or (password is not None):
     984              if password is not None:
     985                  self._log(DEBUG, 'Attempting password auth...')
     986                  self.auth_password(username, password)
     987              else:
     988                  self._log(DEBUG, 'Attempting public-key auth...')
     989                  self.auth_publickey(username, pkey)
     990
     991          return
     992
     993 -    def get_exception(self):
     994          """
     995          Return any exception that happened during the last server request.
     996          This can be used to fetch more specific error information after using
     997          calls like L{start_client}.  The exception (if any) is cleared after
     998          this call.
     999
    1000          @return: an exception, or C{None} if there is no stored exception.
    1001          @rtype: Exception
    1002
    1003          @since: 1.1
    1004          """
    1005          self.lock.acquire()
    1006          try:
    1007              e = self.saved_exception
    1008              self.saved_exception = None
    1009              return e
    1010          finally:
    1011              self.lock.release()
    1012
    1013 -    def set_subsystem_handler(self, name, handler, *larg, **kwarg):
    1014          """
    1015          Set the handler class for a subsystem in server mode.  If a request
    1016          for this subsystem is made on an open ssh channel later, this handler
    1017          will be constructed and called -- see L{SubsystemHandler} for more
    1018          detailed documentation.
    1019
    1020          Any extra parameters (including keyword arguments) are saved and
    1021          passed to the L{SubsystemHandler} constructor later.
    1022
    1023          @param name: name of the subsystem.
    1024          @type name: str
    1025          @param handler: subclass of L{SubsystemHandler} that handles this
    1026              subsystem.
    1027          @type handler: class
    1028          """
    1029          try:
    1030              self.lock.acquire()
    1031              self.subsystem_table[name] = (handler, larg, kwarg)
    1032          finally:
    1033              self.lock.release()
    1034
    1035 -    def is_authenticated(self):
    1036          """
    1037          Return true if this session is active and authenticated.
    1038
    1039          @return: True if the session is still open and has been authenticated
    1040              successfully; False if authentication failed and/or the session is
    1041              closed.
    1042          @rtype: bool
    1043          """
    1044          return self.active and (self.auth_handler is not None) and self.auth_handler.is_authenticated()
    1045
    1046 -    def get_username(self):
    1047          """
    1048          Return the username this connection is authenticated for.  If the
    1049          session is not authenticated (or authentication failed), this method
    1050          returns C{None}.
    1051
    1052          @return: username that was authenticated, or C{None}.
    1053          @rtype: string
    1054          """
    1055          if not self.active or (self.auth_handler is None):
    1056              return None
    1057          return self.auth_handler.get_username()
    1058
    1059 -    def auth_none(self, username):
    1060          """
    1061          Try to authenticate to the server using no authentication at all.
    1062          This will almost always fail.  It may be useful for determining the
    1063          list of authentication types supported by the server, by catching the
    1064          L{BadAuthenticationType} exception raised.
    1065
    1066          @param username: the username to authenticate as
    1067          @type username: string
    1068          @return: list of auth types permissible for the next stage of
    1069              authentication (normally empty)
    1070          @rtype: list
    1071
    1072          @raise BadAuthenticationType: if "none" authentication isn't allowed
    1073              by the server for this user
    1074          @raise SSHException: if the authentication failed due to a network
    1075              error
    1076
    1077          @since: 1.5
    1078          """
    1079          if (not self.active) or (not self.initial_kex_done):
    1080              raise SSHException('No existing session')
    1081          my_event = threading.Event()
    1082          self.auth_handler = AuthHandler(self)
    1083          self.auth_handler.auth_none(username, my_event)
    1084          return self.auth_handler.wait_for_response(my_event)
    1085
    1086 -    def auth_password(self, username, password, event=None, fallback=True):
    1087          """
    1088          Authenticate to the server using a password.  The username and password
    1089          are sent over an encrypted link.
    1090
    1091          If an C{event} is passed in, this method will return immediately, and
    1092          the event will be triggered once authentication succeeds or fails.  On
    1093          success, L{is_authenticated} will return C{True}.  On failure, you may
    1094          use L{get_exception} to get more detailed error information.
    1095
    1096          Since 1.1, if no event is passed, this method will block until the
    1097          authentication succeeds or fails.  On failure, an exception is raised.
    1098          Otherwise, the method simply returns.
    1099
    1100          Since 1.5, if no event is passed and C{fallback} is C{True} (the
    1101          default), if the server doesn't support plain password authentication
    1102          but does support so-called "keyboard-interactive" mode, an attempt
    1103          will be made to authenticate using this interactive mode.  If it fails,
    1104          the normal exception will be thrown as if the attempt had never been
    1105          made.  This is useful for some recent Gentoo and Debian distributions,
    1106          which turn off plain password authentication in a misguided belief
    1107          that interactive authentication is "more secure".  (It's not.)
    1108
    1109          If the server requires multi-step authentication (which is very rare),
    1110          this method will return a list of auth types permissible for the next
    1111          step.  Otherwise, in the normal case, an empty list is returned.
    1112
    1113          @param username: the username to authenticate as
    1114          @type username: str
    1115          @param password: the password to authenticate with
    1116          @type password: str or unicode
    1117          @param event: an event to trigger when the authentication attempt is
    1118              complete (whether it was successful or not)
    1119          @type event: threading.Event
    1120          @param fallback: C{True} if an attempt at an automated "interactive"
    1121              password auth should be made if the server doesn't support normal
    1122              password auth
    1123          @type fallback: bool
    1124          @return: list of auth types permissible for the next stage of
    1125              authentication (normally empty)
    1126          @rtype: list
    1127
    1128          @raise BadAuthenticationType: if password authentication isn't
    1129              allowed by the server for this user (and no event was passed in)
    1130          @raise AuthenticationException: if the authentication failed (and no
    1131              event was passed in)
    1132          @raise SSHException: if there was a network error
    1133          """
    1134          if (not self.active) or (not self.initial_kex_done):
    1135              # we should never try to send the password unless we're on a secure link
    1136              raise SSHException('No existing session')
    1137          if event is None:
    1138              my_event = threading.Event()
    1139          else:
    1140              my_event = event
    1141          self.auth_handler = AuthHandler(self)
    1142          self.auth_handler.auth_password(username, password, my_event)
    1143          if event is not None:
    1144              # caller wants to wait for event themselves
    1145              return []
    1146          try:
    1147              return self.auth_handler.wait_for_response(my_event)
    1148          except BadAuthenticationType, x:
    1149              # if password auth isn't allowed, but keyboard-interactive *is*, try to fudge it
    1150              if not fallback or ('keyboard-interactive' not in x.allowed_types):
    1151                  raise
    1152              try:
    1153                  def handler(title, instructions, fields):
    1154                      if len(fields) > 1:
    1155                          raise SSHException('Fallback authentication failed.')
    1156                      if len(fields) == 0:
    1157                          # for some reason, at least on os x, a 2nd request will
    1158                          # be made with zero fields requested.  maybe it's just
    1159                          # to try to fake out automated scripting of the exact
    1160                          # type we're doing here.  *shrug* :)
    1161                          return []
    1162                      return [ password ]
    1163                  return self.auth_interactive(username, handler)
    1164              except SSHException, ignored:
    1165                  # attempt failed; just raise the original exception
    1166                  raise x
    1167          return None
    1168
    1169 -    def auth_publickey(self, username, key, event=None):
    1170          """
    1171          Authenticate to the server using a private key.  The key is used to
    1172          sign data from the server, so it must include the private part.
    1173
    1174          If an C{event} is passed in, this method will return immediately, and
    1175          the event will be triggered once authentication succeeds or fails.  On
    1176          success, L{is_authenticated} will return C{True}.  On failure, you may
    1177          use L{get_exception} to get more detailed error information.
    1178
    1179          Since 1.1, if no event is passed, this method will block until the
    1180          authentication succeeds or fails.  On failure, an exception is raised.
    1181          Otherwise, the method simply returns.
    1182
    1183          If the server requires multi-step authentication (which is very rare),
    1184          this method will return a list of auth types permissible for the next
    1185          step.  Otherwise, in the normal case, an empty list is returned.
    1186
    1187          @param username: the username to authenticate as
    1188          @type username: string
    1189          @param key: the private key to authenticate with
    1190          @type key: L{PKey <pkey.PKey>}
    1191          @param event: an event to trigger when the authentication attempt is
    1192              complete (whether it was successful or not)
    1193          @type event: threading.Event
    1194          @return: list of auth types permissible for the next stage of
    1195              authentication (normally empty)
    1196          @rtype: list
    1197
    1198          @raise BadAuthenticationType: if public-key authentication isn't
    1199              allowed by the server for this user (and no event was passed in)
    1200          @raise AuthenticationException: if the authentication failed (and no
    1201              event was passed in)
    1202          @raise SSHException: if there was a network error
    1203          """
    1204          if (not self.active) or (not self.initial_kex_done):
    1205              # we should never try to authenticate unless we're on a secure link
    1206              raise SSHException('No existing session')
    1207          if event is None:
    1208              my_event = threading.Event()
    1209          else:
    1210              my_event = event
    1211          self.auth_handler = AuthHandler(self)
    1212          self.auth_handler.auth_publickey(username, key, my_event)
    1213          if event is not None:
    1214              # caller wants to wait for event themselves
    1215              return []
    1216          return self.auth_handler.wait_for_response(my_event)
    1217
    1218 -    def auth_interactive(self, username, handler, submethods=''):
    1219          """
    1220          Authenticate to the server interactively.  A handler is used to answer
    1221          arbitrary questions from the server.  On many servers, this is just a
    1222          dumb wrapper around PAM.
    1223
    1224          This method will block until the authentication succeeds or fails,
    1225          peroidically calling the handler asynchronously to get answers to
    1226          authentication questions.  The handler may be called more than once
    1227          if the server continues to ask questions.
    1228
    1229          The handler is expected to be a callable that will handle calls of the
    1230          form: C{handler(title, instructions, prompt_list)}.  The C{title} is
    1231          meant to be a dialog-window title, and the C{instructions} are user
    1232          instructions (both are strings).  C{prompt_list} will be a list of
    1233          prompts, each prompt being a tuple of C{(str, bool)}.  The string is
    1234          the prompt and the boolean indicates whether the user text should be
    1235          echoed.
    1236
    1237          A sample call would thus be:
    1238          C{handler('title', 'instructions', [('Password:', False)])}.
    1239
    1240          The handler should return a list or tuple of answers to the server's
    1241          questions.
    1242
    1243          If the server requires multi-step authentication (which is very rare),
    1244          this method will return a list of auth types permissible for the next
    1245          step.  Otherwise, in the normal case, an empty list is returned.
    1246
    1247          @param username: the username to authenticate as
    1248          @type username: string
    1249          @param handler: a handler for responding to server questions
    1250          @type handler: callable
    1251          @param submethods: a string list of desired submethods (optional)
    1252          @type submethods: str
    1253          @return: list of auth types permissible for the next stage of
    1254              authentication (normally empty).
    1255          @rtype: list
    1256
    1257          @raise BadAuthenticationType: if public-key authentication isn't
    1258              allowed by the server for this user
    1259          @raise AuthenticationException: if the authentication failed
    1260          @raise SSHException: if there was a network error
    1261
    1262          @since: 1.5
    1263          """
    1264          if (not self.active) or (not self.initial_kex_done):
    1265              # we should never try to authenticate unless we're on a secure link
    1266              raise SSHException('No existing session')
    1267          my_event = threading.Event()
    1268          self.auth_handler = AuthHandler(self)
    1269          self.auth_handler.auth_interactive(username, handler, my_event, submethods)
    1270          return self.auth_handler.wait_for_response(my_event)
    1271
    1272 -    def set_log_channel(self, name):
    1273          """
    1274          Set the channel for this transport's logging.  The default is
    1275          C{"paramiko.transport"} but it can be set to anything you want.
    1276          (See the C{logging} module for more info.)  SSH Channels will log
    1277          to a sub-channel of the one specified.
    1278
    1279          @param name: new channel name for logging
    1280          @type name: str
    1281
    1282          @since: 1.1
    1283          """
    1284          self.log_name = name
    1285          self.logger = util.get_logger(name)
    1286          self.packetizer.set_log(self.logger)
    1287
    1288 -    def get_log_channel(self):
    1289          """
    1290          Return the channel name used for this transport's logging.
    1291
    1292          @return: channel name.
    1293          @rtype: str
    1294
    1295          @since: 1.2
    1296          """
    1297          return self.log_name
    1298
    1299 -    def set_hexdump(self, hexdump):
    1300          """
    1301          Turn on/off logging a hex dump of protocol traffic at DEBUG level in
    1302          the logs.  Normally you would want this off (which is the default),
    1303          but if you are debugging something, it may be useful.
    1304
    1305          @param hexdump: C{True} to log protocol traffix (in hex) to the log;
    1306              C{False} otherwise.
    1307          @type hexdump: bool
    1308          """
    1309          self.packetizer.set_hexdump(hexdump)
    1310
    1311 -    def get_hexdump(self):
    1312          """
    1313          Return C{True} if the transport is currently logging hex dumps of
    1314          protocol traffic.
    1315
    1316          @return: C{True} if hex dumps are being logged
    1317          @rtype: bool
    1318
    1319          @since: 1.4
    1320          """
    1321          return self.packetizer.get_hexdump()
    1322
    1323 -    def use_compression(self, compress=True):
    1324          """
    1325          Turn on/off compression.  This will only have an affect before starting
    1326          the transport (ie before calling L{connect}, etc).  By default,
    1327          compression is off since it negatively affects interactive sessions.
    1328
    1329          @param compress: C{True} to ask the remote client/server to compress
    1330              traffic; C{False} to refuse compression
    1331          @type compress: bool
    1332
    1333          @since: 1.5.2
    1334          """
    1335          if compress:
    1336              self._preferred_compression = ( 'zlib@openssh.com', 'zlib', 'none' )
    1337          else:
    1338              self._preferred_compression = ( 'none', )
    1339
    1340 -    def getpeername(self):
    1341          """
    1342          Return the address of the remote side of this Transport, if possible.
    1343          This is effectively a wrapper around C{'getpeername'} on the underlying
    1344          socket.  If the socket-like object has no C{'getpeername'} method,
    1345          then C{("unknown", 0)} is returned.
    1346
    1347          @return: the address if the remote host, if known
    1348          @rtype: tuple(str, int)
    1349          """
    1350          gp = getattr(self.sock, 'getpeername', None)
    1351          if gp is None:
    1352              return ('unknown', 0)
    1353          return gp()
    1354
    1355 -    def stop_thread(self):
    1356          self.active = False
    1357          self.packetizer.close()
    1358
    1359
    1360      ###  internals...
    1361
    1362
    1363 -    def _log(self, level, msg, *args):
    1364          if issubclass(type(msg), list):
    1365              for m in msg:
    1366                  self.logger.log(level, m)
    1367          else:
    1368              self.logger.log(level, msg, *args)
    1369
    1370 -    def _get_modulus_pack(self):
    1371          "used by KexGex to find primes for group exchange"
    1372          return self._modulus_pack
    1373
    1374 -    def _next_channel(self):
    1375          "you are holding the lock"
    1376          chanid = self._channel_counter
    1377          while self._channels.get(chanid) is not None:
    1378              self._channel_counter = (self._channel_counter + 1) & 0xffffff
    1379              chanid = self._channel_counter
    1380          self._channel_counter = (self._channel_counter + 1) & 0xffffff
    1381          return chanid
    1382
    1383 -    def _unlink_channel(self, chanid):
    1384          "used by a Channel to remove itself from the active channel list"
    1385          self._channels.delete(chanid)
    1386
    1387 -    def _send_message(self, data):
    1388          self.packetizer.send_message(data)
    1389
    1390 -    def _send_user_message(self, data):
    1391          """
    1392          send a message, but block if we're in key negotiation.  this is used
    1393          for user-initiated requests.
    1394          """
    1395          while True:
    1396              self.clear_to_send.wait(0.1)
    1397              if not self.active:
    1398                  self._log(DEBUG, 'Dropping user packet because connection is dead.')
    1399                  return
    1400              self.clear_to_send_lock.acquire()
    1401              if self.clear_to_send.isSet():
    1402                  break
    1403              self.clear_to_send_lock.release()
    1404          try:
    1405              self._send_message(data)
    1406          finally:
    1407              self.clear_to_send_lock.release()
    1408
    1409 -    def _set_K_H(self, k, h):
    1410          "used by a kex object to set the K (root key) and H (exchange hash)"
    1411          self.K = k
    1412          self.H = h
    1413          if self.session_id == None:
    1414              self.session_id = h
    1415
    1416 -    def _expect_packet(self, *ptypes):
    1417          "used by a kex object to register the next packet type it expects to see"
    1418          self._expected_packet = tuple(ptypes)
    1419
    1420 -    def _verify_key(self, host_key, sig):
    1421          key = self._key_info[self.host_key_type](Message(host_key))
    1422          if key is None:
    1423              raise SSHException('Unknown host key type')
    1424          if not key.verify_ssh_sig(self.H, Message(sig)):
    1425              raise SSHException('Signature verification (%s) failed.  Boo.  Robey should debug this.' % self.host_key_type)
    1426          self.host_key = key
    1427
    1428 -    def _compute_key(self, id, nbytes):
    1429          "id is 'A' - 'F' for the various keys used by ssh"
    1430          m = Message()
    1431          m.add_mpint(self.K)
    1432          m.add_bytes(self.H)
    1433          m.add_byte(id)
    1434          m.add_bytes(self.session_id)
    1435          out = sofar = SHA.new(str(m)).digest()
    1436          while len(out) < nbytes:
    1437              m = Message()
    1438              m.add_mpint(self.K)
    1439              m.add_bytes(self.H)
    1440              m.add_bytes(sofar)
    1441              digest = SHA.new(str(m)).digest()
    1442              out += digest
    1443              sofar += digest
    1444          return out[:nbytes]
    1445
    1446 -    def _get_cipher(self, name, key, iv):
    1447          if name not in self._cipher_info:
    1448              raise SSHException('Unknown client cipher ' + name)
    1449          return self._cipher_info[name]['class'].new(key, self._cipher_info[name]['mode'], iv)
    1450
    1451 -    def _set_x11_handler(self, handler):
    1452          # only called if a channel has turned on x11 forwarding
    1453          if handler is None:
    1454              # by default, use the same mechanism as accept()
    1455              def default_handler(channel, (src_addr, src_port)):
    1456                  self._queue_incoming_channel(channel)
    1457              self._x11_handler = default_handler
    1458          else:
    1459              self._x11_handler = handler
    1460
    1461 -    def _queue_incoming_channel(self, channel):
    1462          self.lock.acquire()
    1463          try:
    1464              self.server_accepts.append(channel)
    1465              self.server_accept_cv.notify()
    1466          finally:
    1467              self.lock.release()
    1468
    1469 -    def run(self):
    1470          # (use the exposed "run" method, because if we specify a thread target
    1471          # of a private method, threading.Thread will keep a reference to it
    1472          # indefinitely, creating a GC cycle and not letting Transport ever be
    1473          # GC'd.  it's a bug in Thread.)
    1474
    1475          # active=True occurs before the thread is launched, to avoid a race
    1476          _active_threads.append(self)
    1477          if self.server_mode:
    1478              self._log(DEBUG, 'starting thread (server mode): %s' % hex(long(id(self)) & 0xffffffffL))
    1479          else:
    1480              self._log(DEBUG, 'starting thread (client mode): %s' % hex(long(id(self)) & 0xffffffffL))
    1481          try:
    1482              self.packetizer.write_all(self.local_version + '\r\n')
    1483              self._check_banner()
    1484              self._send_kex_init()
    1485              self._expect_packet(MSG_KEXINIT)
    1486
    1487              while self.active:
    1488                  if self.packetizer.need_rekey() and not self.in_kex:
    1489                      self._send_kex_init()
    1490                  try:
    1491                      ptype, m = self.packetizer.read_message()
    1492                  except NeedRekeyException:
    1493                      continue
    1494                  if ptype == MSG_IGNORE:
    1495                      continue
    1496                  elif ptype == MSG_DISCONNECT:
    1497                      self._parse_disconnect(m)
    1498                      self.active = False
    1499                      self.packetizer.close()
    1500                      break
    1501                  elif ptype == MSG_DEBUG:
    1502                      self._parse_debug(m)
    1503                      continue
    1504                  if len(self._expected_packet) > 0:
    1505                      if ptype not in self._expected_packet:
    1506                          raise SSHException('Expecting packet from %r, got %d' % (self._expected_packet, ptype))
    1507                      self._expected_packet = tuple()
    1508                      if (ptype >= 30) and (ptype <= 39):
    1509                          self.kex_engine.parse_next(ptype, m)
    1510                          continue
    1511
    1512                  if ptype in self._handler_table:
    1513                      self._handler_table[ptype](self, m)
    1514                  elif ptype in self._channel_handler_table:
    1515                      chanid = m.get_int()
    1516                      chan = self._channels.get(chanid)
    1517                      if chan is not None:
    1518                          self._channel_handler_table[ptype](chan, m)
    1519                      elif chanid in self.channels_seen:
    1520                          self._log(DEBUG, 'Ignoring message for dead channel %d' % chanid)
    1521                      else:
    1522                          self._log(ERROR, 'Channel request for unknown channel %d' % chanid)
    1523                          self.active = False
    1524                          self.packetizer.close()
    1525                  elif (self.auth_handler is not None) and (ptype in self.auth_handler._handler_table):
    1526                      self.auth_handler._handler_table[ptype](self.auth_handler, m)
    1527                  else:
    1528                      self._log(WARNING, 'Oops, unhandled type %d' % ptype)
    1529                      msg = Message()
    1530                      msg.add_byte(chr(MSG_UNIMPLEMENTED))
    1531                      msg.add_int(m.seqno)
    1532                      self._send_message(msg)
    1533          except SSHException, e:
    1534              self._log(ERROR, 'Exception: ' + str(e))
    1535              self._log(ERROR, util.tb_strings())
    1536              self.saved_exception = e
    1537          except EOFError, e:
    1538              self._log(DEBUG, 'EOF in transport thread')
    1539              #self._log(DEBUG, util.tb_strings())
    1540              self.saved_exception = e
    1541          except socket.error, e:
    1542              if type(e.args) is tuple:
    1543                  emsg = '%s (%d)' % (e.args[1], e.args[0])
    1544              else:
    1545                  emsg = e.args
    1546              self._log(ERROR, 'Socket exception: ' + emsg)
    1547              self.saved_exception = e
    1548          except Exception, e:
    1549              self._log(ERROR, 'Unknown exception: ' + str(e))
    1550              self._log(ERROR, util.tb_strings())
    1551              self.saved_exception = e
    1552          _active_threads.remove(self)
    1553          for chan in self._channels.values():
    1554              chan._unlink()
    1555          if self.active:
    1556              self.active = False
    1557              self.packetizer.close()
    1558              if self.completion_event != None:
    1559                  self.completion_event.set()
    1560              if self.auth_handler is not None:
    1561                  self.auth_handler.abort()
    1562              for event in self.channel_events.values():
    1563                  event.set()
    1564              try:
    1565                  self.lock.acquire()
    1566                  self.server_accept_cv.notify()
    1567              finally:
    1568                  self.lock.release()
    1569          self.sock.close()
    1570
    1571
    1572      ###  protocol stages
    1573
    1574
    1575 -    def _negotiate_keys(self, m):
    1576          # throws SSHException on anything unusual
    1577          self.clear_to_send_lock.acquire()
    1578          try:
    1579              self.clear_to_send.clear()
    1580          finally:
    1581              self.clear_to_send_lock.release()
    1582          if self.local_kex_init == None:
    1583              # remote side wants to renegotiate
    1584              self._send_kex_init()
    1585          self._parse_kex_init(m)
    1586          self.kex_engine.start_kex()
    1587
    1588 -    def _check_banner(self):
    1589          # this is slow, but we only have to do it once
    1590          for i in range(5):
    1591              # give them 15 seconds for the first line, then just 2 seconds
    1592              # each additional line.  (some sites have very high latency.)
    1593              if i == 0:
    1594                  timeout = self.banner_timeout
    1595              else:
    1596                  timeout = 2
    1597              try:
    1598                  buf = self.packetizer.readline(timeout)
    1599              except Exception, x:
    1600                  raise SSHException('Error reading SSH protocol banner' + str(x))
    1601              if buf[:4] == 'SSH-':
    1602                  break
    1603              self._log(DEBUG, 'Banner: ' + buf)
    1604          if buf[:4] != 'SSH-':
    1605              raise SSHException('Indecipherable protocol version "' + buf + '"')
    1606          # save this server version string for later
    1607          self.remote_version = buf
    1608          # pull off any attached comment
    1609          comment = ''
    1610          i = string.find(buf, ' ')
    1611          if i >= 0:
    1612              comment = buf[i+1:]
    1613              buf = buf[:i]
    1614          # parse out version string and make sure it matches
    1615          segs = buf.split('-', 2)
    1616          if len(segs) < 3:
    1617              raise SSHException('Invalid SSH banner')
    1618          version = segs[1]
    1619          client = segs[2]
    1620          if version != '1.99' and version != '2.0':
    1621              raise SSHException('Incompatible version (%s instead of 2.0)' % (version,))
    1622          self._log(INFO, 'Connected (version %s, client %s)' % (version, client))
    1623
    1624 -    def _send_kex_init(self):
    1625          """
    1626          announce to the other side that we'd like to negotiate keys, and what
    1627          kind of key negotiation we support.
    1628          """
    1629          self.clear_to_send_lock.acquire()
    1630          try:
    1631              self.clear_to_send.clear()
    1632          finally:
    1633              self.clear_to_send_lock.release()
    1634          self.in_kex = True
    1635          if self.server_mode:
    1636              if (self._modulus_pack is None) and ('diffie-hellman-group-exchange-sha1' in self._preferred_kex):
    1637                  # can't do group-exchange if we don't have a pack of potential primes
    1638                  pkex = list(self.get_security_options().kex)
    1639                  pkex.remove('diffie-hellman-group-exchange-sha1')
    1640                  self.get_security_options().kex = pkex
    1641              available_server_keys = filter(self.server_key_dict.keys().__contains__,
    1642                                             self._preferred_keys)
    1643          else:
    1644              available_server_keys = self._preferred_keys
    1645
    1646          randpool.stir()
    1647          m = Message()
    1648          m.add_byte(chr(MSG_KEXINIT))
    1649          m.add_bytes(randpool.get_bytes(16))
    1650          m.add_list(self._preferred_kex)
    1651          m.add_list(available_server_keys)
    1652          m.add_list(self._preferred_ciphers)
    1653          m.add_list(self._preferred_ciphers)
    1654          m.add_list(self._preferred_macs)
    1655          m.add_list(self._preferred_macs)
    1656          m.add_list(self._preferred_compression)
    1657          m.add_list(self._preferred_compression)
    1658          m.add_string('')
    1659          m.add_string('')
    1660          m.add_boolean(False)
    1661          m.add_int(0)
    1662          # save a copy for later (needed to compute a hash)
    1663          self.local_kex_init = str(m)
    1664          self._send_message(m)
    1665
    1666 -    def _parse_kex_init(self, m):
    1667          cookie = m.get_bytes(16)
    1668          kex_algo_list = m.get_list()
    1669          server_key_algo_list = m.get_list()
    1670          client_encrypt_algo_list = m.get_list()
    1671          server_encrypt_algo_list = m.get_list()
    1672          client_mac_algo_list = m.get_list()
    1673          server_mac_algo_list = m.get_list()
    1674          client_compress_algo_list = m.get_list()
    1675          server_compress_algo_list = m.get_list()
    1676          client_lang_list = m.get_list()
    1677          server_lang_list = m.get_list()
    1678          kex_follows = m.get_boolean()
    1679          unused = m.get_int()
    1680
    1681          self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) + \
    1682                    ' client encrypt:' + str(client_encrypt_algo_list) + \
    1683                    ' server encrypt:' + str(server_encrypt_algo_list) + \
    1684                    ' client mac:' + str(client_mac_algo_list) + \
    1685                    ' server mac:' + str(server_mac_algo_list) + \
    1686                    ' client compress:' + str(client_compress_algo_list) + \
    1687                    ' server compress:' + str(server_compress_algo_list) + \
    1688                    ' client lang:' + str(client_lang_list) + \
    1689                    ' server lang:' + str(server_lang_list) + \
    1690                    ' kex follows?' + str(kex_follows))
    1691
    1692          # as a server, we pick the first item in the client's list that we support.
    1693          # as a client, we pick the first item in our list that the server supports.
    1694          if self.server_mode:
    1695              agreed_kex = filter(self._preferred_kex.__contains__, kex_algo_list)
    1696          else:
    1697              agreed_kex = filter(kex_algo_list.__contains__, self._preferred_kex)
    1698          if len(agreed_kex) == 0:
    1699              raise SSHException('Incompatible ssh peer (no acceptable kex algorithm)')
    1700          self.kex_engine = self._kex_info[agreed_kex[0]](self)
    1701
    1702          if self.server_mode:
    1703              available_server_keys = filter(self.server_key_dict.keys().__contains__,
    1704                                             self._preferred_keys)
    1705              agreed_keys = filter(available_server_keys.__contains__, server_key_algo_list)
    1706          else:
    1707              agreed_keys = filter(server_key_algo_list.__contains__, self._preferred_keys)
    1708          if len(agreed_keys) == 0:
    1709              raise SSHException('Incompatible ssh peer (no acceptable host key)')
    1710          self.host_key_type = agreed_keys[0]
    1711          if self.server_mode and (self.get_server_key() is None):
    1712              raise SSHException('Incompatible ssh peer (can\'t match requested host key type)')
    1713
    1714          if self.server_mode:
    1715              agreed_local_ciphers = filter(self._preferred_ciphers.__contains__,
    1716                                             server_encrypt_algo_list)
    1717              agreed_remote_ciphers = filter(self._preferred_ciphers.__contains__,
    1718                                            client_encrypt_algo_list)
    1719          else:
    1720              agreed_local_ciphers = filter(client_encrypt_algo_list.__contains__,
    1721                                            self._preferred_ciphers)
    1722              agreed_remote_ciphers = filter(server_encrypt_algo_list.__contains__,
    1723                                             self._preferred_ciphers)
    1724          if (len(agreed_local_ciphers) == 0) or (len(agreed_remote_ciphers) == 0):
    1725              raise SSHException('Incompatible ssh server (no acceptable ciphers)')
    1726          self.local_cipher = agreed_local_ciphers[0]
    1727          self.remote_cipher = agreed_remote_ciphers[0]
    1728          self._log(DEBUG, 'Ciphers agreed: local=%s, remote=%s' % (self.local_cipher, self.remote_cipher))
    1729
    1730          if self.server_mode:
    1731              agreed_remote_macs = filter(self._preferred_macs.__contains__, client_mac_algo_list)
    1732              agreed_local_macs = filter(self._preferred_macs.__contains__, server_mac_algo_list)
    1733          else:
    1734              agreed_local_macs = filter(client_mac_algo_list.__contains__, self._preferred_macs)
    1735              agreed_remote_macs = filter(server_mac_algo_list.__contains__, self._preferred_macs)
    1736          if (len(agreed_local_macs) == 0) or (len(agreed_remote_macs) == 0):
    1737              raise SSHException('Incompatible ssh server (no acceptable macs)')
    1738          self.local_mac = agreed_local_macs[0]
    1739          self.remote_mac = agreed_remote_macs[0]
    1740
    1741          if self.server_mode:
    1742              agreed_remote_compression = filter(self._preferred_compression.__contains__, client_compress_algo_list)
    1743              agreed_local_compression = filter(self._preferred_compression.__contains__, server_compress_algo_list)
    1744          else:
    1745              agreed_local_compression = filter(client_compress_algo_list.__contains__, self._preferred_compression)
    1746              agreed_remote_compression = filter(server_compress_algo_list.__contains__, self._preferred_compression)
    1747          if (len(agreed_local_compression) == 0) or (len(agreed_remote_compression) == 0):
    1748              raise SSHException('Incompatible ssh server (no acceptable compression) %r %r %r' % (agreed_local_compression, agreed_remote_compression, self._preferred_compression))
    1749          self.local_compression = agreed_local_compression[0]
    1750          self.remote_compression = agreed_remote_compression[0]
    1751
    1752          self._log(DEBUG, 'using kex %s; server key type %s; cipher: local %s, remote %s; mac: local %s, remote %s; compression: local %s, remote %s' %
    1753                    (agreed_kex[0], self.host_key_type, self.local_cipher, self.remote_cipher, self.local_mac,
    1754                     self.remote_mac, self.local_compression, self.remote_compression))
    1755
    1756          # save for computing hash later...
    1757          # now wait!  openssh has a bug (and others might too) where there are
    1758          # actually some extra bytes (one NUL byte in openssh's case) added to
    1759          # the end of the packet but not parsed.  turns out we need to throw
    1760          # away those bytes because they aren't part of the hash.
    1761          self.remote_kex_init = chr(MSG_KEXINIT) + m.get_so_far()
    1762
    1763 -    def _activate_inbound(self):
    1764          "switch on newly negotiated encryption parameters for inbound traffic"
    1765          block_size = self._cipher_info[self.remote_cipher]['block-size']
    1766          if self.server_mode:
    1767              IV_in = self._compute_key('A', block_size)
    1768              key_in = self._compute_key('C', self._cipher_info[self.remote_cipher]['key-size'])
    1769          else:
    1770              IV_in = self._compute_key('B', block_size)
    1771              key_in = self._compute_key('D', self._cipher_info[self.remote_cipher]['key-size'])
    1772          engine = self._get_cipher(self.remote_cipher, key_in, IV_in)
    1773          mac_size = self._mac_info[self.remote_mac]['size']
    1774          mac_engine = self._mac_info[self.remote_mac]['class']
    1775          # initial mac keys are done in the hash's natural size (not the potentially truncated
    1776          # transmission size)
    1777          if self.server_mode:
    1778              mac_key = self._compute_key('E', mac_engine.digest_size)
    1779          else:
    1780              mac_key = self._compute_key('F', mac_engine.digest_size)
    1781          self.packetizer.set_inbound_cipher(engine, block_size, mac_engine, mac_size, mac_key)
    1782          compress_in = self._compression_info[self.remote_compression][1]
    1783          if (compress_in is not None) and ((self.remote_compression != 'zlib@openssh.com') or self.authenticated):
    1784              self._log(DEBUG, 'Switching on inbound compression ...')
    1785              self.packetizer.set_inbound_compressor(compress_in())
    1786
    1787 -    def _activate_outbound(self):
    1788          "switch on newly negotiated encryption parameters for outbound traffic"
    1789          m = Message()
    1790          m.add_byte(chr(MSG_NEWKEYS))
    1791          self._send_message(m)
    1792          block_size = self._cipher_info[self.local_cipher]['block-size']
    1793          if self.server_mode:
    1794              IV_out = self._compute_key('B', block_size)
    1795              key_out = self._compute_key('D', self._cipher_info[self.local_cipher]['key-size'])
    1796          else:
    1797              IV_out = self._compute_key('A', block_size)
    1798              key_out = self._compute_key('C', self._cipher_info[self.local_cipher]['key-size'])
    1799          engine = self._get_cipher(self.local_cipher, key_out, IV_out)
    1800          mac_size = self._mac_info[self.local_mac]['size']
    1801          mac_engine = self._mac_info[self.local_mac]['class']
    1802          # initial mac keys are done in the hash's natural size (not the potentially truncated
    1803          # transmission size)
    1804          if self.server_mode:
    1805              mac_key = self._compute_key('F', mac_engine.digest_size)
    1806          else:
    1807              mac_key = self._compute_key('E', mac_engine.digest_size)
    1808          self.packetizer.set_outbound_cipher(engine, block_size, mac_engine, mac_size, mac_key)
    1809          compress_out = self._compression_info[self.local_compression][0]
    1810          if (compress_out is not None) and ((self.local_compression != 'zlib@openssh.com') or self.authenticated):
    1811              self._log(DEBUG, 'Switching on outbound compression ...')
    1812              self.packetizer.set_outbound_compressor(compress_out())
    1813          if not self.packetizer.need_rekey():
    1814              self.in_kex = False
    1815          # we always expect to receive NEWKEYS now
    1816          self._expect_packet(MSG_NEWKEYS)
    1817
    1818 -    def _auth_trigger(self):
    1819          self.authenticated = True
    1820          # delayed initiation of compression
    1821          if self.local_compression == 'zlib@openssh.com':
    1822              compress_out = self._compression_info[self.local_compression][0]
    1823              self._log(DEBUG, 'Switching on outbound compression ...')
    1824              self.packetizer.set_outbound_compressor(compress_out())
    1825          if self.remote_compression == 'zlib@openssh.com':
    1826              compress_in = self._compression_info[self.remote_compression][1]
    1827              self._log(DEBUG, 'Switching on inbound compression ...')
    1828              self.packetizer.set_inbound_compressor(compress_in())
    1829
    1830 -    def _parse_newkeys(self, m):
    1831          self._log(DEBUG, 'Switch to new keys ...')
    1832          self._activate_inbound()
    1833          # can also free a bunch of stuff here
    1834          self.local_kex_init = self.remote_kex_init = None
    1835          self.K = None
    1836          self.kex_engine = None
    1837          if self.server_mode and (self.auth_handler is None):
    1838              # create auth handler for server mode
    1839              self.auth_handler = AuthHandler(self)
    1840          if not self.initial_kex_done:
    1841              # this was the first key exchange
    1842              self.initial_kex_done = True
    1843          # send an event?
    1844          if self.completion_event != None:
    1845              self.completion_event.set()
    1846          # it's now okay to send data again (if this was a re-key)
    1847          if not self.packetizer.need_rekey():
    1848              self.in_kex = False
    1849          self.clear_to_send_lock.acquire()
    1850          try:
    1851              self.clear_to_send.set()
    1852          finally:
    1853              self.clear_to_send_lock.release()
    1854          return
    1855
    1856 -    def _parse_disconnect(self, m):
    1857          code = m.get_int()
    1858          desc = m.get_string()
    1859          self._log(INFO, 'Disconnect (code %d): %s' % (code, desc))
    1860
    1861 -    def _parse_global_request(self, m):
    1862          kind = m.get_string()
    1863          self._log(DEBUG, 'Received global request "%s"' % kind)
    1864          want_reply = m.get_boolean()
    1865          if not self.server_mode:
    1866              self._log(DEBUG, 'Rejecting "%s" global request from server.' % kind)
    1867              ok = False
    1868          elif kind == 'tcpip-forward':
    1869              address = m.get_string()
    1870              port = m.get_int()
    1871              ok = self.server_object.check_port_forward_request(address, port)
    1872              if ok != False:
    1873                  ok = (ok,)
    1874          elif kind == 'cancel-tcpip-forward':
    1875              address = m.get_string()
    1876              port = m.get_int()
    1877              self.server_object.cancel_port_forward_request(address, port)
    1878              ok = True
    1879          else:
    1880              ok = self.server_object.check_global_request(kind, m)
    1881          extra = ()
    1882          if type(ok) is tuple:
    1883              extra = ok
    1884              ok = True
    1885          if want_reply:
    1886              msg = Message()
    1887              if ok:
    1888                  msg.add_byte(chr(MSG_REQUEST_SUCCESS))
    1889                  msg.add(*extra)
    1890              else:
    1891                  msg.add_byte(chr(MSG_REQUEST_FAILURE))
    1892              self._send_message(msg)
    1893
    1894 -    def _parse_request_success(self, m):
    1895          self._log(DEBUG, 'Global request successful.')
    1896          self.global_response = m
    1897          if self.completion_event is not None:
    1898              self.completion_event.set()
    1899
    1900 -    def _parse_request_failure(self, m):
    1901          self._log(DEBUG, 'Global request denied.')
    1902          self.global_response = None
    1903          if self.completion_event is not None:
    1904              self.completion_event.set()
    1905
    1906 -    def _parse_channel_open_success(self, m):
    1907          chanid = m.get_int()
    1908          server_chanid = m.get_int()
    1909          server_window_size = m.get_int()
    1910          server_max_packet_size = m.get_int()
    1911          chan = self._channels.get(chanid)
    1912          if chan is None:
    1913              self._log(WARNING, 'Success for unrequested channel! [??]')
    1914              return
    1915          self.lock.acquire()
    1916          try:
    1917              chan._set_remote_channel(server_chanid, server_window_size, server_max_packet_size)
    1918              self._log(INFO, 'Secsh channel %d opened.' % chanid)
    1919              if chanid in self.channel_events:
    1920                  self.channel_events[chanid].set()
    1921                  del self.channel_events[chanid]
    1922          finally:
    1923              self.lock.release()
    1924          return
    1925
    1926 -    def _parse_channel_open_failure(self, m):
    1927          chanid = m.get_int()
    1928          reason = m.get_int()
    1929          reason_str = m.get_string()
    1930          lang = m.get_string()
    1931          reason_text = CONNECTION_FAILED_CODE.get(reason, '(unknown code)')
    1932          self._log(INFO, 'Secsh channel %d open FAILED: %s: %s' % (chanid, reason_str, reason_text))
    1933          self.lock.acquire()
    1934          try:
    1935              self.saved_exception = ChannelException(reason, reason_text)
    1936              if chanid in self.channel_events:
    1937                  self._channels.delete(chanid)
    1938                  if chanid in self.channel_events:
    1939                      self.channel_events[chanid].set()
    1940                      del self.channel_events[chanid]
    1941          finally:
    1942              self.lock.release()
    1943          return
    1944
    1945 -    def _parse_channel_open(self, m):
    1946          kind = m.get_string()
    1947          chanid = m.get_int()
    1948          initial_window_size = m.get_int()
    1949          max_packet_size = m.get_int()
    1950          reject = False
    1951          if (kind == 'x11') and (self._x11_handler is not None):
    1952              origin_addr = m.get_string()
    1953              origin_port = m.get_int()
    1954              self._log(DEBUG, 'Incoming x11 connection from %s:%d' % (origin_addr, origin_port))
    1955              self.lock.acquire()
    1956              try:
    1957                  my_chanid = self._next_channel()
    1958              finally:
    1959                  self.lock.release()
    1960          elif (kind == 'forwarded-tcpip') and (self._tcp_handler is not None):
    1961              server_addr = m.get_string()
    1962              server_port = m.get_int()
    1963              origin_addr = m.get_string()
    1964              origin_port = m.get_int()
    1965              self._log(DEBUG, 'Incoming tcp forwarded connection from %s:%d' % (origin_addr, origin_port))
    1966              self.lock.acquire()
    1967              try:
    1968                  my_chanid = self._next_channel()
    1969              finally:
    1970                  self.lock.release()
    1971          elif not self.server_mode:
    1972              self._log(DEBUG, 'Rejecting "%s" channel request from server.' % kind)
    1973              reject = True
    1974              reason = OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
    1975          else:
    1976              self.lock.acquire()
    1977              try:
    1978                  my_chanid = self._next_channel()
    1979              finally:
    1980                  self.lock.release()
    1981              if kind == 'direct-tcpip':
    1982                  # handle direct-tcpip requests comming from the client
    1983                  dest_addr = m.get_string()
    1984                  dest_port = m.get_int()
    1985                  origin_addr = m.get_string()
    1986                  origin_port = m.get_int()
    1987                  reason = self.server_object.check_channel_direct_tcpip_request(
    1988                                  my_chanid, (origin_addr, origin_port),
    1989                                             (dest_addr, dest_port))
    1990              else:
    1991                  reason = self.server_object.check_channel_request(kind, my_chanid)
    1992              if reason != OPEN_SUCCEEDED:
    1993                  self._log(DEBUG, 'Rejecting "%s" channel request from client.' % kind)
    1994                  reject = True
    1995          if reject:
    1996              msg = Message()
    1997              msg.add_byte(chr(MSG_CHANNEL_OPEN_FAILURE))
    1998              msg.add_int(chanid)
    1999              msg.add_int(reason)
    2000              msg.add_string('')
    2001              msg.add_string('en')
    2002              self._send_message(msg)
    2003              return
    2004
    2005          chan = Channel(my_chanid)
    2006          self.lock.acquire()
    2007          try:
    2008              self._channels.put(my_chanid, chan)
    2009              self.channels_seen[my_chanid] = True
    2010              chan._set_transport(self)
    2011              chan._set_window(self.window_size, self.max_packet_size)
    2012              chan._set_remote_channel(chanid, initial_window_size, max_packet_size)
    2013          finally:
    2014              self.lock.release()
    2015          m = Message()
    2016          m.add_byte(chr(MSG_CHANNEL_OPEN_SUCCESS))
    2017          m.add_int(chanid)
    2018          m.add_int(my_chanid)
    2019          m.add_int(self.window_size)
    2020          m.add_int(self.max_packet_size)
    2021          self._send_message(m)
    2022          self._log(INFO, 'Secsh channel %d (%s) opened.', my_chanid, kind)
    2023          if kind == 'x11':
    2024              self._x11_handler(chan, (origin_addr, origin_port))
    2025          elif kind == 'forwarded-tcpip':
    2026              chan.origin_addr = (origin_addr, origin_port)
    2027              self._tcp_handler(chan, (origin_addr, origin_port), (server_addr, server_port))
    2028          else:
    2029              self._queue_incoming_channel(chan)
    2030
    2031 -    def _parse_debug(self, m):
    2032          always_display = m.get_boolean()
    2033          msg = m.get_string()
    2034          lang = m.get_string()
    2035          self._log(DEBUG, 'Debug msg: ' + util.safe_string(msg))
    2036
    2037 -    def _get_subsystem_handler(self, name):
    2038          try:
    2039              self.lock.acquire()
    2040              if name not in self.subsystem_table:
    2041                  return (None, [], {})
    2042              return self.subsystem_table[name]
    2043          finally:
    2044              self.lock.release()
    2045
    2046      _handler_table = {
    2047          MSG_NEWKEYS: _parse_newkeys,
    2048          MSG_GLOBAL_REQUEST: _parse_global_request,
    2049          MSG_REQUEST_SUCCESS: _parse_request_success,
    2050          MSG_REQUEST_FAILURE: _parse_request_failure,
    2051          MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success,
    2052          MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
    2053          MSG_CHANNEL_OPEN: _parse_channel_open,
    2054          MSG_KEXINIT: _negotiate_keys,
    2055          }
    2056
    2057      _channel_handler_table = {
    2058          MSG_CHANNEL_SUCCESS: Channel._request_success,
    2059          MSG_CHANNEL_FAILURE: Channel._request_failed,
    2060          MSG_CHANNEL_DATA: Channel._feed,
    2061          MSG_CHANNEL_EXTENDED_DATA: Channel._feed_extended,
    2062          MSG_CHANNEL_WINDOW_ADJUST: Channel._window_adjust,
    2063          MSG_CHANNEL_REQUEST: Channel._handle_request,
    2064          MSG_CHANNEL_EOF: Channel._handle_eof,
    2065          MSG_CHANNEL_CLOSE: Channel._handle_close,
    2066          }
    2067