From 8fafd1aa1716bdf50575c4c3f98e46a2c7e73f8c Mon Sep 17 00:00:00 2001 From: Robey Pointer Date: Mon, 5 Apr 2004 10:12:59 +0000 Subject: [PATCH] [project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-36] add common.py for commonly used constants and globals common.py now stores the constants and globals. lots of renaming because of this. --- paramiko/auth_transport.py | 42 +++++++++---------- paramiko/channel.py | 25 ++++++------ paramiko/kex_gex.py | 10 +++-- paramiko/kex_group1.py | 7 ++-- paramiko/transport.py | 84 ++++++++++++-------------------------- paramiko/util.py | 22 +++++++++- 6 files changed, 88 insertions(+), 102 deletions(-) diff --git a/paramiko/auth_transport.py b/paramiko/auth_transport.py index 7ef77a8..ccb7149 100644 --- a/paramiko/auth_transport.py +++ b/paramiko/auth_transport.py @@ -23,16 +23,12 @@ L{Transport} is a subclass of L{BaseTransport} that handles authentication. This separation keeps either class file from being too unwieldy. """ +from common import * from transport import BaseTransport -from transport import _MSG_SERVICE_REQUEST, _MSG_SERVICE_ACCEPT, _MSG_USERAUTH_REQUEST, _MSG_USERAUTH_FAILURE, \ - _MSG_USERAUTH_SUCCESS, _MSG_USERAUTH_BANNER from message import Message from ssh_exception import SSHException from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL -_DISCONNECT_SERVICE_NOT_AVAILABLE, _DISCONNECT_AUTH_CANCELLED_BY_USER, \ - _DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 7, 13, 14 - class Transport (BaseTransport): """ @@ -244,14 +240,14 @@ class Transport (BaseTransport): def _request_auth(self): m = Message() - m.add_byte(chr(_MSG_SERVICE_REQUEST)) + m.add_byte(chr(MSG_SERVICE_REQUEST)) m.add_string('ssh-userauth') self._send_message(m) def _disconnect_service_not_available(self): m = Message() - m.add_byte(chr(_MSG_DISCONNECT)) - m.add_int(_DISCONNECT_SERVICE_NOT_AVAILABLE) + m.add_byte(chr(MSG_DISCONNECT)) + m.add_int(DISCONNECT_SERVICE_NOT_AVAILABLE) m.add_string('Service not available') m.add_string('en') self._send_message(m) @@ -259,8 +255,8 @@ class Transport (BaseTransport): def _disconnect_no_more_auth(self): m = Message() - m.add_byte(chr(_MSG_DISCONNECT)) - m.add_int(_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) + m.add_byte(chr(MSG_DISCONNECT)) + m.add_int(DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) m.add_string('No more auth methods available') m.add_string('en') self._send_message(m) @@ -269,7 +265,7 @@ class Transport (BaseTransport): def _get_session_blob(self, key, service, username): m = Message() m.add_string(self.session_id) - m.add_byte(chr(_MSG_USERAUTH_REQUEST)) + m.add_byte(chr(MSG_USERAUTH_REQUEST)) m.add_string(username) m.add_string(service) m.add_string('publickey') @@ -283,7 +279,7 @@ class Transport (BaseTransport): if self.server_mode and (service == 'ssh-userauth'): # accepted m = Message() - m.add_byte(chr(_MSG_SERVICE_ACCEPT)) + m.add_byte(chr(MSG_SERVICE_ACCEPT)) m.add_string(service) self._send_message(m) return @@ -295,7 +291,7 @@ class Transport (BaseTransport): if service == 'ssh-userauth': self._log(DEBUG, 'userauth is OK') m = Message() - m.add_byte(chr(_MSG_USERAUTH_REQUEST)) + m.add_byte(chr(MSG_USERAUTH_REQUEST)) m.add_string(self.username) m.add_string('ssh-connection') m.add_string(self.auth_method) @@ -319,7 +315,7 @@ class Transport (BaseTransport): if not self.server_mode: # er, uh... what? m = Message() - m.add_byte(chr(_MSG_USERAUTH_FAILURE)) + m.add_byte(chr(MSG_USERAUTH_FAILURE)) m.add_string('none') m.add_boolean(0) self._send_message(m) @@ -368,7 +364,7 @@ class Transport (BaseTransport): # client wants to know if this key is acceptable, before it # signs anything... send special "ok" message m = Message() - m.add_byte(chr(_MSG_USERAUTH_PK_OK)) + m.add_byte(chr(MSG_USERAUTH_PK_OK)) m.add_string(keytype) m.add_string(keyblob) self._send_message(m) @@ -384,11 +380,11 @@ class Transport (BaseTransport): m = Message() if result == self.AUTH_SUCCESSFUL: self._log(DEBUG, 'Auth granted.') - m.add_byte(chr(_MSG_USERAUTH_SUCCESS)) + m.add_byte(chr(MSG_USERAUTH_SUCCESS)) self.auth_complete = 1 else: self._log(DEBUG, 'Auth rejected.') - m.add_byte(chr(_MSG_USERAUTH_FAILURE)) + m.add_byte(chr(MSG_USERAUTH_FAILURE)) m.add_string(self.get_allowed_auths(username)) if result == self.AUTH_PARTIALLY_SUCCESSFUL: m.add_boolean(1) @@ -427,11 +423,11 @@ class Transport (BaseTransport): _handler_table = BaseTransport._handler_table.copy() _handler_table.update({ - _MSG_SERVICE_REQUEST: _parse_service_request, - _MSG_SERVICE_ACCEPT: _parse_service_accept, - _MSG_USERAUTH_REQUEST: _parse_userauth_request, - _MSG_USERAUTH_SUCCESS: _parse_userauth_success, - _MSG_USERAUTH_FAILURE: _parse_userauth_failure, - _MSG_USERAUTH_BANNER: _parse_userauth_banner, + MSG_SERVICE_REQUEST: _parse_service_request, + MSG_SERVICE_ACCEPT: _parse_service_accept, + MSG_USERAUTH_REQUEST: _parse_userauth_request, + MSG_USERAUTH_SUCCESS: _parse_userauth_success, + MSG_USERAUTH_FAILURE: _parse_userauth_failure, + MSG_USERAUTH_BANNER: _parse_userauth_banner, }) diff --git a/paramiko/channel.py b/paramiko/channel.py index c634f93..cf2ff63 100644 --- a/paramiko/channel.py +++ b/paramiko/channel.py @@ -22,10 +22,9 @@ Abstraction for an SSH2 channel. """ +from common import * from message import Message from ssh_exception import SSHException -from transport import _MSG_CHANNEL_REQUEST, _MSG_CHANNEL_CLOSE, _MSG_CHANNEL_WINDOW_ADJUST, _MSG_CHANNEL_DATA, \ - _MSG_CHANNEL_EOF, _MSG_CHANNEL_SUCCESS, _MSG_CHANNEL_FAILURE from file import BufferedFile import time, threading, logging, socket, os @@ -116,7 +115,7 @@ class Channel (object): if self.closed or self.eof_received or self.eof_sent or not self.active: raise SSHException('Channel is not open') m = Message() - m.add_byte(chr(_MSG_CHANNEL_REQUEST)) + m.add_byte(chr(MSG_CHANNEL_REQUEST)) m.add_int(self.remote_chanid) m.add_string('pty-req') m.add_boolean(0) @@ -137,7 +136,7 @@ class Channel (object): if self.closed or self.eof_received or self.eof_sent or not self.active: raise SSHException('Channel is not open') m = Message() - m.add_byte(chr(_MSG_CHANNEL_REQUEST)) + m.add_byte(chr(MSG_CHANNEL_REQUEST)) m.add_int(self.remote_chanid) m.add_string('shell') m.add_boolean(1) @@ -155,7 +154,7 @@ class Channel (object): if self.closed or self.eof_received or self.eof_sent or not self.active: raise SSHException('Channel is not open') m = Message() - m.add_byte(chr(_MSG_CHANNEL_REQUEST)) + m.add_byte(chr(MSG_CHANNEL_REQUEST)) m.add_int(self.remote_chanid) m.add_string('exec') m.add_boolean(1) @@ -174,7 +173,7 @@ class Channel (object): if self.closed or self.eof_received or self.eof_sent or not self.active: raise SSHException('Channel is not open') m = Message() - m.add_byte(chr(_MSG_CHANNEL_REQUEST)) + m.add_byte(chr(MSG_CHANNEL_REQUEST)) m.add_int(self.remote_chanid) m.add_string('subsystem') m.add_boolean(1) @@ -194,7 +193,7 @@ class Channel (object): if self.closed or self.eof_received or self.eof_sent or not self.active: raise SSHException('Channel is not open') m = Message() - m.add_byte(chr(_MSG_CHANNEL_REQUEST)) + m.add_byte(chr(MSG_CHANNEL_REQUEST)) m.add_int(self.remote_chanid) m.add_string('window-change') m.add_boolean(0) @@ -300,7 +299,7 @@ class Channel (object): if self.active and not self.closed: self._send_eof() m = Message() - m.add_byte(chr(_MSG_CHANNEL_CLOSE)) + m.add_byte(chr(MSG_CHANNEL_CLOSE)) m.add_int(self.remote_chanid) self.transport._send_message(m) self.closed = 1 @@ -417,7 +416,7 @@ class Channel (object): if self.out_max_packet_size < size: size = self.out_max_packet_size m = Message() - m.add_byte(chr(_MSG_CHANNEL_DATA)) + m.add_byte(chr(MSG_CHANNEL_DATA)) m.add_int(self.remote_chanid) m.add_string(s[:size]) self.transport._send_message(m) @@ -686,9 +685,9 @@ class Channel (object): if want_reply: m = Message() if ok: - m.add_byte(chr(_MSG_CHANNEL_SUCCESS)) + m.add_byte(chr(MSG_CHANNEL_SUCCESS)) else: - m.add_byte(chr(_MSG_CHANNEL_FAILURE)) + m.add_byte(chr(MSG_CHANNEL_FAILURE)) m.add_int(self.remote_chanid) self.transport._send_message(m) @@ -728,7 +727,7 @@ class Channel (object): if self.eof_sent: return m = Message() - m.add_byte(chr(_MSG_CHANNEL_EOF)) + m.add_byte(chr(MSG_CHANNEL_EOF)) m.add_int(self.remote_chanid) self.transport._send_message(m) self.eof_sent = 1 @@ -828,7 +827,7 @@ class Channel (object): if self.in_window_sofar > self.in_window_threshold: self._log(DEBUG, 'addwindow send %d' % self.in_window_sofar) m = Message() - m.add_byte(chr(_MSG_CHANNEL_WINDOW_ADJUST)) + m.add_byte(chr(MSG_CHANNEL_WINDOW_ADJUST)) m.add_int(self.remote_chanid) m.add_int(self.in_window_sofar) self.transport._send_message(m) diff --git a/paramiko/kex_gex.py b/paramiko/kex_gex.py index a83c84b..c7b07a3 100644 --- a/paramiko/kex_gex.py +++ b/paramiko/kex_gex.py @@ -24,14 +24,16 @@ generator "g" are provided by the server. A bit more work is required on the client side, and a B{lot} more on the server side. """ -from message import Message -from util import inflate_long, deflate_long, bit_length -from ssh_exception import SSHException -from transport import _MSG_NEWKEYS from Crypto.Hash import SHA from Crypto.Util import number from logging import DEBUG +from common import * +from message import Message +from util import inflate_long, deflate_long, bit_length +from ssh_exception import SSHException + + _MSG_KEXDH_GEX_GROUP, _MSG_KEXDH_GEX_INIT, _MSG_KEXDH_GEX_REPLY, _MSG_KEXDH_GEX_REQUEST = range(31, 35) diff --git a/paramiko/kex_group1.py b/paramiko/kex_group1.py index 94e6bea..77857f8 100644 --- a/paramiko/kex_group1.py +++ b/paramiko/kex_group1.py @@ -23,12 +23,13 @@ Standard SSH key exchange ("kex" if you wanna sound cool). Diffie-Hellman of 1024 bit key halves, using a known "p" prime and "g" generator. """ -from message import Message, inflate_long -from ssh_exception import SSHException -from transport import _MSG_NEWKEYS from Crypto.Hash import SHA from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL +from common import * +from message import Message, inflate_long +from ssh_exception import SSHException + _MSG_KEXDH_INIT, _MSG_KEXDH_REPLY = range(30, 32) # draft-ietf-secsh-transport-09.txt, page 17 diff --git a/paramiko/transport.py b/paramiko/transport.py index 1ec63eb..58508c0 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -22,18 +22,9 @@ L{BaseTransport} handles the core SSH2 protocol. """ -_MSG_DISCONNECT, _MSG_IGNORE, _MSG_UNIMPLEMENTED, _MSG_DEBUG, _MSG_SERVICE_REQUEST, \ - _MSG_SERVICE_ACCEPT = range(1, 7) -_MSG_KEXINIT, _MSG_NEWKEYS = range(20, 22) -_MSG_USERAUTH_REQUEST, _MSG_USERAUTH_FAILURE, _MSG_USERAUTH_SUCCESS, \ - _MSG_USERAUTH_BANNER = range(50, 54) -_MSG_USERAUTH_PK_OK = 60 -_MSG_CHANNEL_OPEN, _MSG_CHANNEL_OPEN_SUCCESS, _MSG_CHANNEL_OPEN_FAILURE, \ - _MSG_CHANNEL_WINDOW_ADJUST, _MSG_CHANNEL_DATA, _MSG_CHANNEL_EXTENDED_DATA, \ - _MSG_CHANNEL_EOF, _MSG_CHANNEL_CLOSE, _MSG_CHANNEL_REQUEST, \ - _MSG_CHANNEL_SUCCESS, _MSG_CHANNEL_FAILURE = range(90, 101) - import sys, os, string, threading, socket, logging, struct + +from common import * from ssh_exception import SSHException from message import Message from channel import Channel @@ -49,33 +40,12 @@ from primes import ModulusPack # i believe this on the standards track. # PyCrypt compiled for Win32 can be downloaded from the HashTar homepage: # http://nitace.bsd.uchicago.edu:8080/hashtar -from Crypto.Util.randpool import PersistentRandomPool, RandomPool from Crypto.Cipher import Blowfish, AES, DES3 from Crypto.Hash import SHA, MD5, HMAC -from Crypto.PublicKey import RSA from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL -# channel request failed reasons: -_CONNECTION_FAILED_CODE = { - 1: 'Administratively prohibited', - 2: 'Connect failed', - 3: 'Unknown channel type', - 4: 'Resource shortage' -} - - -# keep a crypto-strong PRNG nearby -try: - randpool = PersistentRandomPool(os.getenv('HOME') + '/.randpool') -except: - # the above will likely fail on Windows - fall back to non-persistent random pool - randpool = RandomPool() - -randpool.randomize() - - # for thread cleanup _active_threads = [] def _join_lingering_threads(): @@ -428,7 +398,7 @@ class BaseTransport (threading.Thread): chanid = self.channel_counter self.channel_counter += 1 m = Message() - m.add_byte(chr(_MSG_CHANNEL_OPEN)) + m.add_byte(chr(MSG_CHANNEL_OPEN)) m.add_string(kind) m.add_int(chanid) m.add_int(self.window_size) @@ -466,7 +436,7 @@ class BaseTransport (threading.Thread): @type bytes: int """ m = Message() - m.add_byte(chr(_MSG_IGNORE)) + m.add_byte(chr(MSG_IGNORE)) if bytes is None: bytes = (ord(randpool.get_bytes(1)) % 32) + 10 m.add_bytes(randpool.get_bytes(bytes)) @@ -821,17 +791,17 @@ class BaseTransport (threading.Thread): self._write_all(self.local_version + '\r\n') self._check_banner() self._send_kex_init() - self.expected_packet = _MSG_KEXINIT + self.expected_packet = MSG_KEXINIT while self.active: ptype, m = self._read_message() - if ptype == _MSG_IGNORE: + if ptype == MSG_IGNORE: continue - elif ptype == _MSG_DISCONNECT: + elif ptype == MSG_DISCONNECT: self._parse_disconnect(m) self.active = False break - elif ptype == _MSG_DEBUG: + elif ptype == MSG_DEBUG: self._parse_debug(m) continue if self.expected_packet != 0: @@ -851,7 +821,7 @@ class BaseTransport (threading.Thread): else: self._log(WARNING, 'Oops, unhandled type %d' % ptype) msg = Message() - msg.add_byte(chr(_MSG_UNIMPLEMENTED)) + msg.add_byte(chr(MSG_UNIMPLEMENTED)) msg.add_int(m.seqno) self._send_message(msg) except SSHException, e: @@ -936,7 +906,7 @@ class BaseTransport (threading.Thread): available_server_keys = self.preferred_keys m = Message() - m.add_byte(chr(_MSG_KEXINIT)) + m.add_byte(chr(MSG_KEXINIT)) m.add_bytes(randpool.get_bytes(16)) m.add(','.join(self.preferred_kex)) m.add(','.join(available_server_keys)) @@ -1047,7 +1017,7 @@ class BaseTransport (threading.Thread): # actually some extra bytes (one NUL byte in openssh's case) added to # the end of the packet but not parsed. turns out we need to throw # away those bytes because they aren't part of the hash. - self.remote_kex_init = chr(_MSG_KEXINIT) + m.get_so_far() + self.remote_kex_init = chr(MSG_KEXINIT) + m.get_so_far() def _activate_inbound(self): "switch on newly negotiated encryption parameters for inbound traffic" @@ -1071,7 +1041,7 @@ class BaseTransport (threading.Thread): def _activate_outbound(self): "switch on newly negotiated encryption parameters for outbound traffic" m = Message() - m.add_byte(chr(_MSG_NEWKEYS)) + m.add_byte(chr(MSG_NEWKEYS)) self._send_message(m) self.block_size_out = self._cipher_info[self.local_cipher]['block-size'] if self.server_mode: @@ -1090,7 +1060,7 @@ class BaseTransport (threading.Thread): else: self.mac_key_out = self._compute_key('E', self.local_mac_engine.digest_size) # we always expect to receive NEWKEYS now - self.expected_packet = _MSG_NEWKEYS + self.expected_packet = MSG_NEWKEYS def _parse_newkeys(self, m): self._log(DEBUG, 'Switch to new keys ...') @@ -1179,7 +1149,7 @@ class BaseTransport (threading.Thread): reason = self.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED if reject: msg = Message() - msg.add_byte(chr(_MSG_CHANNEL_OPEN_FAILURE)) + msg.add_byte(chr(MSG_CHANNEL_OPEN_FAILURE)) msg.add_int(chanid) msg.add_int(reason) msg.add_string('') @@ -1195,7 +1165,7 @@ class BaseTransport (threading.Thread): finally: self.lock.release() m = Message() - m.add_byte(chr(_MSG_CHANNEL_OPEN_SUCCESS)) + m.add_byte(chr(MSG_CHANNEL_OPEN_SUCCESS)) m.add_int(chanid) m.add_int(my_chanid) m.add_int(self.window_size) @@ -1216,19 +1186,19 @@ class BaseTransport (threading.Thread): self._log(DEBUG, 'Debug msg: ' + safe_string(msg)) _handler_table = { - _MSG_NEWKEYS: _parse_newkeys, - _MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success, - _MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure, - _MSG_CHANNEL_OPEN: _parse_channel_open, - _MSG_KEXINIT: _negotiate_keys, + MSG_NEWKEYS: _parse_newkeys, + MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success, + MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure, + MSG_CHANNEL_OPEN: _parse_channel_open, + MSG_KEXINIT: _negotiate_keys, } _channel_handler_table = { - _MSG_CHANNEL_SUCCESS: Channel._request_success, - _MSG_CHANNEL_FAILURE: Channel._request_failed, - _MSG_CHANNEL_DATA: Channel._feed, - _MSG_CHANNEL_WINDOW_ADJUST: Channel._window_adjust, - _MSG_CHANNEL_REQUEST: Channel._handle_request, - _MSG_CHANNEL_EOF: Channel._handle_eof, - _MSG_CHANNEL_CLOSE: Channel._handle_close, + MSG_CHANNEL_SUCCESS: Channel._request_success, + MSG_CHANNEL_FAILURE: Channel._request_failed, + MSG_CHANNEL_DATA: Channel._feed, + MSG_CHANNEL_WINDOW_ADJUST: Channel._window_adjust, + MSG_CHANNEL_REQUEST: Channel._handle_request, + MSG_CHANNEL_EOF: Channel._handle_eof, + MSG_CHANNEL_CLOSE: Channel._handle_close, } diff --git a/paramiko/util.py b/paramiko/util.py index cc71c6c..4fa4ec8 100644 --- a/paramiko/util.py +++ b/paramiko/util.py @@ -24,7 +24,7 @@ Useful functions used by the rest of paramiko. import sys, struct, traceback -def inflate_long(s, always_positive=0): +def inflate_long(s, always_positive=False): "turns a normalized byte string into a long-int (adapted from Crypto.Util.number)" out = 0L negative = 0 @@ -41,7 +41,7 @@ def inflate_long(s, always_positive=0): out -= (1L << (8 * len(s))) return out -def deflate_long(n, add_sign_padding=1): +def deflate_long(n, add_sign_padding=True): "turns a long-int into a normalized byte string (adapted from Crypto.Util.number)" # after much testing, this algorithm was deemed to be the fastest s = '' @@ -99,6 +99,10 @@ def hexify(s): "turn a string into a hex sequence" return ''.join(['%02X' % ord(c) for c in s]) +def unhexify(s): + "turn a hex sequence back into a string" + return ''.join([chr(int(s[i:i+2], 16)) for i in range(0, len(s), 2)]) + def safe_string(s): out = '' for c in s: @@ -155,3 +159,17 @@ def generate_key_bytes(hashclass, salt, key, nbytes): keydata += digest[:size] nbytes -= size return keydata + +def mod_inverse(x, m): + # it's crazy how small python can make this function. + u1, u2, u3 = 1, 0, m + v1, v2, v3 = 0, 1, x + + while v3 > 0: + q = u3 // v3 + u1, v1 = v1, u1 - v1 * q + u2, v2 = v2, u2 - v2 * q + u3, v3 = v3, u3 - v3 * q + if u2 < 0: + u2 += m + return u2