Coverage for /pythoncovmergedfiles/medio/medio/src/paramiko/paramiko/transport.py: 15%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1430 statements  

1# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com> 

2# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com> 

3# 

4# This file is part of paramiko. 

5# 

6# Paramiko is free software; you can redistribute it and/or modify it under the 

7# terms of the GNU Lesser General Public License as published by the Free 

8# Software Foundation; either version 2.1 of the License, or (at your option) 

9# any later version. 

10# 

11# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY 

12# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 

13# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 

14# details. 

15# 

16# You should have received a copy of the GNU Lesser General Public License 

17# along with Paramiko; if not, write to the Free Software Foundation, Inc., 

18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 

19 

20""" 

21Core protocol implementation 

22""" 

23 

24import os 

25import socket 

26import sys 

27import threading 

28import time 

29import weakref 

30from hashlib import md5, sha1, sha256, sha512 

31 

32from cryptography.hazmat.backends import default_backend 

33from cryptography.hazmat.primitives.ciphers import ( 

34 algorithms, 

35 Cipher, 

36 modes, 

37 aead, 

38) 

39 

40import paramiko 

41from paramiko import util 

42from paramiko.auth_handler import AuthHandler, AuthOnlyHandler 

43from paramiko.ssh_gss import GSSAuth 

44from paramiko.channel import Channel 

45from paramiko.common import ( 

46 xffffffff, 

47 cMSG_CHANNEL_OPEN, 

48 cMSG_IGNORE, 

49 cMSG_GLOBAL_REQUEST, 

50 DEBUG, 

51 MSG_KEXINIT, 

52 MSG_IGNORE, 

53 MSG_DISCONNECT, 

54 MSG_DEBUG, 

55 ERROR, 

56 WARNING, 

57 cMSG_UNIMPLEMENTED, 

58 INFO, 

59 cMSG_KEXINIT, 

60 cMSG_NEWKEYS, 

61 MSG_NEWKEYS, 

62 cMSG_REQUEST_SUCCESS, 

63 cMSG_REQUEST_FAILURE, 

64 CONNECTION_FAILED_CODE, 

65 OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, 

66 OPEN_SUCCEEDED, 

67 cMSG_CHANNEL_OPEN_FAILURE, 

68 cMSG_CHANNEL_OPEN_SUCCESS, 

69 MSG_GLOBAL_REQUEST, 

70 MSG_REQUEST_SUCCESS, 

71 MSG_REQUEST_FAILURE, 

72 cMSG_SERVICE_REQUEST, 

73 MSG_SERVICE_ACCEPT, 

74 MSG_CHANNEL_OPEN_SUCCESS, 

75 MSG_CHANNEL_OPEN_FAILURE, 

76 MSG_CHANNEL_OPEN, 

77 MSG_CHANNEL_SUCCESS, 

78 MSG_CHANNEL_FAILURE, 

79 MSG_CHANNEL_DATA, 

80 MSG_CHANNEL_EXTENDED_DATA, 

81 MSG_CHANNEL_WINDOW_ADJUST, 

82 MSG_CHANNEL_REQUEST, 

83 MSG_CHANNEL_EOF, 

84 MSG_CHANNEL_CLOSE, 

85 MIN_WINDOW_SIZE, 

86 MIN_PACKET_SIZE, 

87 MAX_WINDOW_SIZE, 

88 DEFAULT_WINDOW_SIZE, 

89 DEFAULT_MAX_PACKET_SIZE, 

90 HIGHEST_USERAUTH_MESSAGE_ID, 

91 MSG_UNIMPLEMENTED, 

92 MSG_NAMES, 

93 MSG_EXT_INFO, 

94 cMSG_EXT_INFO, 

95 byte_ord, 

96) 

97from paramiko.compress import ZlibCompressor, ZlibDecompressor 

98from paramiko.dsskey import DSSKey 

99from paramiko.ed25519key import Ed25519Key 

100from paramiko.kex_curve25519 import KexCurve25519 

101from paramiko.kex_gex import KexGex, KexGexSHA256 

102from paramiko.kex_group1 import KexGroup1 

103from paramiko.kex_group14 import KexGroup14, KexGroup14SHA256 

104from paramiko.kex_group16 import KexGroup16SHA512 

105from paramiko.kex_ecdh_nist import KexNistp256, KexNistp384, KexNistp521 

106from paramiko.kex_gss import KexGSSGex, KexGSSGroup1, KexGSSGroup14 

107from paramiko.message import Message 

108from paramiko.packet import Packetizer, NeedRekeyException 

109from paramiko.primes import ModulusPack 

110from paramiko.rsakey import RSAKey 

111from paramiko.ecdsakey import ECDSAKey 

112from paramiko.server import ServerInterface 

113from paramiko.sftp_client import SFTPClient 

114from paramiko.ssh_exception import ( 

115 BadAuthenticationType, 

116 ChannelException, 

117 IncompatiblePeer, 

118 MessageOrderError, 

119 ProxyCommandFailure, 

120 SSHException, 

121) 

122from paramiko.util import ( 

123 ClosingContextManager, 

124 clamp_value, 

125 b, 

126) 

127 

128 

129# TripleDES is moving from `cryptography.hazmat.primitives.ciphers.algorithms` 

130# in cryptography>=43.0.0 to `cryptography.hazmat.decrepit.ciphers.algorithms` 

131# It will be removed from `cryptography.hazmat.primitives.ciphers.algorithms` 

132# in cryptography==48.0.0. 

133# 

134# Source References: 

135# - https://github.com/pyca/cryptography/commit/722a6393e61b3ac 

136# - https://github.com/pyca/cryptography/pull/11407/files 

137try: 

138 from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES 

139except ImportError: 

140 from cryptography.hazmat.primitives.ciphers.algorithms import TripleDES 

141 

142 

143# for thread cleanup 

144_active_threads = [] 

145 

146 

147def _join_lingering_threads(): 

148 for thr in _active_threads: 

149 thr.stop_thread() 

150 

151 

152import atexit 

153 

154atexit.register(_join_lingering_threads) 

155 

156 

157class Transport(threading.Thread, ClosingContextManager): 

158 """ 

159 An SSH Transport attaches to a stream (usually a socket), negotiates an 

160 encrypted session, authenticates, and then creates stream tunnels, called 

161 `channels <.Channel>`, across the session. Multiple channels can be 

162 multiplexed across a single session (and often are, in the case of port 

163 forwardings). 

164 

165 Instances of this class may be used as context managers. 

166 """ 

167 

168 _ENCRYPT = object() 

169 _DECRYPT = object() 

170 

171 _PROTO_ID = "2.0" 

172 _CLIENT_ID = "paramiko_{}".format(paramiko.__version__) 

173 

174 # These tuples of algorithm identifiers are in preference order; do not 

175 # reorder without reason! 

176 # NOTE: if you need to modify these, we suggest leveraging the 

177 # `disabled_algorithms` constructor argument (also available in SSHClient) 

178 # instead of monkeypatching or subclassing. 

179 _preferred_ciphers = ( 

180 "aes128-ctr", 

181 "aes192-ctr", 

182 "aes256-ctr", 

183 "aes128-cbc", 

184 "aes192-cbc", 

185 "aes256-cbc", 

186 "3des-cbc", 

187 "aes128-gcm@openssh.com", 

188 "aes256-gcm@openssh.com", 

189 ) 

190 _preferred_macs = ( 

191 "hmac-sha2-256", 

192 "hmac-sha2-512", 

193 "hmac-sha2-256-etm@openssh.com", 

194 "hmac-sha2-512-etm@openssh.com", 

195 "hmac-sha1", 

196 "hmac-md5", 

197 "hmac-sha1-96", 

198 "hmac-md5-96", 

199 ) 

200 # ~= HostKeyAlgorithms in OpenSSH land 

201 _preferred_keys = ( 

202 "ssh-ed25519", 

203 "ecdsa-sha2-nistp256", 

204 "ecdsa-sha2-nistp384", 

205 "ecdsa-sha2-nistp521", 

206 "rsa-sha2-512", 

207 "rsa-sha2-256", 

208 "ssh-rsa", 

209 "ssh-dss", 

210 ) 

211 # ~= PubKeyAcceptedAlgorithms 

212 _preferred_pubkeys = ( 

213 "ssh-ed25519", 

214 "ecdsa-sha2-nistp256", 

215 "ecdsa-sha2-nistp384", 

216 "ecdsa-sha2-nistp521", 

217 "rsa-sha2-512", 

218 "rsa-sha2-256", 

219 "ssh-rsa", 

220 "ssh-dss", 

221 ) 

222 _preferred_kex = ( 

223 "ecdh-sha2-nistp256", 

224 "ecdh-sha2-nistp384", 

225 "ecdh-sha2-nistp521", 

226 "diffie-hellman-group16-sha512", 

227 "diffie-hellman-group-exchange-sha256", 

228 "diffie-hellman-group14-sha256", 

229 "diffie-hellman-group-exchange-sha1", 

230 "diffie-hellman-group14-sha1", 

231 "diffie-hellman-group1-sha1", 

232 ) 

233 if KexCurve25519.is_available(): 

234 _preferred_kex = ("curve25519-sha256@libssh.org",) + _preferred_kex 

235 _preferred_gsskex = ( 

236 "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==", 

237 "gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==", 

238 "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==", 

239 ) 

240 _preferred_compression = ("none",) 

241 

242 _cipher_info = { 

243 "aes128-ctr": { 

244 "class": algorithms.AES, 

245 "mode": modes.CTR, 

246 "block-size": 16, 

247 "key-size": 16, 

248 }, 

249 "aes192-ctr": { 

250 "class": algorithms.AES, 

251 "mode": modes.CTR, 

252 "block-size": 16, 

253 "key-size": 24, 

254 }, 

255 "aes256-ctr": { 

256 "class": algorithms.AES, 

257 "mode": modes.CTR, 

258 "block-size": 16, 

259 "key-size": 32, 

260 }, 

261 "aes128-cbc": { 

262 "class": algorithms.AES, 

263 "mode": modes.CBC, 

264 "block-size": 16, 

265 "key-size": 16, 

266 }, 

267 "aes192-cbc": { 

268 "class": algorithms.AES, 

269 "mode": modes.CBC, 

270 "block-size": 16, 

271 "key-size": 24, 

272 }, 

273 "aes256-cbc": { 

274 "class": algorithms.AES, 

275 "mode": modes.CBC, 

276 "block-size": 16, 

277 "key-size": 32, 

278 }, 

279 "3des-cbc": { 

280 "class": TripleDES, 

281 "mode": modes.CBC, 

282 "block-size": 8, 

283 "key-size": 24, 

284 }, 

285 "aes128-gcm@openssh.com": { 

286 "class": aead.AESGCM, 

287 "block-size": 16, 

288 "iv-size": 12, 

289 "key-size": 16, 

290 "is_aead": True, 

291 }, 

292 "aes256-gcm@openssh.com": { 

293 "class": aead.AESGCM, 

294 "block-size": 16, 

295 "iv-size": 12, 

296 "key-size": 32, 

297 "is_aead": True, 

298 }, 

299 } 

300 

301 _mac_info = { 

302 "hmac-sha1": {"class": sha1, "size": 20}, 

303 "hmac-sha1-96": {"class": sha1, "size": 12}, 

304 "hmac-sha2-256": {"class": sha256, "size": 32}, 

305 "hmac-sha2-256-etm@openssh.com": {"class": sha256, "size": 32}, 

306 "hmac-sha2-512": {"class": sha512, "size": 64}, 

307 "hmac-sha2-512-etm@openssh.com": {"class": sha512, "size": 64}, 

308 "hmac-md5": {"class": md5, "size": 16}, 

309 "hmac-md5-96": {"class": md5, "size": 12}, 

310 } 

311 

312 _key_info = { 

313 # TODO: at some point we will want to drop this as it's no longer 

314 # considered secure due to using SHA-1 for signatures. OpenSSH 8.8 no 

315 # longer supports it. Question becomes at what point do we want to 

316 # prevent users with older setups from using this? 

317 "ssh-rsa": RSAKey, 

318 "ssh-rsa-cert-v01@openssh.com": RSAKey, 

319 "rsa-sha2-256": RSAKey, 

320 "rsa-sha2-256-cert-v01@openssh.com": RSAKey, 

321 "rsa-sha2-512": RSAKey, 

322 "rsa-sha2-512-cert-v01@openssh.com": RSAKey, 

323 "ssh-dss": DSSKey, 

324 "ssh-dss-cert-v01@openssh.com": DSSKey, 

325 "ecdsa-sha2-nistp256": ECDSAKey, 

326 "ecdsa-sha2-nistp256-cert-v01@openssh.com": ECDSAKey, 

327 "ecdsa-sha2-nistp384": ECDSAKey, 

328 "ecdsa-sha2-nistp384-cert-v01@openssh.com": ECDSAKey, 

329 "ecdsa-sha2-nistp521": ECDSAKey, 

330 "ecdsa-sha2-nistp521-cert-v01@openssh.com": ECDSAKey, 

331 "ssh-ed25519": Ed25519Key, 

332 "ssh-ed25519-cert-v01@openssh.com": Ed25519Key, 

333 } 

334 

335 _kex_info = { 

336 "diffie-hellman-group1-sha1": KexGroup1, 

337 "diffie-hellman-group14-sha1": KexGroup14, 

338 "diffie-hellman-group-exchange-sha1": KexGex, 

339 "diffie-hellman-group-exchange-sha256": KexGexSHA256, 

340 "diffie-hellman-group14-sha256": KexGroup14SHA256, 

341 "diffie-hellman-group16-sha512": KexGroup16SHA512, 

342 "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==": KexGSSGroup1, 

343 "gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==": KexGSSGroup14, 

344 "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==": KexGSSGex, 

345 "ecdh-sha2-nistp256": KexNistp256, 

346 "ecdh-sha2-nistp384": KexNistp384, 

347 "ecdh-sha2-nistp521": KexNistp521, 

348 } 

349 if KexCurve25519.is_available(): 

350 _kex_info["curve25519-sha256@libssh.org"] = KexCurve25519 

351 

352 _compression_info = { 

353 # zlib@openssh.com is just zlib, but only turned on after a successful 

354 # authentication. openssh servers may only offer this type because 

355 # they've had troubles with security holes in zlib in the past. 

356 "zlib@openssh.com": (ZlibCompressor, ZlibDecompressor), 

357 "zlib": (ZlibCompressor, ZlibDecompressor), 

358 "none": (None, None), 

359 } 

360 

361 _modulus_pack = None 

362 _active_check_timeout = 0.1 

363 

364 def __init__( 

365 self, 

366 sock, 

367 default_window_size=DEFAULT_WINDOW_SIZE, 

368 default_max_packet_size=DEFAULT_MAX_PACKET_SIZE, 

369 gss_kex=False, 

370 gss_deleg_creds=True, 

371 disabled_algorithms=None, 

372 server_sig_algs=True, 

373 strict_kex=True, 

374 packetizer_class=None, 

375 ): 

376 """ 

377 Create a new SSH session over an existing socket, or socket-like 

378 object. This only creates the `.Transport` object; it doesn't begin 

379 the SSH session yet. Use `connect` or `start_client` to begin a client 

380 session, or `start_server` to begin a server session. 

381 

382 If the object is not actually a socket, it must have the following 

383 methods: 

384 

385 - ``send(bytes)``: Writes from 1 to ``len(bytes)`` bytes, and returns 

386 an int representing the number of bytes written. Returns 

387 0 or raises ``EOFError`` if the stream has been closed. 

388 - ``recv(int)``: Reads from 1 to ``int`` bytes and returns them as a 

389 string. Returns 0 or raises ``EOFError`` if the stream has been 

390 closed. 

391 - ``close()``: Closes the socket. 

392 - ``settimeout(n)``: Sets a (float) timeout on I/O operations. 

393 

394 For ease of use, you may also pass in an address (as a tuple) or a host 

395 string as the ``sock`` argument. (A host string is a hostname with an 

396 optional port (separated by ``":"``) which will be converted into a 

397 tuple of ``(hostname, port)``.) A socket will be connected to this 

398 address and used for communication. Exceptions from the ``socket`` 

399 call may be thrown in this case. 

400 

401 .. note:: 

402 Modifying the the window and packet sizes might have adverse 

403 effects on your channels created from this transport. The default 

404 values are the same as in the OpenSSH code base and have been 

405 battle tested. 

406 

407 :param socket sock: 

408 a socket or socket-like object to create the session over. 

409 :param int default_window_size: 

410 sets the default window size on the transport. (defaults to 

411 2097152) 

412 :param int default_max_packet_size: 

413 sets the default max packet size on the transport. (defaults to 

414 32768) 

415 :param bool gss_kex: 

416 Whether to enable GSSAPI key exchange when GSSAPI is in play. 

417 Default: ``False``. 

418 :param bool gss_deleg_creds: 

419 Whether to enable GSSAPI credential delegation when GSSAPI is in 

420 play. Default: ``True``. 

421 :param dict disabled_algorithms: 

422 If given, must be a dictionary mapping algorithm type to an 

423 iterable of algorithm identifiers, which will be disabled for the 

424 lifetime of the transport. 

425 

426 Keys should match the last word in the class' builtin algorithm 

427 tuple attributes, such as ``"ciphers"`` to disable names within 

428 ``_preferred_ciphers``; or ``"kex"`` to disable something defined 

429 inside ``_preferred_kex``. Values should exactly match members of 

430 the matching attribute. 

431 

432 For example, if you need to disable 

433 ``diffie-hellman-group16-sha512`` key exchange (perhaps because 

434 your code talks to a server which implements it differently from 

435 Paramiko), specify ``disabled_algorithms={"kex": 

436 ["diffie-hellman-group16-sha512"]}``. 

437 :param bool server_sig_algs: 

438 Whether to send an extra message to compatible clients, in server 

439 mode, with a list of supported pubkey algorithms. Default: 

440 ``True``. 

441 :param bool strict_kex: 

442 Whether to advertise (and implement, if client also advertises 

443 support for) a "strict kex" mode for safer handshaking. Default: 

444 ``True``. 

445 :param packetizer_class: 

446 Which class to use for instantiating the internal packet handler. 

447 Default: ``None`` (i.e.: use `Packetizer` as normal). 

448 

449 .. versionchanged:: 1.15 

450 Added the ``default_window_size`` and ``default_max_packet_size`` 

451 arguments. 

452 .. versionchanged:: 1.15 

453 Added the ``gss_kex`` and ``gss_deleg_creds`` kwargs. 

454 .. versionchanged:: 2.6 

455 Added the ``disabled_algorithms`` kwarg. 

456 .. versionchanged:: 2.9 

457 Added the ``server_sig_algs`` kwarg. 

458 .. versionchanged:: 3.4 

459 Added the ``strict_kex`` kwarg. 

460 .. versionchanged:: 3.4 

461 Added the ``packetizer_class`` kwarg. 

462 """ 

