brittspace.

This commit is contained in:
Robey Pointer 2009-11-01 21:33:13 -08:00
parent 71e872e23a
commit e0a9f91c14
3 changed files with 103 additions and 103 deletions

View File

@ -33,7 +33,7 @@ class HostKeyEntry:
""" """
Representation of a line in an OpenSSH-style "known hosts" file. Representation of a line in an OpenSSH-style "known hosts" file.
""" """
def __init__(self, hostnames=None, key=None): def __init__(self, hostnames=None, key=None):
self.valid = (hostnames is not None) and (key is not None) self.valid = (hostnames is not None) and (key is not None)
self.hostnames = hostnames self.hostnames = hostnames
@ -83,7 +83,7 @@ class HostKeyEntry:
return '%s %s %s\n' % (','.join(self.hostnames), self.key.get_name(), return '%s %s %s\n' % (','.join(self.hostnames), self.key.get_name(),
self.key.get_base64()) self.key.get_base64())
return None return None
def __repr__(self): def __repr__(self):
return '<HostKeyEntry %r: %r>' % (self.hostnames, self.key) return '<HostKeyEntry %r: %r>' % (self.hostnames, self.key)
@ -93,18 +93,18 @@ class HostKeys (UserDict.DictMixin):
Representation of an openssh-style "known hosts" file. Host keys can be Representation of an openssh-style "known hosts" file. Host keys can be
read from one or more files, and then individual hosts can be looked up to read from one or more files, and then individual hosts can be looked up to
verify server keys during SSH negotiation. verify server keys during SSH negotiation.
A HostKeys object can be treated like a dict; any dict lookup is equivalent A HostKeys object can be treated like a dict; any dict lookup is equivalent
to calling L{lookup}. to calling L{lookup}.
@since: 1.5.3 @since: 1.5.3
""" """
def __init__(self, filename=None): def __init__(self, filename=None):
""" """
Create a new HostKeys object, optionally loading keys from an openssh Create a new HostKeys object, optionally loading keys from an openssh
style host-key file. style host-key file.
@param filename: filename to load host keys from, or C{None} @param filename: filename to load host keys from, or C{None}
@type filename: str @type filename: str
""" """
@ -112,12 +112,12 @@ class HostKeys (UserDict.DictMixin):
self._entries = [] self._entries = []
if filename is not None: if filename is not None:
self.load(filename) self.load(filename)
def add(self, hostname, keytype, key): def add(self, hostname, keytype, key):
""" """
Add a host key entry to the table. Any existing entry for a Add a host key entry to the table. Any existing entry for a
C{(hostname, keytype)} pair will be replaced. C{(hostname, keytype)} pair will be replaced.
@param hostname: the hostname (or IP) to add @param hostname: the hostname (or IP) to add
@type hostname: str @type hostname: str
@param keytype: key type (C{"ssh-rsa"} or C{"ssh-dss"}) @param keytype: key type (C{"ssh-rsa"} or C{"ssh-dss"})
@ -130,21 +130,21 @@ class HostKeys (UserDict.DictMixin):
e.key = key e.key = key
return return
self._entries.append(HostKeyEntry([hostname], key)) self._entries.append(HostKeyEntry([hostname], key))
def load(self, filename): def load(self, filename):
""" """
Read a file of known SSH host keys, in the format used by openssh. Read a file of known SSH host keys, in the format used by openssh.
This type of file unfortunately doesn't exist on Windows, but on This type of file unfortunately doesn't exist on Windows, but on
posix, it will usually be stored in posix, it will usually be stored in
C{os.path.expanduser("~/.ssh/known_hosts")}. C{os.path.expanduser("~/.ssh/known_hosts")}.
If this method is called multiple times, the host keys are merged, If this method is called multiple times, the host keys are merged,
not cleared. So multiple calls to C{load} will just call L{add}, not cleared. So multiple calls to C{load} will just call L{add},
replacing any existing entries and adding new ones. replacing any existing entries and adding new ones.
@param filename: name of the file to read host keys from @param filename: name of the file to read host keys from
@type filename: str @type filename: str
@raise IOError: if there was an error reading the file @raise IOError: if there was an error reading the file
""" """
f = open(filename, 'r') f = open(filename, 'r')
@ -156,19 +156,19 @@ class HostKeys (UserDict.DictMixin):
if e is not None: if e is not None:
self._entries.append(e) self._entries.append(e)
f.close() f.close()
def save(self, filename): def save(self, filename):
""" """
Save host keys into a file, in the format used by openssh. The order of Save host keys into a file, in the format used by openssh. The order of
keys in the file will be preserved when possible (if these keys were keys in the file will be preserved when possible (if these keys were
loaded from a file originally). The single exception is that combined loaded from a file originally). The single exception is that combined
lines will be split into individual key lines, which is arguably a bug. lines will be split into individual key lines, which is arguably a bug.
@param filename: name of the file to write @param filename: name of the file to write
@type filename: str @type filename: str
@raise IOError: if there was an error writing the file @raise IOError: if there was an error writing the file
@since: 1.6.1 @since: 1.6.1
""" """
f = open(filename, 'w') f = open(filename, 'w')
@ -183,7 +183,7 @@ class HostKeys (UserDict.DictMixin):
Find a hostkey entry for a given hostname or IP. If no entry is found, Find a hostkey entry for a given hostname or IP. If no entry is found,
C{None} is returned. Otherwise a dictionary of keytype to key is C{None} is returned. Otherwise a dictionary of keytype to key is
returned. The keytype will be either C{"ssh-rsa"} or C{"ssh-dss"}. returned. The keytype will be either C{"ssh-rsa"} or C{"ssh-dss"}.
@param hostname: the hostname (or IP) to lookup @param hostname: the hostname (or IP) to lookup
@type hostname: str @type hostname: str
@return: keys associated with this host (or C{None}) @return: keys associated with this host (or C{None})
@ -194,13 +194,13 @@ class HostKeys (UserDict.DictMixin):
self._hostname = hostname self._hostname = hostname
self._entries = entries self._entries = entries
self._hostkeys = hostkeys self._hostkeys = hostkeys
def __getitem__(self, key): def __getitem__(self, key):
for e in self._entries: for e in self._entries:
if e.key.get_name() == key: if e.key.get_name() == key:
return e.key return e.key
raise KeyError(key) raise KeyError(key)
def __setitem__(self, key, val): def __setitem__(self, key, val):
for e in self._entries: for e in self._entries:
if e.key is None: if e.key is None:
@ -214,7 +214,7 @@ class HostKeys (UserDict.DictMixin):
e = HostKeyEntry([hostname], val) e = HostKeyEntry([hostname], val)
self._entries.append(e) self._entries.append(e)
self._hostkeys._entries.append(e) self._hostkeys._entries.append(e)
def keys(self): def keys(self):
return [e.key.get_name() for e in self._entries if e.key is not None] return [e.key.get_name() for e in self._entries if e.key is not None]
@ -226,12 +226,12 @@ class HostKeys (UserDict.DictMixin):
if len(entries) == 0: if len(entries) == 0:
return None return None
return SubDict(hostname, entries, self) return SubDict(hostname, entries, self)
def check(self, hostname, key): def check(self, hostname, key):
""" """
Return True if the given key is associated with the given hostname Return True if the given key is associated with the given hostname
in this dictionary. in this dictionary.
@param hostname: hostname (or IP) of the SSH server @param hostname: hostname (or IP) of the SSH server
@type hostname: str @type hostname: str
@param key: the key to check @param key: the key to check
@ -253,13 +253,13 @@ class HostKeys (UserDict.DictMixin):
Remove all host keys from the dictionary. Remove all host keys from the dictionary.
""" """
self._entries = [] self._entries = []
def __getitem__(self, key): def __getitem__(self, key):
ret = self.lookup(key) ret = self.lookup(key)
if ret is None: if ret is None:
raise KeyError(key) raise KeyError(key)
return ret return ret
def __setitem__(self, hostname, entry): def __setitem__(self, hostname, entry):
# don't use this please. # don't use this please.
if len(entry) == 0: if len(entry) == 0:
@ -274,7 +274,7 @@ class HostKeys (UserDict.DictMixin):
found = True found = True
if not found: if not found:
self._entries.append(HostKeyEntry([hostname], entry[key_type])) self._entries.append(HostKeyEntry([hostname], entry[key_type]))
def keys(self): def keys(self):
# python 2.4 sets would be nice here. # python 2.4 sets would be nice here.
ret = [] ret = []
@ -294,7 +294,7 @@ class HostKeys (UserDict.DictMixin):
""" """
Return a "hashed" form of the hostname, as used by openssh when storing Return a "hashed" form of the hostname, as used by openssh when storing
hashed hostnames in the known_hosts file. hashed hostnames in the known_hosts file.
@param hostname: the hostname to hash @param hostname: the hostname to hash
@type hostname: str @type hostname: str
@param salt: optional salt to use when hashing (must be 20 bytes long) @param salt: optional salt to use when hashing (must be 20 bytes long)

