From ed280d5ac360e2af796e9bd973d7b4df89f0c449 Mon Sep 17 00:00:00 2001 From: "Jeremy T. Bouse" Date: Fri, 27 Nov 2009 16:20:12 -0500 Subject: Imported Upstream version 1.7.4 --- docs/paramiko.packet-pysrc.html | 964 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 964 insertions(+) create mode 100644 docs/paramiko.packet-pysrc.html (limited to 'docs/paramiko.packet-pysrc.html') diff --git a/docs/paramiko.packet-pysrc.html b/docs/paramiko.packet-pysrc.html new file mode 100644 index 0000000..1571204 --- /dev/null +++ b/docs/paramiko.packet-pysrc.html @@ -0,0 +1,964 @@ + + + + + paramiko.packet + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Package paramiko :: + Module packet + + + + + +
[frames] | no frames]
+
+

Source Code for Module paramiko.packet

+
+  1  # Copyright (C) 2003-2007  Robey Pointer <robey@lag.net> 
+  2  # 
+  3  # This file is part of paramiko. 
+  4  # 
+  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
+  6  # terms of the GNU Lesser General Public License as published by the Free 
+  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
+  8  # any later version. 
+  9  # 
+ 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
+ 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
+ 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
+ 13  # details. 
+ 14  # 
+ 15  # You should have received a copy of the GNU Lesser General Public License 
+ 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
+ 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
+ 18   
+ 19  """ 
+ 20  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 
+ 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 
+
42 -def compute_hmac(key, message, digest_class): +
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 +
49 -class NeedRekeyException (Exception): +
50 pass +
51 + 52 +
53 -class Packetizer (object): +
54 """ + 55 Implementation of the base SSH packet protocol. + 56 """ + 57 + 58 # READ the secsh RFC's before raising these values. if anything, + 59 # they should probably be lower. + 60 REKEY_PACKETS = pow(2, 30) + 61 REKEY_BYTES = pow(2, 30) + 62 +
63 - def __init__(self, socket): +
64 self.__socket = socket + 65 self.__logger = None + 66 self.__closed = False + 67 self.__dump_packets = False + 68 self.__need_rekey = False + 69 self.__init_count = 0 + 70 self.__remainder = '' + 71 + 72 # used for noticing when to re-key: + 73 self.__sent_bytes = 0 + 74 self.__sent_packets = 0 + 75 self.__received_bytes = 0 + 76 self.__received_packets = 0 + 77 self.__received_packets_overflow = 0 + 78 + 79 # current inbound/outbound ciphering: + 80 self.__block_size_out = 8 + 81 self.__block_size_in = 8 + 82 self.__mac_size_out = 0 + 83 self.__mac_size_in = 0 + 84 self.__block_engine_out = None + 85 self.__block_engine_in = None + 86 self.__mac_engine_out = None + 87 self.__mac_engine_in = None + 88 self.__mac_key_out = '' + 89 self.__mac_key_in = '' + 90 self.__compress_engine_out = None + 91 self.__compress_engine_in = None + 92 self.__sequence_number_out = 0L + 93 self.__sequence_number_in = 0L + 94 + 95 # lock around outbound writes (packet computation) + 96 self.__write_lock = threading.RLock() + 97 + 98 # keepalives: + 99 self.__keepalive_interval = 0 +100 self.__keepalive_last = time.time() +101 self.__keepalive_callback = None +
102 +
103 - def set_log(self, log): +
104 """ +105 Set the python log object to use for logging. +106 """ +107 self.__logger = log +
108 +
109 - def set_outbound_cipher(self, block_engine, block_size, mac_engine, mac_size, mac_key): +
110 """ +111 Switch outbound data cipher. +112 """ +113 self.__block_engine_out = block_engine +114 self.__block_size_out = block_size +115 self.__mac_engine_out = mac_engine +116 self.__mac_size_out = mac_size +117 self.__mac_key_out = mac_key +118 self.__sent_bytes = 0 +119 self.__sent_packets = 0 +120 # wait until the reset happens in both directions before clearing rekey flag +121 self.__init_count |= 1 +122 if self.__init_count == 3: +123 self.__init_count = 0 +124 self.__need_rekey = False +
125 +
126 - def set_inbound_cipher(self, block_engine, block_size, mac_engine, mac_size, mac_key): +
127 """ +128 Switch inbound data cipher. +129 """ +130 self.__block_engine_in = block_engine +131 self.__block_size_in = block_size +132 self.__mac_engine_in = mac_engine +133 self.__mac_size_in = mac_size +134 self.__mac_key_in = mac_key +135 self.__received_bytes = 0 +136 self.__received_packets = 0 +137 self.__received_packets_overflow = 0 +138 # wait until the reset happens in both directions before clearing rekey flag +139 self.__init_count |= 2 +140 if self.__init_count == 3: +141 self.__init_count = 0 +142 self.__need_rekey = False +
143 +
144 - def set_outbound_compressor(self, compressor): +
145 self.__compress_engine_out = compressor +
146 +
147 - def set_inbound_compressor(self, compressor): +
148 self.__compress_engine_in = compressor +
149 +
150 - def close(self): +
151 self.__closed = True +152 self.__socket.close() +
153 +
154 - def set_hexdump(self, hexdump): +
155 self.__dump_packets = hexdump +
156 +
157 - def get_hexdump(self): +
158 return self.__dump_packets +
159 +
160 - def get_mac_size_in(self): +
161 return self.__mac_size_in +
162 +
163 - def get_mac_size_out(self): +
164 return self.__mac_size_out +
165 +
166 - def need_rekey(self): +
167 """ +168 Returns C{True} if a new set of keys needs to be negotiated. This +169 will be triggered during a packet read or write, so it should be +170 checked after every read or write, or at least after every few. +171 +172 @return: C{True} if a new set of keys needs to be negotiated +173 """ +174 return self.__need_rekey +
175 +
176 - def set_keepalive(self, interval, callback): +
177 """ +178 Turn on/off the callback keepalive. If C{interval} seconds pass with +179 no data read from or written to the socket, the callback will be +180 executed and the timer will be reset. +181 """ +182 self.__keepalive_interval = interval +183 self.__keepalive_callback = callback +184 self.__keepalive_last = time.time() +
185 +
186 - def read_all(self, n, check_rekey=False): +
187 """ +188 Read as close to N bytes as possible, blocking as long as necessary. +189 +190 @param n: number of bytes to read +191 @type n: int +192 @return: the data read +193 @rtype: str +194 @raise EOFError: if the socket was closed before all the bytes could +195 be read +196 """ +197 out = '' +198 # handle over-reading from reading the banner line +199 if len(self.__remainder) > 0: +200 out = self.__remainder[:n] +201 self.__remainder = self.__remainder[n:] +202 n -= len(out) +203 if PY22: +204 return self._py22_read_all(n, out) +205 while n > 0: +206 got_timeout = False +207 try: +208 x = self.__socket.recv(n) +209 if len(x) == 0: +210 raise EOFError() +211 out += x +212 n -= len(x) +213 except socket.timeout: +214 got_timeout = True +215 except socket.error, e: +216 # on Linux, sometimes instead of socket.timeout, we get +217 # EAGAIN. this is a bug in recent (> 2.6.9) kernels but +218 # we need to work around it. +219 if (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EAGAIN): +220 got_timeout = True +221 elif (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EINTR): +222 # syscall interrupted; try again +223 pass +224 elif self.__closed: +225 raise EOFError() +226 else: +227 raise +228 if got_timeout: +229 if self.__closed: +230 raise EOFError() +231 if check_rekey and (len(out) == 0) and self.__need_rekey: +232 raise NeedRekeyException() +233 self._check_keepalive() +234 return out +
235 +
236 - def write_all(self, out): +
237 self.__keepalive_last = time.time() +238 while len(out) > 0: +239 got_timeout = False +240 try: +241 n = self.__socket.send(out) +242 except socket.timeout: +243 got_timeout = True +244 except socket.error, e: +245 if (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EAGAIN): +246 got_timeout = True +247 elif (type(e.args) is tuple) and (len(e.args) > 0) and (e.args[0] == errno.EINTR): +248 # syscall interrupted; try again +249 pass +250 else: +251 n = -1 +252 except Exception: +253 # could be: (32, 'Broken pipe') +254 n = -1 +255 if got_timeout: +256 n = 0 +257 if self.__closed: +258 n = -1 +259 if n < 0: +260 raise EOFError() +261 if n == len(out): +262 break +263 out = out[n:] +264 return +
265 +
266 - def readline(self, timeout): +
267 """ +268 Read a line from the socket. We assume no data is pending after the +269 line, so it's okay to attempt large reads. +270 """ +271 buf = '' +272 while not '\n' in buf: +273 buf += self._read_timeout(timeout) +274 n = buf.index('\n') +275 self.__remainder += buf[n+1:] +276 buf = buf[:n] +277 if (len(buf) > 0) and (buf[-1] == '\r'): +278 buf = buf[:-1] +279 return buf +
280 +
281 - def send_message(self, data): +
282 """ +283 Write a block of data using the current cipher, as an SSH block. +284 """ +285 # encrypt this sucka +286 data = str(data) +287 cmd = ord(data[0]) +288 if cmd in MSG_NAMES: +289 cmd_name = MSG_NAMES[cmd] +290 else: +291 cmd_name = '$%x' % cmd +292 orig_len = len(data) +293 self.__write_lock.acquire() +294 try: +295 if self.__compress_engine_out is not None: +296 data = self.__compress_engine_out(data) +297 packet = self._build_packet(data) +298 if self.__dump_packets: +299 self._log(DEBUG, 'Write packet <%s>, length %d' % (cmd_name, orig_len)) +300 self._log(DEBUG, util.format_binary(packet, 'OUT: ')) +301 if self.__block_engine_out != None: +302 out = self.__block_engine_out.encrypt(packet) +303 else: +304 out = packet +305 # + mac +306 if self.__block_engine_out != None: +307 payload = struct.pack('>I', self.__sequence_number_out) + packet +308 out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out] +309 self.__sequence_number_out = (self.__sequence_number_out + 1) & 0xffffffffL +310 self.write_all(out) +311 +312 self.__sent_bytes += len(out) +313 self.__sent_packets += 1 +314 if (self.__sent_packets % 100) == 0: +315 # stirring the randpool takes 30ms on my ibook!! +316 randpool.stir() +317 if ((self.__sent_packets >= self.REKEY_PACKETS) or (self.__sent_bytes >= self.REKEY_BYTES)) \ +318 and not self.__need_rekey: +319 # only ask once for rekeying +320 self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' % +321 (self.__sent_packets, self.__sent_bytes)) +322 self.__received_packets_overflow = 0 +323 self._trigger_rekey() +324 finally: +325 self.__write_lock.release() +
326 +
327 - def read_message(self): +
328 """ +329 Only one thread should ever be in this function (no other locking is +330 done). +331 +332 @raise SSHException: if the packet is mangled +333 @raise NeedRekeyException: if the transport should rekey +334 """ +335 header = self.read_all(self.__block_size_in, check_rekey=True) +336 if self.__block_engine_in != None: +337 header = self.__block_engine_in.decrypt(header) +338 if self.__dump_packets: +339 self._log(DEBUG, util.format_binary(header, 'IN: ')); +340 packet_size = struct.unpack('>I', header[:4])[0] +341 # leftover contains decrypted bytes from the first block (after the length field) +342 leftover = header[4:] +343 if (packet_size - len(leftover)) % self.__block_size_in != 0: +344 raise SSHException('Invalid packet blocking') +345 buf = self.read_all(packet_size + self.__mac_size_in - len(leftover)) +346 packet = buf[:packet_size - len(leftover)] +347 post_packet = buf[packet_size - len(leftover):] +348 if self.__block_engine_in != None: +349 packet = self.__block_engine_in.decrypt(packet) +350 if self.__dump_packets: +351 self._log(DEBUG, util.format_binary(packet, 'IN: ')); +352 packet = leftover + packet +353 +354 if self.__mac_size_in > 0: +355 mac = post_packet[:self.__mac_size_in] +356 mac_payload = struct.pack('>II', self.__sequence_number_in, packet_size) + packet +357 my_mac = compute_hmac(self.__mac_key_in, mac_payload, self.__mac_engine_in)[:self.__mac_size_in] +358 if my_mac != mac: +359 raise SSHException('Mismatched MAC') +360 padding = ord(packet[0]) +361 payload = packet[1:packet_size - padding] +362 randpool.add_event() +363 if self.__dump_packets: +364 self._log(DEBUG, 'Got payload (%d bytes, %d padding)' % (packet_size, padding)) +365 +366 if self.__compress_engine_in is not None: +367 payload = self.__compress_engine_in(payload) +368 +369 msg = Message(payload[1:]) +370 msg.seqno = self.__sequence_number_in +371 self.__sequence_number_in = (self.__sequence_number_in + 1) & 0xffffffffL +372 +373 # check for rekey +374 self.__received_bytes += packet_size + self.__mac_size_in + 4 +375 self.__received_packets += 1 +376 if self.__need_rekey: +377 # we've asked to rekey -- give them 20 packets to comply before +378 # dropping the connection +379 self.__received_packets_overflow += 1 +380 if self.__received_packets_overflow >= 20: +381 raise SSHException('Remote transport is ignoring rekey requests') +382 elif (self.__received_packets >= self.REKEY_PACKETS) or \ +383 (self.__received_bytes >= self.REKEY_BYTES): +384 # only ask once for rekeying +385 self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes received)' % +386 (self.__received_packets, self.__received_bytes)) +387 self.__received_packets_overflow = 0 +388 self._trigger_rekey() +389 +390 cmd = ord(payload[0]) +391 if cmd in MSG_NAMES: +392 cmd_name = MSG_NAMES[cmd] +393 else: +394 cmd_name = '$%x' % cmd +395 if self.__dump_packets: +396 self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload))) +397 return cmd, msg +
398 +399 +400 ########## protected +401 +402 +
403 - def _log(self, level, msg): +
404 if self.__logger is None: +405 return +406 if issubclass(type(msg), list): +407 for m in msg: +408 self.__logger.log(level, m) +409 else: +410 self.__logger.log(level, msg) +
411 +
412 - def _check_keepalive(self): +
413 if (not self.__keepalive_interval) or (not self.__block_engine_out) or \ +414 self.__need_rekey: +415 # wait till we're encrypting, and not in the middle of rekeying +416 return +417 now = time.time() +418 if now > self.__keepalive_last + self.__keepalive_interval: +419 self.__keepalive_callback() +420 self.__keepalive_last = now +
421 +
422 - def _py22_read_all(self, n, out): +
423 while n > 0: +424 r, w, e = select.select([self.__socket], [], [], 0.1) +425 if self.__socket not in r: +426 if self.__closed: +427 raise EOFError() +428 self._check_keepalive() +429 else: +430 x = self.__socket.recv(n) +431 if len(x) == 0: +432 raise EOFError() +433 out += x +434 n -= len(x) +435 return out +
436 +
437 - def _py22_read_timeout(self, timeout): +
438 start = time.time() +439 while True: +440 r, w, e = select.select([self.__socket], [], [], 0.1) +441 if self.__socket in r: +442 x = self.__socket.recv(1) +443 if len(x) == 0: +444 raise EOFError() +445 break +446 if self.__closed: +447 raise EOFError() +448 now = time.time() +449 if now - start >= timeout: +450 raise socket.timeout() +451 return x +
452 +
453 - def _read_timeout(self, timeout): +
454 if PY22: +455 return self._py22_read_timeout(timeout) +456 start = time.time() +457 while True: +458 try: +459 x = self.__socket.recv(128) +460 if len(x) == 0: +461 raise EOFError() +462 break +463 except socket.timeout: +464 pass +465 if self.__closed: +466 raise EOFError() +467 now = time.time() +468 if now - start >= timeout: +469 raise socket.timeout() +470 return x +
471 +
472 - def _build_packet(self, payload): +
473 # pad up at least 4 bytes, to nearest block-size (usually 8) +474 bsize = self.__block_size_out +475 padding = 3 + bsize - ((len(payload) + 8) % bsize) +476 packet = struct.pack('>IB', len(payload) + padding + 1, padding) +477 packet += payload +478 if self.__block_engine_out is not None: +479 packet += randpool.get_bytes(padding) +480 else: +481 # cute trick i caught openssh doing: if we're not encrypting, +482 # don't waste random bytes for the padding +483 packet += (chr(0) * padding) +484 return packet +
485 +
486 - def _trigger_rekey(self): +
487 # outside code should check for this flag +488 self.__need_rekey = True +
489 +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + -- cgit v1.2.3