463 self.active = False 

464 self.hostname = None 

465 self.server_extensions = {} 

466 self.advertise_strict_kex = strict_kex 

467 self.agreed_on_strict_kex = False 

468 

469 # TODO: these two overrides on sock's type should go away sometime, too 

470 # many ways to do it! 

471 if isinstance(sock, str): 

472 # convert "host:port" into (host, port) 

473 hl = sock.split(":", 1) 

474 self.hostname = hl[0] 

475 if len(hl) == 1: 

476 sock = (hl[0], 22) 

477 else: 

478 sock = (hl[0], int(hl[1])) 

479 if type(sock) is tuple: 

480 # connect to the given (host, port) 

481 hostname, port = sock 

482 self.hostname = hostname 

483 reason = "No suitable address family" 

484 addrinfos = socket.getaddrinfo( 

485 hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM 

486 ) 

487 for family, socktype, proto, canonname, sockaddr in addrinfos: 

488 if socktype == socket.SOCK_STREAM: 

489 af = family 

490 # addr = sockaddr 

491 sock = socket.socket(af, socket.SOCK_STREAM) 

492 try: 

493 sock.connect((hostname, port)) 

494 except socket.error as e: 

495 reason = str(e) 

496 else: 

497 break 

498 else: 

499 raise SSHException( 

500 "Unable to connect to {}: {}".format(hostname, reason) 

501 ) 

502 # okay, normal socket-ish flow here... 

503 threading.Thread.__init__(self) 

504 self.daemon = True 

505 self.sock = sock 

506 # we set the timeout so we can check self.active periodically to 

507 # see if we should bail. socket.timeout exception is never propagated. 

508 self.sock.settimeout(self._active_check_timeout) 

509 

510 # negotiated crypto parameters 

511 self.packetizer = (packetizer_class or Packetizer)(sock) 

512 self.local_version = "SSH-" + self._PROTO_ID + "-" + self._CLIENT_ID 

513 self.remote_version = "" 

514 self.local_cipher = self.remote_cipher = "" 

515 self.local_kex_init = self.remote_kex_init = None 

516 self.local_mac = self.remote_mac = None 

517 self.local_compression = self.remote_compression = None 

518 self.session_id = None 

519 self.host_key_type = None 

520 self.host_key = None 

521 

522 # GSS-API / SSPI Key Exchange 

523 self.use_gss_kex = gss_kex 

524 # This will be set to True if GSS-API Key Exchange was performed 

525 self.gss_kex_used = False 

526 self.kexgss_ctxt = None 

527 self.gss_host = None 

528 if self.use_gss_kex: 

529 self.kexgss_ctxt = GSSAuth("gssapi-keyex", gss_deleg_creds) 

530 self._preferred_kex = self._preferred_gsskex + self._preferred_kex 

531 

532 # state used during negotiation 

533 self.kex_engine = None 

534 self.H = None 

535 self.K = None 

536 

537 self.initial_kex_done = False 

538 self.in_kex = False 

539 self.authenticated = False 

540 self._expected_packet = tuple() 

541 # synchronization (always higher level than write_lock) 

542 self.lock = threading.Lock() 

543 

544 # tracking open channels 

545 self._channels = ChannelMap() 

546 self.channel_events = {} # (id -> Event) 

547 self.channels_seen = {} # (id -> True) 

548 self._channel_counter = 0 

549 self.default_max_packet_size = default_max_packet_size 

550 self.default_window_size = default_window_size 

551 self._forward_agent_handler = None 

552 self._x11_handler = None 

553 self._tcp_handler = None 

554 

555 self.saved_exception = None 

556 self.clear_to_send = threading.Event() 

557 self.clear_to_send_lock = threading.Lock() 

558 self.clear_to_send_timeout = 30.0 

559 self.log_name = "paramiko.transport" 

560 self.logger = util.get_logger(self.log_name) 

561 self.packetizer.set_log(self.logger) 

562 self.auth_handler = None 

563 # response Message from an arbitrary global request 

564 self.global_response = None 

565 # user-defined event callbacks 

566 self.completion_event = None 

567 # how long (seconds) to wait for the SSH banner 

568 self.banner_timeout = 15 

569 # how long (seconds) to wait for the handshake to finish after SSH 

570 # banner sent. 

571 self.handshake_timeout = 15 

572 # how long (seconds) to wait for the auth response. 

573 self.auth_timeout = 30 

574 # how long (seconds) to wait for opening a channel 

575 self.channel_timeout = 60 * 60 

576 self.disabled_algorithms = disabled_algorithms or {} 

577 self.server_sig_algs = server_sig_algs 

578 

579 # server mode: 

580 self.server_mode = False 

581 self.server_object = None 

582 self.server_key_dict = {} 

583 self.server_accepts = [] 

584 self.server_accept_cv = threading.Condition(self.lock) 

585 self.subsystem_table = {} 

586 

587 # Handler table, now set at init time for easier per-instance 

588 # manipulation and subclass twiddling. 

589 self._handler_table = { 

590 MSG_EXT_INFO: self._parse_ext_info, 

591 MSG_NEWKEYS: self._parse_newkeys, 

592 MSG_GLOBAL_REQUEST: self._parse_global_request, 

593 MSG_REQUEST_SUCCESS: self._parse_request_success, 

594 MSG_REQUEST_FAILURE: self._parse_request_failure, 

595 MSG_CHANNEL_OPEN_SUCCESS: self._parse_channel_open_success, 

596 MSG_CHANNEL_OPEN_FAILURE: self._parse_channel_open_failure, 

597 MSG_CHANNEL_OPEN: self._parse_channel_open, 

598 MSG_KEXINIT: self._negotiate_keys, 

599 } 

600 

601 def _filter_algorithm(self, type_): 

602 default = getattr(self, "_preferred_{}".format(type_)) 

603 return tuple( 

604 x 

605 for x in default 

606 if x not in self.disabled_algorithms.get(type_, []) 

607 ) 

608 

609 @property 

610 def preferred_ciphers(self): 

611 return self._filter_algorithm("ciphers") 

612 

613 @property 

614 def preferred_macs(self): 

615 return self._filter_algorithm("macs") 

616 

617 @property 

618 def preferred_keys(self): 

619 # Interleave cert variants here; resistant to various background 

620 # overwriting of _preferred_keys, and necessary as hostkeys can't use 

621 # the logic pubkey auth does re: injecting/checking for certs at 

622 # runtime 

623 filtered = self._filter_algorithm("keys") 

624 return tuple( 

625 filtered 

626 + tuple("{}-cert-v01@openssh.com".format(x) for x in filtered) 

627 ) 

628 

629 @property 

630 def preferred_pubkeys(self): 

631 return self._filter_algorithm("pubkeys") 

632 

633 @property 

634 def preferred_kex(self): 

635 return self._filter_algorithm("kex") 

636 

637 @property 

638 def preferred_compression(self): 

639 return self._filter_algorithm("compression") 

640 

641 def __repr__(self): 

642 """ 

643 Returns a string representation of this object, for debugging. 

644 """ 

645 id_ = hex(id(self) & xffffffff) 

646 out = "<paramiko.Transport at {}".format(id_) 

647 if not self.active: 

648 out += " (unconnected)" 

649 else: 

650 if self.local_cipher != "": 

651 out += " (cipher {}, {:d} bits)".format( 

652 self.local_cipher, 

653 self._cipher_info[self.local_cipher]["key-size"] * 8, 

654 ) 

655 if self.is_authenticated(): 

656 out += " (active; {} open channel(s))".format( 

657 len(self._channels) 

658 ) 

659 elif self.initial_kex_done: 

660 out += " (connected; awaiting auth)" 

661 else: 

662 out += " (connecting)" 

663 out += ">" 

664 return out 

665 

666 def atfork(self): 

667 """ 

668 Terminate this Transport without closing the session. On posix 

669 systems, if a Transport is open during process forking, both parent 

670 and child will share the underlying socket, but only one process can 

671 use the connection (without corrupting the session). Use this method 

672 to clean up a Transport object without disrupting the other process. 

673 

674 .. versionadded:: 1.5.3 

675 """ 

676 self.sock.close() 

677 self.close() 

678 

679 def get_security_options(self): 

680 """ 

681 Return a `.SecurityOptions` object which can be used to tweak the 

682 encryption algorithms this transport will permit (for encryption, 

683 digest/hash operations, public keys, and key exchanges) and the order 

684 of preference for them. 

685 """ 

686 return SecurityOptions(self) 

687 

688 def set_gss_host(self, gss_host, trust_dns=True, gssapi_requested=True): 

689 """ 

690 Normalize/canonicalize ``self.gss_host`` depending on various factors. 

691 

692 :param str gss_host: 

693 The explicitly requested GSS-oriented hostname to connect to (i.e. 

694 what the host's name is in the Kerberos database.) Defaults to 

695 ``self.hostname`` (which will be the 'real' target hostname and/or 

696 host portion of given socket object.) 

697 :param bool trust_dns: 

698 Indicates whether or not DNS is trusted; if true, DNS will be used 

699 to canonicalize the GSS hostname (which again will either be 

700 ``gss_host`` or the transport's default hostname.) 

701 (Defaults to True due to backwards compatibility.) 

702 :param bool gssapi_requested: 

703 Whether GSSAPI key exchange or authentication was even requested. 

704 If not, this is a no-op and nothing happens 

705 (and ``self.gss_host`` is not set.) 

706 (Defaults to True due to backwards compatibility.) 

707 :returns: ``None``. 

708 """ 

709 # No GSSAPI in play == nothing to do 

710 if not gssapi_requested: 

711 return 

712 # Obtain the correct host first - did user request a GSS-specific name 

713 # to use that is distinct from the actual SSH target hostname? 

714 if gss_host is None: 

715 gss_host = self.hostname 

716 # Finally, canonicalize via DNS if DNS is trusted. 

717 if trust_dns and gss_host is not None: 

718 gss_host = socket.getfqdn(gss_host) 

719 # And set attribute for reference later. 

720 self.gss_host = gss_host 

721 

722 def start_client(self, event=None, timeout=None): 

723 """ 

724 Negotiate a new SSH2 session as a client. This is the first step after 

725 creating a new `.Transport`. A separate thread is created for protocol 

726 negotiation. 

727 

728 If an event is passed in, this method returns immediately. When 

729 negotiation is done (successful or not), the given ``Event`` will 

730 be triggered. On failure, `is_active` will return ``False``. 

731 

732 (Since 1.4) If ``event`` is ``None``, this method will not return until 

733 negotiation is done. On success, the method returns normally. 

734 Otherwise an SSHException is raised. 

735 

736 After a successful negotiation, you will usually want to authenticate, 

737 calling `auth_password <Transport.auth_password>` or 

738 `auth_publickey <Transport.auth_publickey>`. 

739 

740 .. note:: `connect` is a simpler method for connecting as a client. 

741 

742 .. note:: 

743 After calling this method (or `start_server` or `connect`), you 

744 should no longer directly read from or write to the original socket 

745 object. 

746 

747 :param .threading.Event event: 

748 an event to trigger when negotiation is complete (optional) 

749 

750 :param float timeout: 

751 a timeout, in seconds, for SSH2 session negotiation (optional) 

752 

753 :raises: 

754 `.SSHException` -- if negotiation fails (and no ``event`` was 

755 passed in) 

756 """ 

757 self.active = True 

758 if event is not None: 

759 # async, return immediately and let the app poll for completion 

760 self.completion_event = event 

761 self.start() 

762 return 

763 

764 # synchronous, wait for a result 

765 self.completion_event = event = threading.Event() 

766 self.start() 

767 max_time = time.time() + timeout if timeout is not None else None 

768 while True: 

769 event.wait(0.1) 

770 if not self.active: 

771 e = self.get_exception() 

772 if e is not None: 

773 raise e 

774 raise SSHException("Negotiation failed.") 

775 if event.is_set() or ( 

776 timeout is not None and time.time() >= max_time 

777 ): 

778 break 

779 

780 def start_server(self, event=None, server=None): 

781 """ 

782 Negotiate a new SSH2 session as a server. This is the first step after 

783 creating a new `.Transport` and setting up your server host key(s). A 

784 separate thread is created for protocol negotiation. 

785 

786 If an event is passed in, this method returns immediately. When 

787 negotiation is done (successful or not), the given ``Event`` will 

788 be triggered. On failure, `is_active` will return ``False``. 

789 

790 (Since 1.4) If ``event`` is ``None``, this method will not return until 

791 negotiation is done. On success, the method returns normally. 

792 Otherwise an SSHException is raised. 

793 

794 After a successful negotiation, the client will need to authenticate. 

795 Override the methods `get_allowed_auths 

796 <.ServerInterface.get_allowed_auths>`, `check_auth_none 

797 <.ServerInterface.check_auth_none>`, `check_auth_password 

798 <.ServerInterface.check_auth_password>`, and `check_auth_publickey 

799 <.ServerInterface.check_auth_publickey>` in the given ``server`` object 

800 to control the authentication process. 

801 

802 After a successful authentication, the client should request to open a 

803 channel. Override `check_channel_request 

804 <.ServerInterface.check_channel_request>` in the given ``server`` 

805 object to allow channels to be opened. 

806 

807 .. note:: 

808 After calling this method (or `start_client` or `connect`), you 

809 should no longer directly read from or write to the original socket 

810 object. 

811 

812 :param .threading.Event event: 

813 an event to trigger when negotiation is complete. 

814 :param .ServerInterface server: 

815 an object used to perform authentication and create `channels 

816 <.Channel>` 

817 

818 :raises: 

819 `.SSHException` -- if negotiation fails (and no ``event`` was 

820 passed in) 

821 """ 

822 if server is None: 

823 server = ServerInterface() 

824 self.server_mode = True 

825 self.server_object = server 

826 self.active = True 

827 if event is not None: 

828 # async, return immediately and let the app poll for completion 

829 self.completion_event = event 

830 self.start() 

831 return 

832 

833 # synchronous, wait for a result 

834 self.completion_event = event = threading.Event() 

835 self.start() 

836 while True: 

837 event.wait(0.1) 

838 if not self.active: 

839 e = self.get_exception() 

840 if e is not None: 

841 raise e 

842 raise SSHException("Negotiation failed.") 

843 if event.is_set(): 

844 break 

845 

846 def add_server_key(self, key): 

847 """ 

848 Add a host key to the list of keys used for server mode. When behaving 

849 as a server, the host key is used to sign certain packets during the 

850 SSH2 negotiation, so that the client can trust that we are who we say 

851 we are. Because this is used for signing, the key must contain private 

852 key info, not just the public half. Only one key of each type (RSA or 

853 DSS) is kept. 

854 

855 :param .PKey key: 

856 the host key to add, usually an `.RSAKey` or `.DSSKey`. 

857 """ 

858 self.server_key_dict[key.get_name()] = key 

859 # Handle SHA-2 extensions for RSA by ensuring that lookups into 

860 # self.server_key_dict will yield this key for any of the algorithm 

861 # names. 

862 if isinstance(key, RSAKey): 

863 self.server_key_dict["rsa-sha2-256"] = key 

864 self.server_key_dict["rsa-sha2-512"] = key 

865 

866 def get_server_key(self): 

