1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 Packetizer.
21 """
22
23 import errno
24 import select
25 import socket
26 import struct
27 import threading
28 import time
29
30 from paramiko.common import *
31 from paramiko import util
32 from paramiko.ssh_exception import SSHException, ProxyCommandFailure
33 from paramiko.message import Message
34
35
36 got_r_hmac = False
37 try:
38 import r_hmac
39 got_r_hmac = True
40 except ImportError:
41 pass
43 if got_r_hmac:
44 return r_hmac.HMAC(key, message, digest_class).digest()
45 from Crypto.Hash import HMAC
46 return HMAC.HMAC(key, message, digest_class).digest()
47
48
51
52
54 """
55 Implementation of the base SSH packet protocol.
56 """
57
58
59
60 REKEY_PACKETS = pow(2, 29)
61 REKEY_BYTES = pow(2, 29)
62
63 REKEY_PACKETS_OVERFLOW_MAX = pow(2,29)
64 REKEY_BYTES_OVERFLOW_MAX = pow(2,29)
65
67 self.__socket = socket
68 self.__logger = None
69 self.__closed = False
70 self.__dump_packets = False
71 self.__need_rekey = False
72 self.__init_count = 0
73 self.__remainder = ''
74
75
76 self.__sent_bytes = 0
77 self.__sent_packets = 0
78 self.__received_bytes = 0
79 self.__received_packets = 0
80 self.__received_bytes_overflow = 0
81 self.__received_packets_overflow = 0
82
83
84 self.__block_size_out = 8
85 self.__block_size_in = 8
86 self.__mac_size_out = 0
87 self.__mac_size_in = 0
88 self.__block_engine_out = None
89 self.__block_engine_in = None
90 self.__sdctr_out = False
91 self.__mac_engine_out = None
92 self.__mac_engine_in = None
93 self.__mac_key_out = ''
94 self.__mac_key_in = ''
95 self.__compress_engine_out = None
96 self.__compress_engine_in = None
97 self.__sequence_number_out = 0L
98 self.__sequence_number_in = 0L
99
100
101 self.__write_lock = threading.RLock()
102
103
104 self.__keepalive_interval = 0
105 self.__keepalive_last = time.time()
106 self.__keepalive_callback = None
107
109 """
110 Set the python log object to use for logging.
111 """
112 self.__logger = log
113
114 - def set_outbound_cipher(self, block_engine, block_size, mac_engine, mac_size, mac_key, sdctr=False):
115 """
116 Switch outbound data cipher.
117 """
118 self.__block_engine_out = block_engine
119 self.__sdctr_out = sdctr
120 self.__block_size_out = block_size
121 self.__mac_engine_out = mac_engine
122 self.__mac_size_out = mac_size
123 self.__mac_key_out = mac_key
124 self.__sent_bytes = 0
125 self.__sent_packets = 0
126
127 self.__init_count |= 1
128 if self.__init_count == 3:
129 self.__init_count = 0
130 self.__need_rekey = False
131
133 """
134 Switch inbound data cipher.
135 """
136 self.__block_engine_in = block_engine
137 self.__block_size_in = block_size
138 self.__mac_engine_in = mac_engine
139 self.__mac_size_in = mac_size
140 self.__mac_key_in = mac_key
141 self.__received_bytes = 0
142 self.__received_packets = 0
143 self.__received_bytes_overflow = 0
144 self.__received_packets_overflow = 0
145
146 self.__init_count |= 2
147 if self.__init_count == 3:
148 self.__init_count = 0
149 self.__need_rekey = False
150
152 self.__compress_engine_out = compressor
153
155 self.__compress_engine_in = compressor
156
158 self.__closed = True
159 self.__socket.close()
160
162 self.__dump_packets = hexdump
163
165 return self.__dump_packets
166
168 return self.__mac_size_in
169
171 return self.__mac_size_out
172
174 """
175 Returns C{True} if a new set of keys needs to be negotiated. This
176 will be triggered during a packet read or write, so it should be
177 checked after every read or write, or at least after every few.
178
179 @return: C{True} if a new set of keys needs to be negotiated
180 """
181 return self.__need_rekey
182
184 """
185 Turn on/off the callback keepalive. If C{interval} seconds pass with
186 no data read from or written to the socket, the callback will be
187 executed and the timer will be reset.
188 """
189 self.__keepalive_interval = interval
190 self.__keepalive_callback = callback
191 self.__keepalive_last = time.time()
192
193 - def read_all(self, n, check_rekey=False):
194 """
195 Read as close to N bytes as possible, blocking as long as necessary.
196
197 @param n: number of bytes to read
198 @type n: int
199 @return: the data read
200 @rtype: str
201 @raise EOFError: if the socket was closed before all the bytes could
202 be read
203 """
204 out = ''
205
206 if len(self.__remainder) > 0:
207 out = self.__remainder[:n]
208 self.__remainder = self.__remainder[n:]
209 n -= len(out)
210 if PY22:
211 return self._py22_read_all(n, out)
212 while n > 0:
213 got_timeout = False
214 try:
215 x = self.__socket.recv(n)
216 if len(x) == 0:
217 raise EOFError()
218 out += x
219 n -= len(x)
220 except socket.timeout:
221 got_timeout = True
222 except socket.error, e:
223
224
225
226 if (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EAGAIN):
227 got_timeout = True
228 elif (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EINTR):
229
230 pass
231 elif self.__closed:
232 raise EOFError()
233 else:
234 raise
235 if got_timeout:
236 if self.__closed:
237 raise EOFError()
238 if check_rekey and (len(out) == 0) and self.__need_rekey:
239 raise NeedRekeyException()
240 self._check_keepalive()
241 return out
242
244 self.__keepalive_last = time.time()
245 while len(out) > 0:
246 retry_write = False
247 try:
248 n = self.__socket.send(out)
249 except socket.timeout:
250 retry_write = True
251 except socket.error, e:
252 if (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EAGAIN):
253 retry_write = True
254 elif (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EINTR):
255
256 retry_write = True
257 else:
258 n = -1
259 except ProxyCommandFailure:
260 raise
261 except Exception:
262
263 n = -1
264 if retry_write:
265 n = 0
266 if self.__closed:
267 n = -1
268 if n < 0:
269 raise EOFError()
270 if n == len(out):
271 break
272 out = out[n:]
273 return
274
276 """
277 Read a line from the socket. We assume no data is pending after the
278 line, so it's okay to attempt large reads.
279 """
280 buf = self.__remainder
281 while not '\n' in buf:
282 buf += self._read_timeout(timeout)
283 n = buf.index('\n')
284 self.__remainder = buf[n+1:]
285 buf = buf[:n]
286 if (len(buf) > 0) and (buf[-1] == '\r'):
287 buf = buf[:-1]
288 return buf
289
291 """
292 Write a block of data using the current cipher, as an SSH block.
293 """
294
295 data = str(data)
296 cmd = ord(data[0])
297 if cmd in MSG_NAMES:
298 cmd_name = MSG_NAMES[cmd]
299 else:
300 cmd_name = '$%x' % cmd
301 orig_len = len(data)
302 self.__write_lock.acquire()
303 try:
304 if self.__compress_engine_out is not None:
305 data = self.__compress_engine_out(data)
306 packet = self._build_packet(data)
307 if self.__dump_packets:
308 self._log(DEBUG, 'Write packet <%s>, length %d' % (cmd_name, orig_len))
309 self._log(DEBUG, util.format_binary(packet, 'OUT: '))
310 if self.__block_engine_out != None:
311 out = self.__block_engine_out.encrypt(packet)
312 else:
313 out = packet
314
315 if self.__block_engine_out != None:
316 payload = struct.pack('>I', self.__sequence_number_out) + packet
317 out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out]
318 self.__sequence_number_out = (self.__sequence_number_out + 1) & 0xffffffffL
319 self.write_all(out)
320
321 self.__sent_bytes += len(out)
322 self.__sent_packets += 1
323 if ((self.__sent_packets >= self.REKEY_PACKETS) or (self.__sent_bytes >= self.REKEY_BYTES)) \
324 and not self.__need_rekey:
325
326 self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' %
327 (self.__sent_packets, self.__sent_bytes))
328 self.__received_bytes_overflow = 0
329 self.__received_packets_overflow = 0
330 self._trigger_rekey()
331 finally:
332 self.__write_lock.release()
333
335 """
336 Only one thread should ever be in this function (no other locking is
337 done).
338
339 @raise SSHException: if the packet is mangled
340 @raise NeedRekeyException: if the transport should rekey
341 """
342 header = self.read_all(self.__block_size_in, check_rekey=True)
343 if self.__block_engine_in != None:
344 header = self.__block_engine_in.decrypt(header)
345 if self.__dump_packets:
346 self._log(DEBUG, util.format_binary(header, 'IN: '));
347 packet_size = struct.unpack('>I', header[:4])[0]
348
349 leftover = header[4:]
350 if (packet_size - len(leftover)) % self.__block_size_in != 0:
351 raise SSHException('Invalid packet blocking')
352 buf = self.read_all(packet_size + self.__mac_size_in - len(leftover))
353 packet = buf[:packet_size - len(leftover)]
354 post_packet = buf[packet_size - len(leftover):]
355 if self.__block_engine_in != None:
356 packet = self.__block_engine_in.decrypt(packet)
357 if self.__dump_packets:
358 self._log(DEBUG, util.format_binary(packet, 'IN: '));
359 packet = leftover + packet
360
361 if self.__mac_size_in > 0:
362 mac = post_packet[:self.__mac_size_in]
363 mac_payload = struct.pack('>II', self.__sequence_number_in, packet_size) + packet
364 my_mac = compute_hmac(self.__mac_key_in, mac_payload, self.__mac_engine_in)[:self.__mac_size_in]
365 if my_mac != mac:
366 raise SSHException('Mismatched MAC')
367 padding = ord(packet[0])
368 payload = packet[1:packet_size - padding]
369
370 if self.__dump_packets:
371 self._log(DEBUG, 'Got payload (%d bytes, %d padding)' % (packet_size, padding))
372
373 if self.__compress_engine_in is not None:
374 payload = self.__compress_engine_in(payload)
375
376 msg = Message(payload[1:])
377 msg.seqno = self.__sequence_number_in
378 self.__sequence_number_in = (self.__sequence_number_in + 1) & 0xffffffffL
379
380
381 raw_packet_size = packet_size + self.__mac_size_in + 4
382 self.__received_bytes += raw_packet_size
383 self.__received_packets += 1
384 if self.__need_rekey:
385
386
387 self.__received_bytes_overflow += raw_packet_size
388 self.__received_packets_overflow += 1
389 if (self.__received_packets_overflow >= self.REKEY_PACKETS_OVERFLOW_MAX) or \
390 (self.__received_bytes_overflow >= self.REKEY_BYTES_OVERFLOW_MAX):
391 raise SSHException('Remote transport is ignoring rekey requests')
392 elif (self.__received_packets >= self.REKEY_PACKETS) or \
393 (self.__received_bytes >= self.REKEY_BYTES):
394
395 self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes received)' %
396 (self.__received_packets, self.__received_bytes))
397 self.__received_bytes_overflow = 0
398 self.__received_packets_overflow = 0
399 self._trigger_rekey()
400
401 cmd = ord(payload[0])
402 if cmd in MSG_NAMES:
403 cmd_name = MSG_NAMES[cmd]
404 else:
405 cmd_name = '$%x' % cmd
406 if self.__dump_packets:
407 self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload)))
408 return cmd, msg
409
410
411
412
413
414 - def _log(self, level, msg):
415 if self.__logger is None:
416 return
417 if issubclass(type(msg), list):
418 for m in msg:
419 self.__logger.log(level, m)
420 else:
421 self.__logger.log(level, msg)
422
424 if (not self.__keepalive_interval) or (not self.__block_engine_out) or \
425 self.__need_rekey:
426
427 return
428 now = time.time()
429 if now > self.__keepalive_last + self.__keepalive_interval:
430 self.__keepalive_callback()
431 self.__keepalive_last = now
432
434 while n > 0:
435 r, w, e = select.select([self.__socket], [], [], 0.1)
436 if self.__socket not in r:
437 if self.__closed:
438 raise EOFError()
439 self._check_keepalive()
440 else:
441 x = self.__socket.recv(n)
442 if len(x) == 0:
443 raise EOFError()
444 out += x
445 n -= len(x)
446 return out
447
449 start = time.time()
450 while True:
451 r, w, e = select.select([self.__socket], [], [], 0.1)
452 if self.__socket in r:
453 x = self.__socket.recv(1)
454 if len(x) == 0:
455 raise EOFError()
456 break
457 if self.__closed:
458 raise EOFError()
459 now = time.time()
460 if now - start >= timeout:
461 raise socket.timeout()
462 return x
463
465 if PY22:
466 return self._py22_read_timeout(timeout)
467 start = time.time()
468 while True:
469 try:
470 x = self.__socket.recv(128)
471 if len(x) == 0:
472 raise EOFError()
473 break
474 except socket.timeout:
475 pass
476 except EnvironmentError, e:
477 if ((type(e.args) is tuple) and (len(e.args) > 0) and
478 (e.args[0] == errno.EINTR)):
479 pass
480 else:
481 raise
482 if self.__closed:
483 raise EOFError()
484 now = time.time()
485 if now - start >= timeout:
486 raise socket.timeout()
487 return x
488
490
491 bsize = self.__block_size_out
492 padding = 3 + bsize - ((len(payload) + 8) % bsize)
493 packet = struct.pack('>IB', len(payload) + padding + 1, padding)
494 packet += payload
495 if self.__sdctr_out or self.__block_engine_out is None:
496
497
498 packet += (chr(0) * padding)
499 else:
500 packet += rng.read(padding)
501 return packet
502
504
505 self.__need_rekey = True
506