paramiko.transport

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

# Source Code for Module paramiko.transport

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