867 """ 

868 Return the active host key, in server mode. After negotiating with the 

869 client, this method will return the negotiated host key. If only one 

870 type of host key was set with `add_server_key`, that's the only key 

871 that will ever be returned. But in cases where you have set more than 

872 one type of host key (for example, an RSA key and a DSS key), the key 

873 type will be negotiated by the client, and this method will return the 

874 key of the type agreed on. If the host key has not been negotiated 

875 yet, ``None`` is returned. In client mode, the behavior is undefined. 

876 

877 :return: 

878 host key (`.PKey`) of the type negotiated by the client, or 

879 ``None``. 

880 """ 

881 try: 

882 return self.server_key_dict[self.host_key_type] 

883 except KeyError: 

884 pass 

885 return None 

886 

887 @staticmethod 

888 def load_server_moduli(filename=None): 

889 """ 

890 (optional) 

891 Load a file of prime moduli for use in doing group-exchange key 

892 negotiation in server mode. It's a rather obscure option and can be 

893 safely ignored. 

894 

895 In server mode, the remote client may request "group-exchange" key 

896 negotiation, which asks the server to send a random prime number that 

897 fits certain criteria. These primes are pretty difficult to compute, 

898 so they can't be generated on demand. But many systems contain a file 

899 of suitable primes (usually named something like ``/etc/ssh/moduli``). 

900 If you call `load_server_moduli` and it returns ``True``, then this 

901 file of primes has been loaded and we will support "group-exchange" in 

902 server mode. Otherwise server mode will just claim that it doesn't 

903 support that method of key negotiation. 

904 

905 :param str filename: 

906 optional path to the moduli file, if you happen to know that it's 

907 not in a standard location. 

908 :return: 

909 True if a moduli file was successfully loaded; False otherwise. 

910 

911 .. note:: This has no effect when used in client mode. 

912 """ 

913 Transport._modulus_pack = ModulusPack() 

914 # places to look for the openssh "moduli" file 

915 file_list = ["/etc/ssh/moduli", "/usr/local/etc/moduli"] 

916 if filename is not None: 

917 file_list.insert(0, filename) 

918 for fn in file_list: 

919 try: 

920 Transport._modulus_pack.read_file(fn) 

921 return True 

922 except IOError: 

923 pass 

924 # none succeeded 

925 Transport._modulus_pack = None 

926 return False 

927 

928 def close(self): 

929 """ 

930 Close this session, and any open channels that are tied to it. 

931 """ 

932 if not self.active: 

933 return 

934 self.stop_thread() 

935 for chan in list(self._channels.values()): 

936 chan._unlink() 

937 self.sock.close() 

938 

939 def get_remote_server_key(self): 

940 """ 

941 Return the host key of the server (in client mode). 

942 

943 .. note:: 

944 Previously this call returned a tuple of ``(key type, key 

945 string)``. You can get the same effect by calling `.PKey.get_name` 

946 for the key type, and ``str(key)`` for the key string. 

947 

948 :raises: `.SSHException` -- if no session is currently active. 

949 

950 :return: public key (`.PKey`) of the remote server 

951 """ 

952 if (not self.active) or (not self.initial_kex_done): 

953 raise SSHException("No existing session") 

954 return self.host_key 

955 

956 def is_active(self): 

957 """ 

958 Return true if this session is active (open). 

959 

960 :return: 

961 True if the session is still active (open); False if the session is 

962 closed 

963 """ 

964 return self.active 

965 

966 def open_session( 

967 self, window_size=None, max_packet_size=None, timeout=None 

968 ): 

969 """ 

970 Request a new channel to the server, of type ``"session"``. This is 

971 just an alias for calling `open_channel` with an argument of 

972 ``"session"``. 

973 

974 .. note:: Modifying the the window and packet sizes might have adverse 

975 effects on the session created. The default values are the same 

976 as in the OpenSSH code base and have been battle tested. 

977 

978 :param int window_size: 

979 optional window size for this session. 

980 :param int max_packet_size: 

981 optional max packet size for this session. 

982 

983 :return: a new `.Channel` 

984 

985 :raises: 

986 `.SSHException` -- if the request is rejected or the session ends 

987 prematurely 

988 

989 .. versionchanged:: 1.13.4/1.14.3/1.15.3 

990 Added the ``timeout`` argument. 

991 .. versionchanged:: 1.15 

992 Added the ``window_size`` and ``max_packet_size`` arguments. 

993 """ 

994 return self.open_channel( 

995 "session", 

996 window_size=window_size, 

997 max_packet_size=max_packet_size, 

998 timeout=timeout, 

999 ) 

1000 

1001 def open_x11_channel(self, src_addr=None): 

1002 """ 

1003 Request a new channel to the client, of type ``"x11"``. This 

1004 is just an alias for ``open_channel('x11', src_addr=src_addr)``. 

1005 

1006 :param tuple src_addr: 

1007 the source address (``(str, int)``) of the x11 server (port is the 

1008 x11 port, ie. 6010) 

1009 :return: a new `.Channel` 

1010 

1011 :raises: 

1012 `.SSHException` -- if the request is rejected or the session ends 

1013 prematurely 

1014 """ 

1015 return self.open_channel("x11", src_addr=src_addr) 

1016 

1017 def open_forward_agent_channel(self): 

1018 """ 

1019 Request a new channel to the client, of type 

1020 ``"auth-agent@openssh.com"``. 

1021 

1022 This is just an alias for ``open_channel('auth-agent@openssh.com')``. 

1023 

1024 :return: a new `.Channel` 

1025 

1026 :raises: `.SSHException` -- 

1027 if the request is rejected or the session ends prematurely 

1028 """ 

1029 return self.open_channel("auth-agent@openssh.com") 

1030 

1031 def open_forwarded_tcpip_channel(self, src_addr, dest_addr): 

1032 """ 

1033 Request a new channel back to the client, of type ``forwarded-tcpip``. 

1034 

1035 This is used after a client has requested port forwarding, for sending 

1036 incoming connections back to the client. 

1037 

1038 :param src_addr: originator's address 

1039 :param dest_addr: local (server) connected address 

1040 """ 

1041 return self.open_channel("forwarded-tcpip", dest_addr, src_addr) 

1042 

1043 def open_channel( 

1044 self, 

1045 kind, 

1046 dest_addr=None, 

1047 src_addr=None, 

1048 window_size=None, 

1049 max_packet_size=None, 

1050 timeout=None, 

1051 ): 

1052 """ 

1053 Request a new channel to the server. `Channels <.Channel>` are 

1054 socket-like objects used for the actual transfer of data across the 

1055 session. You may only request a channel after negotiating encryption 

1056 (using `connect` or `start_client`) and authenticating. 

1057 

1058 .. note:: Modifying the the window and packet sizes might have adverse 

1059 effects on the channel created. The default values are the same 

1060 as in the OpenSSH code base and have been battle tested. 

1061 

1062 :param str kind: 

1063 the kind of channel requested (usually ``"session"``, 

1064 ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"``) 

1065 :param tuple dest_addr: 

1066 the destination address (address + port tuple) of this port 

1067 forwarding, if ``kind`` is ``"forwarded-tcpip"`` or 

1068 ``"direct-tcpip"`` (ignored for other channel types) 

1069 :param src_addr: the source address of this port forwarding, if 

1070 ``kind`` is ``"forwarded-tcpip"``, ``"direct-tcpip"``, or ``"x11"`` 

1071 :param int window_size: 

1072 optional window size for this session. 

1073 :param int max_packet_size: 

1074 optional max packet size for this session. 

1075 :param float timeout: 

1076 optional timeout opening a channel, default 3600s (1h) 

1077 

1078 :return: a new `.Channel` on success 

1079 

1080 :raises: 

1081 `.SSHException` -- if the request is rejected, the session ends 

1082 prematurely or there is a timeout opening a channel 

1083 

1084 .. versionchanged:: 1.15 

1085 Added the ``window_size`` and ``max_packet_size`` arguments. 

1086 """ 

1087 if not self.active: 

1088 raise SSHException("SSH session not active") 

1089 timeout = self.channel_timeout if timeout is None else timeout 

1090 self.lock.acquire() 

1091 try: 

1092 window_size = self._sanitize_window_size(window_size) 

1093 max_packet_size = self._sanitize_packet_size(max_packet_size) 

1094 chanid = self._next_channel() 

1095 m = Message() 

1096 m.add_byte(cMSG_CHANNEL_OPEN) 

1097 m.add_string(kind) 

1098 m.add_int(chanid) 

1099 m.add_int(window_size) 

1100 m.add_int(max_packet_size) 

1101 if (kind == "forwarded-tcpip") or (kind == "direct-tcpip"): 

1102 m.add_string(dest_addr[0]) 

1103 m.add_int(dest_addr[1]) 

1104 m.add_string(src_addr[0]) 

1105 m.add_int(src_addr[1]) 

1106 elif kind == "x11": 

1107 m.add_string(src_addr[0]) 

1108 m.add_int(src_addr[1]) 

1109 chan = Channel(chanid) 

1110 self._channels.put(chanid, chan) 

1111 self.channel_events[chanid] = event = threading.Event() 

1112 self.channels_seen[chanid] = True 

1113 chan._set_transport(self) 

1114 chan._set_window(window_size, max_packet_size) 

1115 finally: 

1116 self.lock.release() 

1117 self._send_user_message(m) 

1118 start_ts = time.time() 

1119 while True: 

1120 event.wait(0.1) 

1121 if not self.active: 

1122 e = self.get_exception() 

1123 if e is None: 

1124 e = SSHException("Unable to open channel.") 

1125 raise e 

1126 if event.is_set(): 

1127 break 

1128 elif start_ts + timeout < time.time(): 

1129 raise SSHException("Timeout opening channel.") 

1130 chan = self._channels.get(chanid) 

1131 if chan is not None: 

1132 return chan 

1133 e = self.get_exception() 

1134 if e is None: 

1135 e = SSHException("Unable to open channel.") 

1136 raise e 

1137 

1138 def request_port_forward(self, address, port, handler=None): 

1139 """ 

1140 Ask the server to forward TCP connections from a listening port on 

1141 the server, across this SSH session. 

1142 

1143 If a handler is given, that handler is called from a different thread 

1144 whenever a forwarded connection arrives. The handler parameters are:: 

1145 

1146 handler( 

1147 channel, 

1148 (origin_addr, origin_port), 

1149 (server_addr, server_port), 

1150 ) 

1151 

1152 where ``server_addr`` and ``server_port`` are the address and port that 

1153 the server was listening on. 

1154 

1155 If no handler is set, the default behavior is to send new incoming 

1156 forwarded connections into the accept queue, to be picked up via 

1157 `accept`. 

1158 

1159 :param str address: the address to bind when forwarding 

1160 :param int port: 

1161 the port to forward, or 0 to ask the server to allocate any port 

1162 :param callable handler: 

1163 optional handler for incoming forwarded connections, of the form 

1164 ``func(Channel, (str, int), (str, int))``. 

1165 

1166 :return: the port number (`int`) allocated by the server 

1167 

1168 :raises: 

1169 `.SSHException` -- if the server refused the TCP forward request 

1170 """ 

1171 if not self.active: 

1172 raise SSHException("SSH session not active") 

1173 port = int(port) 

1174 response = self.global_request( 

1175 "tcpip-forward", (address, port), wait=True 

1176 ) 

1177 if response is None: 

1178 raise SSHException("TCP forwarding request denied") 

1179 if port == 0: 

1180 port = response.get_int() 

1181 if handler is None: 

1182 

1183 def default_handler(channel, src_addr, dest_addr_port): 

1184 # src_addr, src_port = src_addr_port 

1185 # dest_addr, dest_port = dest_addr_port 

1186 self._queue_incoming_channel(channel) 

1187 

1188 handler = default_handler 

1189 self._tcp_handler = handler 

1190 return port 

1191 

1192 def cancel_port_forward(self, address, port): 

1193 """ 

1194 Ask the server to cancel a previous port-forwarding request. No more 

1195 connections to the given address & port will be forwarded across this 

1196 ssh connection. 

1197 

1198 :param str address: the address to stop forwarding 

1199 :param int port: the port to stop forwarding 

1200 """ 

1201 if not self.active: 

1202 return 

1203 self._tcp_handler = None 

1204 self.global_request("cancel-tcpip-forward", (address, port), wait=True) 

1205 

1206 def open_sftp_client(self): 

1207 """ 

1208 Create an SFTP client channel from an open transport. On success, an 

1209 SFTP session will be opened with the remote host, and a new 

1210 `.SFTPClient` object will be returned. 

1211 

1212 :return: 

1213 a new `.SFTPClient` referring to an sftp session (channel) across 

1214 this transport 

1215 """ 

1216 return SFTPClient.from_transport(self) 

1217 

1218 def send_ignore(self, byte_count=None): 

1219 """ 

1220 Send a junk packet across the encrypted link. This is sometimes used 

1221 to add "noise" to a connection to confuse would-be attackers. It can 

1222 also be used as a keep-alive for long lived connections traversing 

1223 firewalls. 

1224 

1225 :param int byte_count: 

1226 the number of random bytes to send in the payload of the ignored 

1227 packet -- defaults to a random number from 10 to 41. 

1228 """ 

1229 m = Message() 

1230 m.add_byte(cMSG_IGNORE) 

1231 if byte_count is None: 

1232 byte_count = (byte_ord(os.urandom(1)) % 32) + 10 

1233 m.add_bytes(os.urandom(byte_count)) 

1234 self._send_user_message(m) 

1235 

1236 def renegotiate_keys(self): 

1237 """ 

1238 Force this session to switch to new keys. Normally this is done 

1239 automatically after the session hits a certain number of packets or 

1240 bytes sent or received, but this method gives you the option of forcing 

1241 new keys whenever you want. Negotiating new keys causes a pause in 

1242 traffic both ways as the two sides swap keys and do computations. This 

1243 method returns when the session has switched to new keys. 

1244 

1245 :raises: 

1246 `.SSHException` -- if the key renegotiation failed (which causes 

1247 the session to end) 

1248 """ 

1249 self.completion_event = threading.Event() 

1250 self._send_kex_init() 

1251 while True: 

1252 self.completion_event.wait(0.1) 

1253 if not self.active: 

1254 e = self.get_exception() 

1255 if e is not None: 

1256 raise e 

1257 raise SSHException("Negotiation failed.") 

1258 if self.completion_event.is_set(): 

1259 break 

1260 return 

1261 

1262 def set_keepalive(self, interval): 

1263 """ 

1264 Turn on/off keepalive packets (default is off). If this is set, after 

1265 ``interval`` seconds without sending any data over the connection, a 

1266 "keepalive" packet will be sent (and ignored by the remote host). This 

1267 can be useful to keep connections alive over a NAT, for example. 

1268 

1269 :param int interval: 

1270 seconds to wait before sending a keepalive packet (or 

1271 0 to disable keepalives). 

1272 """ 

1273 

1274 def _request(x=weakref.proxy(self)): 

1275 return x.global_request("keepalive@lag.net", wait=False) 

1276 

1277 self.packetizer.set_keepalive(interval, _request) 

1278 

1279 def global_request(self, kind, data=None, wait=True): 

1280 """ 

1281 Make a global request to the remote host. These are normally 

1282 extensions to the SSH2 protocol. 

1283 

1284 :param str kind: name of the request. 

1285 :param tuple data: 

1286 an optional tuple containing additional data to attach to the 

1287 request. 

1288 :param bool wait: 

1289 ``True`` if this method should not return until a response is 

1290 received; ``False`` otherwise. 

1291 :return: 

1292 a `.Message` containing possible additional data if the request was 

1293 successful (or an empty `.Message` if ``wait`` was ``False``); 

1294 ``None`` if the request was denied. 

1295 """ 

1296 if wait: 

1297 self.completion_event = threading.Event() 

1298 m = Message() 

1299 m.add_byte(cMSG_GLOBAL_REQUEST) 

1300 m.add_string(kind) 

1301 m.add_boolean(wait) 

1302 if data is not None: 

1303 m.add(*data) 

1304 self._log(DEBUG, 'Sending global request "{}"'.format(kind)) 

1305 self._send_user_message(m) 

1306 if not wait: 

1307 return None 

1308 while True: 

1309 self.completion_event.wait(0.1) 

1310 if not self.active: 

1311 return None 

1312 if self.completion_event.is_set(): 

1313 break 

1314 return self.global_response 

1315 

1316 def accept(self, timeout=None): 

1317 """ 

1318 Return the next channel opened by the client over this transport, in 

1319 server mode. If no channel is opened before the given timeout, 

1320 ``None`` is returned. 

1321 

1322 :param int timeout: 

1323 seconds to wait for a channel, or ``None`` to wait forever 

1324 :return: a new `.Channel` opened by the client 

1325 """ 

1326 self.lock.acquire() 

1327 try: 

1328 if len(self.server_accepts) > 0: 

1329 chan = self.server_accepts.pop(0) 

1330 else: 

1331 self.server_accept_cv.wait(timeout) 

1332 if len(self.server_accepts) > 0: 

1333 chan = self.server_accepts.pop(0) 

1334 else: 

1335 # timeout 

1336 chan = None 

1337 finally: 

1338 self.lock.release() 

1339 return chan 

1340 

