[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.
This commit is contained in:
Robey Pointer 2004-04-05 10:12:59 +00:00
parent d757f90ac5
commit 8fafd1aa17
6 changed files with 88 additions and 102 deletions

View File

@ -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,
})

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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,
}

View File

@ -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