View File

@ -43,7 +43,7 @@ def open_rng_device(device_path=None):
f = None f = None
g = None g = None
if device_path is None: if device_path is None:
device_path = "/dev/urandom" device_path = "/dev/urandom"
@ -54,7 +54,7 @@ def open_rng_device(device_path=None):
f = open(device_path, "rb", 0) f = open(device_path, "rb", 0)
except EnvironmentError: except EnvironmentError:
raise error("Unable to open /dev/urandom") raise error("Unable to open /dev/urandom")
# Open a second file descriptor for sanity checking later. # Open a second file descriptor for sanity checking later.
try: try:
g = open(device_path, "rb", 0) g = open(device_path, "rb", 0)
@ -65,17 +65,17 @@ def open_rng_device(device_path=None):
st = os.fstat(f.fileno()) # f st = os.fstat(f.fileno()) # f
if stat.S_ISREG(st.st_mode) or not stat.S_ISCHR(st.st_mode): if stat.S_ISREG(st.st_mode) or not stat.S_ISCHR(st.st_mode):
raise error("/dev/urandom is not a character special device") raise error("/dev/urandom is not a character special device")
st = os.fstat(g.fileno()) # g st = os.fstat(g.fileno()) # g
if stat.S_ISREG(st.st_mode) or not stat.S_ISCHR(st.st_mode): if stat.S_ISREG(st.st_mode) or not stat.S_ISCHR(st.st_mode):
raise error("/dev/urandom is not a character special device") raise error("/dev/urandom is not a character special device")
# Check that /dev/urandom always returns the number of bytes requested # Check that /dev/urandom always returns the number of bytes requested
x = f.read(20) x = f.read(20)
y = g.read(20) y = g.read(20)
if len(x) != 20 or len(y) != 20: if len(x) != 20 or len(y) != 20:
raise error("Error reading from /dev/urandom: input truncated") raise error("Error reading from /dev/urandom: input truncated")
# Check that different reads return different data # Check that different reads return different data
if x == y: if x == y:
raise error("/dev/urandom is broken; returning identical data: %r == %r" % (x, y)) raise error("/dev/urandom is broken; returning identical data: %r == %r" % (x, y))