1341 def connect( 

1342 self, 

1343 hostkey=None, 

1344 username="", 

1345 password=None, 

1346 pkey=None, 

1347 gss_host=None, 

1348 gss_auth=False, 

1349 gss_kex=False, 

1350 gss_deleg_creds=True, 

1351 gss_trust_dns=True, 

1352 ): 

1353 """ 

1354 Negotiate an SSH2 session, and optionally verify the server's host key 

1355 and authenticate using a password or private key. This is a shortcut 

1356 for `start_client`, `get_remote_server_key`, and 

1357 `Transport.auth_password` or `Transport.auth_publickey`. Use those 

1358 methods if you want more control. 

1359 

1360 You can use this method immediately after creating a Transport to 

1361 negotiate encryption with a server. If it fails, an exception will be 

1362 thrown. On success, the method will return cleanly, and an encrypted 

1363 session exists. You may immediately call `open_channel` or 

1364 `open_session` to get a `.Channel` object, which is used for data 

1365 transfer. 

1366 

1367 .. note:: 

1368 If you fail to supply a password or private key, this method may 

1369 succeed, but a subsequent `open_channel` or `open_session` call may 

1370 fail because you haven't authenticated yet. 

1371 

1372 :param .PKey hostkey: 

1373 the host key expected from the server, or ``None`` if you don't 

1374 want to do host key verification. 

1375 :param str username: the username to authenticate as. 

1376 :param str password: 

1377 a password to use for authentication, if you want to use password 

1378 authentication; otherwise ``None``. 

1379 :param .PKey pkey: 

1380 a private key to use for authentication, if you want to use private 

1381 key authentication; otherwise ``None``. 

1382 :param str gss_host: 

1383 The target's name in the kerberos database. Default: hostname 

1384 :param bool gss_auth: 

1385 ``True`` if you want to use GSS-API authentication. 

1386 :param bool gss_kex: 

1387 Perform GSS-API Key Exchange and user authentication. 

1388 :param bool gss_deleg_creds: 

1389 Whether to delegate GSS-API client credentials. 

1390 :param gss_trust_dns: 

1391 Indicates whether or not the DNS is trusted to securely 

1392 canonicalize the name of the host being connected to (default 

1393 ``True``). 

1394 

1395 :raises: `.SSHException` -- if the SSH2 negotiation fails, the host key 

1396 supplied by the server is incorrect, or authentication fails. 

1397 

1398 .. versionchanged:: 2.3 

1399 Added the ``gss_trust_dns`` argument. 

1400 """ 

1401 if hostkey is not None: 

1402 # TODO: a more robust implementation would be to ask each key class 

1403 # for its nameS plural, and just use that. 

1404 # TODO: that could be used in a bunch of other spots too 

1405 if isinstance(hostkey, RSAKey): 

1406 self._preferred_keys = [ 

1407 "rsa-sha2-512", 

1408 "rsa-sha2-256", 

1409 "ssh-rsa", 

1410 ] 

1411 else: 

1412 self._preferred_keys = [hostkey.get_name()] 

1413 

1414 self.set_gss_host( 

1415 gss_host=gss_host, 

1416 trust_dns=gss_trust_dns, 

1417 gssapi_requested=gss_kex or gss_auth, 

1418 ) 

1419 

1420 self.start_client() 

1421 

1422 # check host key if we were given one 

1423 # If GSS-API Key Exchange was performed, we are not required to check 

1424 # the host key. 

1425 if (hostkey is not None) and not gss_kex: 

1426 key = self.get_remote_server_key() 

1427 if ( 

1428 key.get_name() != hostkey.get_name() 

1429 or key.asbytes() != hostkey.asbytes() 

1430 ): 

1431 self._log(DEBUG, "Bad host key from server") 

1432 self._log( 

1433 DEBUG, 

1434 "Expected: {}: {}".format( 

1435 hostkey.get_name(), repr(hostkey.asbytes()) 

1436 ), 

1437 ) 

1438 self._log( 

1439 DEBUG, 

1440 "Got : {}: {}".format( 

1441 key.get_name(), repr(key.asbytes()) 

1442 ), 

1443 ) 

1444 raise SSHException("Bad host key from server") 

1445 self._log( 

1446 DEBUG, "Host key verified ({})".format(hostkey.get_name()) 

1447 ) 

1448 

1449 if (pkey is not None) or (password is not None) or gss_auth or gss_kex: 

1450 if gss_auth: 

1451 self._log( 

1452 DEBUG, "Attempting GSS-API auth... (gssapi-with-mic)" 

1453 ) # noqa 

1454 self.auth_gssapi_with_mic( 

1455 username, self.gss_host, gss_deleg_creds 

1456 ) 

1457 elif gss_kex: 

1458 self._log(DEBUG, "Attempting GSS-API auth... (gssapi-keyex)") 

1459 self.auth_gssapi_keyex(username) 

1460 elif pkey is not None: 

1461 self._log(DEBUG, "Attempting public-key auth...") 

1462 self.auth_publickey(username, pkey) 

1463 else: 

1464 self._log(DEBUG, "Attempting password auth...") 

1465 self.auth_password(username, password) 

1466 

1467 return 

1468 

1469 def get_exception(self): 

1470 """ 

1471 Return any exception that happened during the last server request. 

1472 This can be used to fetch more specific error information after using 

1473 calls like `start_client`. The exception (if any) is cleared after 

1474 this call. 

1475 

1476 :return: 

1477 an exception, or ``None`` if there is no stored exception. 

1478 

1479 .. versionadded:: 1.1 

1480 """ 

1481 self.lock.acquire() 

1482 try: 

1483 e = self.saved_exception 

1484 self.saved_exception = None 

1485 return e 

1486 finally: 

1487 self.lock.release() 

1488 

1489 def set_subsystem_handler(self, name, handler, *args, **kwargs): 

1490 """ 

1491 Set the handler class for a subsystem in server mode. If a request 

1492 for this subsystem is made on an open ssh channel later, this handler 

1493 will be constructed and called -- see `.SubsystemHandler` for more 

1494 detailed documentation. 

1495 

1496 Any extra parameters (including keyword arguments) are saved and 

1497 passed to the `.SubsystemHandler` constructor later. 

1498 

1499 :param str name: name of the subsystem. 

1500 :param handler: 

1501 subclass of `.SubsystemHandler` that handles this subsystem. 

1502 """ 

1503 try: 

1504 self.lock.acquire() 

1505 self.subsystem_table[name] = (handler, args, kwargs) 

1506 finally: 

1507 self.lock.release() 

1508 

1509 def is_authenticated(self): 

1510 """ 

1511 Return true if this session is active and authenticated. 

1512 

1513 :return: 

1514 True if the session is still open and has been authenticated 

1515 successfully; False if authentication failed and/or the session is 

1516 closed. 

1517 """ 

1518 return ( 

1519 self.active 

1520 and self.auth_handler is not None 

1521 and self.auth_handler.is_authenticated() 

1522 ) 

1523 

1524 def get_username(self): 

1525 """ 

1526 Return the username this connection is authenticated for. If the 

1527 session is not authenticated (or authentication failed), this method 

1528 returns ``None``. 

1529 

1530 :return: username that was authenticated (a `str`), or ``None``. 

1531 """ 

1532 if not self.active or (self.auth_handler is None): 

1533 return None 

1534 return self.auth_handler.get_username() 

1535 

1536 def get_banner(self): 

1537 """ 

1538 Return the banner supplied by the server upon connect. If no banner is 

1539 supplied, this method returns ``None``. 

1540 

1541 :returns: server supplied banner (`str`), or ``None``. 

1542 

1543 .. versionadded:: 1.13 

1544 """ 

1545 if not self.active or (self.auth_handler is None): 

1546 return None 

1547 return self.auth_handler.banner 

1548 

1549 def auth_none(self, username): 

1550 """ 

1551 Try to authenticate to the server using no authentication at all. 

1552 This will almost always fail. It may be useful for determining the 

1553 list of authentication types supported by the server, by catching the 

1554 `.BadAuthenticationType` exception raised. 

1555 

1556 :param str username: the username to authenticate as 

1557 :return: 

1558 list of auth types permissible for the next stage of 

1559 authentication (normally empty) 

1560 

1561 :raises: 

1562 `.BadAuthenticationType` -- if "none" authentication isn't allowed 

1563 by the server for this user 

1564 :raises: 

1565 `.SSHException` -- if the authentication failed due to a network 

1566 error 

1567 

1568 .. versionadded:: 1.5 

1569 """ 

1570 if (not self.active) or (not self.initial_kex_done): 

1571 raise SSHException("No existing session") 

1572 my_event = threading.Event() 

1573 self.auth_handler = AuthHandler(self) 

1574 self.auth_handler.auth_none(username, my_event) 

1575 return self.auth_handler.wait_for_response(my_event) 

1576 

1577 def auth_password(self, username, password, event=None, fallback=True): 

1578 """ 

1579 Authenticate to the server using a password. The username and password 

1580 are sent over an encrypted link. 

1581 

1582 If an ``event`` is passed in, this method will return immediately, and 

1583 the event will be triggered once authentication succeeds or fails. On 

1584 success, `is_authenticated` will return ``True``. On failure, you may 

1585 use `get_exception` to get more detailed error information. 

1586 

1587 Since 1.1, if no event is passed, this method will block until the 

1588 authentication succeeds or fails. On failure, an exception is raised. 

1589 Otherwise, the method simply returns. 

1590 

1591 Since 1.5, if no event is passed and ``fallback`` is ``True`` (the 

1592 default), if the server doesn't support plain password authentication 

1593 but does support so-called "keyboard-interactive" mode, an attempt 

1594 will be made to authenticate using this interactive mode. If it fails, 

1595 the normal exception will be thrown as if the attempt had never been 

1596 made. This is useful for some recent Gentoo and Debian distributions, 

1597 which turn off plain password authentication in a misguided belief 

1598 that interactive authentication is "more secure". (It's not.) 

1599 

1600 If the server requires multi-step authentication (which is very rare), 

1601 this method will return a list of auth types permissible for the next 

1602 step. Otherwise, in the normal case, an empty list is returned. 

1603 

1604 :param str username: the username to authenticate as 

1605 :param basestring password: the password to authenticate with 

1606 :param .threading.Event event: 

1607 an event to trigger when the authentication attempt is complete 

1608 (whether it was successful or not) 

1609 :param bool fallback: 

1610 ``True`` if an attempt at an automated "interactive" password auth 

1611 should be made if the server doesn't support normal password auth 

1612 :return: 

1613 list of auth types permissible for the next stage of 

1614 authentication (normally empty) 

1615 

1616 :raises: 

1617 `.BadAuthenticationType` -- if password authentication isn't 

1618 allowed by the server for this user (and no event was passed in) 

1619 :raises: 

1620 `.AuthenticationException` -- if the authentication failed (and no 

1621 event was passed in) 

1622 :raises: `.SSHException` -- if there was a network error 

1623 """ 

1624 if (not self.active) or (not self.initial_kex_done): 

1625 # we should never try to send the password unless we're on a secure 

1626 # link 

1627 raise SSHException("No existing session") 

1628 if event is None: 

1629 my_event = threading.Event() 

1630 else: 

1631 my_event = event 

1632 self.auth_handler = AuthHandler(self) 

1633 self.auth_handler.auth_password(username, password, my_event) 

1634 if event is not None: 

1635 # caller wants to wait for event themselves 

1636 return [] 

1637 try: 

1638 return self.auth_handler.wait_for_response(my_event) 

1639 except BadAuthenticationType as e: 

1640 # if password auth isn't allowed, but keyboard-interactive *is*, 

1641 # try to fudge it 

1642 if not fallback or ("keyboard-interactive" not in e.allowed_types): 

1643 raise 

1644 try: 

1645 

1646 def handler(title, instructions, fields): 

1647 if len(fields) > 1: 

1648 raise SSHException("Fallback authentication failed.") 

1649 if len(fields) == 0: 

1650 # for some reason, at least on os x, a 2nd request will 

1651 # be made with zero fields requested. maybe it's just 

1652 # to try to fake out automated scripting of the exact 

1653 # type we're doing here. *shrug* :) 

1654 return [] 

1655 return [password] 

1656 

1657 return self.auth_interactive(username, handler) 

1658 except SSHException: 

1659 # attempt failed; just raise the original exception 

1660 raise e 

1661 

1662 def auth_publickey(self, username, key, event=None): 

1663 """ 

1664 Authenticate to the server using a private key. The key is used to 

1665 sign data from the server, so it must include the private part. 

1666 

1667 If an ``event`` is passed in, this method will return immediately, and 

1668 the event will be triggered once authentication succeeds or fails. On 

1669 success, `is_authenticated` will return ``True``. On failure, you may 

1670 use `get_exception` to get more detailed error information. 

1671 

1672 Since 1.1, if no event is passed, this method will block until the 

1673 authentication succeeds or fails. On failure, an exception is raised. 

1674 Otherwise, the method simply returns. 

1675 

1676 If the server requires multi-step authentication (which is very rare), 

1677 this method will return a list of auth types permissible for the next 

1678 step. Otherwise, in the normal case, an empty list is returned. 

1679 

1680 :param str username: the username to authenticate as 

1681 :param .PKey key: the private key to authenticate with 

1682 :param .threading.Event event: 

1683 an event to trigger when the authentication attempt is complete 

1684 (whether it was successful or not) 

1685 :return: 

1686 list of auth types permissible for the next stage of 

1687 authentication (normally empty) 

1688 

1689 :raises: 

1690 `.BadAuthenticationType` -- if public-key authentication isn't 

1691 allowed by the server for this user (and no event was passed in) 

1692 :raises: 

1693 `.AuthenticationException` -- if the authentication failed (and no 

1694 event was passed in) 

1695 :raises: `.SSHException` -- if there was a network error 

1696 """ 

1697 if (not self.active) or (not self.initial_kex_done): 

1698 # we should never try to authenticate unless we're on a secure link 

1699 raise SSHException("No existing session") 

1700 if event is None: 

1701 my_event = threading.Event() 

1702 else: 

1703 my_event = event 

1704 self.auth_handler = AuthHandler(self) 

1705 self.auth_handler.auth_publickey(username, key, my_event) 

1706 if event is not None: 

1707 # caller wants to wait for event themselves 

1708 return [] 

1709 return self.auth_handler.wait_for_response(my_event) 

1710 

1711 def auth_interactive(self, username, handler, submethods=""): 

1712 """ 

1713 Authenticate to the server interactively. A handler is used to answer 

1714 arbitrary questions from the server. On many servers, this is just a 

1715 dumb wrapper around PAM. 

1716 

1717 This method will block until the authentication succeeds or fails, 

1718 periodically calling the handler asynchronously to get answers to 

1719 authentication questions. The handler may be called more than once 

1720 if the server continues to ask questions. 

1721 

1722 The handler is expected to be a callable that will handle calls of the 

1723 form: ``handler(title, instructions, prompt_list)``. The ``title`` is 

1724 meant to be a dialog-window title, and the ``instructions`` are user 

1725 instructions (both are strings). ``prompt_list`` will be a list of 

1726 prompts, each prompt being a tuple of ``(str, bool)``. The string is 

1727 the prompt and the boolean indicates whether the user text should be 

1728 echoed. 

1729 

1730 A sample call would thus be: 

1731 ``handler('title', 'instructions', [('Password:', False)])``. 

1732 

1733 The handler should return a list or tuple of answers to the server's 

1734 questions. 

1735 

1736 If the server requires multi-step authentication (which is very rare), 

1737 this method will return a list of auth types permissible for the next 

1738 step. Otherwise, in the normal case, an empty list is returned. 

1739 

1740 :param str username: the username to authenticate as 

1741 :param callable handler: a handler for responding to server questions 

1742 :param str submethods: a string list of desired submethods (optional) 

1743 :return: 

1744 list of auth types permissible for the next stage of 

1745 authentication (normally empty). 

1746 

1747 :raises: `.BadAuthenticationType` -- if public-key authentication isn't 

1748 allowed by the server for this user 

1749 :raises: `.AuthenticationException` -- if the authentication failed 

1750 :raises: `.SSHException` -- if there was a network error 

1751 

1752 .. versionadded:: 1.5 

1753 """ 

1754 if (not self.active) or (not self.initial_kex_done): 

1755 # we should never try to authenticate unless we're on a secure link 

1756 raise SSHException("No existing session") 

1757 my_event = threading.Event() 

1758 self.auth_handler = AuthHandler(self) 

1759 self.auth_handler.auth_interactive( 

1760 username, handler, my_event, submethods 

1761 ) 

1762 return self.auth_handler.wait_for_response(my_event) 

1763 

1764 def auth_interactive_dumb(self, username, handler=None, submethods=""): 

1765 """ 

1766 Authenticate to the server interactively but dumber. 

1767 Just print the prompt and / or instructions to stdout and send back 

1768 the response. This is good for situations where partial auth is 

1769 achieved by key and then the user has to enter a 2fac token. 

1770 """ 

1771 

1772 if not handler: 

1773 

1774 def handler(title, instructions, prompt_list): 

1775 answers = [] 

1776 if title: 

