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