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  # these come from PyCrypt
      49  #     http://www.amk.ca/python/writing/pycrypt/
      50  # i believe this on the standards track.
      51  # PyCrypt compiled for Win32 can be downloaded from the HashTar homepage:
      52  #     http://nitace.bsd.uchicago.edu:8080/hashtar
      53  from Crypto.Cipher import Blowfish, AES, DES3, ARC4
      54  from Crypto.Hash import SHA, MD5
      55  try:
      56      from Crypto.Util import Counter
      57  except ImportError:
      58      from paramiko.util import Counter
      59
      60
      61  # for thread cleanup
      62  _active_threads = []
      63 -def _join_lingering_threads():
      64      for thr in _active_threads:
      65          thr.stop_thread()
      66  import atexit
      67  atexit.register(_join_lingering_threads)
      68
      69
      70 -class SecurityOptions (object):
      71      """
      72      Simple object containing the security preferences of an ssh transport.
      73      These are tuples of acceptable ciphers, digests, key types, and key
      74      exchange algorithms, listed in order of preference.
      75
      76      Changing the contents and/or order of these fields affects the underlying
      77      L{Transport} (but only if you change them before starting the session).
      78      If you try to add an algorithm that paramiko doesn't recognize,
      79      C{ValueError} will be raised.  If you try to assign something besides a
      80      tuple to one of the fields, C{TypeError} will be raised.
      81      """
      82      __slots__ = [ 'ciphers', 'digests', 'key_types', 'kex', 'compression', '_transport' ]
      83
      84 -    def __init__(self, transport):
      85          self._transport = transport
      86
      87 -    def __repr__(self):
      88          """
      89          Returns a string representation of this object, for debugging.
      90
      91          @rtype: str
      92          """
      93          return '<paramiko.SecurityOptions for %s>' % repr(self._transport)
      94
      95 -    def _get_ciphers(self):
      96          return self._transport._preferred_ciphers
      97
      98 -    def _get_digests(self):
      99          return self._transport._preferred_macs
     100
     101 -    def _get_key_types(self):
     102          return self._transport._preferred_keys
     103
     104 -    def _get_kex(self):
     105          return self._transport._preferred_kex
     106
     107 -    def _get_compression(self):
     108          return self._transport._preferred_compression
     109
     110 -    def _set(self, name, orig, x):
     111          if type(x) is list:
     112              x = tuple(x)
     113          if type(x) is not tuple:
     114              raise TypeError('expected tuple or list')
     115          possible = getattr(self._transport, orig).keys()
     116          forbidden = filter(lambda n: n not in possible, x)
     117          if len(forbidden) > 0:
     118              raise ValueError('unknown cipher')
     119          setattr(self._transport, name, x)
     120
     121 -    def _set_ciphers(self, x):
     122          self._set('_preferred_ciphers', '_cipher_info', x)
     123
     124 -    def _set_digests(self, x):
     125          self._set('_preferred_macs', '_mac_info', x)
     126
     127 -    def _set_key_types(self, x):
     128          self._set('_preferred_keys', '_key_info', x)
     129
     130 -    def _set_kex(self, x):
     131          self._set('_preferred_kex', '_kex_info', x)
     132
     133 -    def _set_compression(self, x):
     134          self._set('_preferred_compression', '_compression_info', x)
     135
     136      ciphers = property(_get_ciphers, _set_ciphers, None,
     137                         "Symmetric encryption ciphers")
     138      digests = property(_get_digests, _set_digests, None,
     139                         "Digest (one-way hash) algorithms")
     140      key_types = property(_get_key_types, _set_key_types, None,
     141                           "Public-key algorithms")
     142      kex = property(_get_kex, _set_kex, None, "Key exchange algorithms")
     143      compression = property(_get_compression, _set_compression, None,
     144                             "Compression algorithms")
     145
     146
     147 -class ChannelMap (object):
     148 -    def __init__(self):
     149          # (id -> Channel)
     150          self._map = weakref.WeakValueDictionary()
     151          self._lock = threading.Lock()
     152
     153 -    def put(self, chanid, chan):
     154          self._lock.acquire()
     155          try:
     156              self._map[chanid] = chan
     157          finally:
     158              self._lock.release()
     159
     160 -    def get(self, chanid):
     161          self._lock.acquire()
     162          try:
     163              return self._map.get(chanid, None)
     164          finally:
     165              self._lock.release()
     166
     167 -    def delete(self, chanid):
     168          self._lock.acquire()
     169          try:
     170              try:
     171                  del self._map[chanid]
     172              except KeyError:
     173                  pass
     174          finally:
     175              self._lock.release()
     176
     177 -    def values(self):
     178          self._lock.acquire()
     179          try:
     180              return self._map.values()
     181          finally:
     182              self._lock.release()
     183
     184 -    def __len__(self):
     185          self._lock.acquire()
     186          try:
     187              return len(self._map)
     188          finally:
     189              self._lock.release()
     190
     191
     192 -class Transport (threading.Thread):
     193      """
     194      An SSH Transport attaches to a stream (usually a socket), negotiates an
     195      encrypted session, authenticates, and then creates stream tunnels, called
     196      L{Channel}s, across the session.  Multiple channels can be multiplexed
     197      across a single session (and often are, in the case of port forwardings).
     198      """
     199
     200      _PROTO_ID = '2.0'
     201      _CLIENT_ID = 'paramiko_1.7.6'
     202
     203      _preferred_ciphers = ( 'aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc', 'aes256-cbc', '3des-cbc',
     204          'arcfour128', 'arcfour256' )
     205      _preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' )
     206      _preferred_keys = ( 'ssh-rsa', 'ssh-dss' )
     207      _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' )
     208      _preferred_compression = ( 'none', )
     209
     210      _cipher_info = {
     211          'aes128-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16 },
     212          'aes256-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32 },
     213          'blowfish-cbc': { 'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16 },
     214          'aes128-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16 },
     215          'aes256-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32 },
     216          '3des-cbc': { 'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24 },
     217          'arcfour128': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16 },
     218          'arcfour256': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32 },
     219          }
     220
     221      _mac_info = {
     222          'hmac-sha1': { 'class': SHA, 'size': 20 },
     223          'hmac-sha1-96': { 'class': SHA, 'size': 12 },
     224          'hmac-md5': { 'class': MD5, 'size': 16 },
     225          'hmac-md5-96': { 'class': MD5, 'size': 12 },
     226          }
     227
     228      _key_info = {
     229          'ssh-rsa': RSAKey,
     230          'ssh-dss': DSSKey,
     231          }
     232
     233      _kex_info = {
     234          'diffie-hellman-group1-sha1': KexGroup1,
     235          'diffie-hellman-group-exchange-sha1': KexGex,
     236          }
     237
     238      _compression_info = {
     239          # zlib@openssh.com is just zlib, but only turned on after a successful
     240          # authentication.  openssh servers may only offer this type because
     241          # they've had troubles with security holes in zlib in the past.
     242          'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ),
     243          'zlib': ( ZlibCompressor, ZlibDecompressor ),
     244          'none': ( None, None ),
     245      }
     246
     247
     248      _modulus_pack = None
     249
     250 -    def __init__(self, sock):
     251          """
     252          Create a new SSH session over an existing socket, or socket-like
     253          object.  This only creates the Transport object; it doesn't begin the
     254          SSH session yet.  Use L{connect} or L{start_client} to begin a client
     255          session, or L{start_server} to begin a server session.
     256
     257          If the object is not actually a socket, it must have the following
     258          methods:
     259              - C{send(str)}: Writes from 1 to C{len(str)} bytes, and
     260                returns an int representing the number of bytes written.  Returns
     261                0 or raises C{EOFError} if the stream has been closed.
     262              - C{recv(int)}: Reads from 1 to C{int} bytes and returns them as a
     263                string.  Returns 0 or raises C{EOFError} if the stream has been
     264                closed.
     265              - C{close()}: Closes the socket.
     266              - C{settimeout(n)}: Sets a (float) timeout on I/O operations.
     267
     268          For ease of use, you may also pass in an address (as a tuple) or a host
     269          string as the C{sock} argument.  (A host string is a hostname with an
     270          optional port (separated by C{":"}) which will be converted into a
     271          tuple of C{(hostname, port)}.)  A socket will be connected to this
     272          address and used for communication.  Exceptions from the C{socket} call
     273          may be thrown in this case.
     274
     275          @param sock: a socket or socket-like object to create the session over.
     276          @type sock: socket
     277          """
     278          if isinstance(sock, (str, unicode)):
     279              # convert "host:port" into (host, port)
     280              hl = sock.split(':', 1)
     281              if len(hl) == 1:
     282                  sock = (hl[0], 22)
     283              else:
     284                  sock = (hl[0], int(hl[1]))
     285          if type(sock) is tuple:
     286              # connect to the given (host, port)
     287              hostname, port = sock
     288              for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
     289                  if socktype == socket.SOCK_STREAM:
     290                      af = family
     291                      addr = sockaddr
     292                      break
     293              else:
     294                  raise SSHException('No suitable address family for %s' % hostname)
     295              sock = socket.socket(af, socket.SOCK_STREAM)
     296              sock.connect((hostname, port))
     297          # okay, normal socket-ish flow here...
     298          threading.Thread.__init__(self)
     299          self.setDaemon(True)
     300          self.randpool = randpool
     301          self.sock = sock
     302          # Python < 2.3 doesn't have the settimeout method - RogerB
     303          try:
     304              # we set the timeout so we can check self.active periodically to
     305              # see if we should bail.  socket.timeout exception is never
     306              # propagated.
     307              self.sock.settimeout(0.1)
     308          except AttributeError:
     309              pass
     310
     311          # negotiated crypto parameters
     312          self.packetizer = Packetizer(sock)
     313          self.local_version = 'SSH-' + self._PROTO_ID + '-' + self._CLIENT_ID
     314          self.remote_version = ''
     315          self.local_cipher = self.remote_cipher = ''
     316          self.local_kex_init = self.remote_kex_init = None
     317          self.local_mac = self.remote_mac = None
     318          self.local_compression = self.remote_compression = None
     319          self.session_id = None
     320          self.host_key_type = None
     321          self.host_key = None
     322
     323          # state used during negotiation
     324          self.kex_engine = None
     325          self.H = None
     326          self.K = None
     327
     328          self.active = False
     329          self.initial_kex_done = False
     330          self.in_kex = False
     331          self.authenticated = False
     332          self._expected_packet = tuple()
     333          self.lock = threading.Lock()    # synchronization (always higher level than write_lock)
     334
     335          # tracking open channels
     336          self._channels = ChannelMap()
     337          self.channel_events = { }       # (id -> Event)
     338          self.channels_seen = { }        # (id -> True)
     339          self._channel_counter = 1
     340          self.window_size = 65536
     341          self.max_packet_size = 34816
     342          self._x11_handler = None
     343          self._tcp_handler = None
     344
     345          self.saved_exception = None
     346          self.clear_to_send = threading.Event()
     347          self.clear_to_send_lock = threading.Lock()
     348          self.clear_to_send_timeout = 30.0
     349          self.log_name = 'paramiko.transport'
     350          self.logger = util.get_logger(self.log_name)
     351          self.packetizer.set_log(self.logger)
     352          self.auth_handler = None
     353          self.global_response = None     # response Message from an arbitrary global request
     354          self.completion_event = None    # user-defined event callbacks
     355          self.banner_timeout = 15        # how long (seconds) to wait for the SSH banner
     356
     357          # server mode:
     358          self.server_mode = False
     359          self.server_object = None
     360          self.server_key_dict = { }
     361          self.server_accepts = [ ]
     362          self.server_accept_cv = threading.Condition(self.lock)
     363          self.subsystem_table = { }
     364
     365 -    def __repr__(self):
     366          """
     367          Returns a string representation of this object, for debugging.
     368
     369          @rtype: str
     370          """
     371          out = '<paramiko.Transport at %s' % hex(long(id(self)) & 0xffffffffL)
     372          if not self.active:
     373              out += ' (unconnected)'
     374          else:
     375              if self.local_cipher != '':
     376                  out += ' (cipher %s, %d bits)' % (self.local_cipher,
     377                                                    self._cipher_info[self.local_cipher]['key-size'] * 8)
     378              if self.is_authenticated():
     379                  out += ' (active; %d open channel(s))' % len(self._channels)
     380              elif self.initial_kex_done:
     381                  out += ' (connected; awaiting auth)'
     382              else:
     383                  out += ' (connecting)'
     384          out += '>'
     385          return out
     386
     387 -    def atfork(self):
     388          """
     389          Terminate this Transport without closing the session.  On posix
     390          systems, if a Transport is open during process forking, both parent
     391          and child will share the underlying socket, but only one process can
     392          use the connection (without corrupting the session).  Use this method
     393          to clean up a Transport object without disrupting the other process.
     394
     395          @since: 1.5.3
     396          """
     397          self.sock.close()
     398          self.close()
     399
     400 -    def get_security_options(self):
     401          """
     402          Return a L{SecurityOptions} object which can be used to tweak the
     403          encryption algorithms this transport will permit, and the order of
     404          preference for them.
     405
     406          @return: an object that can be used to change the preferred algorithms
     407              for encryption, digest (hash), public key, and key exchange.
     408          @rtype: L{SecurityOptions}
     409          """
     410          return SecurityOptions(self)
     411
     412 -    def start_client(self, event=None):
     413          """
     414          Negotiate a new SSH2 session as a client.  This is the first step after
     415          creating a new L{Transport}.  A separate thread is created for protocol
     416          negotiation.
     417
     418          If an event is passed in, this method returns immediately.  When
     419          negotiation is done (successful or not), the given C{Event} will
     420          be triggered.  On failure, L{is_active} will return C{False}.
     421
     422          (Since 1.4) If C{event} is C{None}, this method will not return until
     423          negotation is done.  On success, the method returns normally.
     424          Otherwise an SSHException is raised.
     425
     426          After a successful negotiation, you will usually want to authenticate,
     427          calling L{auth_password <Transport.auth_password>} or
     428          L{auth_publickey <Transport.auth_publickey>}.
     429
     430          @note: L{connect} is a simpler method for connecting as a client.
     431
     432          @note: After calling this method (or L{start_server} or L{connect}),
     433              you should no longer directly read from or write to the original
     434              socket object.
     435
     436          @param event: an event to trigger when negotiation is complete
     437              (optional)
     438          @type event: threading.Event
     439
     440          @raise SSHException: if negotiation fails (and no C{event} was passed
     441              in)
     442          """
     443          self.active = True
     444          if event is not None:
     445              # async, return immediately and let the app poll for completion
     446              self.completion_event = event
     447              self.start()
     448              return
     449
     450          # synchronous, wait for a result
     451          self.completion_event = event = threading.Event()
     452          self.start()
     453          while True:
     454              event.wait(0.1)
     455              if not self.active:
     456                  e = self.get_exception()
     457                  if e is not None:
     458                      raise e
     459                  raise SSHException('Negotiation failed.')
     460              if event.isSet():
     461                  break
     462
     463 -    def start_server(self, event=None, server=None):
     464          """
     465          Negotiate a new SSH2 session as a server.  This is the first step after
     466          creating a new L{Transport} and setting up your server host key(s).  A
     467          separate thread is created for protocol negotiation.
     468
     469          If an event is passed in, this method returns immediately.  When
     470          negotiation is done (successful or not), the given C{Event} will
     471          be triggered.  On failure, L{is_active} will return C{False}.
     472
     473          (Since 1.4) If C{event} is C{None}, this method will not return until
     474          negotation is done.  On success, the method returns normally.
     475          Otherwise an SSHException is raised.
     476
     477          After a successful negotiation, the client will need to authenticate.
     478          Override the methods
     479          L{get_allowed_auths <ServerInterface.get_allowed_auths>},
     480          L{check_auth_none <ServerInterface.check_auth_none>},
     481          L{check_auth_password <ServerInterface.check_auth_password>}, and
     482          L{check_auth_publickey <ServerInterface.check_auth_publickey>} in the
     483          given C{server} object to control the authentication process.
     484
     485          After a successful authentication, the client should request to open
     486          a channel.  Override
     487          L{check_channel_request <ServerInterface.check_channel_request>} in the
     488          given C{server} object to allow channels to be opened.
     489
     490          @note: After calling this method (or L{start_client} or L{connect}),
     491              you should no longer directly read from or write to the original
     492              socket object.
     493
     494          @param event: an event to trigger when negotiation is complete.
     495          @type event: threading.Event
     496          @param server: an object used to perform authentication and create
     497              L{Channel}s.
     498          @type server: L{server.ServerInterface}
     499
     500          @raise SSHException: if negotiation fails (and no C{event} was passed
     501              in)
     502          """
     503          if server is None:
     504              server = ServerInterface()
     505          self.server_mode = True
     506          self.server_object = server
     507          self.active = True
     508          if event is not None:
     509              # async, return immediately and let the app poll for completion
     510              self.completion_event = event
     511              self.start()
     512              return
     513
     514          # synchronous, wait for a result
     515          self.completion_event = event = threading.Event()
     516          self.start()
     517          while True:
     518              event.wait(0.1)
     519              if not self.active:
     520                  e = self.get_exception()
     521                  if e is not None:
     522                      raise e
     523                  raise SSHException('Negotiation failed.')
     524              if event.isSet():
     525                  break
     526
     527 -    def add_server_key(self, key):
     528          """
     529          Add a host key to the list of keys used for server mode.  When behaving
     530          as a server, the host key is used to sign certain packets during the
     531          SSH2 negotiation, so that the client can trust that we are who we say
     532          we are.  Because this is used for signing, the key must contain private
     533          key info, not just the public half.  Only one key of each type (RSA or
     534          DSS) is kept.
     535
     536          @param key: the host key to add, usually an L{RSAKey <rsakey.RSAKey>} or
     537              L{DSSKey <dsskey.DSSKey>}.
     538          @type key: L{PKey <pkey.PKey>}
     539          """
     540          self.server_key_dict[key.get_name()] = key
     541
     542 -    def get_server_key(self):
     543          """
     544          Return the active host key, in server mode.  After negotiating with the
     545          client, this method will return the negotiated host key.  If only one
     546          type of host key was set with L{add_server_key}, that's the only key
     547          that will ever be returned.  But in cases where you have set more than
     548          one type of host key (for example, an RSA key and a DSS key), the key
     549          type will be negotiated by the client, and this method will return the
     550          key of the type agreed on.  If the host key has not been negotiated
     551          yet, C{None} is returned.  In client mode, the behavior is undefined.
     552
     553          @return: host key of the type negotiated by the client, or C{None}.
     554          @rtype: L{PKey <pkey.PKey>}
     555          """
     556          try:
     557              return self.server_key_dict[self.host_key_type]
     558          except KeyError:
     559              pass
     560          return None
     561
     562 -    def load_server_moduli(filename=None):
     563          """
     564          I{(optional)}
     565          Load a file of prime moduli for use in doing group-exchange key
     566          negotiation in server mode.  It's a rather obscure option and can be
     567          safely ignored.
     568
     569          In server mode, the remote client may request "group-exchange" key
     570          negotiation, which asks the server to send a random prime number that
     571          fits certain criteria.  These primes are pretty difficult to compute,
     572          so they can't be generated on demand.  But many systems contain a file
     573          of suitable primes (usually named something like C{/etc/ssh/moduli}).
     574          If you call C{load_server_moduli} and it returns C{True}, then this
     575          file of primes has been loaded and we will support "group-exchange" in
     576          server mode.  Otherwise server mode will just claim that it doesn't
     577          support that method of key negotiation.
     578
     579          @param filename: optional path to the moduli file, if you happen to
     580              know that it's not in a standard location.
     581          @type filename: str
     582          @return: True if a moduli file was successfully loaded; False
     583              otherwise.
     584          @rtype: bool
     585
     586          @note: This has no effect when used in client mode.
     587          """
     588          Transport._modulus_pack = ModulusPack(randpool)
     589          # places to look for the openssh "moduli" file
     590          file_list = [ '/etc/ssh/moduli', '/usr/local/etc/moduli' ]
     591          if filename is not None:
     592              file_list.insert(0, filename)
     593          for fn in file_list:
     594              try:
     595                  Transport._modulus_pack.read_file(fn)
     596                  return True
     597              except IOError:
     598                  pass
     599          # none succeeded
     600          Transport._modulus_pack = None
     601          return False
     602      load_server_moduli = staticmethod(load_server_moduli)
     603
     604 -    def close(self):
     605          """
     606          Close this session, and any open channels that are tied to it.
     607          """
     608          if not self.active:
     609              return
     610          self.active = False
     611          self.packetizer.close()
     612          self.join()
     613          for chan in self._channels.values():
     614              chan._unlink()
     615
     616 -    def get_remote_server_key(self):
     617          """
     618          Return the host key of the server (in client mode).
     619
     620          @note: Previously this call returned a tuple of (key type, key string).
     621              You can get the same effect by calling
     622              L{PKey.get_name <pkey.PKey.get_name>} for the key type, and
     623              C{str(key)} for the key string.
     624
     625          @raise SSHException: if no session is currently active.
     626
     627          @return: public key of the remote server
     628          @rtype: L{PKey <pkey.PKey>}
     629          """
     630          if (not self.active) or (not self.initial_kex_done):
     631              raise SSHException('No existing session')
     632          return self.host_key
     633
     634 -    def is_active(self):
     635          """
     636          Return true if this session is active (open).
     637
     638          @return: True if the session is still active (open); False if the
     639              session is closed
     640          @rtype: bool
     641          """
     642          return self.active
     643
     644 -    def open_session(self):
     645          """
     646          Request a new channel to the server, of type C{"session"}.  This
     647          is just an alias for C{open_channel('session')}.
     648
     649          @return: a new L{Channel}
     650          @rtype: L{Channel}
     651
     652          @raise SSHException: if the request is rejected or the session ends
     653              prematurely
     654          """
     655          return self.open_channel('session')
     656
     657 -    def open_x11_channel(self, src_addr=None):
     658          """
     659          Request a new channel to the client, of type C{"x11"}.  This
     660          is just an alias for C{open_channel('x11', src_addr=src_addr)}.
     661
     662          @param src_addr: the source address of the x11 server (port is the
     663              x11 port, ie. 6010)
     664          @type src_addr: (str, int)
     665          @return: a new L{Channel}
     666          @rtype: L{Channel}
     667
     668          @raise SSHException: if the request is rejected or the session ends
     669              prematurely
     670          """
     671          return self.open_channel('x11', src_addr=src_addr)
     672
     673 -    def open_forwarded_tcpip_channel(self, (src_addr, src_port), (dest_addr, dest_port)):
     674          """
     675          Request a new channel back to the client, of type C{"forwarded-tcpip"}.
     676          This is used after a client has requested port forwarding, for sending
     677          incoming connections back to the client.
     678
     679          @param src_addr: originator's address
     680          @param src_port: originator's port
     681          @param dest_addr: local (server) connected address
     682          @param dest_port: local (server) connected port
     683          """
     684          return self.open_channel('forwarded-tcpip', (dest_addr, dest_port), (src_addr, src_port))
     685
     686 -    def open_channel(self, kind, dest_addr=None, src_addr=None):
     687          """
     688          Request a new channel to the server.  L{Channel}s are socket-like
     689          objects used for the actual transfer of data across the session.
     690          You may only request a channel after negotiating encryption (using
     691          L{connect} or L{start_client}) and authenticating.
     692
     693          @param kind: the kind of channel requested (usually C{"session"},
     694              C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"})
     695          @type kind: str
     696          @param dest_addr: the destination address of this port forwarding,
     697              if C{kind} is C{"forwarded-tcpip"} or C{"direct-tcpip"} (ignored
     698              for other channel types)
     699          @type dest_addr: (str, int)
     700          @param src_addr: the source address of this port forwarding, if
     701              C{kind} is C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"}
     702          @type src_addr: (str, int)
     703          @return: a new L{Channel} on success
     704          @rtype: L{Channel}
     705
     706          @raise SSHException: if the request is rejected or the session ends
     707              prematurely
     708          """
     709          chan = None
     710          if not self.active:
     711              # don't bother trying to allocate a channel
     712              return None
     713          self.lock.acquire()
     714          try:
     715              chanid = self._next_channel()
     716              m = Message()
     717              m.add_byte(chr(MSG_CHANNEL_OPEN))
     718              m.add_string(kind)
     719              m.add_int(chanid)
     720              m.add_int(self.window_size)
     721              m.add_int(self.max_packet_size)
     722              if (kind == 'forwarded-tcpip') or (kind == 'direct-tcpip'):
     723                  m.add_string(dest_addr[0])
     724                  m.add_int(dest_addr[1])
     725                  m.add_string(src_addr[0])
     726                  m.add_int(src_addr[1])
     727              elif kind == 'x11':
     728                  m.add_string(src_addr[0])
     729                  m.add_int(src_addr[1])
     730              chan = Channel(chanid)
     731              self._channels.put(chanid, chan)
     732              self.channel_events[chanid] = event = threading.Event()
     733              self.channels_seen[chanid] = True
     734              chan._set_transport(self)
     735              chan._set_window(self.window_size, self.max_packet_size)
     736          finally:
     737              self.lock.release()
     738          self._send_user_message(m)
     739          while True:
     740              event.wait(0.1);
     741              if not self.active:
     742                  e = self.get_exception()
     743                  if e is None:
     744                      e = SSHException('Unable to open channel.')
     745                  raise e
     746              if event.isSet():
     747                  break
     748          chan = self._channels.get(chanid)
     749          if chan is not None:
     750              return chan
     751          e = self.get_exception()
     752          if e is None:
     753              e = SSHException('Unable to open channel.')
     754          raise e
     755
     756 -    def request_port_forward(self, address, port, handler=None):
     757          """
     758          Ask the server to forward TCP connections from a listening port on
     759          the server, across this SSH session.
     760
     761          If a handler is given, that handler is called from a different thread
     762          whenever a forwarded connection arrives.  The handler parameters are::
     763
     764              handler(channel, (origin_addr, origin_port), (server_addr, server_port))
     765
     766          where C{server_addr} and C{server_port} are the address and port that
     767          the server was listening on.
     768
     769          If no handler is set, the default behavior is to send new incoming
     770          forwarded connections into the accept queue, to be picked up via
     771          L{accept}.
     772
     773          @param address: the address to bind when forwarding
     774          @type address: str
     775          @param port: the port to forward, or 0 to ask the server to allocate
     776              any port
     777          @type port: int
     778          @param handler: optional handler for incoming forwarded connections
     779          @type handler: function(Channel, (str, int), (str, int))
     780          @return: the port # allocated by the server
     781          @rtype: int
     782
     783          @raise SSHException: if the server refused the TCP forward request
     784          """
     785          if not self.active:
     786              raise SSHException('SSH session not active')
     787          address = str(address)
     788          port = int(port)
     789          response = self.global_request('tcpip-forward', (address, port), wait=True)
     790          if response is None:
     791              raise SSHException('TCP forwarding request denied')
     792          if port == 0:
     793              port = response.get_int()
     794          if handler is None:
     795              def default_handler(channel, (src_addr, src_port), (dest_addr, dest_port)):
     796                  self._queue_incoming_channel(channel)
     797              handler = default_handler
     798          self._tcp_handler = handler
     799          return port
     800
     801 -    def cancel_port_forward(self, address, port):
     802          """
     803          Ask the server to cancel a previous port-forwarding request.  No more
     804          connections to the given address & port will be forwarded across this
     805          ssh connection.
     806
     807          @param address: the address to stop forwarding
     808          @type address: str
     809          @param port: the port to stop forwarding
     810          @type port: int
     811          """
     812          if not self.active:
     813              return
     814          self._tcp_handler = None
     815          self.global_request('cancel-tcpip-forward', (address, port), wait=True)
     816
     817 -    def open_sftp_client(self):
     818          """
     819          Create an SFTP client channel from an open transport.  On success,
     820          an SFTP session will be opened with the remote host, and a new
     821          SFTPClient object will be returned.
     822
     823          @return: a new L{SFTPClient} object, referring to an sftp session
     824              (channel) across this transport
     825          @rtype: L{SFTPClient}
     826          """
     827          return SFTPClient.from_transport(self)
     828
     829 -    def send_ignore(self, bytes=None):
     830          """
     831          Send a junk packet across the encrypted link.  This is sometimes used
     832          to add "noise" to a connection to confuse would-be attackers.  It can
     833          also be used as a keep-alive for long lived connections traversing
     834          firewalls.
     835
     836          @param bytes: the number of random bytes to send in the payload of the
     837              ignored packet -- defaults to a random number from 10 to 41.
     838          @type bytes: int
     839          """
     840          m = Message()
     841          m.add_byte(chr(MSG_IGNORE))
     842          randpool.stir()
     843          if bytes is None:
     844              bytes = (ord(randpool.get_bytes(1)) % 32) + 10
     845          m.add_bytes(randpool.get_bytes(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          randpool.stir()
    1680          m = Message()
    1681          m.add_byte(chr(MSG_KEXINIT))
    1682          m.add_bytes(randpool.get_bytes(16))
    1683          m.add_list(self._preferred_kex)
    1684          m.add_list(available_server_keys)
    1685          m.add_list(self._preferred_ciphers)
    1686          m.add_list(self._preferred_ciphers)
    1687          m.add_list(self._preferred_macs)
    1688          m.add_list(self._preferred_macs)
    1689          m.add_list(self._preferred_compression)
    1690          m.add_list(self._preferred_compression)
    1691          m.add_string('')
    1692          m.add_string('')
    1693          m.add_boolean(False)
    1694          m.add_int(0)
    1695          # save a copy for later (needed to compute a hash)
    1696          self.local_kex_init = str(m)
    1697          self._send_message(m)
    1698
    1699 -    def _parse_kex_init(self, m):
    1700          cookie = m.get_bytes(16)
    1701          kex_algo_list = m.get_list()
    1702          server_key_algo_list = m.get_list()
    1703          client_encrypt_algo_list = m.get_list()
    1704          server_encrypt_algo_list = m.get_list()
    1705          client_mac_algo_list = m.get_list()
    1706          server_mac_algo_list = m.get_list()
    1707          client_compress_algo_list = m.get_list()
    1708          server_compress_algo_list = m.get_list()
    1709          client_lang_list = m.get_list()
    1710          server_lang_list = m.get_list()
    1711          kex_follows = m.get_boolean()
    1712          unused = m.get_int()
    1713
    1714          self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) + \
    1715                    ' client encrypt:' + str(client_encrypt_algo_list) + \
    1716                    ' server encrypt:' + str(server_encrypt_algo_list) + \
    1717                    ' client mac:' + str(client_mac_algo_list) + \
    1718                    ' server mac:' + str(server_mac_algo_list) + \
    1719                    ' client compress:' + str(client_compress_algo_list) + \
    1720                    ' server compress:' + str(server_compress_algo_list) + \
    1721                    ' client lang:' + str(client_lang_list) + \
    1722                    ' server lang:' + str(server_lang_list) + \
    1723                    ' kex follows?' + str(kex_follows))
    1724
    1725          # as a server, we pick the first item in the client's list that we support.
    1726          # as a client, we pick the first item in our list that the server supports.
    1727          if self.server_mode:
    1728              agreed_kex = filter(self._preferred_kex.__contains__, kex_algo_list)
    1729          else:
    1730              agreed_kex = filter(kex_algo_list.__contains__, self._preferred_kex)
    1731          if len(agreed_kex) == 0:
    1732              raise SSHException('Incompatible ssh peer (no acceptable kex algorithm)')
    1733          self.kex_engine = self._kex_info[agreed_kex[0]](self)
    1734
    1735          if self.server_mode:
    1736              available_server_keys = filter(self.server_key_dict.keys().__contains__,
    1737                                             self._preferred_keys)
    1738              agreed_keys = filter(available_server_keys.__contains__, server_key_algo_list)
    1739          else:
    1740              agreed_keys = filter(server_key_algo_list.__contains__, self._preferred_keys)
    1741          if len(agreed_keys) == 0:
    1742              raise SSHException('Incompatible ssh peer (no acceptable host key)')
    1743          self.host_key_type = agreed_keys[0]
    1744          if self.server_mode and (self.get_server_key() is None):
    1745              raise SSHException('Incompatible ssh peer (can\'t match requested host key type)')
    1746
    1747          if self.server_mode:
    1748              agreed_local_ciphers = filter(self._preferred_ciphers.__contains__,
    1749                                             server_encrypt_algo_list)
    1750              agreed_remote_ciphers = filter(self._preferred_ciphers.__contains__,
    1751                                            client_encrypt_algo_list)
    1752          else:
    1753              agreed_local_ciphers = filter(client_encrypt_algo_list.__contains__,
    1754                                            self._preferred_ciphers)
    1755              agreed_remote_ciphers = filter(server_encrypt_algo_list.__contains__,
    1756                                             self._preferred_ciphers)
    1757          if (len(agreed_local_ciphers) == 0) or (len(agreed_remote_ciphers) == 0):
    1758              raise SSHException('Incompatible ssh server (no acceptable ciphers)')
    1759          self.local_cipher = agreed_local_ciphers[0]
    1760          self.remote_cipher = agreed_remote_ciphers[0]
    1761          self._log(DEBUG, 'Ciphers agreed: local=%s, remote=%s' % (self.local_cipher, self.remote_cipher))
    1762
    1763          if self.server_mode:
    1764              agreed_remote_macs = filter(self._preferred_macs.__contains__, client_mac_algo_list)
    1765              agreed_local_macs = filter(self._preferred_macs.__contains__, server_mac_algo_list)
    1766          else:
    1767              agreed_local_macs = filter(client_mac_algo_list.__contains__, self._preferred_macs)
    1768              agreed_remote_macs = filter(server_mac_algo_list.__contains__, self._preferred_macs)
    1769          if (len(agreed_local_macs) == 0) or (len(agreed_remote_macs) == 0):
    1770              raise SSHException('Incompatible ssh server (no acceptable macs)')
    1771          self.local_mac = agreed_local_macs[0]
    1772          self.remote_mac = agreed_remote_macs[0]
    1773
    1774          if self.server_mode:
    1775              agreed_remote_compression = filter(self._preferred_compression.__contains__, client_compress_algo_list)
    1776              agreed_local_compression = filter(self._preferred_compression.__contains__, server_compress_algo_list)
    1777          else:
    1778              agreed_local_compression = filter(client_compress_algo_list.__contains__, self._preferred_compression)
    1779              agreed_remote_compression = filter(server_compress_algo_list.__contains__, self._preferred_compression)
    1780          if (len(agreed_local_compression) == 0) or (len(agreed_remote_compression) == 0):
    1781              raise SSHException('Incompatible ssh server (no acceptable compression) %r %r %r' % (agreed_local_compression, agreed_remote_compression, self._preferred_compression))
    1782          self.local_compression = agreed_local_compression[0]
    1783          self.remote_compression = agreed_remote_compression[0]
    1784
    1785          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' %
    1786                    (agreed_kex[0], self.host_key_type, self.local_cipher, self.remote_cipher, self.local_mac,
    1787                     self.remote_mac, self.local_compression, self.remote_compression))
    1788
    1789          # save for computing hash later...
    1790          # now wait!  openssh has a bug (and others might too) where there are
    1791          # actually some extra bytes (one NUL byte in openssh's case) added to
    1792          # the end of the packet but not parsed.  turns out we need to throw
    1793          # away those bytes because they aren't part of the hash.
    1794          self.remote_kex_init = chr(MSG_KEXINIT) + m.get_so_far()
    1795
    1796 -    def _activate_inbound(self):
    1797          "switch on newly negotiated encryption parameters for inbound traffic"
    1798          block_size = self._cipher_info[self.remote_cipher]['block-size']
    1799          if self.server_mode:
    1800              IV_in = self._compute_key('A', block_size)
    1801              key_in = self._compute_key('C', self._cipher_info[self.remote_cipher]['key-size'])
    1802          else:
    1803              IV_in = self._compute_key('B', block_size)
    1804              key_in = self._compute_key('D', self._cipher_info[self.remote_cipher]['key-size'])
    1805          engine = self._get_cipher(self.remote_cipher, key_in, IV_in)
    1806          mac_size = self._mac_info[self.remote_mac]['size']
    1807          mac_engine = self._mac_info[self.remote_mac]['class']
    1808          # initial mac keys are done in the hash's natural size (not the potentially truncated
    1809          # transmission size)
    1810          if self.server_mode:
    1811              mac_key = self._compute_key('E', mac_engine.digest_size)
    1812          else:
    1813              mac_key = self._compute_key('F', mac_engine.digest_size)
    1814          self.packetizer.set_inbound_cipher(engine, block_size, mac_engine, mac_size, mac_key)
    1815          compress_in = self._compression_info[self.remote_compression][1]
    1816          if (compress_in is not None) and ((self.remote_compression != 'zlib@openssh.com') or self.authenticated):
    1817              self._log(DEBUG, 'Switching on inbound compression ...')
    1818              self.packetizer.set_inbound_compressor(compress_in())
    1819
    1820 -    def _activate_outbound(self):
    1821          "switch on newly negotiated encryption parameters for outbound traffic"
    1822          m = Message()
    1823          m.add_byte(chr(MSG_NEWKEYS))
    1824          self._send_message(m)
    1825          block_size = self._cipher_info[self.local_cipher]['block-size']
    1826          if self.server_mode:
    1827              IV_out = self._compute_key('B', block_size)
    1828              key_out = self._compute_key('D', self._cipher_info[self.local_cipher]['key-size'])
    1829          else:
    1830              IV_out = self._compute_key('A', block_size)
    1831              key_out = self._compute_key('C', self._cipher_info[self.local_cipher]['key-size'])
    1832          engine = self._get_cipher(self.local_cipher, key_out, IV_out)
    1833          mac_size = self._mac_info[self.local_mac]['size']
    1834          mac_engine = self._mac_info[self.local_mac]['class']
    1835          # initial mac keys are done in the hash's natural size (not the potentially truncated
    1836          # transmission size)
    1837          if self.server_mode:
    1838              mac_key = self._compute_key('F', mac_engine.digest_size)
    1839          else:
    1840              mac_key = self._compute_key('E', mac_engine.digest_size)
    1841          self.packetizer.set_outbound_cipher(engine, block_size, mac_engine, mac_size, mac_key)
    1842          compress_out = self._compression_info[self.local_compression][0]
    1843          if (compress_out is not None) and ((self.local_compression != 'zlib@openssh.com') or self.authenticated):
    1844              self._log(DEBUG, 'Switching on outbound compression ...')
    1845              self.packetizer.set_outbound_compressor(compress_out())
    1846          if not self.packetizer.need_rekey():
    1847              self.in_kex = False
    1848          # we always expect to receive NEWKEYS now
    1849          self._expect_packet(MSG_NEWKEYS)
    1850
    1851 -    def _auth_trigger(self):
    1852          self.authenticated = True
    1853          # delayed initiation of compression
    1854          if self.local_compression == 'zlib@openssh.com':
    1855              compress_out = self._compression_info[self.local_compression][0]
    1856              self._log(DEBUG, 'Switching on outbound compression ...')
    1857              self.packetizer.set_outbound_compressor(compress_out())
    1858          if self.remote_compression == 'zlib@openssh.com':
    1859              compress_in = self._compression_info[self.remote_compression][1]
    1860              self._log(DEBUG, 'Switching on inbound compression ...')
    1861              self.packetizer.set_inbound_compressor(compress_in())
    1862
    1863 -    def _parse_newkeys(self, m):
    1864          self._log(DEBUG, 'Switch to new keys ...')
    1865          self._activate_inbound()
    1866          # can also free a bunch of stuff here
    1867          self.local_kex_init = self.remote_kex_init = None
    1868          self.K = None
    1869          self.kex_engine = None
    1870          if self.server_mode and (self.auth_handler is None):
    1871              # create auth handler for server mode
    1872              self.auth_handler = AuthHandler(self)
    1873          if not self.initial_kex_done:
    1874              # this was the first key exchange
    1875              self.initial_kex_done = True
    1876          # send an event?
    1877          if self.completion_event != None:
    1878              self.completion_event.set()
    1879          # it's now okay to send data again (if this was a re-key)
    1880          if not self.packetizer.need_rekey():
    1881              self.in_kex = False
    1882          self.clear_to_send_lock.acquire()
    1883          try:
    1884              self.clear_to_send.set()
    1885          finally:
    1886              self.clear_to_send_lock.release()
    1887          return
    1888
    1889 -    def _parse_disconnect(self, m):
    1890          code = m.get_int()
    1891          desc = m.get_string()
    1892          self._log(INFO, 'Disconnect (code %d): %s' % (code, desc))
    1893
    1894 -    def _parse_global_request(self, m):
    1895          kind = m.get_string()
    1896          self._log(DEBUG, 'Received global request "%s"' % kind)
    1897          want_reply = m.get_boolean()
    1898          if not self.server_mode:
    1899              self._log(DEBUG, 'Rejecting "%s" global request from server.' % kind)
    1900              ok = False
    1901          elif kind == 'tcpip-forward':
    1902              address = m.get_string()
    1903              port = m.get_int()
    1904              ok = self.server_object.check_port_forward_request(address, port)
    1905              if ok != False:
    1906                  ok = (ok,)
    1907          elif kind == 'cancel-tcpip-forward':
    1908              address = m.get_string()
    1909              port = m.get_int()
    1910              self.server_object.cancel_port_forward_request(address, port)
    1911              ok = True
    1912          else:
    1913              ok = self.server_object.check_global_request(kind, m)
    1914          extra = ()
    1915          if type(ok) is tuple:
    1916              extra = ok
    1917              ok = True
    1918          if want_reply:
    1919              msg = Message()
    1920              if ok:
    1921                  msg.add_byte(chr(MSG_REQUEST_SUCCESS))
    1922                  msg.add(*extra)
    1923              else:
    1924                  msg.add_byte(chr(MSG_REQUEST_FAILURE))
    1925              self._send_message(msg)
    1926
    1927 -    def _parse_request_success(self, m):
    1928          self._log(DEBUG, 'Global request successful.')
    1929          self.global_response = m
    1930          if self.completion_event is not None:
    1931              self.completion_event.set()
    1932
    1933 -    def _parse_request_failure(self, m):
    1934          self._log(DEBUG, 'Global request denied.')
    1935          self.global_response = None
    1936          if self.completion_event is not None:
    1937              self.completion_event.set()
    1938
    1939 -    def _parse_channel_open_success(self, m):
    1940          chanid = m.get_int()
    1941          server_chanid = m.get_int()
    1942          server_window_size = m.get_int()
    1943          server_max_packet_size = m.get_int()
    1944          chan = self._channels.get(chanid)
    1945          if chan is None:
    1946              self._log(WARNING, 'Success for unrequested channel! [??]')
    1947              return
    1948          self.lock.acquire()
    1949          try:
    1950              chan._set_remote_channel(server_chanid, server_window_size, server_max_packet_size)
    1951              self._log(INFO, 'Secsh channel %d opened.' % chanid)
    1952              if chanid in self.channel_events:
    1953                  self.channel_events[chanid].set()
    1954                  del self.channel_events[chanid]
    1955          finally:
    1956              self.lock.release()
    1957          return
    1958
    1959 -    def _parse_channel_open_failure(self, m):
    1960          chanid = m.get_int()
    1961          reason = m.get_int()
    1962          reason_str = m.get_string()
    1963          lang = m.get_string()
    1964          reason_text = CONNECTION_FAILED_CODE.get(reason, '(unknown code)')
    1965          self._log(INFO, 'Secsh channel %d open FAILED: %s: %s' % (chanid, reason_str, reason_text))
    1966          self.lock.acquire()
    1967          try:
    1968              self.saved_exception = ChannelException(reason, reason_text)
    1969              if chanid in self.channel_events:
    1970                  self._channels.delete(chanid)
    1971                  if chanid in self.channel_events:
    1972                      self.channel_events[chanid].set()
    1973                      del self.channel_events[chanid]
    1974          finally:
    1975              self.lock.release()
    1976          return
    1977
    1978 -    def _parse_channel_open(self, m):
    1979          kind = m.get_string()
    1980          chanid = m.get_int()
    1981          initial_window_size = m.get_int()
    1982          max_packet_size = m.get_int()
    1983          reject = False
    1984          if (kind == 'x11') and (self._x11_handler is not None):
    1985              origin_addr = m.get_string()
    1986              origin_port = m.get_int()
    1987              self._log(DEBUG, 'Incoming x11 connection from %s:%d' % (origin_addr, origin_port))
    1988              self.lock.acquire()
    1989              try:
    1990                  my_chanid = self._next_channel()
    1991              finally:
    1992                  self.lock.release()
    1993          elif (kind == 'forwarded-tcpip') and (self._tcp_handler is not None):
    1994              server_addr = m.get_string()
    1995              server_port = m.get_int()
    1996              origin_addr = m.get_string()
    1997              origin_port = m.get_int()
    1998              self._log(DEBUG, 'Incoming tcp forwarded connection from %s:%d' % (origin_addr, origin_port))
    1999              self.lock.acquire()
    2000              try:
    2001                  my_chanid = self._next_channel()
    2002              finally:
    2003                  self.lock.release()
    2004          elif not self.server_mode:
    2005              self._log(DEBUG, 'Rejecting "%s" channel request from server.' % kind)
    2006              reject = True
    2007              reason = OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
    2008          else:
    2009              self.lock.acquire()
    2010              try:
    2011                  my_chanid = self._next_channel()
    2012              finally:
    2013                  self.lock.release()
    2014              if kind == 'direct-tcpip':
    2015                  # handle direct-tcpip requests comming from the client
    2016                  dest_addr = m.get_string()
    2017                  dest_port = m.get_int()
    2018                  origin_addr = m.get_string()
    2019                  origin_port = m.get_int()
    2020                  reason = self.server_object.check_channel_direct_tcpip_request(
    2021                                  my_chanid, (origin_addr, origin_port),
    2022                                             (dest_addr, dest_port))
    2023              else:
    2024                  reason = self.server_object.check_channel_request(kind, my_chanid)
    2025              if reason != OPEN_SUCCEEDED:
    2026                  self._log(DEBUG, 'Rejecting "%s" channel request from client.' % kind)
    2027                  reject = True
    2028          if reject:
    2029              msg = Message()
    2030              msg.add_byte(chr(MSG_CHANNEL_OPEN_FAILURE))
    2031              msg.add_int(chanid)
    2032              msg.add_int(reason)
    2033              msg.add_string('')
    2034              msg.add_string('en')
    2035              self._send_message(msg)
    2036              return
    2037
    2038          chan = Channel(my_chanid)
    2039          self.lock.acquire()
    2040          try:
    2041              self._channels.put(my_chanid, chan)
    2042              self.channels_seen[my_chanid] = True
    2043              chan._set_transport(self)
    2044              chan._set_window(self.window_size, self.max_packet_size)
    2045              chan._set_remote_channel(chanid, initial_window_size, max_packet_size)
    2046          finally:
    2047              self.lock.release()
    2048          m = Message()
    2049          m.add_byte(chr(MSG_CHANNEL_OPEN_SUCCESS))
    2050          m.add_int(chanid)
    2051          m.add_int(my_chanid)
    2052          m.add_int(self.window_size)
    2053          m.add_int(self.max_packet_size)
    2054          self._send_message(m)
    2055          self._log(INFO, 'Secsh channel %d (%s) opened.', my_chanid, kind)
    2056          if kind == 'x11':
    2057              self._x11_handler(chan, (origin_addr, origin_port))
    2058          elif kind == 'forwarded-tcpip':
    2059              chan.origin_addr = (origin_addr, origin_port)
    2060              self._tcp_handler(chan, (origin_addr, origin_port), (server_addr, server_port))
    2061          else:
    2062              self._queue_incoming_channel(chan)
    2063
    2064 -    def _parse_debug(self, m):
    2065          always_display = m.get_boolean()
    2066          msg = m.get_string()
    2067          lang = m.get_string()
    2068          self._log(DEBUG, 'Debug msg: ' + util.safe_string(msg))
    2069
    2070 -    def _get_subsystem_handler(self, name):
    2071          try:
    2072              self.lock.acquire()
    2073              if name not in self.subsystem_table:
    2074                  return (None, [], {})
    2075              return self.subsystem_table[name]
    2076          finally:
    2077              self.lock.release()
    2078
    2079      _handler_table = {
    2080          MSG_NEWKEYS: _parse_newkeys,
    2081          MSG_GLOBAL_REQUEST: _parse_global_request,
    2082          MSG_REQUEST_SUCCESS: _parse_request_success,
    2083          MSG_REQUEST_FAILURE: _parse_request_failure,
    2084          MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success,
    2085          MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
    2086          MSG_CHANNEL_OPEN: _parse_channel_open,
    2087          MSG_KEXINIT: _negotiate_keys,
    2088          }
    2089
    2090      _channel_handler_table = {
    2091          MSG_CHANNEL_SUCCESS: Channel._request_success,
    2092          MSG_CHANNEL_FAILURE: Channel._request_failed,
    2093          MSG_CHANNEL_DATA: Channel._feed,
    2094          MSG_CHANNEL_EXTENDED_DATA: Channel._feed_extended,
    2095          MSG_CHANNEL_WINDOW_ADJUST: Channel._window_adjust,
    2096          MSG_CHANNEL_REQUEST: Channel._handle_request,
    2097          MSG_CHANNEL_EOF: Channel._handle_eof,
    2098          MSG_CHANNEL_CLOSE: Channel._handle_close,
    2099          }
    2100