1777 print(title.strip()) 

1778 if instructions: 

1779 print(instructions.strip()) 

1780 for prompt, show_input in prompt_list: 

1781 print(prompt.strip(), end=" ") 

1782 answers.append(input()) 

1783 return answers 

1784 

1785 return self.auth_interactive(username, handler, submethods) 

1786 

1787 def auth_gssapi_with_mic(self, username, gss_host, gss_deleg_creds): 

1788 """ 

1789 Authenticate to the Server using GSS-API / SSPI. 

1790 

1791 :param str username: The username to authenticate as 

1792 :param str gss_host: The target host 

1793 :param bool gss_deleg_creds: Delegate credentials or not 

1794 :return: list of auth types permissible for the next stage of 

1795 authentication (normally empty) 

1796 :raises: `.BadAuthenticationType` -- if gssapi-with-mic isn't 

1797 allowed by the server (and no event was passed in) 

1798 :raises: 

1799 `.AuthenticationException` -- if the authentication failed (and no 

1800 event was passed in) 

1801 :raises: `.SSHException` -- if there was a network error 

1802 """ 

1803 if (not self.active) or (not self.initial_kex_done): 

1804 # we should never try to authenticate unless we're on a secure link 

1805 raise SSHException("No existing session") 

1806 my_event = threading.Event() 

1807 self.auth_handler = AuthHandler(self) 

1808 self.auth_handler.auth_gssapi_with_mic( 

1809 username, gss_host, gss_deleg_creds, my_event 

1810 ) 

1811 return self.auth_handler.wait_for_response(my_event) 

1812 

1813 def auth_gssapi_keyex(self, username): 

1814 """ 

1815 Authenticate to the server with GSS-API/SSPI if GSS-API kex is in use. 

1816 

1817 :param str username: The username to authenticate as. 

1818 :returns: 

1819 a list of auth types permissible for the next stage of 

1820 authentication (normally empty) 

1821 :raises: `.BadAuthenticationType` -- 

1822 if GSS-API Key Exchange was not performed (and no event was passed 

1823 in) 

1824 :raises: `.AuthenticationException` -- 

1825 if the authentication failed (and no event was passed in) 

1826 :raises: `.SSHException` -- if there was a network error 

1827 """ 

1828 if (not self.active) or (not self.initial_kex_done): 

1829 # we should never try to authenticate unless we're on a secure link 

1830 raise SSHException("No existing session") 

1831 my_event = threading.Event() 

1832 self.auth_handler = AuthHandler(self) 

1833 self.auth_handler.auth_gssapi_keyex(username, my_event) 

1834 return self.auth_handler.wait_for_response(my_event) 

1835 

1836 def set_log_channel(self, name): 

1837 """ 

1838 Set the channel for this transport's logging. The default is 

1839 ``"paramiko.transport"`` but it can be set to anything you want. (See 

1840 the `.logging` module for more info.) SSH Channels will log to a 

1841 sub-channel of the one specified. 

1842 

1843 :param str name: new channel name for logging 

1844 

1845 .. versionadded:: 1.1 

1846 """ 

1847 self.log_name = name 

1848 self.logger = util.get_logger(name) 

1849 self.packetizer.set_log(self.logger) 

1850 

1851 def get_log_channel(self): 

1852 """ 

1853 Return the channel name used for this transport's logging. 

1854 

1855 :return: channel name as a `str` 

1856 

1857 .. versionadded:: 1.2 

1858 """ 

1859 return self.log_name 

1860 

1861 def set_hexdump(self, hexdump): 

1862 """ 

1863 Turn on/off logging a hex dump of protocol traffic at DEBUG level in 

1864 the logs. Normally you would want this off (which is the default), 

1865 but if you are debugging something, it may be useful. 

1866 

1867 :param bool hexdump: 

1868 ``True`` to log protocol traffix (in hex) to the log; ``False`` 

1869 otherwise. 

1870 """ 

1871 self.packetizer.set_hexdump(hexdump) 

1872 

1873 def get_hexdump(self): 

1874 """ 

1875 Return ``True`` if the transport is currently logging hex dumps of 

1876 protocol traffic. 

1877 

1878 :return: ``True`` if hex dumps are being logged, else ``False``. 

1879 

1880 .. versionadded:: 1.4 

1881 """ 

1882 return self.packetizer.get_hexdump() 

1883 

1884 def use_compression(self, compress=True): 

1885 """ 

1886 Turn on/off compression. This will only have an affect before starting 

1887 the transport (ie before calling `connect`, etc). By default, 

1888 compression is off since it negatively affects interactive sessions. 

1889 

1890 :param bool compress: 

1891 ``True`` to ask the remote client/server to compress traffic; 

1892 ``False`` to refuse compression 

1893 

1894 .. versionadded:: 1.5.2 

1895 """ 

1896 if compress: 

1897 self._preferred_compression = ("zlib@openssh.com", "zlib", "none") 

1898 else: 

1899 self._preferred_compression = ("none",) 

1900 

1901 def getpeername(self): 

1902 """ 

1903 Return the address of the remote side of this Transport, if possible. 

1904 

1905 This is effectively a wrapper around ``getpeername`` on the underlying 

1906 socket. If the socket-like object has no ``getpeername`` method, then 

1907 ``("unknown", 0)`` is returned. 

1908 

1909 :return: 

1910 the address of the remote host, if known, as a ``(str, int)`` 

1911 tuple. 

1912 """ 

1913 gp = getattr(self.sock, "getpeername", None) 

1914 if gp is None: 

1915 return "unknown", 0 

1916 return gp() 

1917 

1918 def stop_thread(self): 

1919 self.active = False 

1920 self.packetizer.close() 

1921 # Keep trying to join() our main thread, quickly, until: 

1922 # * We join()ed successfully (self.is_alive() == False) 

1923 # * Or it looks like we've hit issue #520 (socket.recv hitting some 

1924 # race condition preventing it from timing out correctly), wherein 

1925 # our socket and packetizer are both closed (but where we'd 

1926 # otherwise be sitting forever on that recv()). 

1927 while ( 

1928 self.is_alive() 

1929 and self is not threading.current_thread() 

1930 and not self.sock._closed 

1931 and not self.packetizer.closed 

1932 ): 

1933 self.join(0.1) 

1934 

1935 # internals... 

1936 

1937 # TODO 4.0: make a public alias for this because multiple other classes 

1938 # already explicitly rely on it...or just rewrite logging :D 

1939 def _log(self, level, msg, *args): 

1940 if issubclass(type(msg), list): 

1941 for m in msg: 

1942 self.logger.log(level, m) 

1943 else: 

1944 self.logger.log(level, msg, *args) 

1945 

1946 def _get_modulus_pack(self): 

1947 """used by KexGex to find primes for group exchange""" 

1948 return self._modulus_pack 

1949 

1950 def _next_channel(self): 

1951 """you are holding the lock""" 

1952 chanid = self._channel_counter 

1953 while self._channels.get(chanid) is not None: 

1954 self._channel_counter = (self._channel_counter + 1) & 0xFFFFFF 

1955 chanid = self._channel_counter 

1956 self._channel_counter = (self._channel_counter + 1) & 0xFFFFFF 

1957 return chanid 

1958 

1959 def _unlink_channel(self, chanid): 

1960 """used by a Channel to remove itself from the active channel list""" 

1961 self._channels.delete(chanid) 

1962 

1963 def _send_message(self, data): 

1964 self.packetizer.send_message(data) 

1965 

1966 def _send_user_message(self, data): 

1967 """ 

1968 send a message, but block if we're in key negotiation. this is used 

1969 for user-initiated requests. 

1970 """ 

1971 start = time.time() 

1972 while True: 

1973 self.clear_to_send.wait(0.1) 

1974 if not self.active: 

1975 self._log( 

1976 DEBUG, "Dropping user packet because connection is dead." 

1977 ) # noqa 

1978 return 

1979 self.clear_to_send_lock.acquire() 

1980 if self.clear_to_send.is_set(): 

1981 break 

1982 self.clear_to_send_lock.release() 

1983 if time.time() > start + self.clear_to_send_timeout: 

1984 raise SSHException( 

1985 "Key-exchange timed out waiting for key negotiation" 

1986 ) # noqa 

1987 try: 

1988 self._send_message(data) 

1989 finally: 

1990 self.clear_to_send_lock.release() 

1991 

1992 def _set_K_H(self, k, h): 

1993 """ 

1994 Used by a kex obj to set the K (root key) and H (exchange hash). 

1995 """ 

1996 self.K = k 

1997 self.H = h 

1998 if self.session_id is None: 

1999 self.session_id = h 

2000 

2001 def _expect_packet(self, *ptypes): 

2002 """ 

2003 Used by a kex obj to register the next packet type it expects to see. 

2004 """ 

2005 self._expected_packet = tuple(ptypes) 

2006 

2007 def _verify_key(self, host_key, sig): 

2008 key = self._key_info[self.host_key_type](Message(host_key)) 

2009 if key is None: 

2010 raise SSHException("Unknown host key type") 

2011 if not key.verify_ssh_sig(self.H, Message(sig)): 

2012 raise SSHException( 

2013 "Signature verification ({}) failed.".format( 

2014 self.host_key_type 

2015 ) 

2016 ) # noqa 

2017 self.host_key = key 

2018 

2019 def _compute_key(self, id, nbytes): 

2020 """id is 'A' - 'F' for the various keys used by ssh""" 

2021 m = Message() 

2022 m.add_mpint(self.K) 

2023 m.add_bytes(self.H) 

2024 m.add_byte(b(id)) 

2025 m.add_bytes(self.session_id) 

2026 # Fallback to SHA1 for kex engines that fail to specify a hex 

2027 # algorithm, or for e.g. transport tests that don't run kexinit. 

2028 hash_algo = getattr(self.kex_engine, "hash_algo", None) 

2029 hash_select_msg = "kex engine {} specified hash_algo {!r}".format( 

2030 self.kex_engine.__class__.__name__, hash_algo 

2031 ) 

2032 if hash_algo is None: 

2033 hash_algo = sha1 

2034 hash_select_msg += ", falling back to sha1" 

2035 if not hasattr(self, "_logged_hash_selection"): 

2036 self._log(DEBUG, hash_select_msg) 

2037 setattr(self, "_logged_hash_selection", True) 

2038 out = sofar = hash_algo(m.asbytes()).digest() 

2039 while len(out) < nbytes: 

2040 m = Message() 

2041 m.add_mpint(self.K) 

2042 m.add_bytes(self.H) 

2043 m.add_bytes(sofar) 

2044 digest = hash_algo(m.asbytes()).digest() 

2045 out += digest 

2046 sofar += digest 

2047 return out[:nbytes] 

2048 

2049 def _get_engine(self, name, key, iv=None, operation=None, aead=False): 

2050 if name not in self._cipher_info: 

2051 raise SSHException("Unknown cipher " + name) 

2052 info = self._cipher_info[name] 

2053 algorithm = info["class"](key) 

2054 # AEAD types (eg GCM) use their algorithm class /as/ the encryption 

2055 # engine (they expose the same encrypt/decrypt API as a CipherContext) 

2056 if aead: 

2057 return algorithm 

2058 # All others go through the Cipher class. 

2059 cipher = Cipher( 

2060 algorithm=algorithm, 

2061 # TODO: why is this getting tickled in aesgcm mode??? 

2062 mode=info["mode"](iv), 

2063 backend=default_backend(), 

2064 ) 

2065 if operation is self._ENCRYPT: 

2066 return cipher.encryptor() 

2067 else: 

2068 return cipher.decryptor() 

2069 

2070 def _set_forward_agent_handler(self, handler): 

2071 if handler is None: 

2072 

2073 def default_handler(channel): 

2074 self._queue_incoming_channel(channel) 

2075 

2076 self._forward_agent_handler = default_handler 

2077 else: 

2078 self._forward_agent_handler = handler 

2079 

2080 def _set_x11_handler(self, handler): 

2081 # only called if a channel has turned on x11 forwarding 

2082 if handler is None: 

2083 # by default, use the same mechanism as accept() 

2084 def default_handler(channel, src_addr_port): 

2085 self._queue_incoming_channel(channel) 

2086 

2087 self._x11_handler = default_handler 

2088 else: 

2089 self._x11_handler = handler 

2090 

2091 def _queue_incoming_channel(self, channel): 

2092 self.lock.acquire() 

2093 try: 

2094 self.server_accepts.append(channel) 

2095 self.server_accept_cv.notify() 

2096 finally: 

2097 self.lock.release() 

2098 

2099 def _sanitize_window_size(self, window_size): 

2100 if window_size is None: 

2101 window_size = self.default_window_size 

2102 return clamp_value(MIN_WINDOW_SIZE, window_size, MAX_WINDOW_SIZE) 

2103 

2104 def _sanitize_packet_size(self, max_packet_size): 

2105 if max_packet_size is None: 

2106 max_packet_size = self.default_max_packet_size 

2107 return clamp_value(MIN_PACKET_SIZE, max_packet_size, MAX_WINDOW_SIZE) 

2108 

2109 def _ensure_authed(self, ptype, message): 

2110 """ 

2111 Checks message type against current auth state. 

2112 

2113 If server mode, and auth has not succeeded, and the message is of a 

2114 post-auth type (channel open or global request) an appropriate error 

2115 response Message is crafted and returned to caller for sending. 

2116 

2117 Otherwise (client mode, authed, or pre-auth message) returns None. 

2118 """ 

2119 if ( 

2120 not self.server_mode 

2121 or ptype <= HIGHEST_USERAUTH_MESSAGE_ID 

2122 or self.is_authenticated() 

2123 ): 

2124 return None 

2125 # WELP. We must be dealing with someone trying to do non-auth things 

2126 # without being authed. Tell them off, based on message class. 

2127 reply = Message() 

2128 # Global requests have no details, just failure. 

2129 if ptype == MSG_GLOBAL_REQUEST: 

2130 reply.add_byte(cMSG_REQUEST_FAILURE) 

2131 # Channel opens let us reject w/ a specific type + message. 

2132 elif ptype == MSG_CHANNEL_OPEN: 

2133 kind = message.get_text() # noqa 

2134 chanid = message.get_int() 

2135 reply.add_byte(cMSG_CHANNEL_OPEN_FAILURE) 

2136 reply.add_int(chanid) 

2137 reply.add_int(OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED) 

2138 reply.add_string("") 

2139 reply.add_string("en") 

2140 # NOTE: Post-open channel messages do not need checking; the above will 

2141 # reject attempts to open channels, meaning that even if a malicious 

2142 # user tries to send a MSG_CHANNEL_REQUEST, it will simply fall under 

2143 # the logic that handles unknown channel IDs (as the channel list will 

2144 # be empty.) 

2145 return reply 

2146 

2147 def _enforce_strict_kex(self, ptype): 

2148 """ 

2149 Conditionally raise `MessageOrderError` during strict initial kex. 

2150 

2151 This method should only be called inside code that handles non-KEXINIT 

2152 messages; it does not interrogate ``ptype`` besides using it to log 

2153 more accurately. 

2154 """ 

2155 if self.agreed_on_strict_kex and not self.initial_kex_done: 

2156 name = MSG_NAMES.get(ptype, f"msg {ptype}") 

2157 raise MessageOrderError( 

2158 f"In strict-kex mode, but was sent {name!r}!" 

2159 ) 

2160 

2161 def run(self): 

2162 # (use the exposed "run" method, because if we specify a thread target 

2163 # of a private method, threading.Thread will keep a reference to it 

2164 # indefinitely, creating a GC cycle and not letting Transport ever be 

2165 # GC'd. it's a bug in Thread.) 

2166 

2167 # Hold reference to 'sys' so we can test sys.modules to detect 

2168 # interpreter shutdown. 

2169 self.sys = sys 

2170 

2171 # active=True occurs before the thread is launched, to avoid a race 

2172 _active_threads.append(self) 

2173 tid = hex(id(self) & xffffffff) 

2174 if self.server_mode: 

2175 self._log(DEBUG, "starting thread (server mode): {}".format(tid)) 

2176 else: 

2177 self._log(DEBUG, "starting thread (client mode): {}".format(tid)) 

2178 try: 

2179 try: 

2180 self.packetizer.write_all(b(self.local_version + "\r\n")) 

2181 self._log( 

2182 DEBUG, 

2183 "Local version/idstring: {}".format(self.local_version), 

2184 ) # noqa 

2185 self._check_banner() 

2186 # The above is actually very much part of the handshake, but 

2187 # sometimes the banner can be read but the machine is not 

2188 # responding, for example when the remote ssh daemon is loaded 

2189 # in to memory but we can not read from the disk/spawn a new 

2190 # shell. 

2191 # Make sure we can specify a timeout for the initial handshake. 

2192 # Re-use the banner timeout for now. 

2193 self.packetizer.start_handshake(self.handshake_timeout) 

2194 self._send_kex_init() 

2195 self._expect_packet(MSG_KEXINIT) 

2196 

2197 while self.active: 

2198 if self.packetizer.need_rekey() and not self.in_kex: 

2199 self._send_kex_init() 

2200 try: 

2201 ptype, m = self.packetizer.read_message() 