View File

@ -103,7 +103,7 @@ class SecurityOptions (object):
def _get_kex(self): def _get_kex(self):
return self._transport._preferred_kex return self._transport._preferred_kex
def _get_compression(self): def _get_compression(self):
return self._transport._preferred_compression return self._transport._preferred_compression
@ -129,7 +129,7 @@ class SecurityOptions (object):
def _set_kex(self, x): def _set_kex(self, x):
self._set('_preferred_kex', '_kex_info', x) self._set('_preferred_kex', '_kex_info', x)
def _set_compression(self, x): def _set_compression(self, x):
self._set('_preferred_compression', '_compression_info', x) self._set('_preferred_compression', '_compression_info', x)
@ -156,14 +156,14 @@ class ChannelMap (object):
self._map[chanid] = chan self._map[chanid] = chan
finally: finally:
self._lock.release() self._lock.release()
def get(self, chanid): def get(self, chanid):
self._lock.acquire() self._lock.acquire()
try: try:
return self._map.get(chanid, None) return self._map.get(chanid, None)
finally: finally:
self._lock.release() self._lock.release()
def delete(self, chanid): def delete(self, chanid):
self._lock.acquire() self._lock.acquire()
try: try:
@ -173,14 +173,14 @@ class ChannelMap (object):
pass pass
finally: finally:
self._lock.release() self._lock.release()
def values(self): def values(self):
self._lock.acquire() self._lock.acquire()
try: try:
return self._map.values() return self._map.values()
finally: finally:
self._lock.release() self._lock.release()
def __len__(self): def __len__(self):
self._lock.acquire() self._lock.acquire()
try: try:
@ -206,7 +206,7 @@ class Transport (threading.Thread):
_preferred_keys = ( 'ssh-rsa', 'ssh-dss' ) _preferred_keys = ( 'ssh-rsa', 'ssh-dss' )
_preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' ) _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' )
_preferred_compression = ( 'none', ) _preferred_compression = ( 'none', )
_cipher_info = { _cipher_info = {
'aes128-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16 }, 'aes128-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16 },
'aes256-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32 }, 'aes256-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32 },
@ -234,7 +234,7 @@ class Transport (threading.Thread):
'diffie-hellman-group1-sha1': KexGroup1, 'diffie-hellman-group1-sha1': KexGroup1,
'diffie-hellman-group-exchange-sha1': KexGex, 'diffie-hellman-group-exchange-sha1': KexGex,
} }
_compression_info = { _compression_info = {
# zlib@openssh.com is just zlib, but only turned on after a successful # zlib@openssh.com is just zlib, but only turned on after a successful
# authentication. openssh servers may only offer this type because # authentication. openssh servers may only offer this type because
@ -319,7 +319,7 @@ class Transport (threading.Thread):
self.session_id = None self.session_id = None
self.host_key_type = None self.host_key_type = None
self.host_key = None self.host_key = None
# state used during negotiation # state used during negotiation
self.kex_engine = None self.kex_engine = None
self.H = None self.H = None
@ -383,7 +383,7 @@ class Transport (threading.Thread):
out += ' (connecting)' out += ' (connecting)'
out += '>' out += '>'
return out return out
def atfork(self): def atfork(self):
""" """
Terminate this Transport without closing the session. On posix Terminate this Transport without closing the session. On posix
@ -391,7 +391,7 @@ class Transport (threading.Thread):
and child will share the underlying socket, but only one process can and child will share the underlying socket, but only one process can
use the connection (without corrupting the session). Use this method use the connection (without corrupting the session). Use this method
to clean up a Transport object without disrupting the other process. to clean up a Transport object without disrupting the other process.
@since: 1.5.3 @since: 1.5.3
""" """
self.sock.close() self.sock.close()
@ -414,11 +414,11 @@ class Transport (threading.Thread):
Negotiate a new SSH2 session as a client. This is the first step after Negotiate a new SSH2 session as a client. This is the first step after
creating a new L{Transport}. A separate thread is created for protocol creating a new L{Transport}. A separate thread is created for protocol
negotiation. negotiation.
If an event is passed in, this method returns immediately. When If an event is passed in, this method returns immediately. When
negotiation is done (successful or not), the given C{Event} will negotiation is done (successful or not), the given C{Event} will
be triggered. On failure, L{is_active} will return C{False}. be triggered. On failure, L{is_active} will return C{False}.
(Since 1.4) If C{event} is C{None}, this method will not return until (Since 1.4) If C{event} is C{None}, this method will not return until
negotation is done. On success, the method returns normally. negotation is done. On success, the method returns normally.
Otherwise an SSHException is raised. Otherwise an SSHException is raised.
@ -428,7 +428,7 @@ class Transport (threading.Thread):
L{auth_publickey <Transport.auth_publickey>}. L{auth_publickey <Transport.auth_publickey>}.
@note: L{connect} is a simpler method for connecting as a client. @note: L{connect} is a simpler method for connecting as a client.
@note: After calling this method (or L{start_server} or L{connect}), @note: After calling this method (or L{start_server} or L{connect}),
you should no longer directly read from or write to the original you should no longer directly read from or write to the original
socket object. socket object.
@ -465,11 +465,11 @@ class Transport (threading.Thread):
Negotiate a new SSH2 session as a server. This is the first step after Negotiate a new SSH2 session as a server. This is the first step after
creating a new L{Transport} and setting up your server host key(s). A creating a new L{Transport} and setting up your server host key(s). A
separate thread is created for protocol negotiation. separate thread is created for protocol negotiation.
If an event is passed in, this method returns immediately. When If an event is passed in, this method returns immediately. When
negotiation is done (successful or not), the given C{Event} will negotiation is done (successful or not), the given C{Event} will
be triggered. On failure, L{is_active} will return C{False}. be triggered. On failure, L{is_active} will return C{False}.
(Since 1.4) If C{event} is C{None}, this method will not return until (Since 1.4) If C{event} is C{None}, this method will not return until
negotation is done. On success, the method returns normally. negotation is done. On success, the method returns normally.
Otherwise an SSHException is raised. Otherwise an SSHException is raised.
@ -532,7 +532,7 @@ class Transport (threading.Thread):
we are. Because this is used for signing, the key must contain private we are. Because this is used for signing, the key must contain private
key info, not just the public half. Only one key of each type (RSA or key info, not just the public half. Only one key of each type (RSA or
DSS) is kept. DSS) is kept.
@param key: the host key to add, usually an L{RSAKey <rsakey.RSAKey>} or @param key: the host key to add, usually an L{RSAKey <rsakey.RSAKey>} or
L{DSSKey <dsskey.DSSKey>}. L{DSSKey <dsskey.DSSKey>}.
@type key: L{PKey <pkey.PKey>} @type key: L{PKey <pkey.PKey>}
@ -582,7 +582,7 @@ class Transport (threading.Thread):
@return: True if a moduli file was successfully loaded; False @return: True if a moduli file was successfully loaded; False
otherwise. otherwise.
@rtype: bool @rtype: bool
@note: This has no effect when used in client mode. @note: This has no effect when used in client mode.
""" """
Transport._modulus_pack = ModulusPack(randpool) Transport._modulus_pack = ModulusPack(randpool)
@ -623,7 +623,7 @@ class Transport (threading.Thread):
C{str(key)} for the key string. C{str(key)} for the key string.
@raise SSHException: if no session is currently active. @raise SSHException: if no session is currently active.
@return: public key of the remote server @return: public key of the remote server
@rtype: L{PKey <pkey.PKey>} @rtype: L{PKey <pkey.PKey>}
""" """
@ -648,7 +648,7 @@ class Transport (threading.Thread):
@return: a new L{Channel} @return: a new L{Channel}
@rtype: L{Channel} @rtype: L{Channel}
@raise SSHException: if the request is rejected or the session ends @raise SSHException: if the request is rejected or the session ends
prematurely prematurely
""" """
@ -664,25 +664,25 @@ class Transport (threading.Thread):
@type src_addr: (str, int) @type src_addr: (str, int)
@return: a new L{Channel} @return: a new L{Channel}
@rtype: L{Channel} @rtype: L{Channel}
@raise SSHException: if the request is rejected or the session ends @raise SSHException: if the request is rejected or the session ends
prematurely prematurely
""" """
return self.open_channel('x11', src_addr=src_addr) return self.open_channel('x11', src_addr=src_addr)
def open_forwarded_tcpip_channel(self, (src_addr, src_port), (dest_addr, dest_port)): def open_forwarded_tcpip_channel(self, (src_addr, src_port), (dest_addr, dest_port)):
""" """
Request a new channel back to the client, of type C{"forwarded-tcpip"}. Request a new channel back to the client, of type C{"forwarded-tcpip"}.
This is used after a client has requested port forwarding, for sending This is used after a client has requested port forwarding, for sending
incoming connections back to the client. incoming connections back to the client.
@param src_addr: originator's address @param src_addr: originator's address
@param src_port: originator's port @param src_port: originator's port
@param dest_addr: local (server) connected address @param dest_addr: local (server) connected address
@param dest_port: local (server) connected port @param dest_port: local (server) connected port
""" """
return self.open_channel('forwarded-tcpip', (dest_addr, dest_port), (src_addr, src_port)) return self.open_channel('forwarded-tcpip', (dest_addr, dest_port), (src_addr, src_port))
def open_channel(self, kind, dest_addr=None, src_addr=None): def open_channel(self, kind, dest_addr=None, src_addr=None):
""" """
Request a new channel to the server. L{Channel}s are socket-like Request a new channel to the server. L{Channel}s are socket-like
@ -757,19 +757,19 @@ class Transport (threading.Thread):
""" """
Ask the server to forward TCP connections from a listening port on Ask the server to forward TCP connections from a listening port on
the server, across this SSH session. the server, across this SSH session.
If a handler is given, that handler is called from a different thread If a handler is given, that handler is called from a different thread
whenever a forwarded connection arrives. The handler parameters are:: whenever a forwarded connection arrives. The handler parameters are::
handler(channel, (origin_addr, origin_port), (server_addr, server_port)) handler(channel, (origin_addr, origin_port), (server_addr, server_port))
where C{server_addr} and C{server_port} are the address and port that where C{server_addr} and C{server_port} are the address and port that
the server was listening on. the server was listening on.
If no handler is set, the default behavior is to send new incoming If no handler is set, the default behavior is to send new incoming
forwarded connections into the accept queue, to be picked up via forwarded connections into the accept queue, to be picked up via
L{accept}. L{accept}.
@param address: the address to bind when forwarding @param address: the address to bind when forwarding
@type address: str @type address: str
@param port: the port to forward, or 0 to ask the server to allocate @param port: the port to forward, or 0 to ask the server to allocate
@ -779,7 +779,7 @@ class Transport (threading.Thread):
@type handler: function(Channel, (str, int), (str, int)) @type handler: function(Channel, (str, int), (str, int))
@return: the port # allocated by the server @return: the port # allocated by the server
@rtype: int @rtype: int
@raise SSHException: if the server refused the TCP forward request @raise SSHException: if the server refused the TCP forward request
""" """
if not self.active: if not self.active:
@ -803,7 +803,7 @@ class Transport (threading.Thread):
Ask the server to cancel a previous port-forwarding request. No more Ask the server to cancel a previous port-forwarding request. No more
connections to the given address & port will be forwarded across this connections to the given address & port will be forwarded across this
ssh connection. ssh connection.
@param address: the address to stop forwarding @param address: the address to stop forwarding
@type address: str @type address: str
@param port: the port to stop forwarding @param port: the port to stop forwarding
@ -813,7 +813,7 @@ class Transport (threading.Thread):
return return
self._tcp_handler = None self._tcp_handler = None
self.global_request('cancel-tcpip-forward', (address, port), wait=True) self.global_request('cancel-tcpip-forward', (address, port), wait=True)
def open_sftp_client(self): def open_sftp_client(self):
""" """
Create an SFTP client channel from an open transport. On success, Create an SFTP client channel from an open transport. On success,
@ -876,7 +876,7 @@ class Transport (threading.Thread):
C{interval} seconds without sending any data over the connection, a C{interval} seconds without sending any data over the connection, a
"keepalive" packet will be sent (and ignored by the remote host). This "keepalive" packet will be sent (and ignored by the remote host). This
can be useful to keep connections alive over a NAT, for example. can be useful to keep connections alive over a NAT, for example.
@param interval: seconds to wait before sending a keepalive packet (or @param interval: seconds to wait before sending a keepalive packet (or
0 to disable keepalives). 0 to disable keepalives).
@type interval: int @type interval: int
@ -927,7 +927,7 @@ class Transport (threading.Thread):
Return the next channel opened by the client over this transport, in Return the next channel opened by the client over this transport, in
server mode. If no channel is opened before the given timeout, C{None} server mode. If no channel is opened before the given timeout, C{None}
is returned. is returned.
@param timeout: seconds to wait for a channel, or C{None} to wait @param timeout: seconds to wait for a channel, or C{None} to wait
forever forever
@type timeout: int @type timeout: int
@ -979,7 +979,7 @@ class Transport (threading.Thread):
@param pkey: a private key to use for authentication, if you want to @param pkey: a private key to use for authentication, if you want to
use private key authentication; otherwise C{None}. use private key authentication; otherwise C{None}.
@type pkey: L{PKey<pkey.PKey>} @type pkey: L{PKey<pkey.PKey>}
@raise SSHException: if the SSH2 negotiation fails, the host key @raise SSHException: if the SSH2 negotiation fails, the host key
supplied by the server is incorrect, or authentication fails. supplied by the server is incorrect, or authentication fails.
""" """
@ -1007,17 +1007,17 @@ class Transport (threading.Thread):
self.auth_publickey(username, pkey) self.auth_publickey(username, pkey)
return return
def get_exception(self): def get_exception(self):
""" """
Return any exception that happened during the last server request. Return any exception that happened during the last server request.
This can be used to fetch more specific error information after using This can be used to fetch more specific error information after using
calls like L{start_client}. The exception (if any) is cleared after calls like L{start_client}. The exception (if any) is cleared after
this call. this call.
@return: an exception, or C{None} if there is no stored exception. @return: an exception, or C{None} if there is no stored exception.
@rtype: Exception @rtype: Exception
@since: 1.1 @since: 1.1
""" """
self.lock.acquire() self.lock.acquire()
@ -1049,7 +1049,7 @@ class Transport (threading.Thread):
self.subsystem_table[name] = (handler, larg, kwarg) self.subsystem_table[name] = (handler, larg, kwarg)
finally: finally:
self.lock.release() self.lock.release()
def is_authenticated(self): def is_authenticated(self):
""" """
Return true if this session is active and authenticated. Return true if this session is active and authenticated.
@ -1060,7 +1060,7 @@ class Transport (threading.Thread):
@rtype: bool @rtype: bool
""" """
return self.active and (self.auth_handler is not None) and self.auth_handler.is_authenticated() return self.active and (self.auth_handler is not None) and self.auth_handler.is_authenticated()
def get_username(self): def get_username(self):
""" """
Return the username this connection is authenticated for. If the Return the username this connection is authenticated for. If the
@ -1080,7 +1080,7 @@ class Transport (threading.Thread):
This will almost always fail. It may be useful for determining the This will almost always fail. It may be useful for determining the
list of authentication types supported by the server, by catching the list of authentication types supported by the server, by catching the
L{BadAuthenticationType} exception raised. L{BadAuthenticationType} exception raised.
@param username: the username to authenticate as @param username: the username to authenticate as
@type username: string @type username: string
@return: list of auth types permissible for the next stage of @return: list of auth types permissible for the next stage of
@ -1091,7 +1091,7 @@ class Transport (threading.Thread):
by the server for this user by the server for this user
@raise SSHException: if the authentication failed due to a network @raise SSHException: if the authentication failed due to a network
error error
@since: 1.5 @since: 1.5
""" """
if (not self.active) or (not self.initial_kex_done): if (not self.active) or (not self.initial_kex_done):
@ -1105,7 +1105,7 @@ class Transport (threading.Thread):
""" """
Authenticate to the server using a password. The username and password Authenticate to the server using a password. The username and password
are sent over an encrypted link. are sent over an encrypted link.
If an C{event} is passed in, this method will return immediately, and If an C{event} is passed in, this method will return immediately, and
the event will be triggered once authentication succeeds or fails. On the event will be triggered once authentication succeeds or fails. On
success, L{is_authenticated} will return C{True}. On failure, you may success, L{is_authenticated} will return C{True}. On failure, you may
@ -1114,7 +1114,7 @@ class Transport (threading.Thread):
Since 1.1, if no event is passed, this method will block until the Since 1.1, if no event is passed, this method will block until the
authentication succeeds or fails. On failure, an exception is raised. authentication succeeds or fails. On failure, an exception is raised.
Otherwise, the method simply returns. Otherwise, the method simply returns.
Since 1.5, if no event is passed and C{fallback} is C{True} (the Since 1.5, if no event is passed and C{fallback} is C{True} (the
default), if the server doesn't support plain password authentication default), if the server doesn't support plain password authentication
but does support so-called "keyboard-interactive" mode, an attempt but does support so-called "keyboard-interactive" mode, an attempt
@ -1123,11 +1123,11 @@ class Transport (threading.Thread):
made. This is useful for some recent Gentoo and Debian distributions, made. This is useful for some recent Gentoo and Debian distributions,
which turn off plain password authentication in a misguided belief which turn off plain password authentication in a misguided belief
that interactive authentication is "more secure". (It's not.) that interactive authentication is "more secure". (It's not.)
If the server requires multi-step authentication (which is very rare), If the server requires multi-step authentication (which is very rare),
this method will return a list of auth types permissible for the next this method will return a list of auth types permissible for the next
step. Otherwise, in the normal case, an empty list is returned. step. Otherwise, in the normal case, an empty list is returned.
@param username: the username to authenticate as @param username: the username to authenticate as
@type username: str @type username: str
@param password: the password to authenticate with @param password: the password to authenticate with
@ -1142,7 +1142,7 @@ class Transport (threading.Thread):
@return: list of auth types permissible for the next stage of @return: list of auth types permissible for the next stage of
authentication (normally empty) authentication (normally empty)
@rtype: list @rtype: list
@raise BadAuthenticationType: if password authentication isn't @raise BadAuthenticationType: if password authentication isn't
allowed by the server for this user (and no event was passed in) allowed by the server for this user (and no event was passed in)
@raise AuthenticationException: if the authentication failed (and no @raise AuthenticationException: if the authentication failed (and no
@ -1188,12 +1188,12 @@ class Transport (threading.Thread):
""" """
Authenticate to the server using a private key. The key is used to Authenticate to the server using a private key. The key is used to
sign data from the server, so it must include the private part. sign data from the server, so it must include the private part.
If an C{event} is passed in, this method will return immediately, and If an C{event} is passed in, this method will return immediately, and
the event will be triggered once authentication succeeds or fails. On the event will be triggered once authentication succeeds or fails. On
success, L{is_authenticated} will return C{True}. On failure, you may success, L{is_authenticated} will return C{True}. On failure, you may
use L{get_exception} to get more detailed error information. use L{get_exception} to get more detailed error information.
Since 1.1, if no event is passed, this method will block until the Since 1.1, if no event is passed, this method will block until the
authentication succeeds or fails. On failure, an exception is raised. authentication succeeds or fails. On failure, an exception is raised.
Otherwise, the method simply returns. Otherwise, the method simply returns.
@ -1212,7 +1212,7 @@ class Transport (threading.Thread):
@return: list of auth types permissible for the next stage of @return: list of auth types permissible for the next stage of
authentication (normally empty) authentication (normally empty)
@rtype: list @rtype: list
@raise BadAuthenticationType: if public-key authentication isn't @raise BadAuthenticationType: if public-key authentication isn't
allowed by the server for this user (and no event was passed in) allowed by the server for this user (and no event was passed in)
@raise AuthenticationException: if the authentication failed (and no @raise AuthenticationException: if the authentication failed (and no
@ -1232,18 +1232,18 @@ class Transport (threading.Thread):
# caller wants to wait for event themselves # caller wants to wait for event themselves
return [] return []
return self.auth_handler.wait_for_response(my_event) return self.auth_handler.wait_for_response(my_event)
def auth_interactive(self, username, handler, submethods=''): def auth_interactive(self, username, handler, submethods=''):
""" """
Authenticate to the server interactively. A handler is used to answer Authenticate to the server interactively. A handler is used to answer
arbitrary questions from the server. On many servers, this is just a arbitrary questions from the server. On many servers, this is just a
dumb wrapper around PAM. dumb wrapper around PAM.
This method will block until the authentication succeeds or fails, This method will block until the authentication succeeds or fails,
peroidically calling the handler asynchronously to get answers to peroidically calling the handler asynchronously to get answers to
authentication questions. The handler may be called more than once authentication questions. The handler may be called more than once
if the server continues to ask questions. if the server continues to ask questions.
The handler is expected to be a callable that will handle calls of the The handler is expected to be a callable that will handle calls of the
form: C{handler(title, instructions, prompt_list)}. The C{title} is form: C{handler(title, instructions, prompt_list)}. The C{title} is
meant to be a dialog-window title, and the C{instructions} are user meant to be a dialog-window title, and the C{instructions} are user
@ -1251,13 +1251,13 @@ class Transport (threading.Thread):
prompts, each prompt being a tuple of C{(str, bool)}. The string is prompts, each prompt being a tuple of C{(str, bool)}. The string is
the prompt and the boolean indicates whether the user text should be the prompt and the boolean indicates whether the user text should be
echoed. echoed.
A sample call would thus be: A sample call would thus be:
C{handler('title', 'instructions', [('Password:', False)])}. C{handler('title', 'instructions', [('Password:', False)])}.
The handler should return a list or tuple of answers to the server's The handler should return a list or tuple of answers to the server's
questions. questions.
If the server requires multi-step authentication (which is very rare), If the server requires multi-step authentication (which is very rare),
this method will return a list of auth types permissible for the next this method will return a list of auth types permissible for the next
step. Otherwise, in the normal case, an empty list is returned. step. Otherwise, in the normal case, an empty list is returned.
@ -1271,12 +1271,12 @@ class Transport (threading.Thread):
@return: list of auth types permissible for the next stage of @return: list of auth types permissible for the next stage of
authentication (normally empty). authentication (normally empty).
@rtype: list @rtype: list
@raise BadAuthenticationType: if public-key authentication isn't @raise BadAuthenticationType: if public-key authentication isn't
allowed by the server for this user allowed by the server for this user
@raise AuthenticationException: if the authentication failed @raise AuthenticationException: if the authentication failed
@raise SSHException: if there was a network error @raise SSHException: if there was a network error
@since: 1.5 @since: 1.5
""" """
if (not self.active) or (not self.initial_kex_done): if (not self.active) or (not self.initial_kex_done):
@ -1325,43 +1325,43 @@ class Transport (threading.Thread):
@type hexdump: bool @type hexdump: bool
""" """
self.packetizer.set_hexdump(hexdump) self.packetizer.set_hexdump(hexdump)
def get_hexdump(self): def get_hexdump(self):
""" """
Return C{True} if the transport is currently logging hex dumps of Return C{True} if the transport is currently logging hex dumps of
protocol traffic. protocol traffic.
@return: C{True} if hex dumps are being logged @return: C{True} if hex dumps are being logged
@rtype: bool @rtype: bool
@since: 1.4 @since: 1.4
""" """
return self.packetizer.get_hexdump() return self.packetizer.get_hexdump()
def use_compression(self, compress=True): def use_compression(self, compress=True):
""" """
Turn on/off compression. This will only have an affect before starting Turn on/off compression. This will only have an affect before starting
the transport (ie before calling L{connect}, etc). By default, the transport (ie before calling L{connect}, etc). By default,
compression is off since it negatively affects interactive sessions. compression is off since it negatively affects interactive sessions.
@param compress: C{True} to ask the remote client/server to compress @param compress: C{True} to ask the remote client/server to compress
traffic; C{False} to refuse compression traffic; C{False} to refuse compression
@type compress: bool @type compress: bool
@since: 1.5.2 @since: 1.5.2
""" """
if compress: if compress:
self._preferred_compression = ( 'zlib@openssh.com', 'zlib', 'none' ) self._preferred_compression = ( 'zlib@openssh.com', 'zlib', 'none' )
else: else:
self._preferred_compression = ( 'none', ) self._preferred_compression = ( 'none', )
def getpeername(self): def getpeername(self):
""" """
Return the address of the remote side of this Transport, if possible. Return the address of the remote side of this Transport, if possible.
This is effectively a wrapper around C{'getpeername'} on the underlying This is effectively a wrapper around C{'getpeername'} on the underlying
socket. If the socket-like object has no C{'getpeername'} method, socket. If the socket-like object has no C{'getpeername'} method,
then C{("unknown", 0)} is returned. then C{("unknown", 0)} is returned.
@return: the address if the remote host, if known @return: the address if the remote host, if known
@rtype: tuple(str, int) @rtype: tuple(str, int)
""" """
@ -1377,7 +1377,7 @@ class Transport (threading.Thread):
### internals... ### internals...
def _log(self, level, msg, *args): def _log(self, level, msg, *args):
if issubclass(type(msg), list): if issubclass(type(msg), list):
for m in msg: for m in msg:
@ -1498,13 +1498,13 @@ class Transport (threading.Thread):
self.server_accept_cv.notify() self.server_accept_cv.notify()
finally: finally:
self.lock.release() self.lock.release()
def run(self): def run(self):
# (use the exposed "run" method, because if we specify a thread target # (use the exposed "run" method, because if we specify a thread target
# of a private method, threading.Thread will keep a reference to it # of a private method, threading.Thread will keep a reference to it
# indefinitely, creating a GC cycle and not letting Transport ever be # indefinitely, creating a GC cycle and not letting Transport ever be
# GC'd. it's a bug in Thread.) # GC'd. it's a bug in Thread.)
# active=True occurs before the thread is launched, to avoid a race # active=True occurs before the thread is launched, to avoid a race
_active_threads.append(self) _active_threads.append(self)
if self.server_mode: if self.server_mode:
@ -1929,7 +1929,7 @@ class Transport (threading.Thread):
self.global_response = m self.global_response = m
if self.completion_event is not None: if self.completion_event is not None:
self.completion_event.set() self.completion_event.set()
def _parse_request_failure(self, m): def _parse_request_failure(self, m):
self._log(DEBUG, 'Global request denied.') self._log(DEBUG, 'Global request denied.')
self.global_response = None self.global_response = None
@ -2018,7 +2018,7 @@ class Transport (threading.Thread):
origin_addr = m.get_string() origin_addr = m.get_string()
origin_port = m.get_int() origin_port = m.get_int()
reason = self.server_object.check_channel_direct_tcpip_request( reason = self.server_object.check_channel_direct_tcpip_request(
my_chanid, (origin_addr, origin_port), my_chanid, (origin_addr, origin_port),
(dest_addr, dest_port)) (dest_addr, dest_port))
else: else:
reason = self.server_object.check_channel_request(kind, my_chanid) reason = self.server_object.check_channel_request(kind, my_chanid)
@ -2034,7 +2034,7 @@ class Transport (threading.Thread):
msg.add_string('en') msg.add_string('en')
self._send_message(msg) self._send_message(msg)
return return
chan = Channel(my_chanid) chan = Channel(my_chanid)
self.lock.acquire() self.lock.acquire()
try: try: