diff options
-rw-r--r-- | paramiko/__init__.py | 91 | ||||
-rw-r--r-- | paramiko/_winapi.py | 18 | ||||
-rw-r--r-- | paramiko/auth_handler.py | 132 | ||||
-rw-r--r-- | paramiko/config.py | 4 | ||||
-rw-r--r-- | paramiko/hostkeys.py | 10 | ||||
-rw-r--r-- | paramiko/kex_gex.py | 27 | ||||
-rw-r--r-- | paramiko/sftp_file.py | 21 | ||||
-rw-r--r-- | paramiko/ssh_exception.py | 36 | ||||
-rw-r--r-- | paramiko/ssh_gss.py | 27 | ||||
-rw-r--r-- | setup.cfg | 2 |
10 files changed, 221 insertions, 147 deletions
diff --git a/paramiko/__init__.py b/paramiko/__init__.py index 9e2ba013..5c1f38b3 100644 --- a/paramiko/__init__.py +++ b/paramiko/__init__.py @@ -28,7 +28,8 @@ __license__ = "GNU Lesser General Public License (LGPL)" from paramiko.transport import SecurityOptions, Transport -from paramiko.client import SSHClient, MissingHostKeyPolicy, AutoAddPolicy, RejectPolicy, WarningPolicy +from paramiko.client import SSHClient, MissingHostKeyPolicy, AutoAddPolicy, \ + RejectPolicy, WarningPolicy from paramiko.auth_handler import AuthHandler from paramiko.ssh_gss import GSSAuth, GSS_AUTH_AVAILABLE from paramiko.channel import Channel, ChannelFile @@ -55,49 +56,53 @@ from paramiko.hostkeys import HostKeys from paramiko.config import SSHConfig from paramiko.proxy import ProxyCommand -from paramiko.common import AUTH_SUCCESSFUL, AUTH_PARTIALLY_SUCCESSFUL, AUTH_FAILED, \ - OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, OPEN_FAILED_CONNECT_FAILED, \ - OPEN_FAILED_UNKNOWN_CHANNEL_TYPE, OPEN_FAILED_RESOURCE_SHORTAGE +from paramiko.common import AUTH_SUCCESSFUL, AUTH_PARTIALLY_SUCCESSFUL, \ + AUTH_FAILED, OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, \ + OPEN_FAILED_CONNECT_FAILED, OPEN_FAILED_UNKNOWN_CHANNEL_TYPE, \ + OPEN_FAILED_RESOURCE_SHORTAGE -from paramiko.sftp import SFTP_OK, SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, SFTP_FAILURE, \ - SFTP_BAD_MESSAGE, SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED +from paramiko.sftp import SFTP_OK, SFTP_EOF, SFTP_NO_SUCH_FILE, \ + SFTP_PERMISSION_DENIED, SFTP_FAILURE, SFTP_BAD_MESSAGE, \ + SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED from paramiko.common import io_sleep -__all__ = [ 'Transport', - 'SSHClient', - 'MissingHostKeyPolicy', - 'AutoAddPolicy', - 'RejectPolicy', - 'WarningPolicy', - 'SecurityOptions', - 'SubsystemHandler', - 'Channel', - 'PKey', - 'RSAKey', - 'DSSKey', - 'Message', - 'SSHException', - 'AuthenticationException', - 'PasswordRequiredException', - 'BadAuthenticationType', - 'ChannelException', - 'BadHostKeyException', - 'ProxyCommand', - 'ProxyCommandFailure', - 'SFTP', - 'SFTPFile', - 'SFTPHandle', - 'SFTPClient', - 'SFTPServer', - 'SFTPError', - 'SFTPAttributes', - 'SFTPServerInterface', - 'ServerInterface', - 'BufferedFile', - 'Agent', - 'AgentKey', - 'HostKeys', - 'SSHConfig', - 'util', - 'io_sleep' ] +__all__ = [ + 'Transport', + 'SSHClient', + 'MissingHostKeyPolicy', + 'AutoAddPolicy', + 'RejectPolicy', + 'WarningPolicy', + 'SecurityOptions', + 'SubsystemHandler', + 'Channel', + 'PKey', + 'RSAKey', + 'DSSKey', + 'Message', + 'SSHException', + 'AuthenticationException', + 'PasswordRequiredException', + 'BadAuthenticationType', + 'ChannelException', + 'BadHostKeyException', + 'ProxyCommand', + 'ProxyCommandFailure', + 'SFTP', + 'SFTPFile', + 'SFTPHandle', + 'SFTPClient', + 'SFTPServer', + 'SFTPError', + 'SFTPAttributes', + 'SFTPServerInterface', + 'ServerInterface', + 'BufferedFile', + 'Agent', + 'AgentKey', + 'HostKeys', + 'SSHConfig', + 'util', + 'io_sleep', +] diff --git a/paramiko/_winapi.py b/paramiko/_winapi.py index c9797d23..a13d7e87 100644 --- a/paramiko/_winapi.py +++ b/paramiko/_winapi.py @@ -41,7 +41,7 @@ def format_system_message(errno): ctypes.byref(result_buffer), buffer_size, arguments, - ) + ) # note the following will cause an infinite loop if GetLastError # repeatedly returns an error that cannot be formatted, although # this should not happen. @@ -52,13 +52,14 @@ def format_system_message(errno): class WindowsError(builtins.WindowsError): - "more info about errors at http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx" + """more info about errors at + http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx""" def __init__(self, value=None): if value is None: value = ctypes.windll.kernel32.GetLastError() strerror = format_system_message(value) - if sys.version_info > (3,3): + if sys.version_info > (3, 3): args = 0, strerror, None, value else: args = value, strerror @@ -78,6 +79,7 @@ class WindowsError(builtins.WindowsError): def __repr__(self): return '{self.__class__.__name__}({self.winerror})'.format(**vars()) + def handle_nonzero_success(result): if result == 0: raise WindowsError() @@ -133,6 +135,7 @@ ctypes.windll.kernel32.LocalFree.argtypes = ctypes.wintypes.HLOCAL, ##################### # jaraco.windows.mmap + class MemoryMap(object): """ A memory map object which can have security attributes overridden. @@ -189,6 +192,7 @@ class MemoryMap(object): ctypes.windll.kernel32.UnmapViewOfFile(self.view) ctypes.windll.kernel32.CloseHandle(self.filemap) + ############################# # jaraco.windows.api.security @@ -252,12 +256,15 @@ POLICY_EXECUTE = ( POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES) + class TokenAccess: TOKEN_QUERY = 0x8 + class TokenInformationClass: TokenUser = 1 + class TOKEN_USER(ctypes.Structure): num = 1 _fields_ = [ @@ -292,6 +299,7 @@ class SECURITY_DESCRIPTOR(ctypes.Structure): ('Dacl', ctypes.c_void_p), ] + class SECURITY_ATTRIBUTES(ctypes.Structure): """ typedef struct _SECURITY_ATTRIBUTES { @@ -329,6 +337,7 @@ ctypes.windll.advapi32.SetSecurityDescriptorOwner.argtypes = ( ######################### # jaraco.windows.security + def GetTokenInformation(token, information_class): """ Given a token, get the token information for it. @@ -343,6 +352,7 @@ def GetTokenInformation(token, information_class): ctypes.byref(data_size))) return ctypes.cast(data, ctypes.POINTER(TOKEN_USER)).contents + def OpenProcessToken(proc_handle, access): result = ctypes.wintypes.HANDLE() proc_handle = ctypes.wintypes.HANDLE(proc_handle) @@ -350,6 +360,7 @@ def OpenProcessToken(proc_handle, access): proc_handle, access, ctypes.byref(result))) return result + def get_current_user(): """ Return a TOKEN_USER for the owner of this process. @@ -360,6 +371,7 @@ def get_current_user(): ) return GetTokenInformation(process, TOKEN_USER) + def get_security_attributes_for_user(user=None): """ Return a SECURITY_ATTRIBUTES structure with the SID set to the diff --git a/paramiko/auth_handler.py b/paramiko/auth_handler.py index cab27a88..ace79638 100644 --- a/paramiko/auth_handler.py +++ b/paramiko/auth_handler.py @@ -22,18 +22,18 @@ import weakref from paramiko.common import cMSG_SERVICE_REQUEST, cMSG_DISCONNECT, \ - DISCONNECT_SERVICE_NOT_AVAILABLE, DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, \ + DISCONNECT_SERVICE_NOT_AVAILABLE, \ + DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, \ cMSG_USERAUTH_REQUEST, cMSG_SERVICE_ACCEPT, DEBUG, AUTH_SUCCESSFUL, INFO, \ cMSG_USERAUTH_SUCCESS, cMSG_USERAUTH_FAILURE, AUTH_PARTIALLY_SUCCESSFUL, \ cMSG_USERAUTH_INFO_REQUEST, WARNING, AUTH_FAILED, cMSG_USERAUTH_PK_OK, \ cMSG_USERAUTH_INFO_RESPONSE, MSG_SERVICE_REQUEST, MSG_SERVICE_ACCEPT, \ MSG_USERAUTH_REQUEST, MSG_USERAUTH_SUCCESS, MSG_USERAUTH_FAILURE, \ - MSG_USERAUTH_BANNER, MSG_USERAUTH_INFO_REQUEST, MSG_USERAUTH_INFO_RESPONSE, \ + MSG_USERAUTH_BANNER, MSG_USERAUTH_INFO_REQUEST, \ + MSG_USERAUTH_INFO_RESPONSE, \ cMSG_USERAUTH_GSSAPI_RESPONSE, cMSG_USERAUTH_GSSAPI_TOKEN, \ - cMSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, cMSG_USERAUTH_GSSAPI_ERROR, \ - cMSG_USERAUTH_GSSAPI_ERRTOK, cMSG_USERAUTH_GSSAPI_MIC,\ - MSG_USERAUTH_GSSAPI_RESPONSE, MSG_USERAUTH_GSSAPI_TOKEN, \ - MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, MSG_USERAUTH_GSSAPI_ERROR, \ + cMSG_USERAUTH_GSSAPI_MIC, MSG_USERAUTH_GSSAPI_RESPONSE, \ + MSG_USERAUTH_GSSAPI_TOKEN, MSG_USERAUTH_GSSAPI_ERROR, \ MSG_USERAUTH_GSSAPI_ERRTOK, MSG_USERAUTH_GSSAPI_MIC, MSG_NAMES from paramiko.message import Message @@ -149,7 +149,7 @@ class AuthHandler (object): if self.auth_event is not None: self.auth_event.set() - ### internals... + # ...internals... def _request_auth(self): m = Message() @@ -237,7 +237,8 @@ class AuthHandler (object): m.add_boolean(True) m.add_string(self.private_key.get_name()) m.add_string(self.private_key) - blob = self._get_session_blob(self.private_key, 'ssh-connection', self.username) + blob = self._get_session_blob( + self.private_key, 'ssh-connection', self.username) sig = self.private_key.sign_ssh_data(blob) m.add_string(sig) elif self.auth_method == 'keyboard-interactive': @@ -267,10 +268,11 @@ class AuthHandler (object): ptype, m = self.transport.packetizer.read_message() if ptype == MSG_USERAUTH_GSSAPI_TOKEN: srv_token = m.get_string() - next_token = sshgss.ssh_init_sec_context(self.gss_host, - mech, - self.username, - srv_token) + next_token = sshgss.ssh_init_sec_context( + self.gss_host, + mech, + self.username, + srv_token) # After this step the GSSAPI should not return any # token. If it does, we keep sending the token to # the server until no more token is returned. @@ -282,7 +284,8 @@ class AuthHandler (object): m.add_string(next_token) self.transport.send_message(m) else: - raise SSHException("Received Package: %s" % MSG_NAMES[ptype]) + raise SSHException( + "Received Package: %s" % MSG_NAMES[ptype]) m = Message() m.add_byte(cMSG_USERAUTH_GSSAPI_MIC) # send the MIC to the server @@ -297,7 +300,6 @@ class AuthHandler (object): maj_status = m.get_int() min_status = m.get_int() err_msg = m.get_string() - lang_tag = m.get_string() # we don't care! raise SSHException("GSS-API Error:\nMajor Status: %s\n\ Minor Status: %s\ \nError Message:\ %s\n") % (str(maj_status), @@ -307,7 +309,8 @@ class AuthHandler (object): self._parse_userauth_failure(m) return else: - raise SSHException("Received Package: %s" % MSG_NAMES[ptype]) + raise SSHException( + "Received Package: %s" % MSG_NAMES[ptype]) elif self.auth_method == 'gssapi-keyex' and\ self.transport.gss_kex_used: kexgss = self.transport.kexgss_ctxt @@ -317,10 +320,13 @@ class AuthHandler (object): elif self.auth_method == 'none': pass else: - raise SSHException('Unknown auth method "%s"' % self.auth_method) + raise SSHException( + 'Unknown auth method "%s"' % self.auth_method) self.transport._send_message(m) else: - self.transport._log(DEBUG, 'Service request "%s" accepted (?)' % service) + self.transport._log( + DEBUG, + 'Service request "%s" accepted (?)' % service) def _send_auth_result(self, username, method, result): # okay, send result @@ -332,7 +338,8 @@ class AuthHandler (object): else: self.transport._log(INFO, 'Auth rejected (%s).' % method) m.add_byte(cMSG_USERAUTH_FAILURE) - m.add_string(self.transport.server_object.get_allowed_auths(username)) + m.add_string( + self.transport.server_object.get_allowed_auths(username)) if result == AUTH_PARTIALLY_SUCCESSFUL: m.add_boolean(True) else: @@ -372,12 +379,19 @@ class AuthHandler (object): username = m.get_text() service = m.get_text() method = m.get_text() - self.transport._log(DEBUG, 'Auth request (type=%s) service=%s, username=%s' % (method, service, username)) + self.transport._log( + DEBUG, + 'Auth request (type=%s) service=%s, username=%s' % ( + method, service, username)) if service != 'ssh-connection': self._disconnect_service_not_available() return - if (self.auth_username is not None) and (self.auth_username != username): - self.transport._log(WARNING, 'Auth rejected because the client attempted to change username in mid-flight') + if ((self.auth_username is not None) and + (self.auth_username != username)): + self.transport._log( + WARNING, + 'Auth rejected because the client attempted to change ' + 'username in mid-flight') self._disconnect_no_more_auth() return self.auth_username = username @@ -396,9 +410,12 @@ class AuthHandler (object): # in this case, just return the raw byte string. pass if changereq: - # always treated as failure, since we don't support changing passwords, but collect - # the list of valid auth types from the callback anyway - self.transport._log(DEBUG, 'Auth request to change passwords (rejected)') + # always treated as failure, since we don't support changing + # passwords, but collect the list of valid auth types from + # the callback anyway + self.transport._log( + DEBUG, + 'Auth request to change passwords (rejected)') newpassword = m.get_binary() try: newpassword = newpassword.decode('UTF-8', 'replace') @@ -406,7 +423,8 @@ class AuthHandler (object): pass result = AUTH_FAILED else: - result = self.transport.server_object.check_auth_password(username, password) + result = self.transport.server_object.check_auth_password( + username, password) elif method == 'publickey': sig_attached = m.get_boolean() keytype = m.get_text() @@ -414,16 +432,21 @@ class AuthHandler (object): try: key = self.transport._key_info[keytype](Message(keyblob)) except SSHException as e: - self.transport._log(INFO, 'Auth rejected: public key: %s' % str(e)) + self.transport._log( + INFO, + 'Auth rejected: public key: %s' % str(e)) key = None except: - self.transport._log(INFO, 'Auth rejected: unsupported or mangled public key') + self.transport._log( + INFO, + 'Auth rejected: unsupported or mangled public key') key = None if key is None: self._disconnect_no_more_auth() return # first check if this key is okay... if not, we can skip the verify - result = self.transport.server_object.check_auth_publickey(username, key) + result = self.transport.server_object.check_auth_publickey( + username, key) if result != AUTH_FAILED: # key is okay, verify it if not sig_attached: @@ -438,12 +461,14 @@ class AuthHandler (object): sig = Message(m.get_binary()) blob = self._get_session_blob(key, service, username) if not key.verify_ssh_sig(blob, sig): - self.transport._log(INFO, 'Auth rejected: invalid signature') + self.transport._log( + INFO, + 'Auth rejected: invalid signature') result = AUTH_FAILED elif method == 'keyboard-interactive': - lang = m.get_string() submethods = m.get_string() - result = self.transport.server_object.check_auth_interactive(username, submethods) + result = self.transport.server_object.check_auth_interactive( + username, submethods) if isinstance(result, InteractiveQuery): # make interactive query instead of response self._interactive_query(result) @@ -457,15 +482,17 @@ class AuthHandler (object): # We can't accept more than one OID, so if the SSH client sends # more than one, disconnect. if mechs > 1: - self.transport._log(INFO, - 'Disconnect: Received more than one GSS-API OID mechanism') + self.transport._log( + INFO, + 'Disconnect: Received more than one GSS-API OID mechanism') self._disconnect_no_more_auth() desired_mech = m.get_string() mech_ok = sshgss.ssh_check_mech(desired_mech) # if we don't support the mechanism, disconnect. if not mech_ok: - self.transport._log(INFO, - 'Disconnect: Received an invalid GSS-API OID mechanism') + self.transport._log( + INFO, + 'Disconnect: Received an invalid GSS-API OID mechanism') self._disconnect_no_more_auth() # send the Kerberos V5 GSSAPI OID to the client supported_mech = sshgss.ssh_gss_oids("server") @@ -515,7 +542,8 @@ class AuthHandler (object): # The OpenSSH server is able to create a TGT with the delegated # client credentials, but this is not supported by GSS-API. result = AUTH_SUCCESSFUL - self.transport.server_object.check_auth_gssapi_with_mic(username, result) + self.transport.server_object.check_auth_gssapi_with_mic( + username, result) elif method == "gssapi-keyex" and gss_auth: mic_token = m.get_string() sshgss = self.transport.kexgss_ctxt @@ -532,14 +560,17 @@ class AuthHandler (object): self._send_auth_result(username, method, result) raise result = AUTH_SUCCESSFUL - self.transport.server_object.check_auth_gssapi_keyex(username, result) + self.transport.server_object.check_auth_gssapi_keyex( + username, result) else: result = self.transport.server_object.check_auth_none(username) # okay, send result self._send_auth_result(username, method, result) def _parse_userauth_success(self, m): - self.transport._log(INFO, 'Authentication (%s) successful!' % self.auth_method) + self.transport._log( + INFO, + 'Authentication (%s) successful!' % self.auth_method) self.authenticated = True self.transport._auth_trigger() if self.auth_event is not None: @@ -553,11 +584,18 @@ class AuthHandler (object): self.transport._log(DEBUG, 'Methods: ' + str(authlist)) self.transport.saved_exception = PartialAuthentication(authlist) elif self.auth_method not in authlist: - self.transport._log(DEBUG, 'Authentication type (%s) not permitted.' % self.auth_method) - self.transport._log(DEBUG, 'Allowed methods: ' + str(authlist)) - self.transport.saved_exception = BadAuthenticationType('Bad authentication type', authlist) + self.transport._log( + DEBUG, + 'Authentication type (%s) not permitted.' % self.auth_method) + self.transport._log( + DEBUG, + 'Allowed methods: ' + str(authlist)) + self.transport.saved_exception = BadAuthenticationType( + 'Bad authentication type', authlist) else: - self.transport._log(INFO, 'Authentication (%s) failed.' % self.auth_method) + self.transport._log( + INFO, + 'Authentication (%s) failed.' % self.auth_method) self.authenticated = False self.username = None if self.auth_event is not None: @@ -566,7 +604,6 @@ class AuthHandler (object): def _parse_userauth_banner(self, m): banner = m.get_string() self.banner = banner - lang = m.get_string() self.transport._log(INFO, 'Auth banner: %s' % banner) # who cares. @@ -580,7 +617,8 @@ class AuthHandler (object): prompt_list = [] for i in range(prompts): prompt_list.append((m.get_text(), m.get_boolean())) - response_list = self.interactive_handler(title, instructions, prompt_list) + response_list = self.interactive_handler( + title, instructions, prompt_list) m = Message() m.add_byte(cMSG_USERAUTH_INFO_RESPONSE) @@ -596,12 +634,14 @@ class AuthHandler (object): responses = [] for i in range(n): responses.append(m.get_text()) - result = self.transport.server_object.check_auth_interactive_response(responses) + result = self.transport.server_object.check_auth_interactive_response( + responses) if isinstance(result, InteractiveQuery): # make interactive query instead of response self._interactive_query(result) return - self._send_auth_result(self.auth_username, 'keyboard-interactive', result) + self._send_auth_result( + self.auth_username, 'keyboard-interactive', result) _handler_table = { MSG_SERVICE_REQUEST: _parse_service_request, diff --git a/paramiko/config.py b/paramiko/config.py index 42831fab..196e32ba 100644 --- a/paramiko/config.py +++ b/paramiko/config.py @@ -58,7 +58,7 @@ class SSHConfig (object): host = {"host": ['*'], "config": {}} for line in file_obj: # Strip any leading or trailing whitespace from the line. - # See https://github.com/paramiko/paramiko/issues/499 for more info. + # Refer to https://github.com/paramiko/paramiko/issues/499 line = line.strip() if not line or line.startswith('#'): continue @@ -68,7 +68,7 @@ class SSHConfig (object): raise Exception("Unparsable line %s" % line) key = match.group(1).lower() value = match.group(2) - + if key == 'host': self._config.append(host) host = { diff --git a/paramiko/hostkeys.py b/paramiko/hostkeys.py index 2ee3d27f..de7fc8ba 100644 --- a/paramiko/hostkeys.py +++ b/paramiko/hostkeys.py @@ -111,8 +111,8 @@ class HostKeys (MutableMapping): def save(self, filename): """ - 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 + 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 loaded from a file originally). The single exception is that combined lines will be split into individual key lines, which is arguably a bug. @@ -135,7 +135,8 @@ class HostKeys (MutableMapping): returned. The keytype will be either ``"ssh-rsa"`` or ``"ssh-dss"``. :param str hostname: the hostname (or IP) to lookup - :return: dict of `str` -> `.PKey` keys associated with this host (or ``None``) + :return: dict of `str` -> `.PKey` keys associated with this host + (or ``None``) """ class SubDict (MutableMapping): def __init__(self, hostname, entries, hostkeys): @@ -220,9 +221,6 @@ class HostKeys (MutableMapping): def __len__(self): return len(self.keys()) - def __delitem__(self, key): - k = self[key] - def __getitem__(self, key): ret = self.lookup(key) if ret is None: diff --git a/paramiko/kex_gex.py b/paramiko/kex_gex.py index c980b690..c407d9f1 100644 --- a/paramiko/kex_gex.py +++ b/paramiko/kex_gex.py @@ -34,8 +34,10 @@ from paramiko.ssh_exception import SSHException _MSG_KEXDH_GEX_REQUEST_OLD, _MSG_KEXDH_GEX_GROUP, _MSG_KEXDH_GEX_INIT, \ _MSG_KEXDH_GEX_REPLY, _MSG_KEXDH_GEX_REQUEST = range(30, 35) + c_MSG_KEXDH_GEX_REQUEST_OLD, c_MSG_KEXDH_GEX_GROUP, c_MSG_KEXDH_GEX_INIT, \ - c_MSG_KEXDH_GEX_REPLY, c_MSG_KEXDH_GEX_REQUEST = [byte_chr(c) for c in range(30, 35)] + c_MSG_KEXDH_GEX_REPLY, c_MSG_KEXDH_GEX_REQUEST = \ + [byte_chr(c) for c in range(30, 35)] class KexGex (object): @@ -58,7 +60,8 @@ class KexGex (object): def start_kex(self, _test_old_style=False): if self.transport.server_mode: - self.transport._expect_packet(_MSG_KEXDH_GEX_REQUEST, _MSG_KEXDH_GEX_REQUEST_OLD) + self.transport._expect_packet( + _MSG_KEXDH_GEX_REQUEST, _MSG_KEXDH_GEX_REQUEST_OLD) return # request a bit range: we accept (min_bits) to (max_bits), but prefer # (preferred_bits). according to the spec, we shouldn't pull the @@ -88,9 +91,10 @@ class KexGex (object): return self._parse_kexdh_gex_reply(m) elif ptype == _MSG_KEXDH_GEX_REQUEST_OLD: return self._parse_kexdh_gex_request_old(m) - raise SSHException('KexGex %s asked to handle packet type %d' % self.name, ptype) + raise SSHException( + 'KexGex %s asked to handle packet type %d' % self.name, ptype) - ### internals... + # ...internals... def _generate_x(self): # generate an "x" (1 < x < (p-1)/2). @@ -134,7 +138,10 @@ class KexGex (object): pack = self.transport._get_modulus_pack() if pack is None: raise SSHException('Can\'t do server-side gex with no modulus pack') - self.transport._log(DEBUG, 'Picking p (%d <= %d <= %d bits)' % (minbits, preferredbits, maxbits)) + self.transport._log( + DEBUG, + 'Picking p (%d <= %d <= %d bits)' % ( + minbits, preferredbits, maxbits)) self.g, self.p = pack.get_modulus(minbits, preferredbits, maxbits) m = Message() m.add_byte(c_MSG_KEXDH_GEX_GROUP) @@ -144,7 +151,8 @@ class KexGex (object): self.transport._expect_packet(_MSG_KEXDH_GEX_INIT) def _parse_kexdh_gex_request_old(self, m): - # same as above, but without min_bits or max_bits (used by older clients like putty) + # same as above, but without min_bits or max_bits (used by older + # clients like putty) self.preferred_bits = m.get_int() # smoosh the user's preferred size into our own limits if self.preferred_bits > self.max_bits: @@ -155,8 +163,10 @@ class KexGex (object): pack = self.transport._get_modulus_pack() if pack is None: raise SSHException('Can\'t do server-side gex with no modulus pack') - self.transport._log(DEBUG, 'Picking p (~ %d bits)' % (self.preferred_bits,)) - self.g, self.p = pack.get_modulus(self.min_bits, self.preferred_bits, self.max_bits) + self.transport._log( + DEBUG, 'Picking p (~ %d bits)' % (self.preferred_bits,)) + self.g, self.p = pack.get_modulus( + self.min_bits, self.preferred_bits, self.max_bits) m = Message() m.add_byte(c_MSG_KEXDH_GEX_GROUP) m.add_mpint(self.p) @@ -244,6 +254,7 @@ class KexGex (object): self.transport._verify_key(host_key, sig) self.transport._activate_outbound() + class KexGexSHA256(KexGex): name = 'diffie-hellman-group-exchange-sha256' hash_algo = sha256 diff --git a/paramiko/sftp_file.py b/paramiko/sftp_file.py index fdf667cd..391d7b0c 100644 --- a/paramiko/sftp_file.py +++ b/paramiko/sftp_file.py @@ -274,7 +274,9 @@ class SFTPFile (BufferedFile): :param int uid: new owner's uid :param int gid: new group id """ - self.sftp._log(DEBUG, 'chown(%s, %r, %r)' % (hexlify(self.handle), uid, gid)) + self.sftp._log( + DEBUG, + 'chown(%s, %r, %r)' % (hexlify(self.handle), uid, gid)) attr = SFTPAttributes() attr.st_uid, attr.st_gid = uid, gid self.sftp._request(CMD_FSETSTAT, self.handle, attr) @@ -308,7 +310,9 @@ class SFTPFile (BufferedFile): :param size: the new size of the file :type size: int or long """ - self.sftp._log(DEBUG, 'truncate(%s, %r)' % (hexlify(self.handle), size)) + self.sftp._log( + DEBUG, + 'truncate(%s, %r)' % (hexlify(self.handle), size)) attr = SFTPAttributes() attr.st_size = size self.sftp._request(CMD_FSETSTAT, self.handle, attr) @@ -362,10 +366,11 @@ class SFTPFile (BufferedFile): .. versionadded:: 1.4 """ - t, msg = self.sftp._request(CMD_EXTENDED, 'check-file', self.handle, - hash_algorithm, long(offset), long(length), block_size) - ext = msg.get_text() - alg = msg.get_text() + t, msg = self.sftp._request( + CMD_EXTENDED, 'check-file', self.handle, + hash_algorithm, long(offset), long(length), block_size) + msg.get_text() # ext + msg.get_text() # alg data = msg.get_remainder() return data @@ -417,7 +422,7 @@ class SFTPFile (BufferedFile): compatibility. """ if file_size is None: - file_size = self.stat().st_size; + file_size = self.stat().st_size # queue up async reads for the rest of the file chunks = [] @@ -465,7 +470,7 @@ class SFTPFile (BufferedFile): self.seek(x[0]) yield self.read(x[1]) - ### internals... + # ...internals... def _get_size(self): try: diff --git a/paramiko/ssh_exception.py b/paramiko/ssh_exception.py index ed36a952..eb63df4e 100644 --- a/paramiko/ssh_exception.py +++ b/paramiko/ssh_exception.py @@ -31,11 +31,11 @@ class AuthenticationException (SSHException): Exception raised when authentication failed for some reason. It may be possible to retry with different credentials. (Other classes specify more specific reasons.) - + .. versionadded:: 1.6 """ pass - + class PasswordRequiredException (AuthenticationException): """ @@ -49,15 +49,15 @@ class BadAuthenticationType (AuthenticationException): Exception raised when an authentication type (like password) is used, but the server isn't allowing that type. (It may only allow public-key, for example.) - + :ivar list allowed_types: list of allowed authentication types provided by the server (possible values are: ``"none"``, ``"password"``, and ``"publickey"``). - + .. versionadded:: 1.1 """ allowed_types = [] - + def __init__(self, explanation, types): AuthenticationException.__init__(self, explanation) self.allowed_types = types @@ -65,7 +65,8 @@ class BadAuthenticationType (AuthenticationException): self.args = (explanation, types, ) def __str__(self): - return SSHException.__str__(self) + ' (allowed_types=%r)' % self.allowed_types + return '{} (allowed_types={!r})'.format( + SSHException.__str__(self), self.allowed_types) class PartialAuthentication (AuthenticationException): @@ -73,7 +74,7 @@ class PartialAuthentication (AuthenticationException): An internal exception thrown in the case of partial authentication. """ allowed_types = [] - + def __init__(self, types): AuthenticationException.__init__(self, 'partial authentication') self.allowed_types = types @@ -84,9 +85,9 @@ class PartialAuthentication (AuthenticationException): class ChannelException (SSHException): """ Exception raised when an attempt to open a new `.Channel` fails. - + :ivar int code: the error code returned by the server - + .. versionadded:: 1.6 """ def __init__(self, code, text): @@ -99,19 +100,20 @@ class ChannelException (SSHException): class BadHostKeyException (SSHException): """ The host key given by the SSH server did not match what we were expecting. - + :ivar str hostname: the hostname of the SSH server :ivar PKey got_key: the host key presented by the server :ivar PKey expected_key: the host key expected - + .. versionadded:: 1.6 """ def __init__(self, hostname, got_key, expected_key): - SSHException.__init__(self, - 'Host key for server %s does not match : got %s expected %s' % ( - hostname, - got_key.get_base64(), - expected_key.get_base64())) + message = 'Host key for server {} does not match : ' \ + 'got {} expected {}' + message = message.format( + hostname, got_key.get_base64(), + expected_key.get_base64()) + SSHException.__init__(self, message) self.hostname = hostname self.key = got_key self.expected_key = expected_key @@ -147,7 +149,7 @@ class NoValidConnectionsError(socket.error): `socket.error` subclass, message, etc) we expose a single unified error message and a ``None`` errno so that instances of this class match most normal handling of `socket.error` objects. - + To see the wrapped exception objects, access the ``errors`` attribute. ``errors`` is a dict whose keys are address tuples (e.g. ``('127.0.0.1', 22)``) and whose values are the exception encountered trying to connect to diff --git a/paramiko/ssh_gss.py b/paramiko/ssh_gss.py index e906a851..6cde0da5 100644 --- a/paramiko/ssh_gss.py +++ b/paramiko/ssh_gss.py @@ -180,7 +180,7 @@ class _SSH_GSSAuth(object): return True # Internals - #-------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def _make_uint32(self, integer): """ Create a 32 bit unsigned integer (The byte sequence of an integer). @@ -258,8 +258,8 @@ class _SSH_GSSAPI(_SSH_GSSAuth): :param str recv_token: The GSS-API token received from the Server :raise SSHException: Is raised if the desired mechanism of the client is not supported - :return: A ``String`` if the GSS-API has returned a token or ``None`` if - no token was returned + :return: A ``String`` if the GSS-API has returned a token or + ``None`` if no token was returned :rtype: String or None """ self._username = username @@ -286,8 +286,9 @@ class _SSH_GSSAPI(_SSH_GSSAuth): else: token = self._gss_ctxt.step(recv_token) except gssapi.GSSException: - raise gssapi.GSSException("{0} Target: {1}".format(sys.exc_info()[1], - self._gss_host)) + message = "{0} Target: {1}".format( + sys.exc_info()[1], self._gss_host) + raise gssapi.GSSException(message) self._gss_ctxt_status = self._gss_ctxt.established return token @@ -408,8 +409,8 @@ class _SSH_SSPI(_SSH_GSSAuth): sspicon.ISC_REQ_MUTUAL_AUTH |\ sspicon.ISC_REQ_DELEGATE else: - self._gss_flags = sspicon.ISC_REQ_INTEGRITY |\ - sspicon.ISC_REQ_MUTUAL_AUTH + self._gss_flags = \ + sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_MUTUAL_AUTH def ssh_init_sec_context(self, target, desired_mech=None, username=None, recv_token=None): @@ -527,13 +528,13 @@ class _SSH_SSPI(_SSH_GSSAuth): self._username, self._service, self._auth_method) - # Verifies data and its signature. If verification fails, an + # Verifies data and its signature. If verification fails, an # sspi.error will be raised. self._gss_srv_ctxt.verify(mic_field, mic_token) else: # for key exchange with gssapi-keyex # client mode - # Verifies data and its signature. If verification fails, an + # Verifies data and its signature. If verification fails, an # sspi.error will be raised. self._gss_ctxt.verify(self._session_id, mic_token) @@ -546,10 +547,10 @@ class _SSH_SSPI(_SSH_GSSAuth): :rtype: Boolean """ return ( - self._gss_flags & sspicon.ISC_REQ_DELEGATE - ) and ( - self._gss_srv_ctxt_status or (self._gss_flags) - ) + self._gss_flags & sspicon.ISC_REQ_DELEGATE + ) and ( + self._gss_srv_ctxt_status or self._gss_flags + ) def save_client_creds(self, client_token): """ @@ -5,6 +5,6 @@ universal = 1 omit = paramiko/_winapi.py [flake8] -exclude = sites,.git,build,dist,alt_env,appveyor,demos,tests,paramiko,test.py +exclude = sites,.git,build,dist,alt_env,appveyor,demos,tests,test.py ignore = E124,E125,E128,E261,E301,E302,E303 max-line-length = 79 |