2202 except NeedRekeyException: 

2203 continue 

2204 if ptype == MSG_IGNORE: 

2205 self._enforce_strict_kex(ptype) 

2206 continue 

2207 elif ptype == MSG_DISCONNECT: 

2208 self._parse_disconnect(m) 

2209 break 

2210 elif ptype == MSG_DEBUG: 

2211 self._enforce_strict_kex(ptype) 

2212 self._parse_debug(m) 

2213 continue 

2214 if len(self._expected_packet) > 0: 

2215 if ptype not in self._expected_packet: 

2216 exc_class = SSHException 

2217 if self.agreed_on_strict_kex: 

2218 exc_class = MessageOrderError 

2219 raise exc_class( 

2220 "Expecting packet from {!r}, got {:d}".format( 

2221 self._expected_packet, ptype 

2222 ) 

2223 ) # noqa 

2224 self._expected_packet = tuple() 

2225 # These message IDs indicate key exchange & will differ 

2226 # depending on exact exchange algorithm 

2227 if (ptype >= 30) and (ptype <= 41): 

2228 self.kex_engine.parse_next(ptype, m) 

2229 continue 

2230 

2231 if ptype in self._handler_table: 

2232 error_msg = self._ensure_authed(ptype, m) 

2233 if error_msg: 

2234 self._send_message(error_msg) 

2235 else: 

2236 self._handler_table[ptype](m) 

2237 elif ptype in self._channel_handler_table: 

2238 chanid = m.get_int() 

2239 chan = self._channels.get(chanid) 

2240 if chan is not None: 

2241 self._channel_handler_table[ptype](chan, m) 

2242 elif chanid in self.channels_seen: 

2243 self._log( 

2244 DEBUG, 

2245 "Ignoring message for dead channel {:d}".format( # noqa 

2246 chanid 

2247 ), 

2248 ) 

2249 else: 

2250 self._log( 

2251 ERROR, 

2252 "Channel request for unknown channel {:d}".format( # noqa 

2253 chanid 

2254 ), 

2255 ) 

2256 break 

2257 elif ( 

2258 self.auth_handler is not None 

2259 and ptype in self.auth_handler._handler_table 

2260 ): 

2261 handler = self.auth_handler._handler_table[ptype] 

2262 handler(m) 

2263 if len(self._expected_packet) > 0: 

2264 continue 

2265 else: 

2266 # Respond with "I don't implement this particular 

2267 # message type" message (unless the message type was 

2268 # itself literally MSG_UNIMPLEMENTED, in which case, we 

2269 # just shut up to avoid causing a useless loop). 

2270 name = MSG_NAMES[ptype] 

2271 warning = "Oops, unhandled type {} ({!r})".format( 

2272 ptype, name 

2273 ) 

2274 self._log(WARNING, warning) 

2275 if ptype != MSG_UNIMPLEMENTED: 

2276 msg = Message() 

2277 msg.add_byte(cMSG_UNIMPLEMENTED) 

2278 msg.add_int(m.seqno) 

2279 self._send_message(msg) 

2280 self.packetizer.complete_handshake() 

2281 except SSHException as e: 

2282 self._log( 

2283 ERROR, 

2284 "Exception ({}): {}".format( 

2285 "server" if self.server_mode else "client", e 

2286 ), 

2287 ) 

2288 self._log(ERROR, util.tb_strings()) 

2289 self.saved_exception = e 

2290 except EOFError as e: 

2291 self._log(DEBUG, "EOF in transport thread") 

2292 self.saved_exception = e 

2293 except socket.error as e: 

2294 if type(e.args) is tuple: 

2295 if e.args: 

2296 emsg = "{} ({:d})".format(e.args[1], e.args[0]) 

2297 else: # empty tuple, e.g. socket.timeout 

2298 emsg = str(e) or repr(e) 

2299 else: 

2300 emsg = e.args 

2301 self._log(ERROR, "Socket exception: " + emsg) 

2302 self.saved_exception = e 

2303 except Exception as e: 

2304 self._log(ERROR, "Unknown exception: " + str(e)) 

2305 self._log(ERROR, util.tb_strings()) 

2306 self.saved_exception = e 

2307 _active_threads.remove(self) 

2308 for chan in list(self._channels.values()): 

2309 chan._unlink() 

2310 if self.active: 

2311 self.active = False 

2312 self.packetizer.close() 

2313 if self.completion_event is not None: 

2314 self.completion_event.set() 

2315 if self.auth_handler is not None: 

2316 self.auth_handler.abort() 

2317 for event in self.channel_events.values(): 

2318 event.set() 

2319 try: 

2320 self.lock.acquire() 

2321 self.server_accept_cv.notify() 

2322 finally: 

2323 self.lock.release() 

2324 self.sock.close() 

2325 except: 

2326 # Don't raise spurious 'NoneType has no attribute X' errors when we 

2327 # wake up during interpreter shutdown. Or rather -- raise 

2328 # everything *if* sys.modules (used as a convenient sentinel) 

2329 # appears to still exist. 

2330 if self.sys.modules is not None: 

2331 raise 

2332 

2333 def _log_agreement(self, which, local, remote): 

2334 # Log useful, non-duplicative line re: an agreed-upon algorithm. 

2335 # Old code implied algorithms could be asymmetrical (different for 

2336 # inbound vs outbound) so we preserve that possibility. 

2337 msg = "{}: ".format(which) 

2338 if local == remote: 

2339 msg += local 

2340 else: 

2341 msg += "local={}, remote={}".format(local, remote) 

2342 self._log(DEBUG, msg) 

2343 

2344 # protocol stages 

2345 

2346 def _negotiate_keys(self, m): 

2347 # throws SSHException on anything unusual 

2348 self.clear_to_send_lock.acquire() 

2349 try: 

2350 self.clear_to_send.clear() 

2351 finally: 

2352 self.clear_to_send_lock.release() 

2353 if self.local_kex_init is None: 

2354 # remote side wants to renegotiate 

2355 self._send_kex_init() 

2356 self._parse_kex_init(m) 

2357 self.kex_engine.start_kex() 

2358 

2359 def _check_banner(self): 

2360 # this is slow, but we only have to do it once 

2361 for i in range(100): 

2362 # give them 15 seconds for the first line, then just 2 seconds 

2363 # each additional line. (some sites have very high latency.) 

2364 if i == 0: 

2365 timeout = self.banner_timeout 

2366 else: 

2367 timeout = 2 

2368 try: 

2369 buf = self.packetizer.readline(timeout) 

2370 except ProxyCommandFailure: 

2371 raise 

2372 except Exception as e: 

2373 raise SSHException( 

2374 "Error reading SSH protocol banner" + str(e) 

2375 ) 

2376 if buf[:4] == "SSH-": 

2377 break 

2378 self._log(DEBUG, "Banner: " + buf) 

2379 if buf[:4] != "SSH-": 

2380 raise SSHException('Indecipherable protocol version "' + buf + '"') 

2381 # save this server version string for later 

2382 self.remote_version = buf 

2383 self._log(DEBUG, "Remote version/idstring: {}".format(buf)) 

2384 # pull off any attached comment 

2385 # NOTE: comment used to be stored in a variable and then...never used. 

2386 # since 2003. ca 877cd974b8182d26fa76d566072917ea67b64e67 

2387 i = buf.find(" ") 

2388 if i >= 0: 

2389 buf = buf[:i] 

2390 # parse out version string and make sure it matches 

2391 segs = buf.split("-", 2) 

2392 if len(segs) < 3: 

2393 raise SSHException("Invalid SSH banner") 

2394 version = segs[1] 

2395 client = segs[2] 

2396 if version != "1.99" and version != "2.0": 

2397 msg = "Incompatible version ({} instead of 2.0)" 

2398 raise IncompatiblePeer(msg.format(version)) 

2399 msg = "Connected (version {}, client {})".format(version, client) 

2400 self._log(INFO, msg) 

2401 

2402 def _send_kex_init(self): 

2403 """ 

2404 announce to the other side that we'd like to negotiate keys, and what 

2405 kind of key negotiation we support. 

2406 """ 

2407 self.clear_to_send_lock.acquire() 

2408 try: 

2409 self.clear_to_send.clear() 

2410 finally: 

2411 self.clear_to_send_lock.release() 

2412 self.gss_kex_used = False 

2413 self.in_kex = True 

2414 kex_algos = list(self.preferred_kex) 

2415 if self.server_mode: 

2416 mp_required_prefix = "diffie-hellman-group-exchange-sha" 

2417 kex_mp = [k for k in kex_algos if k.startswith(mp_required_prefix)] 

2418 if (self._modulus_pack is None) and (len(kex_mp) > 0): 

2419 # can't do group-exchange if we don't have a pack of potential 

2420 # primes 

2421 pkex = [ 

2422 k 

2423 for k in self.get_security_options().kex 

2424 if not k.startswith(mp_required_prefix) 

2425 ] 

2426 self.get_security_options().kex = pkex 

2427 available_server_keys = list( 

2428 filter( 

2429 list(self.server_key_dict.keys()).__contains__, 

2430 # TODO: ensure tests will catch if somebody streamlines 

2431 # this by mistake - case is the admittedly silly one where 

2432 # the only calls to add_server_key() contain keys which 

2433 # were filtered out of the below via disabled_algorithms. 

2434 # If this is streamlined, we would then be allowing the 

2435 # disabled algorithm(s) for hostkey use 

2436 # TODO: honestly this prob just wants to get thrown out 

2437 # when we make kex configuration more straightforward 

2438 self.preferred_keys, 

2439 ) 

2440 ) 

2441 else: 

2442 available_server_keys = self.preferred_keys 

2443 # Signal support for MSG_EXT_INFO so server will send it to us. 

2444 # NOTE: doing this here handily means we don't even consider this 

2445 # value when agreeing on real kex algo to use (which is a common 

2446 # pitfall when adding this apparently). 

2447 kex_algos.append("ext-info-c") 

2448 

2449 # Similar to ext-info, but used in both server modes, so done outside 

2450 # of above if/else. 

2451 if self.advertise_strict_kex: 

2452 which = "s" if self.server_mode else "c" 

2453 kex_algos.append(f"kex-strict-{which}-v00@openssh.com") 

2454 

2455 m = Message() 

2456 m.add_byte(cMSG_KEXINIT) 

2457 m.add_bytes(os.urandom(16)) 

2458 m.add_list(kex_algos) 

2459 m.add_list(available_server_keys) 

2460 m.add_list(self.preferred_ciphers) 

2461 m.add_list(self.preferred_ciphers) 

2462 m.add_list(self.preferred_macs) 

2463 m.add_list(self.preferred_macs) 

2464 m.add_list(self.preferred_compression) 

2465 m.add_list(self.preferred_compression) 

2466 m.add_string(bytes()) 

2467 m.add_string(bytes()) 

2468 m.add_boolean(False) 

2469 m.add_int(0) 

2470 # save a copy for later (needed to compute a hash) 

2471 self.local_kex_init = self._latest_kex_init = m.asbytes() 

2472 self._send_message(m) 

2473 

2474 def _really_parse_kex_init(self, m, ignore_first_byte=False): 

2475 parsed = {} 

2476 if ignore_first_byte: 

2477 m.get_byte() 

2478 m.get_bytes(16) # cookie, discarded 

2479 parsed["kex_algo_list"] = m.get_list() 

2480 parsed["server_key_algo_list"] = m.get_list() 

2481 parsed["client_encrypt_algo_list"] = m.get_list() 

2482 parsed["server_encrypt_algo_list"] = m.get_list() 

2483 parsed["client_mac_algo_list"] = m.get_list() 

2484 parsed["server_mac_algo_list"] = m.get_list() 

2485 parsed["client_compress_algo_list"] = m.get_list() 

2486 parsed["server_compress_algo_list"] = m.get_list() 

2487 parsed["client_lang_list"] = m.get_list() 

2488 parsed["server_lang_list"] = m.get_list() 

2489 parsed["kex_follows"] = m.get_boolean() 

2490 m.get_int() # unused 

2491 return parsed 

2492 

2493 def _get_latest_kex_init(self): 

2494 return self._really_parse_kex_init( 

2495 Message(self._latest_kex_init), 

2496 ignore_first_byte=True, 

2497 ) 

2498 

2499 def _parse_kex_init(self, m): 

2500 parsed = self._really_parse_kex_init(m) 

2501 kex_algo_list = parsed["kex_algo_list"] 

2502 server_key_algo_list = parsed["server_key_algo_list"] 

2503 client_encrypt_algo_list = parsed["client_encrypt_algo_list"] 

2504 server_encrypt_algo_list = parsed["server_encrypt_algo_list"] 

2505 client_mac_algo_list = parsed["client_mac_algo_list"] 

2506 server_mac_algo_list = parsed["server_mac_algo_list"] 

2507 client_compress_algo_list = parsed["client_compress_algo_list"] 

2508 server_compress_algo_list = parsed["server_compress_algo_list"] 

2509 client_lang_list = parsed["client_lang_list"] 

2510 server_lang_list = parsed["server_lang_list"] 

2511 kex_follows = parsed["kex_follows"] 

2512 

2513 self._log(DEBUG, "=== Key exchange possibilities ===") 

2514 for prefix, value in ( 

2515 ("kex algos", kex_algo_list), 

2516 ("server key", server_key_algo_list), 

2517 # TODO: shouldn't these two lines say "cipher" to match usual 

2518 # terminology (including elsewhere in paramiko!)? 

2519 ("client encrypt", client_encrypt_algo_list), 

2520 ("server encrypt", server_encrypt_algo_list), 

2521 ("client mac", client_mac_algo_list), 

2522 ("server mac", server_mac_algo_list), 

2523 ("client compress", client_compress_algo_list), 

2524 ("server compress", server_compress_algo_list), 

2525 ("client lang", client_lang_list), 

2526 ("server lang", server_lang_list), 

2527 ): 

2528 if value == [""]: 

2529 value = ["<none>"] 

2530 value = ", ".join(value) 

2531 self._log(DEBUG, "{}: {}".format(prefix, value)) 

2532 self._log(DEBUG, "kex follows: {}".format(kex_follows)) 

2533 self._log(DEBUG, "=== Key exchange agreements ===") 

2534 

2535 # Record, and strip out, ext-info and/or strict-kex non-algorithms 

2536 self._remote_ext_info = None 

2537 self._remote_strict_kex = None 

2538 to_pop = [] 

2539 for i, algo in enumerate(kex_algo_list): 

2540 if algo.startswith("ext-info-"): 

2541 self._remote_ext_info = algo 

2542 to_pop.insert(0, i) 

2543 elif algo.startswith("kex-strict-"): 

2544 # NOTE: this is what we are expecting from the /remote/ end. 

2545 which = "c" if self.server_mode else "s" 

2546 expected = f"kex-strict-{which}-v00@openssh.com" 

2547 # Set strict mode if agreed. 

2548 self.agreed_on_strict_kex = ( 

2549 algo == expected and self.advertise_strict_kex 

2550 ) 

2551 self._log( 

2552 DEBUG, f"Strict kex mode: {self.agreed_on_strict_kex}" 

2553 ) 

2554 to_pop.insert(0, i) 

2555 for i in to_pop: 

2556 kex_algo_list.pop(i) 

2557 

2558 # CVE mitigation: expect zeroed-out seqno anytime we are performing kex 

2559 # init phase, if strict mode was negotiated. 

2560 if ( 

2561 self.agreed_on_strict_kex 

2562 and not self.initial_kex_done 

2563 and m.seqno != 0 

2564 ): 

2565 raise MessageOrderError( 

2566 "In strict-kex mode, but KEXINIT was not the first packet!" 

2567 ) 

2568 

2569 # as a server, we pick the first item in the client's list that we 

2570 # support. 

2571 # as a client, we pick the first item in our list that the server 

2572 # supports. 

2573 if self.server_mode: 

2574 agreed_kex = list( 

2575 filter(self.preferred_kex.__contains__, kex_algo_list) 

2576 ) 

2577 else: 

2578 agreed_kex = list( 

2579 filter(kex_algo_list.__contains__, self.preferred_kex) 

2580 ) 

2581 if len(agreed_kex) == 0: 

2582 # TODO: do an auth-overhaul style aggregate exception here? 

2583 # TODO: would let us streamline log output & show all failures up 

2584 # front 

2585 raise IncompatiblePeer( 

2586 "Incompatible ssh peer (no acceptable kex algorithm)" 

2587 ) # noqa 

2588 self.kex_engine = self._kex_info[agreed_kex[0]](self) 

2589 self._log(DEBUG, "Kex: {}".format(agreed_kex[0])) 

2590 

2591 if self.server_mode: 

2592 available_server_keys = list( 

2593 filter( 

2594 list(self.server_key_dict.keys()).__contains__, 

2595 self.preferred_keys, 

2596 ) 

2597 ) 

2598 agreed_keys = list( 

2599 filter( 

2600 available_server_keys.__contains__, server_key_algo_list 

2601 ) 

2602 ) 

2603 else: 

2604 agreed_keys = list( 

2605 filter(server_key_algo_list.__contains__, self.preferred_keys) 

2606 ) 

