From 1a716ed46d1d556d4ba6798608ab498320acd886 Mon Sep 17 00:00:00 2001 From: "Jeremy T. Bouse" Date: Sat, 25 May 2013 00:04:32 -0400 Subject: Imported Upstream version 1.10.1 --- docs/paramiko.transport-pysrc.html | 4153 ------------------------------------ 1 file changed, 4153 deletions(-) delete mode 100644 docs/paramiko.transport-pysrc.html (limited to 'docs/paramiko.transport-pysrc.html') diff --git a/docs/paramiko.transport-pysrc.html b/docs/paramiko.transport-pysrc.html deleted file mode 100644 index de00079..0000000 --- a/docs/paramiko.transport-pysrc.html +++ /dev/null @@ -1,4153 +0,0 @@ - - - - - paramiko.transport - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - Package paramiko :: - Module transport - - - - - -
[frames] | no frames]
-
-

Source Code for Module paramiko.transport

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