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