2607 if len(agreed_keys) == 0: 

2608 raise IncompatiblePeer( 

2609 "Incompatible ssh peer (no acceptable host key)" 

2610 ) # noqa 

2611 self.host_key_type = agreed_keys[0] 

2612 if self.server_mode and (self.get_server_key() is None): 

2613 raise IncompatiblePeer( 

2614 "Incompatible ssh peer (can't match requested host key type)" 

2615 ) # noqa 

2616 self._log_agreement("HostKey", agreed_keys[0], agreed_keys[0]) 

2617 

2618 if self.server_mode: 

2619 agreed_local_ciphers = list( 

2620 filter( 

2621 self.preferred_ciphers.__contains__, 

2622 server_encrypt_algo_list, 

2623 ) 

2624 ) 

2625 agreed_remote_ciphers = list( 

2626 filter( 

2627 self.preferred_ciphers.__contains__, 

2628 client_encrypt_algo_list, 

2629 ) 

2630 ) 

2631 else: 

2632 agreed_local_ciphers = list( 

2633 filter( 

2634 client_encrypt_algo_list.__contains__, 

2635 self.preferred_ciphers, 

2636 ) 

2637 ) 

2638 agreed_remote_ciphers = list( 

2639 filter( 

2640 server_encrypt_algo_list.__contains__, 

2641 self.preferred_ciphers, 

2642 ) 

2643 ) 

2644 if len(agreed_local_ciphers) == 0 or len(agreed_remote_ciphers) == 0: 

2645 raise IncompatiblePeer( 

2646 "Incompatible ssh server (no acceptable ciphers)" 

2647 ) # noqa 

2648 self.local_cipher = agreed_local_ciphers[0] 

2649 self.remote_cipher = agreed_remote_ciphers[0] 

2650 self._log_agreement( 

2651 "Cipher", local=self.local_cipher, remote=self.remote_cipher 

2652 ) 

2653 

2654 if self.server_mode: 

2655 agreed_remote_macs = list( 

2656 filter(self.preferred_macs.__contains__, client_mac_algo_list) 

2657 ) 

2658 agreed_local_macs = list( 

2659 filter(self.preferred_macs.__contains__, server_mac_algo_list) 

2660 ) 

2661 else: 

2662 agreed_local_macs = list( 

2663 filter(client_mac_algo_list.__contains__, self.preferred_macs) 

2664 ) 

2665 agreed_remote_macs = list( 

2666 filter(server_mac_algo_list.__contains__, self.preferred_macs) 

2667 ) 

2668 if (len(agreed_local_macs) == 0) or (len(agreed_remote_macs) == 0): 

2669 raise IncompatiblePeer( 

2670 "Incompatible ssh server (no acceptable macs)" 

2671 ) 

2672 self.local_mac = agreed_local_macs[0] 

2673 self.remote_mac = agreed_remote_macs[0] 

2674 self._log_agreement( 

2675 "MAC", local=self.local_mac, remote=self.remote_mac 

2676 ) 

2677 

2678 if self.server_mode: 

2679 agreed_remote_compression = list( 

2680 filter( 

2681 self.preferred_compression.__contains__, 

2682 client_compress_algo_list, 

2683 ) 

2684 ) 

2685 agreed_local_compression = list( 

2686 filter( 

2687 self.preferred_compression.__contains__, 

2688 server_compress_algo_list, 

2689 ) 

2690 ) 

2691 else: 

2692 agreed_local_compression = list( 

2693 filter( 

2694 client_compress_algo_list.__contains__, 

2695 self.preferred_compression, 

2696 ) 

2697 ) 

2698 agreed_remote_compression = list( 

2699 filter( 

2700 server_compress_algo_list.__contains__, 

2701 self.preferred_compression, 

2702 ) 

2703 ) 

2704 if ( 

2705 len(agreed_local_compression) == 0 

2706 or len(agreed_remote_compression) == 0 

2707 ): 

2708 msg = "Incompatible ssh server (no acceptable compression)" 

2709 msg += " {!r} {!r} {!r}" 

2710 raise IncompatiblePeer( 

2711 msg.format( 

2712 agreed_local_compression, 

2713 agreed_remote_compression, 

2714 self.preferred_compression, 

2715 ) 

2716 ) 

2717 self.local_compression = agreed_local_compression[0] 

2718 self.remote_compression = agreed_remote_compression[0] 

2719 self._log_agreement( 

2720 "Compression", 

2721 local=self.local_compression, 

2722 remote=self.remote_compression, 

2723 ) 

2724 self._log(DEBUG, "=== End of kex handshake ===") 

2725 

2726 # save for computing hash later... 

2727 # now wait! openssh has a bug (and others might too) where there are 

2728 # actually some extra bytes (one NUL byte in openssh's case) added to 

2729 # the end of the packet but not parsed. turns out we need to throw 

2730 # away those bytes because they aren't part of the hash. 

2731 self.remote_kex_init = cMSG_KEXINIT + m.get_so_far() 

2732 

2733 def _activate_inbound(self): 

2734 """switch on newly negotiated encryption parameters for 

2735 inbound traffic""" 

2736 info = self._cipher_info[self.remote_cipher] 

2737 aead = info.get("is_aead", False) 

2738 block_size = info["block-size"] 

2739 key_size = info["key-size"] 

2740 # Non-AEAD/GCM type ciphers' IV size is their block size. 

2741 iv_size = info.get("iv-size", block_size) 

2742 if self.server_mode: 

2743 iv_in = self._compute_key("A", iv_size) 

2744 key_in = self._compute_key("C", key_size) 

2745 else: 

2746 iv_in = self._compute_key("B", iv_size) 

2747 key_in = self._compute_key("D", key_size) 

2748 

2749 engine = self._get_engine( 

2750 name=self.remote_cipher, 

2751 key=key_in, 

2752 iv=iv_in, 

2753 operation=self._DECRYPT, 

2754 aead=aead, 

2755 ) 

2756 etm = (not aead) and "etm@openssh.com" in self.remote_mac 

2757 mac_size = self._mac_info[self.remote_mac]["size"] 

2758 mac_engine = self._mac_info[self.remote_mac]["class"] 

2759 # initial mac keys are done in the hash's natural size (not the 

2760 # potentially truncated transmission size) 

2761 if self.server_mode: 

2762 mac_key = self._compute_key("E", mac_engine().digest_size) 

2763 else: 

2764 mac_key = self._compute_key("F", mac_engine().digest_size) 

2765 

2766 self.packetizer.set_inbound_cipher( 

2767 block_engine=engine, 

2768 block_size=block_size, 

2769 mac_engine=None if aead else mac_engine, 

2770 mac_size=16 if aead else mac_size, 

2771 mac_key=None if aead else mac_key, 

2772 etm=etm, 

2773 aead=aead, 

2774 iv_in=iv_in if aead else None, 

2775 ) 

2776 

2777 compress_in = self._compression_info[self.remote_compression][1] 

2778 if compress_in is not None and ( 

2779 self.remote_compression != "zlib@openssh.com" or self.authenticated 

2780 ): 

2781 self._log(DEBUG, "Switching on inbound compression ...") 

2782 self.packetizer.set_inbound_compressor(compress_in()) 

2783 # Reset inbound sequence number if strict mode. 

2784 if self.agreed_on_strict_kex: 

2785 self._log( 

2786 DEBUG, 

2787 "Resetting inbound seqno after NEWKEYS due to strict mode", 

2788 ) 

2789 self.packetizer.reset_seqno_in() 

2790 

2791 def _activate_outbound(self): 

2792 """switch on newly negotiated encryption parameters for 

2793 outbound traffic""" 

2794 m = Message() 

2795 m.add_byte(cMSG_NEWKEYS) 

2796 self._send_message(m) 

2797 # Reset outbound sequence number if strict mode. 

2798 if self.agreed_on_strict_kex: 

2799 self._log( 

2800 DEBUG, 

2801 "Resetting outbound seqno after NEWKEYS due to strict mode", 

2802 ) 

2803 self.packetizer.reset_seqno_out() 

2804 info = self._cipher_info[self.local_cipher] 

2805 aead = info.get("is_aead", False) 

2806 block_size = info["block-size"] 

2807 key_size = info["key-size"] 

2808 # Non-AEAD/GCM type ciphers' IV size is their block size. 

2809 iv_size = info.get("iv-size", block_size) 

2810 if self.server_mode: 

2811 iv_out = self._compute_key("B", iv_size) 

2812 key_out = self._compute_key("D", key_size) 

2813 else: 

2814 iv_out = self._compute_key("A", iv_size) 

2815 key_out = self._compute_key("C", key_size) 

2816 

2817 engine = self._get_engine( 

2818 name=self.local_cipher, 

2819 key=key_out, 

2820 iv=iv_out, 

2821 operation=self._ENCRYPT, 

2822 aead=aead, 

2823 ) 

2824 etm = (not aead) and "etm@openssh.com" in self.local_mac 

2825 mac_size = self._mac_info[self.local_mac]["size"] 

2826 mac_engine = self._mac_info[self.local_mac]["class"] 

2827 # initial mac keys are done in the hash's natural size (not the 

2828 # potentially truncated transmission size) 

2829 if self.server_mode: 

2830 mac_key = self._compute_key("F", mac_engine().digest_size) 

2831 else: 

2832 mac_key = self._compute_key("E", mac_engine().digest_size) 

2833 sdctr = self.local_cipher.endswith("-ctr") 

2834 

2835 self.packetizer.set_outbound_cipher( 

2836 block_engine=engine, 

2837 block_size=block_size, 

2838 mac_engine=None if aead else mac_engine, 

2839 mac_size=16 if aead else mac_size, 

2840 mac_key=None if aead else mac_key, 

2841 sdctr=sdctr, 

2842 etm=etm, 

2843 aead=aead, 

2844 iv_out=iv_out if aead else None, 

2845 ) 

2846 

2847 compress_out = self._compression_info[self.local_compression][0] 

2848 if compress_out is not None and ( 

2849 self.local_compression != "zlib@openssh.com" or self.authenticated 

2850 ): 

2851 self._log(DEBUG, "Switching on outbound compression ...") 

2852 self.packetizer.set_outbound_compressor(compress_out()) 

2853 if not self.packetizer.need_rekey(): 

2854 self.in_kex = False 

2855 # If client indicated extension support, send that packet immediately 

2856 if ( 

2857 self.server_mode 

2858 and self.server_sig_algs 

2859 and self._remote_ext_info == "ext-info-c" 

2860 ): 

2861 extensions = {"server-sig-algs": ",".join(self.preferred_pubkeys)} 

2862 m = Message() 

2863 m.add_byte(cMSG_EXT_INFO) 

2864 m.add_int(len(extensions)) 

2865 for name, value in sorted(extensions.items()): 

2866 m.add_string(name) 

2867 m.add_string(value) 

2868 self._send_message(m) 

2869 # we always expect to receive NEWKEYS now 

2870 self._expect_packet(MSG_NEWKEYS) 

2871 

2872 def _auth_trigger(self): 

2873 self.authenticated = True 

2874 # delayed initiation of compression 

2875 if self.local_compression == "zlib@openssh.com": 

2876 compress_out = self._compression_info[self.local_compression][0] 

2877 self._log(DEBUG, "Switching on outbound compression ...") 

2878 self.packetizer.set_outbound_compressor(compress_out()) 

2879 if self.remote_compression == "zlib@openssh.com": 

2880 compress_in = self._compression_info[self.remote_compression][1] 

2881 self._log(DEBUG, "Switching on inbound compression ...") 

2882 self.packetizer.set_inbound_compressor(compress_in()) 

2883 

2884 def _parse_ext_info(self, msg): 

2885 # Packet is a count followed by that many key-string to possibly-bytes 

2886 # pairs. 

2887 extensions = {} 

2888 for _ in range(msg.get_int()): 

2889 name = msg.get_text() 

2890 value = msg.get_string() 

2891 extensions[name] = value 

2892 self._log(DEBUG, "Got EXT_INFO: {}".format(extensions)) 

2893 # NOTE: this should work ok in cases where a server sends /two/ such 

2894 # messages; the RFC explicitly states a 2nd one should overwrite the 

2895 # 1st. 

2896 self.server_extensions = extensions 

2897 

2898 def _parse_newkeys(self, m): 

2899 self._log(DEBUG, "Switch to new keys ...") 

2900 self._activate_inbound() 

2901 # can also free a bunch of stuff here 

2902 self.local_kex_init = self.remote_kex_init = None 

2903 self.K = None 

2904 self.kex_engine = None 

2905 if self.server_mode and (self.auth_handler is None): 

2906 # create auth handler for server mode 

2907 self.auth_handler = AuthHandler(self) 

2908 if not self.initial_kex_done: 

2909 # this was the first key exchange 

2910 # (also signal to packetizer as it sometimes wants to know this 

2911 # status as well, eg when seqnos rollover) 

2912 self.initial_kex_done = self.packetizer._initial_kex_done = True 

2913 # send an event? 

2914 if self.completion_event is not None: 

2915 self.completion_event.set() 

2916 # it's now okay to send data again (if this was a re-key) 

2917 if not self.packetizer.need_rekey(): 

2918 self.in_kex = False 

2919 self.clear_to_send_lock.acquire() 

2920 try: 

2921 self.clear_to_send.set() 

2922 finally: 

2923 self.clear_to_send_lock.release() 

2924 return 

2925 

2926 def _parse_disconnect(self, m): 

2927 code = m.get_int() 

2928 desc = m.get_text() 

2929 self._log(INFO, "Disconnect (code {:d}): {}".format(code, desc)) 

2930 

2931 def _parse_global_request(self, m): 

2932 kind = m.get_text() 

2933 self._log(DEBUG, 'Received global request "{}"'.format(kind)) 

2934 want_reply = m.get_boolean() 

2935 if not self.server_mode: 

2936 self._log( 

2937 DEBUG, 

2938 'Rejecting "{}" global request from server.'.format(kind), 

2939 ) 

2940 ok = False 

2941 elif kind == "tcpip-forward": 

2942 address = m.get_text() 

2943 port = m.get_int() 

2944 ok = self.server_object.check_port_forward_request(address, port) 

2945 if ok: 

2946 ok = (ok,) 

2947 elif kind == "cancel-tcpip-forward": 

2948 address = m.get_text() 

2949 port = m.get_int() 

2950 self.server_object.cancel_port_forward_request(address, port) 

2951 ok = True 

2952 else: 

2953 ok = self.server_object.check_global_request(kind, m) 

2954 extra = () 

2955 if type(ok) is tuple: 

2956 extra = ok 

2957 ok = True 

2958 if want_reply: 

2959 msg = Message() 

2960 if ok: 

2961 msg.add_byte(cMSG_REQUEST_SUCCESS) 

2962 msg.add(*extra) 

2963 else: 

2964 msg.add_byte(cMSG_REQUEST_FAILURE) 

2965 self._send_message(msg) 

2966 

2967 def _parse_request_success(self, m): 

2968 self._log(DEBUG, "Global request successful.") 

2969 self.global_response = m 

2970 if self.completion_event is not None: 

2971 self.completion_event.set() 

2972 

2973 def _parse_request_failure(self, m): 

2974 self._log(DEBUG, "Global request denied.") 

2975 self.global_response = None 

2976 if self.completion_event is not None: 

2977 self.completion_event.set() 

2978 

2979 def _parse_channel_open_success(self, m): 

2980 chanid = m.get_int() 

2981 server_chanid = m.get_int() 

2982 server_window_size = m.get_int() 

2983 server_max_packet_size = m.get_int() 

2984 chan = self._channels.get(chanid) 

2985 if chan is None: 

2986 self._log(WARNING, "Success for unrequested channel! [??]") 

2987 return 

2988 self.lock.acquire() 

2989 try: 

2990 chan._set_remote_channel( 

2991 server_chanid, server_window_size, server_max_packet_size 

2992 ) 

2993 self._log(DEBUG, "Secsh channel {:d} opened.".format(chanid)) 

2994 if chanid in self.channel_events: 

2995 self.channel_events[chanid].set() 

2996 del self.channel_events[chanid] 

2997 finally: 

2998 self.lock.release() 

2999 return 

3000 

3001 def _parse_channel_open_failure(self, m): 

3002 chanid = m.get_int() 

3003 reason = m.get_int() 

3004 reason_str = m.get_text() 

3005 m.get_text() # ignored language 

3006 reason_text = CONNECTION_FAILED_CODE.get(reason, "(unknown code)") 

3007 self._log( 

3008 ERROR, 

3009 "Secsh channel {:d} open FAILED: {}: {}".format( 

3010 chanid, reason_str, reason_text 

3011 ), 

3012 ) 

3013 self.lock.acquire() 

3014 try: 

3015 self.saved_exception = ChannelException(reason, reason_text) 

3016 if chanid in self.channel_events: 

3017 self._channels.delete(chanid) 

3018 if chanid in self.channel_events: 

3019 self.channel_events[chanid].set() 

3020 del self.channel_events[chanid] 

3021 finally: 

3022 self.lock.release() 

3023 return 

3024 

3025 def _parse_channel_open(self, m): 

3026 kind = m.get_text() 

