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 from paramiko import util
33 from paramiko.auth_handler import AuthHandler
34 from paramiko.channel import Channel
35 from paramiko.common import *
36 from paramiko.compress import ZlibCompressor, ZlibDecompressor
37 from paramiko.dsskey import DSSKey
38 from paramiko.kex_gex import KexGex
39 from paramiko.kex_group1 import KexGroup1
40 from paramiko.message import Message
41 from paramiko.packet import Packetizer, NeedRekeyException
42 from paramiko.primes import ModulusPack
43 from paramiko.rsakey import RSAKey
44 from paramiko.server import ServerInterface
45 from paramiko.sftp_client import SFTPClient
46 from paramiko.ssh_exception import SSHException, BadAuthenticationType, ChannelException
47
48
49
50
51
52
53 from Crypto.Cipher import Blowfish, AES, DES3
54 from Crypto.Hash import SHA, MD5
55
56
57
58 _active_threads = []
62 import atexit
63 atexit.register(_join_lingering_threads)
64
65
67 """
68 Simple object containing the security preferences of an ssh transport.
69 These are tuples of acceptable ciphers, digests, key types, and key
70 exchange algorithms, listed in order of preference.
71
72 Changing the contents and/or order of these fields affects the underlying
73 L{Transport} (but only if you change them before starting the session).
74 If you try to add an algorithm that paramiko doesn't recognize,
75 C{ValueError} will be raised. If you try to assign something besides a
76 tuple to one of the fields, C{TypeError} will be raised.
77 """
78 __slots__ = [ 'ciphers', 'digests', 'key_types', 'kex', 'compression', '_transport' ]
79
82
84 """
85 Returns a string representation of this object, for debugging.
86
87 @rtype: str
88 """
89 return '<paramiko.SecurityOptions for %s>' % repr(self._transport)
90
93
96
99
102
105
106 - def _set(self, name, orig, x):
107 if type(x) is list:
108 x = tuple(x)
109 if type(x) is not tuple:
110 raise TypeError('expected tuple or list')
111 possible = getattr(self._transport, orig).keys()
112 forbidden = filter(lambda n: n not in possible, x)
113 if len(forbidden) > 0:
114 raise ValueError('unknown cipher')
115 setattr(self._transport, name, x)
116
118 self._set('_preferred_ciphers', '_cipher_info', x)
119
121 self._set('_preferred_macs', '_mac_info', x)
122
124 self._set('_preferred_keys', '_key_info', x)
125
127 self._set('_preferred_kex', '_kex_info', x)
128
130 self._set('_preferred_compression', '_compression_info', x)
131
132 ciphers = property(_get_ciphers, _set_ciphers, None,
133 "Symmetric encryption ciphers")
134 digests = property(_get_digests, _set_digests, None,
135 "Digest (one-way hash) algorithms")
136 key_types = property(_get_key_types, _set_key_types, None,
137 "Public-key algorithms")
138 kex = property(_get_kex, _set_kex, None, "Key exchange algorithms")
139 compression = property(_get_compression, _set_compression, None,
140 "Compression algorithms")
141
142
145
146 self._map = weakref.WeakValueDictionary()
147 self._lock = threading.Lock()
148
149 - def put(self, chanid, chan):
150 self._lock.acquire()
151 try:
152 self._map[chanid] = chan
153 finally:
154 self._lock.release()
155
156 - def get(self, chanid):
157 self._lock.acquire()
158 try:
159 return self._map.get(chanid, None)
160 finally:
161 self._lock.release()
162
164 self._lock.acquire()
165 try:
166 try:
167 del self._map[chanid]
168 except KeyError:
169 pass
170 finally:
171 self._lock.release()
172
174 self._lock.acquire()
175 try:
176 return self._map.values()
177 finally:
178 self._lock.release()
179
181 self._lock.acquire()
182 try:
183 return len(self._map)
184 finally:
185 self._lock.release()
186
187
189 """
190 An SSH Transport attaches to a stream (usually a socket), negotiates an
191 encrypted session, authenticates, and then creates stream tunnels, called
192 L{Channel}s, across the session. Multiple channels can be multiplexed
193 across a single session (and often are, in the case of port forwardings).
194 """
195
196 _PROTO_ID = '2.0'
197 _CLIENT_ID = 'paramiko_1.7.4'
198
199 _preferred_ciphers = ( 'aes128-cbc', 'blowfish-cbc', 'aes256-cbc', '3des-cbc' )
200 _preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' )
201 _preferred_keys = ( 'ssh-rsa', 'ssh-dss' )
202 _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' )
203 _preferred_compression = ( 'none', )
204
205 _cipher_info = {
206 'blowfish-cbc': { 'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16 },
207 'aes128-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16 },
208 'aes256-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32 },
209 '3des-cbc': { 'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24 },
210 }
211
212 _mac_info = {
213 'hmac-sha1': { 'class': SHA, 'size': 20 },
214 'hmac-sha1-96': { 'class': SHA, 'size': 12 },
215 'hmac-md5': { 'class': MD5, 'size': 16 },
216 'hmac-md5-96': { 'class': MD5, 'size': 12 },
217 }
218
219 _key_info = {
220 'ssh-rsa': RSAKey,
221 'ssh-dss': DSSKey,
222 }
223
224 _kex_info = {
225 'diffie-hellman-group1-sha1': KexGroup1,
226 'diffie-hellman-group-exchange-sha1': KexGex,
227 }
228
229 _compression_info = {
230
231
232
233 'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ),
234 'zlib': ( ZlibCompressor, ZlibDecompressor ),
235 'none': ( None, None ),
236 }
237
238
239 _modulus_pack = None
240
242 """
243 Create a new SSH session over an existing socket, or socket-like
244 object. This only creates the Transport object; it doesn't begin the
245 SSH session yet. Use L{connect} or L{start_client} to begin a client
246 session, or L{start_server} to begin a server session.
247
248 If the object is not actually a socket, it must have the following
249 methods:
250 - C{send(str)}: Writes from 1 to C{len(str)} bytes, and
251 returns an int representing the number of bytes written. Returns
252 0 or raises C{EOFError} if the stream has been closed.
253 - C{recv(int)}: Reads from 1 to C{int} bytes and returns them as a
254 string. Returns 0 or raises C{EOFError} if the stream has been
255 closed.
256 - C{close()}: Closes the socket.
257 - C{settimeout(n)}: Sets a (float) timeout on I/O operations.
258
259 For ease of use, you may also pass in an address (as a tuple) or a host
260 string as the C{sock} argument. (A host string is a hostname with an
261 optional port (separated by C{":"}) which will be converted into a
262 tuple of C{(hostname, port)}.) A socket will be connected to this
263 address and used for communication. Exceptions from the C{socket} call
264 may be thrown in this case.
265
266 @param sock: a socket or socket-like object to create the session over.
267 @type sock: socket
268 """
269 if type(sock) is str:
270
271 hl = sock.split(':', 1)
272 if len(hl) == 1:
273 sock = (hl[0], 22)
274 else:
275 sock = (hl[0], int(hl[1]))
276 if type(sock) is tuple:
277
278 hostname, port = sock
279 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
280 sock.connect((hostname, port))
281
282 threading.Thread.__init__(self)
283 self.randpool = randpool
284 self.sock = sock
285
286 try:
287
288
289
290 self.sock.settimeout(0.1)
291 except AttributeError:
292 pass
293
294
295 self.packetizer = Packetizer(sock)
296 self.local_version = 'SSH-' + self._PROTO_ID + '-' + self._CLIENT_ID
297 self.remote_version = ''
298 self.local_cipher = self.remote_cipher = ''
299 self.local_kex_init = self.remote_kex_init = None
300 self.local_mac = self.remote_mac = None
301 self.local_compression = self.remote_compression = None
302 self.session_id = None
303 self.host_key_type = None
304 self.host_key = None
305
306
307 self.kex_engine = None
308 self.H = None
309 self.K = None
310
311 self.active = False
312 self.initial_kex_done = False
313 self.in_kex = False
314 self.authenticated = False
315 self._expected_packet = tuple()
316 self.lock = threading.Lock()
317
318
319 self._channels = ChannelMap()
320 self.channel_events = { }
321 self.channels_seen = { }
322 self._channel_counter = 1
323 self.window_size = 65536
324 self.max_packet_size = 34816
325 self._x11_handler = None
326 self._tcp_handler = None
327
328 self.saved_exception = None
329 self.clear_to_send = threading.Event()
330 self.clear_to_send_lock = threading.Lock()
331 self.log_name = 'paramiko.transport'
332 self.logger = util.get_logger(self.log_name)
333 self.packetizer.set_log(self.logger)
334 self.auth_handler = None
335 self.global_response = None
336 self.completion_event = None
337 self.banner_timeout = 15
338
339
340 self.server_mode = False
341 self.server_object = None
342 self.server_key_dict = { }
343 self.server_accepts = [ ]
344 self.server_accept_cv = threading.Condition(self.lock)
345 self.subsystem_table = { }
346
348 """
349 Returns a string representation of this object, for debugging.
350
351 @rtype: str
352 """
353 out = '<paramiko.Transport at %s' % hex(long(id(self)) & 0xffffffffL)
354 if not self.active:
355 out += ' (unconnected)'
356 else:
357 if self.local_cipher != '':
358 out += ' (cipher %s, %d bits)' % (self.local_cipher,
359 self._cipher_info[self.local_cipher]['key-size'] * 8)
360 if self.is_authenticated():
361 out += ' (active; %d open channel(s))' % len(self._channels)
362 elif self.initial_kex_done:
363 out += ' (connected; awaiting auth)'
364 else:
365 out += ' (connecting)'
366 out += '>'
367 return out
368
370 """
371 Terminate this Transport without closing the session. On posix
372 systems, if a Transport is open during process forking, both parent
373 and child will share the underlying socket, but only one process can
374 use the connection (without corrupting the session). Use this method
375 to clean up a Transport object without disrupting the other process.
376
377 @since: 1.5.3
378 """
379 self.sock.close()
380 self.close()
381
383 """
384 Return a L{SecurityOptions} object which can be used to tweak the
385 encryption algorithms this transport will permit, and the order of
386 preference for them.
387
388 @return: an object that can be used to change the preferred algorithms
389 for encryption, digest (hash), public key, and key e