3027 chanid = m.get_int() 

3028 initial_window_size = m.get_int() 

3029 max_packet_size = m.get_int() 

3030 reject = False 

3031 if ( 

3032 kind == "auth-agent@openssh.com" 

3033 and self._forward_agent_handler is not None 

3034 ): 

3035 self._log(DEBUG, "Incoming forward agent connection") 

3036 self.lock.acquire() 

3037 try: 

3038 my_chanid = self._next_channel() 

3039 finally: 

3040 self.lock.release() 

3041 elif (kind == "x11") and (self._x11_handler is not None): 

3042 origin_addr = m.get_text() 

3043 origin_port = m.get_int() 

3044 self._log( 

3045 DEBUG, 

3046 "Incoming x11 connection from {}:{:d}".format( 

3047 origin_addr, origin_port 

3048 ), 

3049 ) 

3050 self.lock.acquire() 

3051 try: 

3052 my_chanid = self._next_channel() 

3053 finally: 

3054 self.lock.release() 

3055 elif (kind == "forwarded-tcpip") and (self._tcp_handler is not None): 

3056 server_addr = m.get_text() 

3057 server_port = m.get_int() 

3058 origin_addr = m.get_text() 

3059 origin_port = m.get_int() 

3060 self._log( 

3061 DEBUG, 

3062 "Incoming tcp forwarded connection from {}:{:d}".format( 

3063 origin_addr, origin_port 

3064 ), 

3065 ) 

3066 self.lock.acquire() 

3067 try: 

3068 my_chanid = self._next_channel() 

3069 finally: 

3070 self.lock.release() 

3071 elif not self.server_mode: 

3072 self._log( 

3073 DEBUG, 

3074 'Rejecting "{}" channel request from server.'.format(kind), 

3075 ) 

3076 reject = True 

3077 reason = OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED 

3078 else: 

3079 self.lock.acquire() 

3080 try: 

3081 my_chanid = self._next_channel() 

3082 finally: 

3083 self.lock.release() 

3084 if kind == "direct-tcpip": 

3085 # handle direct-tcpip requests coming from the client 

3086 dest_addr = m.get_text() 

3087 dest_port = m.get_int() 

3088 origin_addr = m.get_text() 

3089 origin_port = m.get_int() 

3090 reason = self.server_object.check_channel_direct_tcpip_request( 

3091 my_chanid, 

3092 (origin_addr, origin_port), 

3093 (dest_addr, dest_port), 

3094 ) 

3095 else: 

3096 reason = self.server_object.check_channel_request( 

3097 kind, my_chanid 

3098 ) 

3099 if reason != OPEN_SUCCEEDED: 

3100 self._log( 

3101 DEBUG, 

3102 'Rejecting "{}" channel request from client.'.format(kind), 

3103 ) 

3104 reject = True 

3105 if reject: 

3106 msg = Message() 

3107 msg.add_byte(cMSG_CHANNEL_OPEN_FAILURE) 

3108 msg.add_int(chanid) 

3109 msg.add_int(reason) 

3110 msg.add_string("") 

3111 msg.add_string("en") 

3112 self._send_message(msg) 

3113 return 

3114 

3115 chan = Channel(my_chanid) 

3116 self.lock.acquire() 

3117 try: 

3118 self._channels.put(my_chanid, chan) 

3119 self.channels_seen[my_chanid] = True 

3120 chan._set_transport(self) 

3121 chan._set_window( 

3122 self.default_window_size, self.default_max_packet_size 

3123 ) 

3124 chan._set_remote_channel( 

3125 chanid, initial_window_size, max_packet_size 

3126 ) 

3127 finally: 

3128 self.lock.release() 

3129 m = Message() 

3130 m.add_byte(cMSG_CHANNEL_OPEN_SUCCESS) 

3131 m.add_int(chanid) 

3132 m.add_int(my_chanid) 

3133 m.add_int(self.default_window_size) 

3134 m.add_int(self.default_max_packet_size) 

3135 self._send_message(m) 

3136 self._log( 

3137 DEBUG, "Secsh channel {:d} ({}) opened.".format(my_chanid, kind) 

3138 ) 

3139 if kind == "auth-agent@openssh.com": 

3140 self._forward_agent_handler(chan) 

3141 elif kind == "x11": 

3142 self._x11_handler(chan, (origin_addr, origin_port)) 

3143 elif kind == "forwarded-tcpip": 

3144 chan.origin_addr = (origin_addr, origin_port) 

3145 self._tcp_handler( 

3146 chan, (origin_addr, origin_port), (server_addr, server_port) 

3147 ) 

3148 else: 

3149 self._queue_incoming_channel(chan) 

3150 

3151 def _parse_debug(self, m): 

3152 m.get_boolean() # always_display 

3153 msg = m.get_string() 

3154 m.get_string() # language 

3155 self._log(DEBUG, "Debug msg: {}".format(util.safe_string(msg))) 

3156 

3157 def _get_subsystem_handler(self, name): 

3158 try: 

3159 self.lock.acquire() 

3160 if name not in self.subsystem_table: 

3161 return None, [], {} 

3162 return self.subsystem_table[name] 

3163 finally: 

3164 self.lock.release() 

3165 

3166 _channel_handler_table = { 

3167 MSG_CHANNEL_SUCCESS: Channel._request_success, 

3168 MSG_CHANNEL_FAILURE: Channel._request_failed, 

3169 MSG_CHANNEL_DATA: Channel._feed, 

3170 MSG_CHANNEL_EXTENDED_DATA: Channel._feed_extended, 

3171 MSG_CHANNEL_WINDOW_ADJUST: Channel._window_adjust, 

3172 MSG_CHANNEL_REQUEST: Channel._handle_request, 

3173 MSG_CHANNEL_EOF: Channel._handle_eof, 

3174 MSG_CHANNEL_CLOSE: Channel._handle_close, 

3175 } 

3176 

3177 

3178# TODO 4.0: drop this, we barely use it ourselves, it badly replicates the 

3179# Transport-internal algorithm management, AND does so in a way which doesn't 

3180# honor newer things like disabled_algorithms! 

3181class SecurityOptions: 

3182 """ 

3183 Simple object containing the security preferences of an ssh transport. 

3184 These are tuples of acceptable ciphers, digests, key types, and key 

3185 exchange algorithms, listed in order of preference. 

3186 

3187 Changing the contents and/or order of these fields affects the underlying 

3188 `.Transport` (but only if you change them before starting the session). 

3189 If you try to add an algorithm that paramiko doesn't recognize, 

3190 ``ValueError`` will be raised. If you try to assign something besides a 

3191 tuple to one of the fields, ``TypeError`` will be raised. 

3192 """ 

3193 

3194 __slots__ = "_transport" 

3195 

3196 def __init__(self, transport): 

3197 self._transport = transport 

3198 

3199 def __repr__(self): 

3200 """ 

3201 Returns a string representation of this object, for debugging. 

3202 """ 

3203 return "<paramiko.SecurityOptions for {!r}>".format(self._transport) 

3204 

3205 def _set(self, name, orig, x): 

3206 if type(x) is list: 

3207 x = tuple(x) 

3208 if type(x) is not tuple: 

3209 raise TypeError("expected tuple or list") 

3210 possible = list(getattr(self._transport, orig).keys()) 

3211 forbidden = [n for n in x if n not in possible] 

3212 if len(forbidden) > 0: 

3213 raise ValueError("unknown cipher") 

3214 setattr(self._transport, name, x) 

3215 

3216 @property 

3217 def ciphers(self): 

3218 """Symmetric encryption ciphers""" 

3219 return self._transport._preferred_ciphers 

3220 

3221 @ciphers.setter 

3222 def ciphers(self, x): 

3223 self._set("_preferred_ciphers", "_cipher_info", x) 

3224 

3225 @property 

3226 def digests(self): 

3227 """Digest (one-way hash) algorithms""" 

3228 return self._transport._preferred_macs 

3229 

3230 @digests.setter 

3231 def digests(self, x): 

3232 self._set("_preferred_macs", "_mac_info", x) 

3233 

3234 @property 

3235 def key_types(self): 

3236 """Public-key algorithms""" 

3237 return self._transport._preferred_keys 

3238 

3239 @key_types.setter 

3240 def key_types(self, x): 

3241 self._set("_preferred_keys", "_key_info", x) 

3242 

3243 @property 

3244 def kex(self): 

3245 """Key exchange algorithms""" 

3246 return self._transport._preferred_kex 

3247 

3248 @kex.setter 

3249 def kex(self, x): 

3250 self._set("_preferred_kex", "_kex_info", x) 

3251 

3252 @property 

3253 def compression(self): 

3254 """Compression algorithms""" 

3255 return self._transport._preferred_compression 

3256 

3257 @compression.setter 

3258 def compression(self, x): 

3259 self._set("_preferred_compression", "_compression_info", x) 

3260 

3261 

3262class ChannelMap: 

3263 def __init__(self): 

3264 # (id -> Channel) 

3265 self._map = weakref.WeakValueDictionary() 

3266 self._lock = threading.Lock() 

3267 

3268 def put(self, chanid, chan): 

3269 self._lock.acquire() 

3270 try: 

3271 self._map[chanid] = chan 

3272 finally: 

3273 self._lock.release() 

3274 

3275 def get(self, chanid): 

3276 self._lock.acquire() 

3277 try: 

3278 return self._map.get(chanid, None) 

3279 finally: 

3280 self._lock.release() 

3281 

3282 def delete(self, chanid): 

3283 self._lock.acquire() 

3284 try: 

3285 try: 

3286 del self._map[chanid] 

3287 except KeyError: 

3288 pass 

3289 finally: 

3290 self._lock.release() 

3291 

3292 def values(self): 

3293 self._lock.acquire() 

3294 try: 

3295 return list(self._map.values()) 

3296 finally: 

3297 self._lock.release() 

3298 

3299 def __len__(self): 

3300 self._lock.acquire() 

3301 try: 

3302 return len(self._map) 

3303 finally: 

3304 self._lock.release() 

3305 

3306 

3307class ServiceRequestingTransport(Transport): 

3308 """ 

3309 Transport, but also handling service requests, like it oughtta! 

3310 

3311 .. versionadded:: 3.2 

3312 """ 

3313 

3314 # NOTE: this purposefully duplicates some of the parent class in order to 

3315 # modernize, refactor, etc. The intent is that eventually we will collapse 

3316 # this one onto the parent in a backwards incompatible release. 

3317 

3318 def __init__(self, *args, **kwargs): 

3319 super().__init__(*args, **kwargs) 

3320 self._service_userauth_accepted = False 

3321 self._handler_table[MSG_SERVICE_ACCEPT] = self._parse_service_accept 

3322 

3323 def _parse_service_accept(self, m): 

3324 service = m.get_text() 

3325 # Short-circuit for any service name not ssh-userauth. 

3326 # NOTE: it's technically possible for 'service name' in 

3327 # SERVICE_REQUEST/ACCEPT messages to be "ssh-connection" -- 

3328 # but I don't see evidence of Paramiko ever initiating or expecting to 

3329 # receive one of these. We /do/ see the 'service name' field in 

3330 # MSG_USERAUTH_REQUEST/ACCEPT/FAILURE set to this string, but that is a 

3331 # different set of handlers, so...! 

3332 if service != "ssh-userauth": 

3333 # TODO 4.0: consider erroring here (with an ability to opt out?) 

3334 # instead as it probably means something went Very Wrong. 

3335 self._log( 

3336 DEBUG, 'Service request "{}" accepted (?)'.format(service) 

3337 ) 

3338 return 

3339 # Record that we saw a service-userauth acceptance, meaning we are free 

3340 # to submit auth requests. 

3341 self._service_userauth_accepted = True 

3342 self._log(DEBUG, "MSG_SERVICE_ACCEPT received; auth may begin") 

3343 

3344 def ensure_session(self): 

3345 # Make sure we're not trying to auth on a not-yet-open or 

3346 # already-closed transport session; that's our responsibility, not that 

3347 # of AuthHandler. 

3348 if (not self.active) or (not self.initial_kex_done): 

3349 # TODO: better error message? this can happen in many places, eg 

3350 # user error (authing before connecting) or developer error (some 

3351 # improperly handled pre/mid auth shutdown didn't become fatal 

3352 # enough). The latter is much more common & should ideally be fixed 

3353 # by terminating things harder? 

3354 raise SSHException("No existing session") 

3355 # Also make sure we've actually been told we are allowed to auth. 

3356 if self._service_userauth_accepted: 

3357 return 

3358 # Or request to do so, otherwise. 

3359 m = Message() 

3360 m.add_byte(cMSG_SERVICE_REQUEST) 

3361 m.add_string("ssh-userauth") 

3362 self._log(DEBUG, "Sending MSG_SERVICE_REQUEST: ssh-userauth") 

3363 self._send_message(m) 

3364 # Now we wait to hear back; the user is expecting a blocking-style auth 

3365 # request so there's no point giving control back anywhere. 

3366 while not self._service_userauth_accepted: 

3367 # TODO: feels like we're missing an AuthHandler Event like 

3368 # 'self.auth_event' which is set when AuthHandler shuts down in 

3369 # ways good AND bad. Transport only seems to have completion_event 

3370 # which is unclear re: intent, eg it's set by newkeys which always 

3371 # happens on connection, so it'll always be set by the time we get 

3372 # here. 

3373 # NOTE: this copies the timing of event.wait() in 

3374 # AuthHandler.wait_for_response, re: 1/10 of a second. Could 

3375 # presumably be smaller, but seems unlikely this period is going to 

3376 # be "too long" for any code doing ssh networking... 

3377 time.sleep(0.1) 

3378 self.auth_handler = self.get_auth_handler() 

3379 

3380 def get_auth_handler(self): 

3381 # NOTE: using new sibling subclass instead of classic AuthHandler 

3382 return AuthOnlyHandler(self) 

3383 

3384 def auth_none(self, username): 

3385 # TODO 4.0: merge to parent, preserving (most of) docstring 

3386 self.ensure_session() 

3387 return self.auth_handler.auth_none(username) 

3388 

3389 def auth_password(self, username, password, fallback=True): 

3390 # TODO 4.0: merge to parent, preserving (most of) docstring 

3391 self.ensure_session() 

3392 try: 

3393 return self.auth_handler.auth_password(username, password) 

3394 except BadAuthenticationType as e: 

3395 # if password auth isn't allowed, but keyboard-interactive *is*, 

3396 # try to fudge it 

3397 if not fallback or ("keyboard-interactive" not in e.allowed_types): 

3398 raise 

3399 try: 

3400 

3401 def handler(title, instructions, fields): 

3402 if len(fields) > 1: 

3403 raise SSHException("Fallback authentication failed.") 

3404 if len(fields) == 0: 

3405 # for some reason, at least on os x, a 2nd request will 

3406 # be made with zero fields requested. maybe it's just 

3407 # to try to fake out automated scripting of the exact 

3408 # type we're doing here. *shrug* :) 

3409 return [] 

3410 return [password] 

3411 

3412 return self.auth_interactive(username, handler) 

3413 except SSHException: 

3414 # attempt to fudge failed; just raise the original exception 

3415 raise e 

3416 

3417 def auth_publickey(self, username, key): 

3418 # TODO 4.0: merge to parent, preserving (most of) docstring 

3419 self.ensure_session() 

3420 return self.auth_handler.auth_publickey(username, key) 

3421 

3422 def auth_interactive(self, username, handler, submethods=""): 

3423 # TODO 4.0: merge to parent, preserving (most of) docstring 

3424 self.ensure_session() 

3425 return self.auth_handler.auth_interactive( 

3426 username, handler, submethods 

3427 ) 

3428 

3429 def auth_interactive_dumb(self, username, handler=None, submethods=""): 

3430 # TODO 4.0: merge to parent, preserving (most of) docstring 

3431 # NOTE: legacy impl omitted equiv of ensure_session since it just wraps 

3432 # another call to an auth method. however we reinstate it for 

3433 # consistency reasons. 

3434 self.ensure_session() 

3435 if not handler: 

3436 

3437 def handler(title, instructions, prompt_list): 

3438 answers = [] 

3439 if title: 

3440 print(title.strip()) 

3441 if instructions: 

3442 print(instructions.strip()) 

3443 for prompt, show_input in prompt_list: 

3444 print(prompt.strip(), end=" ") 

3445 answers.append(input()) 

3446 return answers 

3447 

3448 return self.auth_interactive(username, handler, submethods) 

3449 

3450 def auth_gssapi_with_mic(self, username, gss_host, gss_deleg_creds): 

3451 # TODO 4.0: merge to parent, preserving (most of) docstring 

3452 self.ensure_session() 

3453 self.auth_handler = self.get_auth_handler() 

3454 return self.auth_handler.auth_gssapi_with_mic( 

3455 username, gss_host, gss_deleg_creds 

3456 ) 

3457 

3458 def auth_gssapi_keyex(self, username): 

3459 # TODO 4.0: merge to parent, preserving (most of) docstring 

3460 self.ensure_session() 

3461 self.auth_handler = self.get_auth_handler() 

3462 return self.auth_handler.auth_gssapi_keyex(username)