Merge remote-tracking branch 'scottkmaxwell/python3-with-import-fix' into python3
This commit is contained in:
commit
ba55eea38d
|
@ -29,12 +29,12 @@ import time
|
||||||
import tempfile
|
import tempfile
|
||||||
import stat
|
import stat
|
||||||
from select import select
|
from select import select
|
||||||
|
from paramiko.common import asbytes, io_sleep
|
||||||
|
from paramiko.py3compat import byte_chr
|
||||||
|
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
from paramiko.pkey import PKey
|
from paramiko.pkey import PKey
|
||||||
from paramiko.channel import Channel
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko.util import retry_on_signal
|
from paramiko.util import retry_on_signal
|
||||||
|
|
||||||
cSSH2_AGENTC_REQUEST_IDENTITIES = byte_chr(11)
|
cSSH2_AGENTC_REQUEST_IDENTITIES = byte_chr(11)
|
||||||
|
@ -43,7 +43,6 @@ cSSH2_AGENTC_SIGN_REQUEST = byte_chr(13)
|
||||||
SSH2_AGENT_SIGN_RESPONSE = 14
|
SSH2_AGENT_SIGN_RESPONSE = 14
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AgentSSH(object):
|
class AgentSSH(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._conn = None
|
self._conn = None
|
||||||
|
@ -107,7 +106,7 @@ class AgentProxyThread(threading.Thread):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
(r,addr) = self.get_connection()
|
(r, addr) = self.get_connection()
|
||||||
self.__inr = r
|
self.__inr = r
|
||||||
self.__addr = addr
|
self.__addr = addr
|
||||||
self._agent.connect()
|
self._agent.connect()
|
||||||
|
@ -163,11 +162,10 @@ class AgentLocalProxy(AgentProxyThread):
|
||||||
try:
|
try:
|
||||||
conn.bind(self._agent._get_filename())
|
conn.bind(self._agent._get_filename())
|
||||||
conn.listen(1)
|
conn.listen(1)
|
||||||
(r,addr) = conn.accept()
|
(r, addr) = conn.accept()
|
||||||
return (r, addr)
|
return r, addr
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class AgentRemoteProxy(AgentProxyThread):
|
class AgentRemoteProxy(AgentProxyThread):
|
||||||
|
@ -179,7 +177,7 @@ class AgentRemoteProxy(AgentProxyThread):
|
||||||
self.__chan = chan
|
self.__chan = chan
|
||||||
|
|
||||||
def get_connection(self):
|
def get_connection(self):
|
||||||
return (self.__chan, None)
|
return self.__chan, None
|
||||||
|
|
||||||
|
|
||||||
class AgentClientProxy(object):
|
class AgentClientProxy(object):
|
||||||
|
@ -280,9 +278,7 @@ class AgentServerProxy(AgentSSH):
|
||||||
:return:
|
:return:
|
||||||
a dict containing the ``SSH_AUTH_SOCK`` environnement variables
|
a dict containing the ``SSH_AUTH_SOCK`` environnement variables
|
||||||
"""
|
"""
|
||||||
env = {}
|
return {'SSH_AUTH_SOCK': self._get_filename()}
|
||||||
env['SSH_AUTH_SOCK'] = self._get_filename()
|
|
||||||
return env
|
|
||||||
|
|
||||||
def _get_filename(self):
|
def _get_filename(self):
|
||||||
return self._file
|
return self._file
|
||||||
|
|
|
@ -20,15 +20,18 @@
|
||||||
`.AuthHandler`
|
`.AuthHandler`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import threading
|
|
||||||
import weakref
|
import weakref
|
||||||
|
from paramiko.common import cMSG_SERVICE_REQUEST, cMSG_DISCONNECT, \
|
||||||
|
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
|
||||||
|
|
||||||
# this helps freezing utils
|
|
||||||
import encodings.utf_8
|
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
|
from paramiko.py3compat import bytestring
|
||||||
from paramiko.ssh_exception import SSHException, AuthenticationException, \
|
from paramiko.ssh_exception import SSHException, AuthenticationException, \
|
||||||
BadAuthenticationType, PartialAuthentication
|
BadAuthenticationType, PartialAuthentication
|
||||||
from paramiko.server import InteractiveQuery
|
from paramiko.server import InteractiveQuery
|
||||||
|
@ -114,10 +117,8 @@ class AuthHandler (object):
|
||||||
if self.auth_event is not None:
|
if self.auth_event is not None:
|
||||||
self.auth_event.set()
|
self.auth_event.set()
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _request_auth(self):
|
def _request_auth(self):
|
||||||
m = Message()
|
m = Message()
|
||||||
m.add_byte(cMSG_SERVICE_REQUEST)
|
m.add_byte(cMSG_SERVICE_REQUEST)
|
||||||
|
@ -149,7 +150,7 @@ class AuthHandler (object):
|
||||||
m.add_string(username)
|
m.add_string(username)
|
||||||
m.add_string(service)
|
m.add_string(service)
|
||||||
m.add_string('publickey')
|
m.add_string('publickey')
|
||||||
m.add_boolean(1)
|
m.add_boolean(True)
|
||||||
m.add_string(key.get_name())
|
m.add_string(key.get_name())
|
||||||
m.add_string(key)
|
m.add_string(key)
|
||||||
return m.asbytes()
|
return m.asbytes()
|
||||||
|
@ -230,9 +231,9 @@ class AuthHandler (object):
|
||||||
m.add_byte(cMSG_USERAUTH_FAILURE)
|
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:
|
if result == AUTH_PARTIALLY_SUCCESSFUL:
|
||||||
m.add_boolean(1)
|
m.add_boolean(True)
|
||||||
else:
|
else:
|
||||||
m.add_boolean(0)
|
m.add_boolean(False)
|
||||||
self.auth_fail_count += 1
|
self.auth_fail_count += 1
|
||||||
self.transport._send_message(m)
|
self.transport._send_message(m)
|
||||||
if self.auth_fail_count >= 10:
|
if self.auth_fail_count >= 10:
|
||||||
|
@ -259,7 +260,7 @@ class AuthHandler (object):
|
||||||
m = Message()
|
m = Message()
|
||||||
m.add_byte(cMSG_USERAUTH_FAILURE)
|
m.add_byte(cMSG_USERAUTH_FAILURE)
|
||||||
m.add_string('none')
|
m.add_string('none')
|
||||||
m.add_boolean(0)
|
m.add_boolean(False)
|
||||||
self.transport._send_message(m)
|
self.transport._send_message(m)
|
||||||
return
|
return
|
||||||
if self.authenticated:
|
if self.authenticated:
|
||||||
|
@ -351,7 +352,7 @@ class AuthHandler (object):
|
||||||
self.transport._log(INFO, 'Authentication (%s) successful!' % self.auth_method)
|
self.transport._log(INFO, 'Authentication (%s) successful!' % self.auth_method)
|
||||||
self.authenticated = True
|
self.authenticated = True
|
||||||
self.transport._auth_trigger()
|
self.transport._auth_trigger()
|
||||||
if self.auth_event != None:
|
if self.auth_event is not None:
|
||||||
self.auth_event.set()
|
self.auth_event.set()
|
||||||
|
|
||||||
def _parse_userauth_failure(self, m):
|
def _parse_userauth_failure(self, m):
|
||||||
|
@ -369,7 +370,7 @@ class AuthHandler (object):
|
||||||
self.transport._log(INFO, 'Authentication (%s) failed.' % self.auth_method)
|
self.transport._log(INFO, 'Authentication (%s) failed.' % self.auth_method)
|
||||||
self.authenticated = False
|
self.authenticated = False
|
||||||
self.username = None
|
self.username = None
|
||||||
if self.auth_event != None:
|
if self.auth_event is not None:
|
||||||
self.auth_event.set()
|
self.auth_event.set()
|
||||||
|
|
||||||
def _parse_userauth_banner(self, m):
|
def _parse_userauth_banner(self, m):
|
||||||
|
@ -412,7 +413,6 @@ class AuthHandler (object):
|
||||||
return
|
return
|
||||||
self._send_auth_result(self.auth_username, 'keyboard-interactive', result)
|
self._send_auth_result(self.auth_username, 'keyboard-interactive', result)
|
||||||
|
|
||||||
|
|
||||||
_handler_table = {
|
_handler_table = {
|
||||||
MSG_SERVICE_REQUEST: _parse_service_request,
|
MSG_SERVICE_REQUEST: _parse_service_request,
|
||||||
MSG_SERVICE_ACCEPT: _parse_service_accept,
|
MSG_SERVICE_ACCEPT: _parse_service_accept,
|
||||||
|
@ -423,4 +423,3 @@ class AuthHandler (object):
|
||||||
MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request,
|
MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request,
|
||||||
MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response,
|
MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
from paramiko.common import max_byte, zero_byte
|
||||||
|
from paramiko.py3compat import b, byte_ord, byte_chr, long
|
||||||
|
|
||||||
import paramiko.util as util
|
import paramiko.util as util
|
||||||
from paramiko.common import *
|
|
||||||
|
|
||||||
|
|
||||||
class BERException (Exception):
|
class BERException (Exception):
|
||||||
|
@ -71,12 +71,12 @@ class BER(object):
|
||||||
t = size & 0x7f
|
t = size & 0x7f
|
||||||
if self.idx + t > len(self.content):
|
if self.idx + t > len(self.content):
|
||||||
return None
|
return None
|
||||||
size = util.inflate_long(self.content[self.idx : self.idx + t], True)
|
size = util.inflate_long(self.content[self.idx: self.idx + t], True)
|
||||||
self.idx += t
|
self.idx += t
|
||||||
if self.idx + size > len(self.content):
|
if self.idx + size > len(self.content):
|
||||||
# can't fit
|
# can't fit
|
||||||
return None
|
return None
|
||||||
data = self.content[self.idx : self.idx + size]
|
data = self.content[self.idx: self.idx + size]
|
||||||
self.idx += size
|
self.idx += size
|
||||||
# now switch on id
|
# now switch on id
|
||||||
if ident == 0x30:
|
if ident == 0x30:
|
||||||
|
@ -91,9 +91,9 @@ class BER(object):
|
||||||
|
|
||||||
def decode_sequence(data):
|
def decode_sequence(data):
|
||||||
out = []
|
out = []
|
||||||
b = BER(data)
|
ber = BER(data)
|
||||||
while True:
|
while True:
|
||||||
x = b.decode_next()
|
x = ber.decode_next()
|
||||||
if x is None:
|
if x is None:
|
||||||
break
|
break
|
||||||
out.append(x)
|
out.append(x)
|
||||||
|
@ -126,8 +126,8 @@ class BER(object):
|
||||||
raise BERException('Unknown type for encoding: %s' % repr(type(x)))
|
raise BERException('Unknown type for encoding: %s' % repr(type(x)))
|
||||||
|
|
||||||
def encode_sequence(data):
|
def encode_sequence(data):
|
||||||
b = BER()
|
ber = BER()
|
||||||
for item in data:
|
for item in data:
|
||||||
b.encode(item)
|
ber.encode(item)
|
||||||
return b.asbytes()
|
return ber.asbytes()
|
||||||
encode_sequence = staticmethod(encode_sequence)
|
encode_sequence = staticmethod(encode_sequence)
|
||||||
|
|
|
@ -25,7 +25,7 @@ read operations are blocking and can have a timeout set.
|
||||||
import array
|
import array
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from paramiko.common import *
|
from paramiko.py3compat import PY2, b
|
||||||
|
|
||||||
|
|
||||||
class PipeTimeout (IOError):
|
class PipeTimeout (IOError):
|
||||||
|
@ -62,7 +62,6 @@ class BufferedPipe (object):
|
||||||
def _buffer_tobytes(self, limit=None):
|
def _buffer_tobytes(self, limit=None):
|
||||||
return self._buffer[:limit].tobytes()
|
return self._buffer[:limit].tobytes()
|
||||||
|
|
||||||
|
|
||||||
def set_event(self, event):
|
def set_event(self, event):
|
||||||
"""
|
"""
|
||||||
Set an event on this buffer. When data is ready to be read (or the
|
Set an event on this buffer. When data is ready to be read (or the
|
||||||
|
@ -208,4 +207,3 @@ class BufferedPipe (object):
|
||||||
return len(self._buffer)
|
return len(self._buffer)
|
||||||
finally:
|
finally:
|
||||||
self._lock.release()
|
self._lock.release()
|
||||||
|
|
||||||
|
|
|
@ -21,15 +21,17 @@ Abstraction for an SSH2 channel.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import socket
|
import socket
|
||||||
import os
|
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.common import cMSG_CHANNEL_REQUEST, cMSG_CHANNEL_WINDOW_ADJUST, \
|
||||||
|
cMSG_CHANNEL_DATA, cMSG_CHANNEL_EXTENDED_DATA, DEBUG, ERROR, \
|
||||||
|
cMSG_CHANNEL_SUCCESS, cMSG_CHANNEL_FAILURE, cMSG_CHANNEL_EOF, \
|
||||||
|
cMSG_CHANNEL_CLOSE
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
|
from paramiko.py3compat import bytes_types
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
from paramiko.file import BufferedFile
|
from paramiko.file import BufferedFile
|
||||||
from paramiko.buffered_pipe import BufferedPipe, PipeTimeout
|
from paramiko.buffered_pipe import BufferedPipe, PipeTimeout
|
||||||
|
@ -112,7 +114,7 @@ class Channel (object):
|
||||||
out += ' (EOF received)'
|
out += ' (EOF received)'
|
||||||
if self.eof_sent:
|
if self.eof_sent:
|
||||||
out += ' (EOF sent)'
|
out += ' (EOF sent)'
|
||||||
out += ' (open) window=%d' % (self.out_window_size)
|
out += ' (open) window=%d' % self.out_window_size
|
||||||
if len(self.in_buffer) > 0:
|
if len(self.in_buffer) > 0:
|
||||||
out += ' in-buffer=%d' % (len(self.in_buffer),)
|
out += ' in-buffer=%d' % (len(self.in_buffer),)
|
||||||
out += ' -> ' + repr(self.transport)
|
out += ' -> ' + repr(self.transport)
|
||||||
|
@ -176,7 +178,7 @@ class Channel (object):
|
||||||
m.add_byte(cMSG_CHANNEL_REQUEST)
|
m.add_byte(cMSG_CHANNEL_REQUEST)
|
||||||
m.add_int(self.remote_chanid)
|
m.add_int(self.remote_chanid)
|
||||||
m.add_string('shell')
|
m.add_string('shell')
|
||||||
m.add_boolean(1)
|
m.add_boolean(True)
|
||||||
self._event_pending()
|
self._event_pending()
|
||||||
self.transport._send_user_message(m)
|
self.transport._send_user_message(m)
|
||||||
self._wait_for_event()
|
self._wait_for_event()
|
||||||
|
@ -465,10 +467,8 @@ class Channel (object):
|
||||||
self._feed(data)
|
self._feed(data)
|
||||||
return old
|
return old
|
||||||
|
|
||||||
|
|
||||||
### socket API
|
### socket API
|
||||||
|
|
||||||
|
|
||||||
def settimeout(self, timeout):
|
def settimeout(self, timeout):
|
||||||
"""
|
"""
|
||||||
Set a timeout on blocking read/write operations. The ``timeout``
|
Set a timeout on blocking read/write operations. The ``timeout``
|
||||||
|
@ -885,10 +885,8 @@ class Channel (object):
|
||||||
"""
|
"""
|
||||||
self.shutdown(1)
|
self.shutdown(1)
|
||||||
|
|
||||||
|
|
||||||
### calls from Transport
|
### calls from Transport
|
||||||
|
|
||||||
|
|
||||||
def _set_transport(self, transport):
|
def _set_transport(self, transport):
|
||||||
self.transport = transport
|
self.transport = transport
|
||||||
self.logger = util.get_logger(self.transport.get_log_channel())
|
self.logger = util.get_logger(self.transport.get_log_channel())
|
||||||
|
@ -1063,10 +1061,8 @@ class Channel (object):
|
||||||
if m is not None:
|
if m is not None:
|
||||||
self.transport._send_user_message(m)
|
self.transport._send_user_message(m)
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _log(self, level, msg, *args):
|
def _log(self, level, msg, *args):
|
||||||
self.logger.log(level, "[chan " + self._name + "] " + msg, *args)
|
self.logger.log(level, "[chan " + self._name + "] " + msg, *args)
|
||||||
|
|
||||||
|
@ -1171,7 +1167,7 @@ class Channel (object):
|
||||||
return 0
|
return 0
|
||||||
then = time.time()
|
then = time.time()
|
||||||
self.out_buffer_cv.wait(timeout)
|
self.out_buffer_cv.wait(timeout)
|
||||||
if timeout != None:
|
if timeout is not None:
|
||||||
timeout -= time.time() - then
|
timeout -= time.time() - then
|
||||||
if timeout <= 0.0:
|
if timeout <= 0.0:
|
||||||
raise socket.timeout()
|
raise socket.timeout()
|
||||||
|
@ -1201,7 +1197,7 @@ class ChannelFile (BufferedFile):
|
||||||
flush the buffer.
|
flush the buffer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, channel, mode = 'r', bufsize = -1):
|
def __init__(self, channel, mode='r', bufsize=-1):
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
BufferedFile.__init__(self)
|
BufferedFile.__init__(self)
|
||||||
self._set_mode(mode, bufsize)
|
self._set_mode(mode, bufsize)
|
||||||
|
@ -1221,7 +1217,7 @@ class ChannelFile (BufferedFile):
|
||||||
|
|
||||||
|
|
||||||
class ChannelStderrFile (ChannelFile):
|
class ChannelStderrFile (ChannelFile):
|
||||||
def __init__(self, channel, mode = 'r', bufsize = -1):
|
def __init__(self, channel, mode='r', bufsize=-1):
|
||||||
ChannelFile.__init__(self, channel, mode, bufsize)
|
ChannelFile.__init__(self, channel, mode, bufsize)
|
||||||
|
|
||||||
def _read(self, size):
|
def _read(self, size):
|
||||||
|
|
|
@ -27,10 +27,11 @@ import socket
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from paramiko.agent import Agent
|
from paramiko.agent import Agent
|
||||||
from paramiko.common import *
|
from paramiko.common import DEBUG
|
||||||
from paramiko.config import SSH_PORT
|
from paramiko.config import SSH_PORT
|
||||||
from paramiko.dsskey import DSSKey
|
from paramiko.dsskey import DSSKey
|
||||||
from paramiko.hostkeys import HostKeys
|
from paramiko.hostkeys import HostKeys
|
||||||
|
from paramiko.py3compat import string_types
|
||||||
from paramiko.resource import ResourceManager
|
from paramiko.resource import ResourceManager
|
||||||
from paramiko.rsakey import RSAKey
|
from paramiko.rsakey import RSAKey
|
||||||
from paramiko.ssh_exception import SSHException, BadHostKeyException
|
from paramiko.ssh_exception import SSHException, BadHostKeyException
|
||||||
|
@ -266,7 +267,7 @@ class SSHClient (object):
|
||||||
if key_filename is None:
|
if key_filename is None:
|
||||||
key_filenames = []
|
key_filenames = []
|
||||||
elif isinstance(key_filename, string_types):
|
elif isinstance(key_filename, string_types):
|
||||||
key_filenames = [ key_filename ]
|
key_filenames = [key_filename]
|
||||||
else:
|
else:
|
||||||
key_filenames = key_filename
|
key_filenames = key_filename
|
||||||
self._auth(username, password, pkey, key_filenames, allow_agent, look_for_keys)
|
self._auth(username, password, pkey, key_filenames, allow_agent, look_for_keys)
|
||||||
|
@ -280,7 +281,7 @@ class SSHClient (object):
|
||||||
self._transport.close()
|
self._transport.close()
|
||||||
self._transport = None
|
self._transport = None
|
||||||
|
|
||||||
if self._agent != None:
|
if self._agent is not None:
|
||||||
self._agent.close()
|
self._agent.close()
|
||||||
self._agent = None
|
self._agent = None
|
||||||
|
|
||||||
|
@ -304,7 +305,7 @@ class SSHClient (object):
|
||||||
:raises SSHException: if the server fails to execute the command
|
:raises SSHException: if the server fails to execute the command
|
||||||
"""
|
"""
|
||||||
chan = self._transport.open_session()
|
chan = self._transport.open_session()
|
||||||
if(get_pty):
|
if get_pty:
|
||||||
chan.get_pty()
|
chan.get_pty()
|
||||||
chan.settimeout(timeout)
|
chan.settimeout(timeout)
|
||||||
chan.exec_command(command)
|
chan.exec_command(command)
|
||||||
|
@ -314,7 +315,7 @@ class SSHClient (object):
|
||||||
return stdin, stdout, stderr
|
return stdin, stdout, stderr
|
||||||
|
|
||||||
def invoke_shell(self, term='vt100', width=80, height=24, width_pixels=0,
|
def invoke_shell(self, term='vt100', width=80, height=24, width_pixels=0,
|
||||||
height_pixels=0):
|
height_pixels=0):
|
||||||
"""
|
"""
|
||||||
Start an interactive shell session on the SSH server. A new `.Channel`
|
Start an interactive shell session on the SSH server. A new `.Channel`
|
||||||
is opened and connected to a pseudo-terminal using the requested
|
is opened and connected to a pseudo-terminal using the requested
|
||||||
|
@ -394,7 +395,7 @@ class SSHClient (object):
|
||||||
saved_exception = e
|
saved_exception = e
|
||||||
|
|
||||||
if not two_factor and allow_agent:
|
if not two_factor and allow_agent:
|
||||||
if self._agent == None:
|
if self._agent is None:
|
||||||
self._agent = Agent()
|
self._agent = Agent()
|
||||||
|
|
||||||
for key in self._agent.get_keys():
|
for key in self._agent.get_keys():
|
||||||
|
@ -445,8 +446,8 @@ class SSHClient (object):
|
||||||
try:
|
try:
|
||||||
self._transport.auth_password(username, password)
|
self._transport.auth_password(username, password)
|
||||||
return
|
return
|
||||||
except SSHException:
|
except SSHException as e:
|
||||||
saved_exception = sys.exc_info()[1]
|
saved_exception = e
|
||||||
elif two_factor:
|
elif two_factor:
|
||||||
raise SSHException('Two-factor authentication requires a password')
|
raise SSHException('Two-factor authentication requires a password')
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
"""
|
"""
|
||||||
Common constants and global variables.
|
Common constants and global variables.
|
||||||
"""
|
"""
|
||||||
from paramiko.py3compat import *
|
import logging
|
||||||
|
from paramiko.py3compat import byte_chr, PY2, bytes_types, string_types, b, long
|
||||||
|
|
||||||
MSG_DISCONNECT, MSG_IGNORE, MSG_UNIMPLEMENTED, MSG_DEBUG, MSG_SERVICE_REQUEST, \
|
MSG_DISCONNECT, MSG_IGNORE, MSG_UNIMPLEMENTED, MSG_DEBUG, MSG_SERVICE_REQUEST, \
|
||||||
MSG_SERVICE_ACCEPT = range(1, 7)
|
MSG_SERVICE_ACCEPT = range(1, 7)
|
||||||
|
@ -34,10 +35,35 @@ MSG_CHANNEL_OPEN, MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, \
|
||||||
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
|
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
|
||||||
MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE = range(90, 101)
|
MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE = range(90, 101)
|
||||||
|
|
||||||
for key in list(locals().keys()):
|
cMSG_DISCONNECT = byte_chr(MSG_DISCONNECT)
|
||||||
if key.startswith('MSG_'):
|
cMSG_IGNORE = byte_chr(MSG_IGNORE)
|
||||||
locals()['c' + key] = byte_chr(locals()[key])
|
cMSG_UNIMPLEMENTED = byte_chr(MSG_UNIMPLEMENTED)
|
||||||
del key
|
cMSG_DEBUG = byte_chr(MSG_DEBUG)
|
||||||
|
cMSG_SERVICE_REQUEST = byte_chr(MSG_SERVICE_REQUEST)
|
||||||
|
cMSG_SERVICE_ACCEPT = byte_chr(MSG_SERVICE_ACCEPT)
|
||||||
|
cMSG_KEXINIT = byte_chr(MSG_KEXINIT)
|
||||||
|
cMSG_NEWKEYS = byte_chr(MSG_NEWKEYS)
|
||||||
|
cMSG_USERAUTH_REQUEST = byte_chr(MSG_USERAUTH_REQUEST)
|
||||||
|
cMSG_USERAUTH_FAILURE = byte_chr(MSG_USERAUTH_FAILURE)
|
||||||
|
cMSG_USERAUTH_SUCCESS = byte_chr(MSG_USERAUTH_SUCCESS)
|
||||||
|
cMSG_USERAUTH_BANNER = byte_chr(MSG_USERAUTH_BANNER)
|
||||||
|
cMSG_USERAUTH_PK_OK = byte_chr(MSG_USERAUTH_PK_OK)
|
||||||
|
cMSG_USERAUTH_INFO_REQUEST = byte_chr(MSG_USERAUTH_INFO_REQUEST)
|
||||||
|
cMSG_USERAUTH_INFO_RESPONSE = byte_chr(MSG_USERAUTH_INFO_RESPONSE)
|
||||||
|
cMSG_GLOBAL_REQUEST = byte_chr(MSG_GLOBAL_REQUEST)
|
||||||
|
cMSG_REQUEST_SUCCESS = byte_chr(MSG_REQUEST_SUCCESS)
|
||||||
|
cMSG_REQUEST_FAILURE = byte_chr(MSG_REQUEST_FAILURE)
|
||||||
|
cMSG_CHANNEL_OPEN = byte_chr(MSG_CHANNEL_OPEN)
|
||||||
|
cMSG_CHANNEL_OPEN_SUCCESS = byte_chr(MSG_CHANNEL_OPEN_SUCCESS)
|
||||||
|
cMSG_CHANNEL_OPEN_FAILURE = byte_chr(MSG_CHANNEL_OPEN_FAILURE)
|
||||||
|
cMSG_CHANNEL_WINDOW_ADJUST = byte_chr(MSG_CHANNEL_WINDOW_ADJUST)
|
||||||
|
cMSG_CHANNEL_DATA = byte_chr(MSG_CHANNEL_DATA)
|
||||||
|
cMSG_CHANNEL_EXTENDED_DATA = byte_chr(MSG_CHANNEL_EXTENDED_DATA)
|
||||||
|
cMSG_CHANNEL_EOF = byte_chr(MSG_CHANNEL_EOF)
|
||||||
|
cMSG_CHANNEL_CLOSE = byte_chr(MSG_CHANNEL_CLOSE)
|
||||||
|
cMSG_CHANNEL_REQUEST = byte_chr(MSG_CHANNEL_REQUEST)
|
||||||
|
cMSG_CHANNEL_SUCCESS = byte_chr(MSG_CHANNEL_SUCCESS)
|
||||||
|
cMSG_CHANNEL_FAILURE = byte_chr(MSG_CHANNEL_FAILURE)
|
||||||
|
|
||||||
# for debugging:
|
# for debugging:
|
||||||
MSG_NAMES = {
|
MSG_NAMES = {
|
||||||
|
@ -105,24 +131,6 @@ from Crypto import Random
|
||||||
# keep a crypto-strong PRNG nearby
|
# keep a crypto-strong PRNG nearby
|
||||||
rng = Random.new()
|
rng = Random.new()
|
||||||
|
|
||||||
import sys
|
|
||||||
if sys.version_info < (2, 3):
|
|
||||||
try:
|
|
||||||
import logging
|
|
||||||
except:
|
|
||||||
import logging22 as logging
|
|
||||||
import select
|
|
||||||
PY22 = True
|
|
||||||
|
|
||||||
import socket
|
|
||||||
if not hasattr(socket, 'timeout'):
|
|
||||||
class timeout(socket.error): pass
|
|
||||||
socket.timeout = timeout
|
|
||||||
del timeout
|
|
||||||
else:
|
|
||||||
import logging
|
|
||||||
PY22 = False
|
|
||||||
|
|
||||||
zero_byte = byte_chr(0)
|
zero_byte = byte_chr(0)
|
||||||
one_byte = byte_chr(1)
|
one_byte = byte_chr(1)
|
||||||
four_byte = byte_chr(4)
|
four_byte = byte_chr(4)
|
||||||
|
|
|
@ -23,8 +23,9 @@ DSS keys.
|
||||||
from Crypto.PublicKey import DSA
|
from Crypto.PublicKey import DSA
|
||||||
from Crypto.Hash import SHA
|
from Crypto.Hash import SHA
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.common import zero_byte, rng
|
||||||
|
from paramiko.py3compat import long
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
from paramiko.ber import BER, BERException
|
from paramiko.ber import BER, BERException
|
||||||
|
@ -110,9 +111,9 @@ class DSSKey (PKey):
|
||||||
rstr = util.deflate_long(r, 0)
|
rstr = util.deflate_long(r, 0)
|
||||||
sstr = util.deflate_long(s, 0)
|
sstr = util.deflate_long(s, 0)
|
||||||
if len(rstr) < 20:
|
if len(rstr) < 20:
|
||||||
rstr = zero_byte * (20 - len(rstr)) + rstr
|
rstr += zero_byte * (20 - len(rstr))
|
||||||
if len(sstr) < 20:
|
if len(sstr) < 20:
|
||||||
sstr = zero_byte * (20 - len(sstr)) + sstr
|
sstr += zero_byte * (20 - len(sstr))
|
||||||
m.add_string(rstr + sstr)
|
m.add_string(rstr + sstr)
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ class DSSKey (PKey):
|
||||||
def _encode_key(self):
|
def _encode_key(self):
|
||||||
if self.x is None:
|
if self.x is None:
|
||||||
raise SSHException('Not enough key information')
|
raise SSHException('Not enough key information')
|
||||||
keylist = [ 0, self.p, self.q, self.g, self.y, self.x ]
|
keylist = [0, self.p, self.q, self.g, self.y, self.x]
|
||||||
try:
|
try:
|
||||||
b = BER()
|
b = BER()
|
||||||
b.encode(keylist)
|
b.encode(keylist)
|
||||||
|
@ -168,10 +169,8 @@ class DSSKey (PKey):
|
||||||
return key
|
return key
|
||||||
generate = staticmethod(generate)
|
generate = staticmethod(generate)
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _from_private_key_file(self, filename, password):
|
def _from_private_key_file(self, filename, password):
|
||||||
data = self._read_private_key_file('DSA', filename, password)
|
data = self._read_private_key_file('DSA', filename, password)
|
||||||
self._decode_key(data)
|
self._decode_key(data)
|
||||||
|
|
|
@ -22,15 +22,13 @@ L{ECDSAKey}
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
from ecdsa import SigningKey, VerifyingKey, der, curves
|
from ecdsa import SigningKey, VerifyingKey, der, curves
|
||||||
from ecdsa.util import number_to_string, sigencode_string, sigencode_strings, sigdecode_strings
|
from Crypto.Hash import SHA256
|
||||||
from Crypto.Hash import SHA256, MD5
|
from ecdsa.test_pyecdsa import ECDSA
|
||||||
from Crypto.Cipher import DES3
|
from paramiko.common import four_byte, one_byte
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
from paramiko.ber import BER, BERException
|
|
||||||
from paramiko.pkey import PKey
|
from paramiko.pkey import PKey
|
||||||
|
from paramiko.py3compat import byte_chr, u
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,10 +143,8 @@ class ECDSAKey (PKey):
|
||||||
return key
|
return key
|
||||||
generate = staticmethod(generate)
|
generate = staticmethod(generate)
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _from_private_key_file(self, filename, password):
|
def _from_private_key_file(self, filename, password):
|
||||||
data = self._read_private_key_file('EC', filename, password)
|
data = self._read_private_key_file('EC', filename, password)
|
||||||
self._decode_key(data)
|
self._decode_key(data)
|
||||||
|
@ -159,6 +155,7 @@ class ECDSAKey (PKey):
|
||||||
|
|
||||||
ALLOWED_PADDINGS = [one_byte, byte_chr(2) * 2, byte_chr(3) * 3, byte_chr(4) * 4,
|
ALLOWED_PADDINGS = [one_byte, byte_chr(2) * 2, byte_chr(3) * 3, byte_chr(4) * 4,
|
||||||
byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7]
|
byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7]
|
||||||
|
|
||||||
def _decode_key(self, data):
|
def _decode_key(self, data):
|
||||||
s, padding = der.remove_sequence(data)
|
s, padding = der.remove_sequence(data)
|
||||||
if padding:
|
if padding:
|
||||||
|
@ -180,4 +177,4 @@ class ECDSAKey (PKey):
|
||||||
msg = Message(sig)
|
msg = Message(sig)
|
||||||
r = msg.get_mpint()
|
r = msg.get_mpint()
|
||||||
s = msg.get_mpint()
|
s = msg.get_mpint()
|
||||||
return (r, s)
|
return r, s
|
||||||
|
|
|
@ -15,8 +15,9 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
from paramiko.common import linefeed_byte_value, crlf, cr_byte, linefeed_byte, \
|
||||||
from paramiko.common import *
|
cr_byte_value
|
||||||
|
from paramiko.py3compat import BytesIO, PY2, u, b, bytes_types
|
||||||
|
|
||||||
|
|
||||||
class BufferedFile (object):
|
class BufferedFile (object):
|
||||||
|
@ -232,7 +233,7 @@ class BufferedFile (object):
|
||||||
pos = line.find(linefeed_byte)
|
pos = line.find(linefeed_byte)
|
||||||
if self._flags & self.FLAG_UNIVERSAL_NEWLINE:
|
if self._flags & self.FLAG_UNIVERSAL_NEWLINE:
|
||||||
rpos = line.find(cr_byte)
|
rpos = line.find(cr_byte)
|
||||||
if (rpos >= 0) and ((rpos < pos) or (pos < 0)):
|
if (rpos >= 0) and (rpos < pos or pos < 0):
|
||||||
pos = rpos
|
pos = rpos
|
||||||
xpos = pos + 1
|
xpos = pos + 1
|
||||||
if (line[pos] == cr_byte_value) and (xpos < len(line)) and (line[xpos] == linefeed_byte_value):
|
if (line[pos] == cr_byte_value) and (xpos < len(line)) and (line[xpos] == linefeed_byte_value):
|
||||||
|
@ -358,10 +359,8 @@ class BufferedFile (object):
|
||||||
def closed(self):
|
def closed(self):
|
||||||
return self._closed
|
return self._closed
|
||||||
|
|
||||||
|
|
||||||
### overrides...
|
### overrides...
|
||||||
|
|
||||||
|
|
||||||
def _read(self, size):
|
def _read(self, size):
|
||||||
"""
|
"""
|
||||||
(subclass override)
|
(subclass override)
|
||||||
|
@ -388,10 +387,8 @@ class BufferedFile (object):
|
||||||
"""
|
"""
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _set_mode(self, mode='r', bufsize=-1):
|
def _set_mode(self, mode='r', bufsize=-1):
|
||||||
"""
|
"""
|
||||||
Subclasses call this method to initialize the BufferedFile.
|
Subclasses call this method to initialize the BufferedFile.
|
||||||
|
@ -419,13 +416,13 @@ class BufferedFile (object):
|
||||||
self._flags |= self.FLAG_READ
|
self._flags |= self.FLAG_READ
|
||||||
if ('w' in mode) or ('+' in mode):
|
if ('w' in mode) or ('+' in mode):
|
||||||
self._flags |= self.FLAG_WRITE
|
self._flags |= self.FLAG_WRITE
|
||||||
if ('a' in mode):
|
if 'a' in mode:
|
||||||
self._flags |= self.FLAG_WRITE | self.FLAG_APPEND
|
self._flags |= self.FLAG_WRITE | self.FLAG_APPEND
|
||||||
self._size = self._get_size()
|
self._size = self._get_size()
|
||||||
self._pos = self._realpos = self._size
|
self._pos = self._realpos = self._size
|
||||||
if ('b' in mode):
|
if 'b' in mode:
|
||||||
self._flags |= self.FLAG_BINARY
|
self._flags |= self.FLAG_BINARY
|
||||||
if ('U' in mode):
|
if 'U' in mode:
|
||||||
self._flags |= self.FLAG_UNIVERSAL_NEWLINE
|
self._flags |= self.FLAG_UNIVERSAL_NEWLINE
|
||||||
# built-in file objects have this attribute to store which kinds of
|
# built-in file objects have this attribute to store which kinds of
|
||||||
# line terminations they've seen:
|
# line terminations they've seen:
|
||||||
|
|
|
@ -17,15 +17,17 @@
|
||||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
|
||||||
|
|
||||||
import base64
|
|
||||||
import binascii
|
import binascii
|
||||||
from Crypto.Hash import SHA, HMAC
|
from Crypto.Hash import SHA, HMAC
|
||||||
|
from paramiko.common import rng
|
||||||
|
from paramiko.py3compat import b, u, encodebytes, decodebytes
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from collections import MutableMapping
|
from collections import MutableMapping
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
from UserDict import DictMixin as MutableMapping
|
from UserDict import DictMixin as MutableMapping
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko.dsskey import DSSKey
|
from paramiko.dsskey import DSSKey
|
||||||
from paramiko.rsakey import RSAKey
|
from paramiko.rsakey import RSAKey
|
||||||
from paramiko.util import get_logger, constant_time_bytes_eq
|
from paramiko.util import get_logger, constant_time_bytes_eq
|
||||||
|
@ -213,7 +215,6 @@ class HostKeys (MutableMapping):
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
k = self[key]
|
k = self[key]
|
||||||
pass
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
ret = self.lookup(key)
|
ret = self.lookup(key)
|
||||||
|
|
|
@ -23,11 +23,11 @@ client side, and a B{lot} more on the server side.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from Crypto.Hash import SHA
|
from Crypto.Hash import SHA
|
||||||
from Crypto.Util import number
|
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.common import DEBUG
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
|
from paramiko.py3compat import byte_chr, byte_ord, byte_mask
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,10 +88,8 @@ class KexGex (object):
|
||||||
return self._parse_kexdh_gex_request_old(m)
|
return self._parse_kexdh_gex_request_old(m)
|
||||||
raise SSHException('KexGex asked to handle packet type %d' % ptype)
|
raise SSHException('KexGex asked to handle packet type %d' % ptype)
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _generate_x(self):
|
def _generate_x(self):
|
||||||
# generate an "x" (1 < x < (p-1)/2).
|
# generate an "x" (1 < x < (p-1)/2).
|
||||||
q = (self.p - 1) // 2
|
q = (self.p - 1) // 2
|
||||||
|
|
|
@ -23,9 +23,10 @@ Standard SSH key exchange ("kex" if you wanna sound cool). Diffie-Hellman of
|
||||||
|
|
||||||
from Crypto.Hash import SHA
|
from Crypto.Hash import SHA
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.common import max_byte, zero_byte
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
|
from paramiko.py3compat import byte_chr, long, byte_mask
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ G = 2
|
||||||
b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7
|
b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7
|
||||||
b0000000000000000 = zero_byte * 8
|
b0000000000000000 = zero_byte * 8
|
||||||
|
|
||||||
|
|
||||||
class KexGroup1(object):
|
class KexGroup1(object):
|
||||||
|
|
||||||
name = 'diffie-hellman-group1-sha1'
|
name = 'diffie-hellman-group1-sha1'
|
||||||
|
@ -71,10 +73,8 @@ class KexGroup1(object):
|
||||||
return self._parse_kexdh_reply(m)
|
return self._parse_kexdh_reply(m)
|
||||||
raise SSHException('KexGroup1 asked to handle packet type %d' % ptype)
|
raise SSHException('KexGroup1 asked to handle packet type %d' % ptype)
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _generate_x(self):
|
def _generate_x(self):
|
||||||
# generate an "x" (1 < x < q), where q is (p-1)/2.
|
# generate an "x" (1 < x < q), where q is (p-1)/2.
|
||||||
# p is a 128-byte (1024-bit) number, where the first 64 bits are 1.
|
# p is a 128-byte (1024-bit) number, where the first 64 bits are 1.
|
||||||
|
@ -84,8 +84,8 @@ class KexGroup1(object):
|
||||||
while 1:
|
while 1:
|
||||||
x_bytes = self.transport.rng.read(128)
|
x_bytes = self.transport.rng.read(128)
|
||||||
x_bytes = byte_mask(x_bytes[0], 0x7f) + x_bytes[1:]
|
x_bytes = byte_mask(x_bytes[0], 0x7f) + x_bytes[1:]
|
||||||
if (x_bytes[:8] != b7fffffffffffffff) and \
|
if (x_bytes[:8] != b7fffffffffffffff and
|
||||||
(x_bytes[:8] != b0000000000000000):
|
x_bytes[:8] != b0000000000000000):
|
||||||
break
|
break
|
||||||
self.x = util.inflate_long(x_bytes)
|
self.x = util.inflate_long(x_bytes)
|
||||||
|
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
|
|
||||||
#
|
|
||||||
# This file is part of paramiko.
|
|
||||||
#
|
|
||||||
# Paramiko is free software; you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU Lesser General Public License as published by the Free
|
|
||||||
# Software Foundation; either version 2.1 of the License, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Stub out logging on Python < 2.3.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
DEBUG = 10
|
|
||||||
INFO = 20
|
|
||||||
WARNING = 30
|
|
||||||
ERROR = 40
|
|
||||||
CRITICAL = 50
|
|
||||||
|
|
||||||
|
|
||||||
def getLogger(name):
|
|
||||||
return _logger
|
|
||||||
|
|
||||||
|
|
||||||
class logger (object):
|
|
||||||
def __init__(self):
|
|
||||||
self.handlers = [ ]
|
|
||||||
self.level = ERROR
|
|
||||||
|
|
||||||
def setLevel(self, level):
|
|
||||||
self.level = level
|
|
||||||
|
|
||||||
def addHandler(self, h):
|
|
||||||
self.handlers.append(h)
|
|
||||||
|
|
||||||
def addFilter(self, filter):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def log(self, level, text):
|
|
||||||
if level >= self.level:
|
|
||||||
for h in self.handlers:
|
|
||||||
h.f.write(text + '\n')
|
|
||||||
h.f.flush()
|
|
||||||
|
|
||||||
class StreamHandler (object):
|
|
||||||
def __init__(self, f):
|
|
||||||
self.f = f
|
|
||||||
|
|
||||||
def setFormatter(self, f):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Formatter (object):
|
|
||||||
def __init__(self, x, y):
|
|
||||||
pass
|
|
||||||
|
|
||||||
_logger = logger()
|
|
|
@ -23,7 +23,8 @@ Implementation of an SSH2 "message".
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
from paramiko.common import *
|
from paramiko.common import zero_byte, max_byte, one_byte, asbytes
|
||||||
|
from paramiko.py3compat import long, BytesIO, u, integer_types
|
||||||
|
|
||||||
|
|
||||||
class Message (object):
|
class Message (object):
|
||||||
|
@ -47,7 +48,7 @@ class Message (object):
|
||||||
the byte stream to use as the message content (passed in only when
|
the byte stream to use as the message content (passed in only when
|
||||||
decomposing a message).
|
decomposing a message).
|
||||||
"""
|
"""
|
||||||
if content != None:
|
if content is not None:
|
||||||
self.packet = BytesIO(content)
|
self.packet = BytesIO(content)
|
||||||
else:
|
else:
|
||||||
self.packet = BytesIO()
|
self.packet = BytesIO()
|
||||||
|
@ -105,8 +106,8 @@ class Message (object):
|
||||||
bytes remaining in the message.
|
bytes remaining in the message.
|
||||||
"""
|
"""
|
||||||
b = self.packet.read(n)
|
b = self.packet.read(n)
|
||||||
max_pad_size = 1<<20 # Limit padding to 1 MB
|
max_pad_size = 1 << 20 # Limit padding to 1 MB
|
||||||
if len(b) < n and n < max_pad_size:
|
if len(b) < n < max_pad_size:
|
||||||
return b + zero_byte * (n - len(b))
|
return b + zero_byte * (n - len(b))
|
||||||
return b
|
return b
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,15 @@ Packet handling
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import select
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.common import linefeed_byte, cr_byte_value, asbytes, MSG_NAMES, \
|
||||||
|
DEBUG, xffffffff, zero_byte, rng
|
||||||
|
from paramiko.py3compat import u, byte_ord
|
||||||
from paramiko.ssh_exception import SSHException, ProxyCommandFailure
|
from paramiko.ssh_exception import SSHException, ProxyCommandFailure
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
|
|
||||||
|
@ -57,8 +58,8 @@ class Packetizer (object):
|
||||||
REKEY_PACKETS = pow(2, 29)
|
REKEY_PACKETS = pow(2, 29)
|
||||||
REKEY_BYTES = pow(2, 29)
|
REKEY_BYTES = pow(2, 29)
|
||||||
|
|
||||||
REKEY_PACKETS_OVERFLOW_MAX = pow(2,29) # Allow receiving this many packets after a re-key request before terminating
|
REKEY_PACKETS_OVERFLOW_MAX = pow(2, 29) # Allow receiving this many packets after a re-key request before terminating
|
||||||
REKEY_BYTES_OVERFLOW_MAX = pow(2,29) # Allow receiving this many bytes after a re-key request before terminating
|
REKEY_BYTES_OVERFLOW_MAX = pow(2, 29) # Allow receiving this many bytes after a re-key request before terminating
|
||||||
|
|
||||||
def __init__(self, socket):
|
def __init__(self, socket):
|
||||||
self.__socket = socket
|
self.__socket = socket
|
||||||
|
@ -201,8 +202,6 @@ class Packetizer (object):
|
||||||
out = self.__remainder[:n]
|
out = self.__remainder[:n]
|
||||||
self.__remainder = self.__remainder[n:]
|
self.__remainder = self.__remainder[n:]
|
||||||
n -= len(out)
|
n -= len(out)
|
||||||
if PY22:
|
|
||||||
return self._py22_read_all(n, out)
|
|
||||||
while n > 0:
|
while n > 0:
|
||||||
got_timeout = False
|
got_timeout = False
|
||||||
try:
|
try:
|
||||||
|
@ -251,7 +250,7 @@ class Packetizer (object):
|
||||||
else:
|
else:
|
||||||
n = -1
|
n = -1
|
||||||
except ProxyCommandFailure:
|
except ProxyCommandFailure:
|
||||||
raise # so it doesn't get swallowed by the below catchall
|
raise # so it doesn't get swallowed by the below catchall
|
||||||
except Exception:
|
except Exception:
|
||||||
# could be: (32, 'Broken pipe')
|
# could be: (32, 'Broken pipe')
|
||||||
n = -1
|
n = -1
|
||||||
|
@ -275,7 +274,7 @@ class Packetizer (object):
|
||||||
while not linefeed_byte in buf:
|
while not linefeed_byte in buf:
|
||||||
buf += self._read_timeout(timeout)
|
buf += self._read_timeout(timeout)
|
||||||
n = buf.index(linefeed_byte)
|
n = buf.index(linefeed_byte)
|
||||||
self.__remainder = buf[n+1:]
|
self.__remainder = buf[n + 1:]
|
||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
if (len(buf) > 0) and (buf[-1] == cr_byte_value):
|
if (len(buf) > 0) and (buf[-1] == cr_byte_value):
|
||||||
buf = buf[:-1]
|
buf = buf[:-1]
|
||||||
|
@ -301,12 +300,12 @@ class Packetizer (object):
|
||||||
if self.__dump_packets:
|
if self.__dump_packets:
|
||||||
self._log(DEBUG, 'Write packet <%s>, length %d' % (cmd_name, orig_len))
|
self._log(DEBUG, 'Write packet <%s>, length %d' % (cmd_name, orig_len))
|
||||||
self._log(DEBUG, util.format_binary(packet, 'OUT: '))
|
self._log(DEBUG, util.format_binary(packet, 'OUT: '))
|
||||||
if self.__block_engine_out != None:
|
if self.__block_engine_out is not None:
|
||||||
out = self.__block_engine_out.encrypt(packet)
|
out = self.__block_engine_out.encrypt(packet)
|
||||||
else:
|
else:
|
||||||
out = packet
|
out = packet
|
||||||
# + mac
|
# + mac
|
||||||
if self.__block_engine_out != None:
|
if self.__block_engine_out is not None:
|
||||||
payload = struct.pack('>I', self.__sequence_number_out) + packet
|
payload = struct.pack('>I', self.__sequence_number_out) + packet
|
||||||
out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out]
|
out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out]
|
||||||
self.__sequence_number_out = (self.__sequence_number_out + 1) & xffffffff
|
self.__sequence_number_out = (self.__sequence_number_out + 1) & xffffffff
|
||||||
|
@ -314,8 +313,8 @@ class Packetizer (object):
|
||||||
|
|
||||||
self.__sent_bytes += len(out)
|
self.__sent_bytes += len(out)
|
||||||
self.__sent_packets += 1
|
self.__sent_packets += 1
|
||||||
if ((self.__sent_packets >= self.REKEY_PACKETS) or (self.__sent_bytes >= self.REKEY_BYTES)) \
|
if (self.__sent_packets >= self.REKEY_PACKETS or self.__sent_bytes >= self.REKEY_BYTES)\
|
||||||
and not self.__need_rekey:
|
and not self.__need_rekey:
|
||||||
# only ask once for rekeying
|
# only ask once for rekeying
|
||||||
self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' %
|
self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' %
|
||||||
(self.__sent_packets, self.__sent_bytes))
|
(self.__sent_packets, self.__sent_bytes))
|
||||||
|
@ -334,10 +333,10 @@ class Packetizer (object):
|
||||||
:raises NeedRekeyException: if the transport should rekey
|
:raises NeedRekeyException: if the transport should rekey
|
||||||
"""
|
"""
|
||||||
header = self.read_all(self.__block_size_in, check_rekey=True)
|
header = self.read_all(self.__block_size_in, check_rekey=True)
|
||||||
if self.__block_engine_in != None:
|
if self.__block_engine_in is not None:
|
||||||
header = self.__block_engine_in.decrypt(header)
|
header = self.__block_engine_in.decrypt(header)
|
||||||
if self.__dump_packets:
|
if self.__dump_packets:
|
||||||
self._log(DEBUG, util.format_binary(header, 'IN: '));
|
self._log(DEBUG, util.format_binary(header, 'IN: '))
|
||||||
packet_size = struct.unpack('>I', header[:4])[0]
|
packet_size = struct.unpack('>I', header[:4])[0]
|
||||||
# leftover contains decrypted bytes from the first block (after the length field)
|
# leftover contains decrypted bytes from the first block (after the length field)
|
||||||
leftover = header[4:]
|
leftover = header[4:]
|
||||||
|
@ -346,10 +345,10 @@ class Packetizer (object):
|
||||||
buf = self.read_all(packet_size + self.__mac_size_in - len(leftover))
|
buf = self.read_all(packet_size + self.__mac_size_in - len(leftover))
|
||||||
packet = buf[:packet_size - len(leftover)]
|
packet = buf[:packet_size - len(leftover)]
|
||||||
post_packet = buf[packet_size - len(leftover):]
|
post_packet = buf[packet_size - len(leftover):]
|
||||||
if self.__block_engine_in != None:
|
if self.__block_engine_in is not None:
|
||||||
packet = self.__block_engine_in.decrypt(packet)
|
packet = self.__block_engine_in.decrypt(packet)
|
||||||
if self.__dump_packets:
|
if self.__dump_packets:
|
||||||
self._log(DEBUG, util.format_binary(packet, 'IN: '));
|
self._log(DEBUG, util.format_binary(packet, 'IN: '))
|
||||||
packet = leftover + packet
|
packet = leftover + packet
|
||||||
|
|
||||||
if self.__mac_size_in > 0:
|
if self.__mac_size_in > 0:
|
||||||
|
@ -401,10 +400,8 @@ class Packetizer (object):
|
||||||
self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload)))
|
self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload)))
|
||||||
return cmd, msg
|
return cmd, msg
|
||||||
|
|
||||||
|
|
||||||
########## protected
|
########## protected
|
||||||
|
|
||||||
|
|
||||||
def _log(self, level, msg):
|
def _log(self, level, msg):
|
||||||
if self.__logger is None:
|
if self.__logger is None:
|
||||||
return
|
return
|
||||||
|
@ -416,7 +413,7 @@ class Packetizer (object):
|
||||||
|
|
||||||
def _check_keepalive(self):
|
def _check_keepalive(self):
|
||||||
if (not self.__keepalive_interval) or (not self.__block_engine_out) or \
|
if (not self.__keepalive_interval) or (not self.__block_engine_out) or \
|
||||||
self.__need_rekey:
|
self.__need_rekey:
|
||||||
# wait till we're encrypting, and not in the middle of rekeying
|
# wait till we're encrypting, and not in the middle of rekeying
|
||||||
return
|
return
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
@ -424,40 +421,7 @@ class Packetizer (object):
|
||||||
self.__keepalive_callback()
|
self.__keepalive_callback()
|
||||||
self.__keepalive_last = now
|
self.__keepalive_last = now
|
||||||
|
|
||||||
def _py22_read_all(self, n, out):
|
|
||||||
while n > 0:
|
|
||||||
r, w, e = select.select([self.__socket], [], [], 0.1)
|
|
||||||
if self.__socket not in r:
|
|
||||||
if self.__closed:
|
|
||||||
raise EOFError()
|
|
||||||
self._check_keepalive()
|
|
||||||
else:
|
|
||||||
x = self.__socket.recv(n)
|
|
||||||
if len(x) == 0:
|
|
||||||
raise EOFError()
|
|
||||||
out += x
|
|
||||||
n -= len(x)
|
|
||||||
return out
|
|
||||||
|
|
||||||
def _py22_read_timeout(self, timeout):
|
|
||||||
start = time.time()
|
|
||||||
while True:
|
|
||||||
r, w, e = select.select([self.__socket], [], [], 0.1)
|
|
||||||
if self.__socket in r:
|
|
||||||
x = self.__socket.recv(1)
|
|
||||||
if len(x) == 0:
|
|
||||||
raise EOFError()
|
|
||||||
break
|
|
||||||
if self.__closed:
|
|
||||||
raise EOFError()
|
|
||||||
now = time.time()
|
|
||||||
if now - start >= timeout:
|
|
||||||
raise socket.timeout()
|
|
||||||
return x
|
|
||||||
|
|
||||||
def _read_timeout(self, timeout):
|
def _read_timeout(self, timeout):
|
||||||
if PY22:
|
|
||||||
return self._py22_read_timeout(timeout)
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
@ -468,8 +432,8 @@ class Packetizer (object):
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
pass
|
pass
|
||||||
except EnvironmentError as e:
|
except EnvironmentError as e:
|
||||||
if ((type(e.args) is tuple) and (len(e.args) > 0) and
|
if (type(e.args) is tuple and len(e.args) > 0 and
|
||||||
(e.args[0] == errno.EINTR)):
|
e.args[0] == errno.EINTR):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -28,10 +28,9 @@ will trigger as readable in `select <select.select>`.
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
from paramiko.py3compat import b
|
|
||||||
|
|
||||||
|
|
||||||
def make_pipe ():
|
def make_pipe():
|
||||||
if sys.platform[:3] != 'win':
|
if sys.platform[:3] != 'win':
|
||||||
p = PosixPipe()
|
p = PosixPipe()
|
||||||
else:
|
else:
|
||||||
|
@ -40,34 +39,34 @@ def make_pipe ():
|
||||||
|
|
||||||
|
|
||||||
class PosixPipe (object):
|
class PosixPipe (object):
|
||||||
def __init__ (self):
|
def __init__(self):
|
||||||
self._rfd, self._wfd = os.pipe()
|
self._rfd, self._wfd = os.pipe()
|
||||||
self._set = False
|
self._set = False
|
||||||
self._forever = False
|
self._forever = False
|
||||||
self._closed = False
|
self._closed = False
|
||||||
|
|
||||||
def close (self):
|
def close(self):
|
||||||
os.close(self._rfd)
|
os.close(self._rfd)
|
||||||
os.close(self._wfd)
|
os.close(self._wfd)
|
||||||
# used for unit tests:
|
# used for unit tests:
|
||||||
self._closed = True
|
self._closed = True
|
||||||
|
|
||||||
def fileno (self):
|
def fileno(self):
|
||||||
return self._rfd
|
return self._rfd
|
||||||
|
|
||||||
def clear (self):
|
def clear(self):
|
||||||
if not self._set or self._forever:
|
if not self._set or self._forever:
|
||||||
return
|
return
|
||||||
os.read(self._rfd, 1)
|
os.read(self._rfd, 1)
|
||||||
self._set = False
|
self._set = False
|
||||||
|
|
||||||
def set (self):
|
def set(self):
|
||||||
if self._set or self._closed:
|
if self._set or self._closed:
|
||||||
return
|
return
|
||||||
self._set = True
|
self._set = True
|
||||||
os.write(self._wfd, b'*')
|
os.write(self._wfd, b'*')
|
||||||
|
|
||||||
def set_forever (self):
|
def set_forever(self):
|
||||||
self._forever = True
|
self._forever = True
|
||||||
self.set()
|
self.set()
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ class WindowsPipe (object):
|
||||||
On Windows, only an OS-level "WinSock" may be used in select(), but reads
|
On Windows, only an OS-level "WinSock" may be used in select(), but reads
|
||||||
and writes must be to the actual socket object.
|
and writes must be to the actual socket object.
|
||||||
"""
|
"""
|
||||||
def __init__ (self):
|
def __init__(self):
|
||||||
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
serv.bind(('127.0.0.1', 0))
|
serv.bind(('127.0.0.1', 0))
|
||||||
serv.listen(1)
|
serv.listen(1)
|
||||||
|
@ -92,13 +91,13 @@ class WindowsPipe (object):
|
||||||
self._forever = False
|
self._forever = False
|
||||||
self._closed = False
|
self._closed = False
|
||||||
|
|
||||||
def close (self):
|
def close(self):
|
||||||
self._rsock.close()
|
self._rsock.close()
|
||||||
self._wsock.close()
|
self._wsock.close()
|
||||||
# used for unit tests:
|
# used for unit tests:
|
||||||
self._closed = True
|
self._closed = True
|
||||||
|
|
||||||
def fileno (self):
|
def fileno(self):
|
||||||
return self._rsock.fileno()
|
return self._rsock.fileno()
|
||||||
|
|
||||||
def clear (self):
|
def clear (self):
|
||||||
|
|
|
@ -27,9 +27,9 @@ import os
|
||||||
from Crypto.Hash import MD5
|
from Crypto.Hash import MD5
|
||||||
from Crypto.Cipher import DES3, AES
|
from Crypto.Cipher import DES3, AES
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
from paramiko.message import Message
|
from paramiko.common import o600, rng, zero_byte
|
||||||
|
from paramiko.py3compat import u, encodebytes, decodebytes, b
|
||||||
from paramiko.ssh_exception import SSHException, PasswordRequiredException
|
from paramiko.ssh_exception import SSHException, PasswordRequiredException
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,11 +40,10 @@ class PKey (object):
|
||||||
|
|
||||||
# known encryption types for private key files:
|
# known encryption types for private key files:
|
||||||
_CIPHER_TABLE = {
|
_CIPHER_TABLE = {
|
||||||
'AES-128-CBC': { 'cipher': AES, 'keysize': 16, 'blocksize': 16, 'mode': AES.MODE_CBC },
|
'AES-128-CBC': {'cipher': AES, 'keysize': 16, 'blocksize': 16, 'mode': AES.MODE_CBC},
|
||||||
'DES-EDE3-CBC': { 'cipher': DES3, 'keysize': 24, 'blocksize': 8, 'mode': DES3.MODE_CBC },
|
'DES-EDE3-CBC': {'cipher': DES3, 'keysize': 24, 'blocksize': 8, 'mode': DES3.MODE_CBC},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, msg=None, data=None):
|
def __init__(self, msg=None, data=None):
|
||||||
"""
|
"""
|
||||||
Create a new instance of this public key type. If ``msg`` is given,
|
Create a new instance of this public key type. If ``msg`` is given,
|
||||||
|
@ -73,6 +72,7 @@ class PKey (object):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.asbytes()
|
return self.asbytes()
|
||||||
|
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
"""
|
"""
|
||||||
Compare this key to another. Returns 0 if this key is equivalent to
|
Compare this key to another. Returns 0 if this key is equivalent to
|
||||||
|
@ -345,7 +345,7 @@ class PKey (object):
|
||||||
s = u(encodebytes(data))
|
s = u(encodebytes(data))
|
||||||
# re-wrap to 64-char lines
|
# re-wrap to 64-char lines
|
||||||
s = ''.join(s.split('\n'))
|
s = ''.join(s.split('\n'))
|
||||||
s = '\n'.join([s[i : i+64] for i in range(0, len(s), 64)])
|
s = '\n'.join([s[i: i + 64] for i in range(0, len(s), 64)])
|
||||||
f.write(s)
|
f.write(s)
|
||||||
f.write('\n')
|
f.write('\n')
|
||||||
f.write('-----END %s PRIVATE KEY-----\n' % tag)
|
f.write('-----END %s PRIVATE KEY-----\n' % tag)
|
||||||
|
|
|
@ -23,16 +23,16 @@ Utility functions for dealing with primes.
|
||||||
from Crypto.Util import number
|
from Crypto.Util import number
|
||||||
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.py3compat import byte_mask, long
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
from paramiko.common import *
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_prime(bits, rng):
|
def _generate_prime(bits, rng):
|
||||||
"primtive attempt at prime generation"
|
"""primtive attempt at prime generation"""
|
||||||
hbyte_mask = pow(2, bits % 8) - 1
|
hbyte_mask = pow(2, bits % 8) - 1
|
||||||
while True:
|
while True:
|
||||||
# loop catches the case where we increment n into a higher bit-range
|
# loop catches the case where we increment n into a higher bit-range
|
||||||
x = rng.read((bits+7) // 8)
|
x = rng.read((bits + 7) // 8)
|
||||||
if hbyte_mask > 0:
|
if hbyte_mask > 0:
|
||||||
x = byte_mask(x[0], hbyte_mask) + x[1:]
|
x = byte_mask(x[0], hbyte_mask) + x[1:]
|
||||||
n = util.inflate_long(x, 1)
|
n = util.inflate_long(x, 1)
|
||||||
|
@ -44,9 +44,10 @@ def _generate_prime(bits, rng):
|
||||||
break
|
break
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
def _roll_random(rng, n):
|
def _roll_random(rng, n):
|
||||||
"returns a random # from 0 to N-1"
|
"""returns a random # from 0 to N-1"""
|
||||||
bits = util.bit_length(n-1)
|
bits = util.bit_length(n - 1)
|
||||||
byte_count = (bits + 7) // 8
|
byte_count = (bits + 7) // 8
|
||||||
hbyte_mask = pow(2, bits % 8) - 1
|
hbyte_mask = pow(2, bits % 8) - 1
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ class ModulusPack (object):
|
||||||
good = -1
|
good = -1
|
||||||
# find nearest bitsize >= preferred
|
# find nearest bitsize >= preferred
|
||||||
for b in bitsizes:
|
for b in bitsizes:
|
||||||
if (b >= prefer) and (b < max) and ((b < good) or (good == -1)):
|
if (b >= prefer) and (b < max) and (b < good or good == -1):
|
||||||
good = b
|
good = b
|
||||||
# if that failed, find greatest bitsize >= min
|
# if that failed, find greatest bitsize >= min
|
||||||
if good == -1:
|
if good == -1:
|
||||||
|
|
|
@ -80,7 +80,7 @@ class ProxyCommand(object):
|
||||||
while len(self.buffer) < size:
|
while len(self.buffer) < size:
|
||||||
if self.timeout is not None:
|
if self.timeout is not None:
|
||||||
elapsed = (datetime.now() - start).microseconds
|
elapsed = (datetime.now() - start).microseconds
|
||||||
timeout = self.timeout * 1000 * 1000 # to microseconds
|
timeout = self.timeout * 1000 * 1000 # to microseconds
|
||||||
if elapsed >= timeout:
|
if elapsed >= timeout:
|
||||||
raise socket.timeout()
|
raise socket.timeout()
|
||||||
r, w, x = select([self.process.stdout], [], [], 0.0)
|
r, w, x = select([self.process.stdout], [], [], 0.0)
|
||||||
|
@ -94,7 +94,7 @@ class ProxyCommand(object):
|
||||||
self.buffer = []
|
self.buffer = []
|
||||||
return result
|
return result
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
raise # socket.timeout is a subclass of IOError
|
raise # socket.timeout is a subclass of IOError
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
raise ProxyCommandFailure(' '.join(self.cmd), e.strerror)
|
raise ProxyCommandFailure(' '.join(self.cmd), e.strerror)
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,14 @@ RSA keys.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto.Hash import SHA, MD5
|
from Crypto.Hash import SHA
|
||||||
from Crypto.Cipher import DES3
|
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.common import rng, max_byte, zero_byte, one_byte
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
from paramiko.ber import BER, BERException
|
from paramiko.ber import BER, BERException
|
||||||
from paramiko.pkey import PKey
|
from paramiko.pkey import PKey
|
||||||
|
from paramiko.py3compat import long
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
|
|
||||||
SHA1_DIGESTINFO = b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'
|
SHA1_DIGESTINFO = b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'
|
||||||
|
@ -113,9 +113,9 @@ class RSAKey (PKey):
|
||||||
def _encode_key(self):
|
def _encode_key(self):
|
||||||
if (self.p is None) or (self.q is None):
|
if (self.p is None) or (self.q is None):
|
||||||
raise SSHException('Not enough key info to write private key file')
|
raise SSHException('Not enough key info to write private key file')
|
||||||
keylist = [ 0, self.n, self.e, self.d, self.p, self.q,
|
keylist = [0, self.n, self.e, self.d, self.p, self.q,
|
||||||
self.d % (self.p - 1), self.d % (self.q - 1),
|
self.d % (self.p - 1), self.d % (self.q - 1),
|
||||||
util.mod_inverse(self.q, self.p) ]
|
util.mod_inverse(self.q, self.p)]
|
||||||
try:
|
try:
|
||||||
b = BER()
|
b = BER()
|
||||||
b.encode(keylist)
|
b.encode(keylist)
|
||||||
|
@ -148,10 +148,8 @@ class RSAKey (PKey):
|
||||||
return key
|
return key
|
||||||
generate = staticmethod(generate)
|
generate = staticmethod(generate)
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _pkcs1imify(self, data):
|
def _pkcs1imify(self, data):
|
||||||
"""
|
"""
|
||||||
turn a 20-byte SHA1 hash into a blob of data as large as the key's N,
|
turn a 20-byte SHA1 hash into a blob of data as large as the key's N,
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
|
from paramiko.common import DEBUG, ERROR, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, AUTH_FAILED
|
||||||
|
from paramiko.py3compat import string_types
|
||||||
|
|
||||||
|
|
||||||
class ServerInterface (object):
|
class ServerInterface (object):
|
||||||
|
@ -291,10 +292,8 @@ class ServerInterface (object):
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
### Channel requests
|
### Channel requests
|
||||||
|
|
||||||
|
|
||||||
def check_channel_pty_request(self, channel, term, width, height, pixelwidth, pixelheight,
|
def check_channel_pty_request(self, channel, term, width, height, pixelwidth, pixelheight,
|
||||||
modes):
|
modes):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -20,32 +20,31 @@ import select
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
from paramiko.channel import Channel
|
from paramiko.common import asbytes, DEBUG
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
|
from paramiko.py3compat import byte_chr, byte_ord
|
||||||
|
|
||||||
|
|
||||||
CMD_INIT, CMD_VERSION, CMD_OPEN, CMD_CLOSE, CMD_READ, CMD_WRITE, CMD_LSTAT, CMD_FSTAT, \
|
CMD_INIT, CMD_VERSION, CMD_OPEN, CMD_CLOSE, CMD_READ, CMD_WRITE, CMD_LSTAT, CMD_FSTAT, \
|
||||||
CMD_SETSTAT, CMD_FSETSTAT, CMD_OPENDIR, CMD_READDIR, CMD_REMOVE, CMD_MKDIR, \
|
CMD_SETSTAT, CMD_FSETSTAT, CMD_OPENDIR, CMD_READDIR, CMD_REMOVE, CMD_MKDIR, \
|
||||||
CMD_RMDIR, CMD_REALPATH, CMD_STAT, CMD_RENAME, CMD_READLINK, CMD_SYMLINK \
|
CMD_RMDIR, CMD_REALPATH, CMD_STAT, CMD_RENAME, CMD_READLINK, CMD_SYMLINK = range(1, 21)
|
||||||
= range(1, 21)
|
|
||||||
CMD_STATUS, CMD_HANDLE, CMD_DATA, CMD_NAME, CMD_ATTRS = range(101, 106)
|
CMD_STATUS, CMD_HANDLE, CMD_DATA, CMD_NAME, CMD_ATTRS = range(101, 106)
|
||||||
CMD_EXTENDED, CMD_EXTENDED_REPLY = range(200, 202)
|
CMD_EXTENDED, CMD_EXTENDED_REPLY = range(200, 202)
|
||||||
|
|
||||||
SFTP_OK = 0
|
SFTP_OK = 0
|
||||||
SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, SFTP_FAILURE, SFTP_BAD_MESSAGE, \
|
SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, SFTP_FAILURE, SFTP_BAD_MESSAGE, \
|
||||||
SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED = range(1, 9)
|
SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED = range(1, 9)
|
||||||
|
|
||||||
SFTP_DESC = [ 'Success',
|
SFTP_DESC = ['Success',
|
||||||
'End of file',
|
'End of file',
|
||||||
'No such file',
|
'No such file',
|
||||||
'Permission denied',
|
'Permission denied',
|
||||||
'Failure',
|
'Failure',
|
||||||
'Bad message',
|
'Bad message',
|
||||||
'No connection',
|
'No connection',
|
||||||
'Connection lost',
|
'Connection lost',
|
||||||
'Operation unsupported' ]
|
'Operation unsupported']
|
||||||
|
|
||||||
SFTP_FLAG_READ = 0x1
|
SFTP_FLAG_READ = 0x1
|
||||||
SFTP_FLAG_WRITE = 0x2
|
SFTP_FLAG_WRITE = 0x2
|
||||||
|
@ -99,10 +98,8 @@ class BaseSFTP (object):
|
||||||
self.sock = None
|
self.sock = None
|
||||||
self.ultra_debug = False
|
self.ultra_debug = False
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _send_version(self):
|
def _send_version(self):
|
||||||
self._send_packet(CMD_INIT, struct.pack('>I', _VERSION))
|
self._send_packet(CMD_INIT, struct.pack('>I', _VERSION))
|
||||||
t, data = self._read_packet()
|
t, data = self._read_packet()
|
||||||
|
@ -121,7 +118,7 @@ class BaseSFTP (object):
|
||||||
raise SFTPError('Incompatible sftp protocol')
|
raise SFTPError('Incompatible sftp protocol')
|
||||||
version = struct.unpack('>I', data[:4])[0]
|
version = struct.unpack('>I', data[:4])[0]
|
||||||
# advertise that we support "check-file"
|
# advertise that we support "check-file"
|
||||||
extension_pairs = [ 'check-file', 'md5,sha1' ]
|
extension_pairs = ['check-file', 'md5,sha1']
|
||||||
msg = Message()
|
msg = Message()
|
||||||
msg.add_int(_VERSION)
|
msg.add_int(_VERSION)
|
||||||
msg.add(*extension_pairs)
|
msg.add(*extension_pairs)
|
||||||
|
@ -151,7 +148,7 @@ class BaseSFTP (object):
|
||||||
# return or raise an exception, but calling select on a closed
|
# return or raise an exception, but calling select on a closed
|
||||||
# socket will.)
|
# socket will.)
|
||||||
while True:
|
while True:
|
||||||
read, write, err = select.select([ self.sock ], [], [], 0.1)
|
read, write, err = select.select([self.sock], [], [], 0.1)
|
||||||
if len(read) > 0:
|
if len(read) > 0:
|
||||||
x = self.sock.recv(n)
|
x = self.sock.recv(n)
|
||||||
break
|
break
|
||||||
|
@ -181,7 +178,7 @@ class BaseSFTP (object):
|
||||||
size = struct.unpack('>I', x)[0]
|
size = struct.unpack('>I', x)[0]
|
||||||
data = self._read_all(size)
|
data = self._read_all(size)
|
||||||
if self.ultra_debug:
|
if self.ultra_debug:
|
||||||
self._log(DEBUG, util.format_binary(data, 'IN: '));
|
self._log(DEBUG, util.format_binary(data, 'IN: '))
|
||||||
if size > 0:
|
if size > 0:
|
||||||
t = byte_ord(data[0])
|
t = byte_ord(data[0])
|
||||||
#self._log(DEBUG2, 'read: %s (len=%d)' % (CMD_NAMES.get(t), '0x%02x' % t, len(data)-1))
|
#self._log(DEBUG2, 'read: %s (len=%d)' % (CMD_NAMES.get(t), '0x%02x' % t, len(data)-1))
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
import stat
|
import stat
|
||||||
import time
|
import time
|
||||||
from paramiko.common import *
|
from paramiko.common import x80000000, o700, o70, xffffffff
|
||||||
from paramiko.sftp import *
|
from paramiko.py3compat import long, b
|
||||||
|
|
||||||
|
|
||||||
class SFTPAttributes (object):
|
class SFTPAttributes (object):
|
||||||
|
@ -84,10 +84,8 @@ class SFTPAttributes (object):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<SFTPAttributes: %s>' % self._debug_str()
|
return '<SFTPAttributes: %s>' % self._debug_str()
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _from_msg(cls, msg, filename=None, longname=None):
|
def _from_msg(cls, msg, filename=None, longname=None):
|
||||||
attr = cls()
|
attr = cls()
|
||||||
attr._unpack(msg)
|
attr._unpack(msg)
|
||||||
|
@ -173,7 +171,7 @@ class SFTPAttributes (object):
|
||||||
_rwx = staticmethod(_rwx)
|
_rwx = staticmethod(_rwx)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"create a unix-style long description of the file (like ls -l)"
|
"""create a unix-style long description of the file (like ls -l)"""
|
||||||
if self.st_mode is not None:
|
if self.st_mode is not None:
|
||||||
kind = stat.S_IFMT(self.st_mode)
|
kind = stat.S_IFMT(self.st_mode)
|
||||||
if kind == stat.S_IFIFO:
|
if kind == stat.S_IFIFO:
|
||||||
|
|
|
@ -24,8 +24,18 @@ import stat
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import weakref
|
import weakref
|
||||||
|
from paramiko import util
|
||||||
|
from paramiko.channel import Channel
|
||||||
|
from paramiko.message import Message
|
||||||
|
from paramiko.common import INFO, DEBUG, o777
|
||||||
|
from paramiko.py3compat import bytestring, b, u, long, string_types, bytes_types
|
||||||
|
from paramiko.sftp import BaseSFTP, CMD_OPENDIR, CMD_HANDLE, SFTPError, CMD_READDIR, \
|
||||||
|
CMD_NAME, CMD_CLOSE, SFTP_FLAG_READ, SFTP_FLAG_WRITE, SFTP_FLAG_CREATE, \
|
||||||
|
SFTP_FLAG_TRUNC, SFTP_FLAG_APPEND, SFTP_FLAG_EXCL, CMD_OPEN, CMD_REMOVE, \
|
||||||
|
CMD_RENAME, CMD_MKDIR, CMD_RMDIR, CMD_STAT, CMD_ATTRS, CMD_LSTAT, \
|
||||||
|
CMD_SYMLINK, CMD_SETSTAT, CMD_READLINK, CMD_REALPATH, CMD_STATUS, SFTP_OK, \
|
||||||
|
SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED
|
||||||
|
|
||||||
from paramiko.sftp import *
|
|
||||||
from paramiko.sftp_attr import SFTPAttributes
|
from paramiko.sftp_attr import SFTPAttributes
|
||||||
from paramiko.ssh_exception import SSHException
|
from paramiko.ssh_exception import SSHException
|
||||||
from paramiko.sftp_file import SFTPFile
|
from paramiko.sftp_file import SFTPFile
|
||||||
|
@ -47,6 +57,7 @@ def _to_unicode(s):
|
||||||
|
|
||||||
b_slash = b'/'
|
b_slash = b'/'
|
||||||
|
|
||||||
|
|
||||||
class SFTPClient(BaseSFTP):
|
class SFTPClient(BaseSFTP):
|
||||||
"""
|
"""
|
||||||
SFTP client object.
|
SFTP client object.
|
||||||
|
@ -106,9 +117,9 @@ class SFTPClient(BaseSFTP):
|
||||||
def _log(self, level, msg, *args):
|
def _log(self, level, msg, *args):
|
||||||
if isinstance(msg, list):
|
if isinstance(msg, list):
|
||||||
for m in msg:
|
for m in msg:
|
||||||
super(SFTPClient, self)._log(level, "[chan %s] " + m, *([ self.sock.get_name() ] + list(args)))
|
super(SFTPClient, self)._log(level, "[chan %s] " + m, *([self.sock.get_name()] + list(args)))
|
||||||
else:
|
else:
|
||||||
super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([ self.sock.get_name() ] + list(args)))
|
super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([self.sock.get_name()] + list(args)))
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
|
@ -222,11 +233,11 @@ class SFTPClient(BaseSFTP):
|
||||||
imode |= SFTP_FLAG_READ
|
imode |= SFTP_FLAG_READ
|
||||||
if ('w' in mode) or ('+' in mode) or ('a' in mode):
|
if ('w' in mode) or ('+' in mode) or ('a' in mode):
|
||||||
imode |= SFTP_FLAG_WRITE
|
imode |= SFTP_FLAG_WRITE
|
||||||
if ('w' in mode):
|
if 'w' in mode:
|
||||||
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC
|
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC
|
||||||
if ('a' in mode):
|
if 'a' in mode:
|
||||||
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_APPEND
|
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_APPEND
|
||||||
if ('x' in mode):
|
if 'x' in mode:
|
||||||
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_EXCL
|
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_EXCL
|
||||||
attrblock = SFTPAttributes()
|
attrblock = SFTPAttributes()
|
||||||
t, msg = self._request(CMD_OPEN, filename, imode, attrblock)
|
t, msg = self._request(CMD_OPEN, filename, imode, attrblock)
|
||||||
|
@ -629,10 +640,8 @@ class SFTPClient(BaseSFTP):
|
||||||
if s.st_size != size:
|
if s.st_size != size:
|
||||||
raise IOError('size mismatch in get! %d != %d' % (s.st_size, size))
|
raise IOError('size mismatch in get! %d != %d' % (s.st_size, size))
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _request(self, t, *arg):
|
def _request(self, t, *arg):
|
||||||
num = self._async_request(type(None), t, *arg)
|
num = self._async_request(type(None), t, *arg)
|
||||||
return self._read_response(num)
|
return self._read_response(num)
|
||||||
|
@ -689,7 +698,7 @@ class SFTPClient(BaseSFTP):
|
||||||
if waitfor is None:
|
if waitfor is None:
|
||||||
# just doing a single check
|
# just doing a single check
|
||||||
break
|
break
|
||||||
return (None, None)
|
return None, None
|
||||||
|
|
||||||
def _finish_responses(self, fileobj):
|
def _finish_responses(self, fileobj):
|
||||||
while fileobj in self._expecting.values():
|
while fileobj in self._expecting.values():
|
||||||
|
|
|
@ -27,10 +27,12 @@ from collections import deque
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from paramiko.common import DEBUG
|
||||||
|
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko.sftp import *
|
|
||||||
from paramiko.file import BufferedFile
|
from paramiko.file import BufferedFile
|
||||||
|
from paramiko.py3compat import long
|
||||||
|
from paramiko.sftp import CMD_CLOSE, CMD_READ, CMD_DATA, SFTPError, CMD_WRITE, \
|
||||||
|
CMD_STATUS, CMD_FSTAT, CMD_ATTRS, CMD_FSETSTAT, CMD_EXTENDED
|
||||||
from paramiko.sftp_attr import SFTPAttributes
|
from paramiko.sftp_attr import SFTPAttributes
|
||||||
|
|
||||||
|
|
||||||
|
@ -438,10 +440,8 @@ class SFTPFile (BufferedFile):
|
||||||
self.seek(x[0])
|
self.seek(x[0])
|
||||||
yield self.read(x[1])
|
yield self.read(x[1])
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _get_size(self):
|
def _get_size(self):
|
||||||
try:
|
try:
|
||||||
return self.stat().st_size
|
return self.stat().st_size
|
||||||
|
@ -483,7 +483,7 @@ class SFTPFile (BufferedFile):
|
||||||
self._prefetch_done = True
|
self._prefetch_done = True
|
||||||
|
|
||||||
def _check_exception(self):
|
def _check_exception(self):
|
||||||
"if there's a saved exception, raise & clear it"
|
"""if there's a saved exception, raise & clear it"""
|
||||||
if self._saved_exception is not None:
|
if self._saved_exception is not None:
|
||||||
x = self._saved_exception
|
x = self._saved_exception
|
||||||
self._saved_exception = None
|
self._saved_exception = None
|
||||||
|
|
|
@ -21,9 +21,7 @@ Abstraction of an SFTP file handle (for server mode).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from paramiko.sftp import SFTP_OP_UNSUPPORTED, SFTP_OK
|
||||||
from paramiko.common import *
|
|
||||||
from paramiko.sftp import *
|
|
||||||
|
|
||||||
|
|
||||||
class SFTPHandle (object):
|
class SFTPHandle (object):
|
||||||
|
@ -46,7 +44,7 @@ class SFTPHandle (object):
|
||||||
self.__flags = flags
|
self.__flags = flags
|
||||||
self.__name = None
|
self.__name = None
|
||||||
# only for handles to folders:
|
# only for handles to folders:
|
||||||
self.__files = { }
|
self.__files = {}
|
||||||
self.__tell = None
|
self.__tell = None
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
@ -166,10 +164,8 @@ class SFTPHandle (object):
|
||||||
"""
|
"""
|
||||||
return SFTP_OP_UNSUPPORTED
|
return SFTP_OP_UNSUPPORTED
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _set_files(self, files):
|
def _set_files(self, files):
|
||||||
"""
|
"""
|
||||||
Used by the SFTP server code to cache a directory listing. (In
|
Used by the SFTP server code to cache a directory listing. (In
|
||||||
|
|
|
@ -24,14 +24,26 @@ import os
|
||||||
import errno
|
import errno
|
||||||
|
|
||||||
from Crypto.Hash import MD5, SHA
|
from Crypto.Hash import MD5, SHA
|
||||||
from paramiko.common import *
|
import sys
|
||||||
|
from paramiko import util
|
||||||
|
from paramiko.sftp import BaseSFTP, Message, SFTP_FAILURE, \
|
||||||
|
SFTP_PERMISSION_DENIED, SFTP_NO_SUCH_FILE
|
||||||
|
from paramiko.sftp_si import SFTPServerInterface
|
||||||
|
from paramiko.sftp_attr import SFTPAttributes
|
||||||
|
from paramiko.common import DEBUG
|
||||||
|
from paramiko.py3compat import long, string_types, bytes_types, b
|
||||||
from paramiko.server import SubsystemHandler
|
from paramiko.server import SubsystemHandler
|
||||||
from paramiko.sftp import *
|
|
||||||
from paramiko.sftp_si import *
|
|
||||||
from paramiko.sftp_attr import *
|
|
||||||
|
|
||||||
|
|
||||||
# known hash algorithms for the "check-file" extension
|
# known hash algorithms for the "check-file" extension
|
||||||
|
from paramiko.sftp import CMD_HANDLE, SFTP_DESC, CMD_STATUS, SFTP_EOF, CMD_NAME, \
|
||||||
|
SFTP_BAD_MESSAGE, CMD_EXTENDED_REPLY, SFTP_FLAG_READ, SFTP_FLAG_WRITE, \
|
||||||
|
SFTP_FLAG_APPEND, SFTP_FLAG_CREATE, SFTP_FLAG_TRUNC, SFTP_FLAG_EXCL, \
|
||||||
|
CMD_NAMES, CMD_OPEN, CMD_CLOSE, SFTP_OK, CMD_READ, CMD_DATA, CMD_WRITE, \
|
||||||
|
CMD_REMOVE, CMD_RENAME, CMD_MKDIR, CMD_RMDIR, CMD_OPENDIR, CMD_READDIR, \
|
||||||
|
CMD_STAT, CMD_ATTRS, CMD_LSTAT, CMD_FSTAT, CMD_SETSTAT, CMD_FSETSTAT, \
|
||||||
|
CMD_READLINK, CMD_SYMLINK, CMD_REALPATH, CMD_EXTENDED, SFTP_OP_UNSUPPORTED
|
||||||
|
|
||||||
_hash_class = {
|
_hash_class = {
|
||||||
'sha1': SHA,
|
'sha1': SHA,
|
||||||
'md5': MD5,
|
'md5': MD5,
|
||||||
|
@ -67,8 +79,8 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
|
||||||
self.ultra_debug = transport.get_hexdump()
|
self.ultra_debug = transport.get_hexdump()
|
||||||
self.next_handle = 1
|
self.next_handle = 1
|
||||||
# map of handle-string to SFTPHandle for files & folders:
|
# map of handle-string to SFTPHandle for files & folders:
|
||||||
self.file_table = { }
|
self.file_table = {}
|
||||||
self.folder_table = { }
|
self.folder_table = {}
|
||||||
self.server = sftp_si(server, *largs, **kwargs)
|
self.server = sftp_si(server, *largs, **kwargs)
|
||||||
|
|
||||||
def _log(self, level, msg):
|
def _log(self, level, msg):
|
||||||
|
@ -163,10 +175,8 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
|
||||||
f.truncate(attr.st_size)
|
f.truncate(attr.st_size)
|
||||||
set_file_attr = staticmethod(set_file_attr)
|
set_file_attr = staticmethod(set_file_attr)
|
||||||
|
|
||||||
|
|
||||||
### internals...
|
### internals...
|
||||||
|
|
||||||
|
|
||||||
def _response(self, request_number, t, *arg):
|
def _response(self, request_number, t, *arg):
|
||||||
msg = Message()
|
msg = Message()
|
||||||
msg.add_int(request_number)
|
msg.add_int(request_number)
|
||||||
|
@ -290,7 +300,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
|
||||||
self._send_packet(CMD_EXTENDED_REPLY, msg)
|
self._send_packet(CMD_EXTENDED_REPLY, msg)
|
||||||
|
|
||||||
def _convert_pflags(self, pflags):
|
def _convert_pflags(self, pflags):
|
||||||
"convert SFTP-style open() flags to Python's os.open() flags"
|
"""convert SFTP-style open() flags to Python's os.open() flags"""
|
||||||
if (pflags & SFTP_FLAG_READ) and (pflags & SFTP_FLAG_WRITE):
|
if (pflags & SFTP_FLAG_READ) and (pflags & SFTP_FLAG_WRITE):
|
||||||
flags = os.O_RDWR
|
flags = os.O_RDWR
|
||||||
elif pflags & SFTP_FLAG_WRITE:
|
elif pflags & SFTP_FLAG_WRITE:
|
||||||
|
|
|
@ -21,9 +21,8 @@ An interface to override for SFTP server support.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from paramiko.common import *
|
from paramiko.sftp import SFTP_OP_UNSUPPORTED
|
||||||
from paramiko.sftp import *
|
|
||||||
|
|
||||||
|
|
||||||
class SFTPServerInterface (object):
|
class SFTPServerInterface (object):
|
||||||
|
@ -41,7 +40,7 @@ class SFTPServerInterface (object):
|
||||||
clients & servers obey the requirement that paths be encoded in UTF-8.
|
clients & servers obey the requirement that paths be encoded in UTF-8.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__ (self, server, *largs, **kwargs):
|
def __init__(self, server, *largs, **kwargs):
|
||||||
"""
|
"""
|
||||||
Create a new SFTPServerInterface object. This method does nothing by
|
Create a new SFTPServerInterface object. This method does nothing by
|
||||||
default and is meant to be overridden by subclasses.
|
default and is meant to be overridden by subclasses.
|
||||||
|
|
|
@ -20,10 +20,7 @@
|
||||||
Core protocol implementation
|
Core protocol implementation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
|
||||||
import socket
|
import socket
|
||||||
import string
|
|
||||||
import struct
|
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
@ -33,7 +30,17 @@ import paramiko
|
||||||
from paramiko import util
|
from paramiko import util
|
||||||
from paramiko.auth_handler import AuthHandler
|
from paramiko.auth_handler import AuthHandler
|
||||||
from paramiko.channel import Channel
|
from paramiko.channel import Channel
|
||||||
from paramiko.common import * # Legit, uses dozens of constants & funcs
|
from paramiko.common import rng, xffffffff, cMSG_CHANNEL_OPEN, cMSG_IGNORE, \
|
||||||
|
cMSG_GLOBAL_REQUEST, DEBUG, MSG_KEXINIT, MSG_IGNORE, MSG_DISCONNECT, \
|
||||||
|
MSG_DEBUG, ERROR, WARNING, cMSG_UNIMPLEMENTED, INFO, cMSG_KEXINIT, \
|
||||||
|
cMSG_NEWKEYS, MSG_NEWKEYS, cMSG_REQUEST_SUCCESS, cMSG_REQUEST_FAILURE, \
|
||||||
|
CONNECTION_FAILED_CODE, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, \
|
||||||
|
OPEN_SUCCEEDED, cMSG_CHANNEL_OPEN_FAILURE, cMSG_CHANNEL_OPEN_SUCCESS, \
|
||||||
|
MSG_GLOBAL_REQUEST, MSG_REQUEST_SUCCESS, MSG_REQUEST_FAILURE, \
|
||||||
|
MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, MSG_CHANNEL_OPEN, \
|
||||||
|
MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE, MSG_CHANNEL_DATA, \
|
||||||
|
MSG_CHANNEL_EXTENDED_DATA, MSG_CHANNEL_WINDOW_ADJUST, MSG_CHANNEL_REQUEST, \
|
||||||
|
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE
|
||||||
from paramiko.compress import ZlibCompressor, ZlibDecompressor
|
from paramiko.compress import ZlibCompressor, ZlibDecompressor
|
||||||
from paramiko.dsskey import DSSKey
|
from paramiko.dsskey import DSSKey
|
||||||
from paramiko.kex_gex import KexGex
|
from paramiko.kex_gex import KexGex
|
||||||
|
@ -41,12 +48,13 @@ from paramiko.kex_group1 import KexGroup1
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
from paramiko.packet import Packetizer, NeedRekeyException
|
from paramiko.packet import Packetizer, NeedRekeyException
|
||||||
from paramiko.primes import ModulusPack
|
from paramiko.primes import ModulusPack
|
||||||
|
from paramiko.py3compat import string_types, long, byte_ord, b
|
||||||
from paramiko.rsakey import RSAKey
|
from paramiko.rsakey import RSAKey
|
||||||
from paramiko.ecdsakey import ECDSAKey
|
from paramiko.ecdsakey import ECDSAKey
|
||||||
from paramiko.server import ServerInterface
|
from paramiko.server import ServerInterface
|
||||||
from paramiko.sftp_client import SFTPClient
|
from paramiko.sftp_client import SFTPClient
|
||||||
from paramiko.ssh_exception import (SSHException, BadAuthenticationType,
|
from paramiko.ssh_exception import (SSHException, BadAuthenticationType,
|
||||||
ChannelException, ProxyCommandFailure)
|
ChannelException, ProxyCommandFailure)
|
||||||
from paramiko.util import retry_on_signal
|
from paramiko.util import retry_on_signal
|
||||||
|
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
|
@ -60,9 +68,11 @@ except ImportError:
|
||||||
|
|
||||||
# for thread cleanup
|
# for thread cleanup
|
||||||
_active_threads = []
|
_active_threads = []
|
||||||
|
|
||||||
def _join_lingering_threads():
|
def _join_lingering_threads():
|
||||||
for thr in _active_threads:
|
for thr in _active_threads:
|
||||||
thr.stop_thread()
|
thr.stop_thread()
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
atexit.register(_join_lingering_threads)
|
atexit.register(_join_lingering_threads)
|
||||||
|
|
||||||
|
@ -76,54 +86,53 @@ class Transport (threading.Thread):
|
||||||
forwardings).
|
forwardings).
|
||||||
"""
|
"""
|
||||||
_PROTO_ID = '2.0'
|
_PROTO_ID = '2.0'
|
||||||
_CLIENT_ID = 'paramiko_%s' % (paramiko.__version__)
|
_CLIENT_ID = 'paramiko_%s' % paramiko.__version__
|
||||||
|
|
||||||
_preferred_ciphers = ( 'aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc', 'aes256-cbc', '3des-cbc',
|
_preferred_ciphers = ('aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc',
|
||||||
'arcfour128', 'arcfour256' )
|
'aes256-cbc', '3des-cbc', 'arcfour128', 'arcfour256')
|
||||||
_preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' )
|
_preferred_macs = ('hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96')
|
||||||
_preferred_keys = ( 'ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256' )
|
_preferred_keys = ('ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256')
|
||||||
_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},
|
||||||
'blowfish-cbc': { 'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16 },
|
'blowfish-cbc': {'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16},
|
||||||
'aes128-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16 },
|
'aes128-cbc': {'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16},
|
||||||
'aes256-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32 },
|
'aes256-cbc': {'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32},
|
||||||
'3des-cbc': { 'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24 },
|
'3des-cbc': {'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24},
|
||||||
'arcfour128': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16 },
|
'arcfour128': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16},
|
||||||
'arcfour256': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32 },
|
'arcfour256': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32},
|
||||||
}
|
}
|
||||||
|
|
||||||
_mac_info = {
|
_mac_info = {
|
||||||
'hmac-sha1': { 'class': SHA, 'size': 20 },
|
'hmac-sha1': {'class': SHA, 'size': 20},
|
||||||
'hmac-sha1-96': { 'class': SHA, 'size': 12 },
|
'hmac-sha1-96': {'class': SHA, 'size': 12},
|
||||||
'hmac-md5': { 'class': MD5, 'size': 16 },
|
'hmac-md5': {'class': MD5, 'size': 16},
|
||||||
'hmac-md5-96': { 'class': MD5, 'size': 12 },
|
'hmac-md5-96': {'class': MD5, 'size': 12},
|
||||||
}
|
}
|
||||||
|
|
||||||
_key_info = {
|
_key_info = {
|
||||||
'ssh-rsa': RSAKey,
|
'ssh-rsa': RSAKey,
|
||||||
'ssh-dss': DSSKey,
|
'ssh-dss': DSSKey,
|
||||||
'ecdsa-sha2-nistp256': ECDSAKey,
|
'ecdsa-sha2-nistp256': ECDSAKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
_kex_info = {
|
_kex_info = {
|
||||||
'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
|
||||||
# they've had troubles with security holes in zlib in the past.
|
# they've had troubles with security holes in zlib in the past.
|
||||||
'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ),
|
'zlib@openssh.com': (ZlibCompressor, ZlibDecompressor),
|
||||||
'zlib': ( ZlibCompressor, ZlibDecompressor ),
|
'zlib': (ZlibCompressor, ZlibDecompressor),
|
||||||
'none': ( None, None ),
|
'none': (None, None),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_modulus_pack = None
|
_modulus_pack = None
|
||||||
|
|
||||||
def __init__(self, sock):
|
def __init__(self, sock):
|
||||||
|
@ -220,8 +229,8 @@ class Transport (threading.Thread):
|
||||||
|
|
||||||
# tracking open channels
|
# tracking open channels
|
||||||
self._channels = ChannelMap()
|
self._channels = ChannelMap()
|
||||||
self.channel_events = { } # (id -> Event)
|
self.channel_events = {} # (id -> Event)
|
||||||
self.channels_seen = { } # (id -> True)
|
self.channels_seen = {} # (id -> True)
|
||||||
self._channel_counter = 1
|
self._channel_counter = 1
|
||||||
self.window_size = 65536
|
self.window_size = 65536
|
||||||
self.max_packet_size = 34816
|
self.max_packet_size = 34816
|
||||||
|
@ -244,10 +253,10 @@ class Transport (threading.Thread):
|
||||||
# server mode:
|
# server mode:
|
||||||
self.server_mode = False
|
self.server_mode = False
|
||||||
self.server_object = None
|
self.server_object = None
|
||||||
self.server_key_dict = { }
|
self.server_key_dict = {}
|
||||||
self.server_accepts = [ ]
|
self.server_accepts = []
|
||||||
self.server_accept_cv = threading.Condition(self.lock)
|
self.server_accept_cv = threading.Condition(self.lock)
|
||||||
self.subsystem_table = { }
|
self.subsystem_table = {}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""
|
"""
|
||||||
|
@ -468,7 +477,7 @@ class Transport (threading.Thread):
|
||||||
"""
|
"""
|
||||||
Transport._modulus_pack = ModulusPack(rng)
|
Transport._modulus_pack = ModulusPack(rng)
|
||||||
# places to look for the openssh "moduli" file
|
# places to look for the openssh "moduli" file
|
||||||
file_list = [ '/etc/ssh/moduli', '/usr/local/etc/moduli' ]
|
file_list = ['/etc/ssh/moduli', '/usr/local/etc/moduli']
|
||||||
if filename is not None:
|
if filename is not None:
|
||||||
file_list.insert(0, filename)
|
file_list.insert(0, filename)
|
||||||
for fn in file_list:
|
for fn in file_list:
|
||||||
|
@ -623,7 +632,7 @@ class Transport (threading.Thread):
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
self._send_user_message(m)
|
self._send_user_message(m)
|
||||||
while True:
|
while True:
|
||||||
event.wait(0.1);
|
event.wait(0.1)
|
||||||
if not self.active:
|
if not self.active:
|
||||||
e = self.get_exception()
|
e = self.get_exception()
|
||||||
if e is None:
|
if e is None:
|
||||||
|
@ -764,7 +773,7 @@ class Transport (threading.Thread):
|
||||||
0 to disable keepalives).
|
0 to disable keepalives).
|
||||||
"""
|
"""
|
||||||
self.packetizer.set_keepalive(interval,
|
self.packetizer.set_keepalive(interval,
|
||||||
lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False))
|
lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False))
|
||||||
|
|
||||||
def global_request(self, kind, data=None, wait=True):
|
def global_request(self, kind, data=None, wait=True):
|
||||||
"""
|
"""
|
||||||
|
@ -863,12 +872,12 @@ class Transport (threading.Thread):
|
||||||
supplied by the server is incorrect, or authentication fails.
|
supplied by the server is incorrect, or authentication fails.
|
||||||
"""
|
"""
|
||||||
if hostkey is not None:
|
if hostkey is not None:
|
||||||
self._preferred_keys = [ hostkey.get_name() ]
|
self._preferred_keys = [hostkey.get_name()]
|
||||||
|
|
||||||
self.start_client()
|
self.start_client()
|
||||||
|
|
||||||
# check host key if we were given one
|
# check host key if we were given one
|
||||||
if (hostkey is not None):
|
if hostkey is not None:
|
||||||
key = self.get_remote_server_key()
|
key = self.get_remote_server_key()
|
||||||
if (key.get_name() != hostkey.get_name()) or (key.asbytes() != hostkey.asbytes()):
|
if (key.get_name() != hostkey.get_name()) or (key.asbytes() != hostkey.asbytes()):
|
||||||
self._log(DEBUG, 'Bad host key from server')
|
self._log(DEBUG, 'Bad host key from server')
|
||||||
|
@ -1061,12 +1070,11 @@ class Transport (threading.Thread):
|
||||||
# to try to fake out automated scripting of the exact
|
# to try to fake out automated scripting of the exact
|
||||||
# type we're doing here. *shrug* :)
|
# type we're doing here. *shrug* :)
|
||||||
return []
|
return []
|
||||||
return [ password ]
|
return [password]
|
||||||
return self.auth_interactive(username, handler)
|
return self.auth_interactive(username, handler)
|
||||||
except SSHException:
|
except SSHException:
|
||||||
# attempt failed; just raise the original exception
|
# attempt failed; just raise the original exception
|
||||||
raise e
|
raise e
|
||||||
return None
|
|
||||||
|
|
||||||
def auth_publickey(self, username, key, event=None):
|
def auth_publickey(self, username, key, event=None):
|
||||||
"""
|
"""
|
||||||
|
@ -1227,9 +1235,9 @@ class Transport (threading.Thread):
|
||||||
.. versionadded:: 1.5.2
|
.. versionadded:: 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):
|
||||||
"""
|
"""
|
||||||
|
@ -1244,7 +1252,7 @@ class Transport (threading.Thread):
|
||||||
"""
|
"""
|
||||||
gp = getattr(self.sock, 'getpeername', None)
|
gp = getattr(self.sock, 'getpeername', None)
|
||||||
if gp is None:
|
if gp is None:
|
||||||
return ('unknown', 0)
|
return 'unknown', 0
|
||||||
return gp()
|
return gp()
|
||||||
|
|
||||||
def stop_thread(self):
|
def stop_thread(self):
|
||||||
|
@ -1253,10 +1261,8 @@ class Transport (threading.Thread):
|
||||||
while self.isAlive():
|
while self.isAlive():
|
||||||
self.join(10)
|
self.join(10)
|
||||||
|
|
||||||
|
|
||||||
### 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:
|
||||||
|
@ -1265,11 +1271,11 @@ class Transport (threading.Thread):
|
||||||
self.logger.log(level, msg, *args)
|
self.logger.log(level, msg, *args)
|
||||||
|
|
||||||
def _get_modulus_pack(self):
|
def _get_modulus_pack(self):
|
||||||
"used by KexGex to find primes for group exchange"
|
"""used by KexGex to find primes for group exchange"""
|
||||||
return self._modulus_pack
|
return self._modulus_pack
|
||||||
|
|
||||||
def _next_channel(self):
|
def _next_channel(self):
|
||||||
"you are holding the lock"
|
"""you are holding the lock"""
|
||||||
chanid = self._channel_counter
|
chanid = self._channel_counter
|
||||||
while self._channels.get(chanid) is not None:
|
while self._channels.get(chanid) is not None:
|
||||||
self._channel_counter = (self._channel_counter + 1) & 0xffffff
|
self._channel_counter = (self._channel_counter + 1) & 0xffffff
|
||||||
|
@ -1278,7 +1284,7 @@ class Transport (threading.Thread):
|
||||||
return chanid
|
return chanid
|
||||||
|
|
||||||
def _unlink_channel(self, chanid):
|
def _unlink_channel(self, chanid):
|
||||||
"used by a Channel to remove itself from the active channel list"
|
"""used by a Channel to remove itself from the active channel list"""
|
||||||
self._channels.delete(chanid)
|
self._channels.delete(chanid)
|
||||||
|
|
||||||
def _send_message(self, data):
|
def _send_message(self, data):
|
||||||
|
@ -1307,14 +1313,14 @@ class Transport (threading.Thread):
|
||||||
self.clear_to_send_lock.release()
|
self.clear_to_send_lock.release()
|
||||||
|
|
||||||
def _set_K_H(self, k, h):
|
def _set_K_H(self, k, h):
|
||||||
"used by a kex object to set the K (root key) and H (exchange hash)"
|
"""used by a kex object to set the K (root key) and H (exchange hash)"""
|
||||||
self.K = k
|
self.K = k
|
||||||
self.H = h
|
self.H = h
|
||||||
if self.session_id == None:
|
if self.session_id is None:
|
||||||
self.session_id = h
|
self.session_id = h
|
||||||
|
|
||||||
def _expect_packet(self, *ptypes):
|
def _expect_packet(self, *ptypes):
|
||||||
"used by a kex object to register the next packet type it expects to see"
|
"""used by a kex object to register the next packet type it expects to see"""
|
||||||
self._expected_packet = tuple(ptypes)
|
self._expected_packet = tuple(ptypes)
|
||||||
|
|
||||||
def _verify_key(self, host_key, sig):
|
def _verify_key(self, host_key, sig):
|
||||||
|
@ -1326,7 +1332,7 @@ class Transport (threading.Thread):
|
||||||
self.host_key = key
|
self.host_key = key
|
||||||
|
|
||||||
def _compute_key(self, id, nbytes):
|
def _compute_key(self, id, nbytes):
|
||||||
"id is 'A' - 'F' for the various keys used by ssh"
|
"""id is 'A' - 'F' for the various keys used by ssh"""
|
||||||
m = Message()
|
m = Message()
|
||||||
m.add_mpint(self.K)
|
m.add_mpint(self.K)
|
||||||
m.add_bytes(self.H)
|
m.add_bytes(self.H)
|
||||||
|
@ -1471,7 +1477,7 @@ class Transport (threading.Thread):
|
||||||
if type(e.args) is tuple:
|
if type(e.args) is tuple:
|
||||||
if e.args:
|
if e.args:
|
||||||
emsg = '%s (%d)' % (e.args[1], e.args[0])
|
emsg = '%s (%d)' % (e.args[1], e.args[0])
|
||||||
else: # empty tuple, e.g. socket.timeout
|
else: # empty tuple, e.g. socket.timeout
|
||||||
emsg = str(e) or repr(e)
|
emsg = str(e) or repr(e)
|
||||||
else:
|
else:
|
||||||
emsg = e.args
|
emsg = e.args
|
||||||
|
@ -1487,7 +1493,7 @@ class Transport (threading.Thread):
|
||||||
if self.active:
|
if self.active:
|
||||||
self.active = False
|
self.active = False
|
||||||
self.packetizer.close()
|
self.packetizer.close()
|
||||||
if self.completion_event != None:
|
if self.completion_event is not None:
|
||||||
self.completion_event.set()
|
self.completion_event.set()
|
||||||
if self.auth_handler is not None:
|
if self.auth_handler is not None:
|
||||||
self.auth_handler.abort()
|
self.auth_handler.abort()
|
||||||
|
@ -1507,10 +1513,8 @@ class Transport (threading.Thread):
|
||||||
if self.sys.modules is not None:
|
if self.sys.modules is not None:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
### protocol stages
|
### protocol stages
|
||||||
|
|
||||||
|
|
||||||
def _negotiate_keys(self, m):
|
def _negotiate_keys(self, m):
|
||||||
# throws SSHException on anything unusual
|
# throws SSHException on anything unusual
|
||||||
self.clear_to_send_lock.acquire()
|
self.clear_to_send_lock.acquire()
|
||||||
|
@ -1518,7 +1522,7 @@ class Transport (threading.Thread):
|
||||||
self.clear_to_send.clear()
|
self.clear_to_send.clear()
|
||||||
finally:
|
finally:
|
||||||
self.clear_to_send_lock.release()
|
self.clear_to_send_lock.release()
|
||||||
if self.local_kex_init == None:
|
if self.local_kex_init is None:
|
||||||
# remote side wants to renegotiate
|
# remote side wants to renegotiate
|
||||||
self._send_kex_init()
|
self._send_kex_init()
|
||||||
self._parse_kex_init(m)
|
self._parse_kex_init(m)
|
||||||
|
@ -1580,7 +1584,7 @@ class Transport (threading.Thread):
|
||||||
pkex.remove('diffie-hellman-group-exchange-sha1')
|
pkex.remove('diffie-hellman-group-exchange-sha1')
|
||||||
self.get_security_options().kex = pkex
|
self.get_security_options().kex = pkex
|
||||||
available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
|
available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
|
||||||
self._preferred_keys))
|
self._preferred_keys))
|
||||||
else:
|
else:
|
||||||
available_server_keys = self._preferred_keys
|
available_server_keys = self._preferred_keys
|
||||||
|
|
||||||
|
@ -1618,15 +1622,15 @@ class Transport (threading.Thread):
|
||||||
kex_follows = m.get_boolean()
|
kex_follows = m.get_boolean()
|
||||||
unused = m.get_int()
|
unused = m.get_int()
|
||||||
|
|
||||||
self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) + \
|
self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) +
|
||||||
' client encrypt:' + str(client_encrypt_algo_list) + \
|
' client encrypt:' + str(client_encrypt_algo_list) +
|
||||||
' server encrypt:' + str(server_encrypt_algo_list) + \
|
' server encrypt:' + str(server_encrypt_algo_list) +
|
||||||
' client mac:' + str(client_mac_algo_list) + \
|
' client mac:' + str(client_mac_algo_list) +
|
||||||
' server mac:' + str(server_mac_algo_list) + \
|
' server mac:' + str(server_mac_algo_list) +
|
||||||
' client compress:' + str(client_compress_algo_list) + \
|
' client compress:' + str(client_compress_algo_list) +
|
||||||
' server compress:' + str(server_compress_algo_list) + \
|
' server compress:' + str(server_compress_algo_list) +
|
||||||
' client lang:' + str(client_lang_list) + \
|
' client lang:' + str(client_lang_list) +
|
||||||
' server lang:' + str(server_lang_list) + \
|
' server lang:' + str(server_lang_list) +
|
||||||
' kex follows?' + str(kex_follows))
|
' kex follows?' + str(kex_follows))
|
||||||
|
|
||||||
# as a server, we pick the first item in the client's list that we support.
|
# as a server, we pick the first item in the client's list that we support.
|
||||||
|
@ -1641,7 +1645,7 @@ class Transport (threading.Thread):
|
||||||
|
|
||||||
if self.server_mode:
|
if self.server_mode:
|
||||||
available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
|
available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
|
||||||
self._preferred_keys))
|
self._preferred_keys))
|
||||||
agreed_keys = list(filter(available_server_keys.__contains__, server_key_algo_list))
|
agreed_keys = list(filter(available_server_keys.__contains__, server_key_algo_list))
|
||||||
else:
|
else:
|
||||||
agreed_keys = list(filter(server_key_algo_list.__contains__, self._preferred_keys))
|
agreed_keys = list(filter(server_key_algo_list.__contains__, self._preferred_keys))
|
||||||
|
@ -1701,7 +1705,7 @@ class Transport (threading.Thread):
|
||||||
self.remote_kex_init = cMSG_KEXINIT + m.get_so_far()
|
self.remote_kex_init = cMSG_KEXINIT + m.get_so_far()
|
||||||
|
|
||||||
def _activate_inbound(self):
|
def _activate_inbound(self):
|
||||||
"switch on newly negotiated encryption parameters for inbound traffic"
|
"""switch on newly negotiated encryption parameters for inbound traffic"""
|
||||||
block_size = self._cipher_info[self.remote_cipher]['block-size']
|
block_size = self._cipher_info[self.remote_cipher]['block-size']
|
||||||
if self.server_mode:
|
if self.server_mode:
|
||||||
IV_in = self._compute_key('A', block_size)
|
IV_in = self._compute_key('A', block_size)
|
||||||
|
@ -1725,7 +1729,7 @@ class Transport (threading.Thread):
|
||||||
self.packetizer.set_inbound_compressor(compress_in())
|
self.packetizer.set_inbound_compressor(compress_in())
|
||||||
|
|
||||||
def _activate_outbound(self):
|
def _activate_outbound(self):
|
||||||
"switch on newly negotiated encryption parameters for outbound traffic"
|
"""switch on newly negotiated encryption parameters for outbound traffic"""
|
||||||
m = Message()
|
m = Message()
|
||||||
m.add_byte(cMSG_NEWKEYS)
|
m.add_byte(cMSG_NEWKEYS)
|
||||||
self._send_message(m)
|
self._send_message(m)
|
||||||
|
@ -1782,7 +1786,7 @@ class Transport (threading.Thread):
|
||||||
# this was the first key exchange
|
# this was the first key exchange
|
||||||
self.initial_kex_done = True
|
self.initial_kex_done = True
|
||||||
# send an event?
|
# send an event?
|
||||||
if self.completion_event != None:
|
if self.completion_event is not None:
|
||||||
self.completion_event.set()
|
self.completion_event.set()
|
||||||
# it's now okay to send data again (if this was a re-key)
|
# it's now okay to send data again (if this was a re-key)
|
||||||
if not self.packetizer.need_rekey():
|
if not self.packetizer.need_rekey():
|
||||||
|
@ -1810,7 +1814,7 @@ class Transport (threading.Thread):
|
||||||
address = m.get_text()
|
address = m.get_text()
|
||||||
port = m.get_int()
|
port = m.get_int()
|
||||||
ok = self.server_object.check_port_forward_request(address, port)
|
ok = self.server_object.check_port_forward_request(address, port)
|
||||||
if ok != False:
|
if ok:
|
||||||
ok = (ok,)
|
ok = (ok,)
|
||||||
elif kind == 'cancel-tcpip-forward':
|
elif kind == 'cancel-tcpip-forward':
|
||||||
address = m.get_text()
|
address = m.get_text()
|
||||||
|
@ -1933,8 +1937,7 @@ class Transport (threading.Thread):
|
||||||
origin_addr = m.get_text()
|
origin_addr = m.get_text()
|
||||||
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)
|
||||||
if reason != OPEN_SUCCEEDED:
|
if reason != OPEN_SUCCEEDED:
|
||||||
|
@ -1988,7 +1991,7 @@ class Transport (threading.Thread):
|
||||||
try:
|
try:
|
||||||
self.lock.acquire()
|
self.lock.acquire()
|
||||||
if name not in self.subsystem_table:
|
if name not in self.subsystem_table:
|
||||||
return (None, [], {})
|
return None, [], {}
|
||||||
return self.subsystem_table[name]
|
return self.subsystem_table[name]
|
||||||
finally:
|
finally:
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
|
@ -2002,7 +2005,7 @@ class Transport (threading.Thread):
|
||||||
MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
|
MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
|
||||||
MSG_CHANNEL_OPEN: _parse_channel_open,
|
MSG_CHANNEL_OPEN: _parse_channel_open,
|
||||||
MSG_KEXINIT: _negotiate_keys,
|
MSG_KEXINIT: _negotiate_keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
_channel_handler_table = {
|
_channel_handler_table = {
|
||||||
MSG_CHANNEL_SUCCESS: Channel._request_success,
|
MSG_CHANNEL_SUCCESS: Channel._request_success,
|
||||||
|
@ -2013,7 +2016,7 @@ class Transport (threading.Thread):
|
||||||
MSG_CHANNEL_REQUEST: Channel._handle_request,
|
MSG_CHANNEL_REQUEST: Channel._handle_request,
|
||||||
MSG_CHANNEL_EOF: Channel._handle_eof,
|
MSG_CHANNEL_EOF: Channel._handle_eof,
|
||||||
MSG_CHANNEL_CLOSE: Channel._handle_close,
|
MSG_CHANNEL_CLOSE: Channel._handle_close,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SecurityOptions (object):
|
class SecurityOptions (object):
|
||||||
|
|
|
@ -29,25 +29,15 @@ import sys
|
||||||
import struct
|
import struct
|
||||||
import traceback
|
import traceback
|
||||||
import threading
|
import threading
|
||||||
|
import logging
|
||||||
|
|
||||||
from paramiko.common import PY2, DEBUG, long, zero_byte, byte_ord, xffffffff, logging, b, max_byte
|
from paramiko.common import DEBUG, zero_byte, xffffffff, max_byte
|
||||||
|
from paramiko.py3compat import PY2, long, byte_ord, b, byte_chr
|
||||||
from paramiko.config import SSHConfig
|
from paramiko.config import SSHConfig
|
||||||
|
|
||||||
|
|
||||||
# Change by RogerB - Python < 2.3 doesn't have enumerate so we implement it
|
|
||||||
if sys.version_info < (2,3):
|
|
||||||
class enumerate:
|
|
||||||
def __init__ (self, sequence):
|
|
||||||
self.sequence = sequence
|
|
||||||
def __iter__ (self):
|
|
||||||
count = 0
|
|
||||||
for item in self.sequence:
|
|
||||||
yield (count, item)
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
|
|
||||||
def inflate_long(s, always_positive=False):
|
def inflate_long(s, always_positive=False):
|
||||||
"turns a normalized byte string into a long-int (adapted from Crypto.Util.number)"
|
"""turns a normalized byte string into a long-int (adapted from Crypto.Util.number)"""
|
||||||
out = long(0)
|
out = long(0)
|
||||||
negative = 0
|
negative = 0
|
||||||
if not always_positive and (len(s) > 0) and (byte_ord(s[0]) >= 0x80):
|
if not always_positive and (len(s) > 0) and (byte_ord(s[0]) >= 0x80):
|
||||||
|
@ -56,6 +46,8 @@ def inflate_long(s, always_positive=False):
|
||||||
filler = zero_byte
|
filler = zero_byte
|
||||||
if negative:
|
if negative:
|
||||||
filler = max_byte
|
filler = max_byte
|
||||||
|
# never convert this to ``s +=`` because this is a string, not a number
|
||||||
|
# noinspection PyAugmentAssignment
|
||||||
s = filler * (4 - len(s) % 4) + s
|
s = filler * (4 - len(s) % 4) + s
|
||||||
for i in range(0, len(s), 4):
|
for i in range(0, len(s), 4):
|
||||||
out = (out << 32) + struct.unpack('>I', s[i:i+4])[0]
|
out = (out << 32) + struct.unpack('>I', s[i:i+4])[0]
|
||||||
|
@ -66,14 +58,15 @@ def inflate_long(s, always_positive=False):
|
||||||
deflate_zero = zero_byte if PY2 else 0
|
deflate_zero = zero_byte if PY2 else 0
|
||||||
deflate_ff = max_byte if PY2 else 0xff
|
deflate_ff = max_byte if PY2 else 0xff
|
||||||
|
|
||||||
|
|
||||||
def deflate_long(n, add_sign_padding=True):
|
def deflate_long(n, add_sign_padding=True):
|
||||||
"turns a long-int into a normalized byte string (adapted from Crypto.Util.number)"
|
"""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
|
# after much testing, this algorithm was deemed to be the fastest
|
||||||
s = bytes()
|
s = bytes()
|
||||||
n = long(n)
|
n = long(n)
|
||||||
while (n != 0) and (n != -1):
|
while (n != 0) and (n != -1):
|
||||||
s = struct.pack('>I', n & xffffffff) + s
|
s = struct.pack('>I', n & xffffffff) + s
|
||||||
n = n >> 32
|
n >>= 32
|
||||||
# strip off leading zeros, FFs
|
# strip off leading zeros, FFs
|
||||||
for i in enumerate(s):
|
for i in enumerate(s):
|
||||||
if (n == 0) and (i[1] != deflate_zero):
|
if (n == 0) and (i[1] != deflate_zero):
|
||||||
|
@ -95,6 +88,7 @@ def deflate_long(n, add_sign_padding=True):
|
||||||
s = max_byte + s
|
s = max_byte + s
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def format_binary(data, prefix=''):
|
def format_binary(data, prefix=''):
|
||||||
x = 0
|
x = 0
|
||||||
out = []
|
out = []
|
||||||
|
@ -105,17 +99,21 @@ def format_binary(data, prefix=''):
|
||||||
out.append(format_binary_line(data[x:]))
|
out.append(format_binary_line(data[x:]))
|
||||||
return [prefix + x for x in out]
|
return [prefix + x for x in out]
|
||||||
|
|
||||||
|
|
||||||
def format_binary_line(data):
|
def format_binary_line(data):
|
||||||
left = ' '.join(['%02X' % byte_ord(c) for c in data])
|
left = ' '.join(['%02X' % byte_ord(c) for c in data])
|
||||||
right = ''.join([('.%c..' % c)[(byte_ord(c)+63)//95] for c in data])
|
right = ''.join([('.%c..' % c)[(byte_ord(c)+63)//95] for c in data])
|
||||||
return '%-50s %s' % (left, right)
|
return '%-50s %s' % (left, right)
|
||||||
|
|
||||||
|
|
||||||
def hexify(s):
|
def hexify(s):
|
||||||
return hexlify(s).upper()
|
return hexlify(s).upper()
|
||||||
|
|
||||||
|
|
||||||
def unhexify(s):
|
def unhexify(s):
|
||||||
return unhexlify(s)
|
return unhexlify(s)
|
||||||
|
|
||||||
|
|
||||||
def safe_string(s):
|
def safe_string(s):
|
||||||
out = ''
|
out = ''
|
||||||
for c in s:
|
for c in s:
|
||||||
|
@ -125,13 +123,12 @@ def safe_string(s):
|
||||||
out += '%%%02X' % byte_ord(c)
|
out += '%%%02X' % byte_ord(c)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
# ''.join([['%%%02X' % ord(c), c][(ord(c) >= 32) and (ord(c) <= 127)] for c in s])
|
|
||||||
|
|
||||||
def bit_length(n):
|
def bit_length(n):
|
||||||
try:
|
try:
|
||||||
return n.bitlength()
|
return n.bitlength()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
norm = deflate_long(n, 0)
|
norm = deflate_long(n, False)
|
||||||
hbyte = byte_ord(norm[0])
|
hbyte = byte_ord(norm[0])
|
||||||
if hbyte == 0:
|
if hbyte == 0:
|
||||||
return 1
|
return 1
|
||||||
|
@ -141,9 +138,11 @@ def bit_length(n):
|
||||||
bitlen -= 1
|
bitlen -= 1
|
||||||
return bitlen
|
return bitlen
|
||||||
|
|
||||||
|
|
||||||
def tb_strings():
|
def tb_strings():
|
||||||
return ''.join(traceback.format_exception(*sys.exc_info())).split('\n')
|
return ''.join(traceback.format_exception(*sys.exc_info())).split('\n')
|
||||||
|
|
||||||
|
|
||||||
def generate_key_bytes(hashclass, salt, key, nbytes):
|
def generate_key_bytes(hashclass, salt, key, nbytes):
|
||||||
"""
|
"""
|
||||||
Given a password, passphrase, or other human-source key, scramble it
|
Given a password, passphrase, or other human-source key, scramble it
|
||||||
|
@ -175,6 +174,7 @@ def generate_key_bytes(hashclass, salt, key, nbytes):
|
||||||
nbytes -= size
|
nbytes -= size
|
||||||
return keydata
|
return keydata
|
||||||
|
|
||||||
|
|
||||||
def load_host_keys(filename):
|
def load_host_keys(filename):
|
||||||
"""
|
"""
|
||||||
Read a file of known SSH host keys, in the format used by openssh, and
|
Read a file of known SSH host keys, in the format used by openssh, and
|
||||||
|
@ -194,6 +194,7 @@ def load_host_keys(filename):
|
||||||
from paramiko.hostkeys import HostKeys
|
from paramiko.hostkeys import HostKeys
|
||||||
return HostKeys(filename)
|
return HostKeys(filename)
|
||||||
|
|
||||||
|
|
||||||
def parse_ssh_config(file_obj):
|
def parse_ssh_config(file_obj):
|
||||||
"""
|
"""
|
||||||
Provided only as a backward-compatible wrapper around `.SSHConfig`.
|
Provided only as a backward-compatible wrapper around `.SSHConfig`.
|
||||||
|
@ -202,12 +203,14 @@ def parse_ssh_config(file_obj):
|
||||||
config.parse(file_obj)
|
config.parse(file_obj)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def lookup_ssh_host_config(hostname, config):
|
def lookup_ssh_host_config(hostname, config):
|
||||||
"""
|
"""
|
||||||
Provided only as a backward-compatible wrapper around `.SSHConfig`.
|
Provided only as a backward-compatible wrapper around `.SSHConfig`.
|
||||||
"""
|
"""
|
||||||
return config.lookup(hostname)
|
return config.lookup(hostname)
|
||||||
|
|
||||||
|
|
||||||
def mod_inverse(x, m):
|
def mod_inverse(x, m):
|
||||||
# it's crazy how small Python can make this function.
|
# it's crazy how small Python can make this function.
|
||||||
u1, u2, u3 = 1, 0, m
|
u1, u2, u3 = 1, 0, m
|
||||||
|
@ -225,6 +228,8 @@ def mod_inverse(x, m):
|
||||||
_g_thread_ids = {}
|
_g_thread_ids = {}
|
||||||
_g_thread_counter = 0
|
_g_thread_counter = 0
|
||||||
_g_thread_lock = threading.Lock()
|
_g_thread_lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
def get_thread_id():
|
def get_thread_id():
|
||||||
global _g_thread_ids, _g_thread_counter, _g_thread_lock
|
global _g_thread_ids, _g_thread_counter, _g_thread_lock
|
||||||
tid = id(threading.currentThread())
|
tid = id(threading.currentThread())
|
||||||
|
@ -239,8 +244,9 @@ def get_thread_id():
|
||||||
_g_thread_lock.release()
|
_g_thread_lock.release()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def log_to_file(filename, level=DEBUG):
|
def log_to_file(filename, level=DEBUG):
|
||||||
"send paramiko logs to a logfile, if they're not already going somewhere"
|
"""send paramiko logs to a logfile, if they're not already going somewhere"""
|
||||||
l = logging.getLogger("paramiko")
|
l = logging.getLogger("paramiko")
|
||||||
if len(l.handlers) > 0:
|
if len(l.handlers) > 0:
|
||||||
return
|
return
|
||||||
|
@ -251,6 +257,7 @@ def log_to_file(filename, level=DEBUG):
|
||||||
'%Y%m%d-%H:%M:%S'))
|
'%Y%m%d-%H:%M:%S'))
|
||||||
l.addHandler(lh)
|
l.addHandler(lh)
|
||||||
|
|
||||||
|
|
||||||
# make only one filter object, so it doesn't get applied more than once
|
# make only one filter object, so it doesn't get applied more than once
|
||||||
class PFilter (object):
|
class PFilter (object):
|
||||||
def filter(self, record):
|
def filter(self, record):
|
||||||
|
@ -258,11 +265,13 @@ class PFilter (object):
|
||||||
return True
|
return True
|
||||||
_pfilter = PFilter()
|
_pfilter = PFilter()
|
||||||
|
|
||||||
|
|
||||||
def get_logger(name):
|
def get_logger(name):
|
||||||
l = logging.getLogger(name)
|
l = logging.getLogger(name)
|
||||||
l.addFilter(_pfilter)
|
l.addFilter(_pfilter)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
|
||||||
def retry_on_signal(function):
|
def retry_on_signal(function):
|
||||||
"""Retries function until it doesn't raise an EINTR error"""
|
"""Retries function until it doesn't raise an EINTR error"""
|
||||||
while True:
|
while True:
|
||||||
|
@ -272,6 +281,7 @@ def retry_on_signal(function):
|
||||||
if e.errno != errno.EINTR:
|
if e.errno != errno.EINTR:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
class Counter (object):
|
class Counter (object):
|
||||||
"""Stateful counter for CTR mode crypto"""
|
"""Stateful counter for CTR mode crypto"""
|
||||||
def __init__(self, nbits, initial_value=long(1), overflow=long(0)):
|
def __init__(self, nbits, initial_value=long(1), overflow=long(0)):
|
||||||
|
@ -307,6 +317,7 @@ def constant_time_bytes_eq(a, b):
|
||||||
if len(a) != len(b):
|
if len(a) != len(b):
|
||||||
return False
|
return False
|
||||||
res = 0
|
res = 0
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
for i in (xrange if PY2 else range)(len(a)):
|
for i in (xrange if PY2 else range)(len(a)):
|
||||||
res |= byte_ord(a[i]) ^ byte_ord(b[i])
|
res |= byte_ord(a[i]) ^ byte_ord(b[i])
|
||||||
return res == 0
|
return res == 0
|
||||||
|
|
|
@ -21,7 +21,6 @@ A stub SFTP server for loopback SFTP testing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from paramiko import ServerInterface, SFTPServerInterface, SFTPServer, SFTPAttributes, \
|
from paramiko import ServerInterface, SFTPServerInterface, SFTPServer, SFTPAttributes, \
|
||||||
SFTPHandle, SFTP_OK, AUTH_SUCCESSFUL, OPEN_SUCCEEDED
|
SFTPHandle, SFTP_OK, AUTH_SUCCESSFUL, OPEN_SUCCEEDED
|
||||||
from paramiko.common import o666
|
from paramiko.common import o666
|
||||||
|
@ -64,7 +63,7 @@ class StubSFTPServer (SFTPServerInterface):
|
||||||
def list_folder(self, path):
|
def list_folder(self, path):
|
||||||
path = self._realpath(path)
|
path = self._realpath(path)
|
||||||
try:
|
try:
|
||||||
out = [ ]
|
out = []
|
||||||
flist = os.listdir(path)
|
flist = os.listdir(path)
|
||||||
for fname in flist:
|
for fname in flist:
|
||||||
attr = SFTPAttributes.from_stat(os.stat(os.path.join(path, fname)))
|
attr = SFTPAttributes.from_stat(os.stat(os.path.join(path, fname)))
|
||||||
|
@ -91,7 +90,7 @@ class StubSFTPServer (SFTPServerInterface):
|
||||||
def open(self, path, flags, attr):
|
def open(self, path, flags, attr):
|
||||||
path = self._realpath(path)
|
path = self._realpath(path)
|
||||||
try:
|
try:
|
||||||
binary_flag = getattr(os, 'O_BINARY', 0)
|
binary_flag = getattr(os, 'O_BINARY', 0)
|
||||||
flags |= binary_flag
|
flags |= binary_flag
|
||||||
mode = getattr(attr, 'st_mode', None)
|
mode = getattr(attr, 'st_mode', None)
|
||||||
if mode is not None:
|
if mode is not None:
|
||||||
|
|
|
@ -25,10 +25,9 @@ import threading
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from paramiko import Transport, ServerInterface, RSAKey, DSSKey, \
|
from paramiko import Transport, ServerInterface, RSAKey, DSSKey, \
|
||||||
SSHException, BadAuthenticationType, InteractiveQuery, ChannelException, \
|
BadAuthenticationType, InteractiveQuery, \
|
||||||
AuthenticationException
|
AuthenticationException
|
||||||
from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL
|
from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL
|
||||||
from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
|
|
||||||
from paramiko.py3compat import u
|
from paramiko.py3compat import u
|
||||||
from tests.loop import LoopSocket
|
from tests.loop import LoopSocket
|
||||||
from tests.util import test_path
|
from tests.util import test_path
|
||||||
|
|
|
@ -22,24 +22,22 @@ Some unit tests for BufferedPipe.
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import unittest
|
|
||||||
from paramiko.buffered_pipe import BufferedPipe, PipeTimeout
|
from paramiko.buffered_pipe import BufferedPipe, PipeTimeout
|
||||||
from paramiko import pipe
|
from paramiko import pipe
|
||||||
from paramiko.py3compat import b
|
|
||||||
|
|
||||||
from tests.util import ParamikoTest
|
from tests.util import ParamikoTest
|
||||||
|
|
||||||
|
|
||||||
def delay_thread(pipe):
|
def delay_thread(p):
|
||||||
pipe.feed('a')
|
p.feed('a')
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
pipe.feed('b')
|
p.feed('b')
|
||||||
pipe.close()
|
p.close()
|
||||||
|
|
||||||
|
|
||||||
def close_thread(pipe):
|
def close_thread(p):
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
pipe.close()
|
p.close()
|
||||||
|
|
||||||
|
|
||||||
class BufferedPipeTest(ParamikoTest):
|
class BufferedPipeTest(ParamikoTest):
|
||||||
|
@ -91,4 +89,3 @@ class BufferedPipeTest(ParamikoTest):
|
||||||
self.assertTrue(p._set)
|
self.assertTrue(p._set)
|
||||||
p2.clear()
|
p2.clear()
|
||||||
self.assertFalse(p._set)
|
self.assertFalse(p._set)
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ class SSHClientTest (unittest.TestCase):
|
||||||
|
|
||||||
self.tc = paramiko.SSHClient()
|
self.tc = paramiko.SSHClient()
|
||||||
self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key)
|
self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key)
|
||||||
self.tc.connect(self.addr, self.port, username='slowdive', key_filename=[ test_path('test_rsa.key'), test_path('test_dss.key') ])
|
self.tc.connect(self.addr, self.port, username='slowdive', key_filename=[test_path('test_rsa.key'), test_path('test_dss.key')])
|
||||||
|
|
||||||
self.event.wait(1.0)
|
self.event.wait(1.0)
|
||||||
self.assertTrue(self.event.isSet())
|
self.assertTrue(self.event.isSet())
|
||||||
|
|
|
@ -20,12 +20,11 @@
|
||||||
Some unit tests for HostKeys.
|
Some unit tests for HostKeys.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import base64
|
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
import paramiko
|
import paramiko
|
||||||
from paramiko.py3compat import b, decodebytes
|
from paramiko.py3compat import decodebytes
|
||||||
|
|
||||||
|
|
||||||
test_hosts_file = """\
|
test_hosts_file = """\
|
||||||
|
|
|
@ -37,8 +37,10 @@ class FakeRng (object):
|
||||||
class FakeKey (object):
|
class FakeKey (object):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'fake-key'
|
return 'fake-key'
|
||||||
|
|
||||||
def asbytes(self):
|
def asbytes(self):
|
||||||
return b'fake-key'
|
return b'fake-key'
|
||||||
|
|
||||||
def sign_ssh_data(self, rng, H):
|
def sign_ssh_data(self, rng, H):
|
||||||
return b'fake-sig'
|
return b'fake-sig'
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ class FakeKey (object):
|
||||||
class FakeModulusPack (object):
|
class FakeModulusPack (object):
|
||||||
P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF
|
P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF
|
||||||
G = 2
|
G = 2
|
||||||
|
|
||||||
def get_modulus(self, min, ask, max):
|
def get_modulus(self, min, ask, max):
|
||||||
return self.G, self.P
|
return self.G, self.P
|
||||||
|
|
||||||
|
@ -59,19 +62,26 @@ class FakeTransport (object):
|
||||||
|
|
||||||
def _send_message(self, m):
|
def _send_message(self, m):
|
||||||
self._message = m
|
self._message = m
|
||||||
|
|
||||||
def _expect_packet(self, *t):
|
def _expect_packet(self, *t):
|
||||||
self._expect = t
|
self._expect = t
|
||||||
|
|
||||||
def _set_K_H(self, K, H):
|
def _set_K_H(self, K, H):
|
||||||
self._K = K
|
self._K = K
|
||||||
self._H = H
|
self._H = H
|
||||||
|
|
||||||
def _verify_key(self, host_key, sig):
|
def _verify_key(self, host_key, sig):
|
||||||
self._verify = (host_key, sig)
|
self._verify = (host_key, sig)
|
||||||
|
|
||||||
def _activate_outbound(self):
|
def _activate_outbound(self):
|
||||||
self._activated = True
|
self._activated = True
|
||||||
|
|
||||||
def _log(self, level, s):
|
def _log(self, level, s):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_server_key(self):
|
def get_server_key(self):
|
||||||
return FakeKey()
|
return FakeKey()
|
||||||
|
|
||||||
def _get_modulus_pack(self):
|
def _get_modulus_pack(self):
|
||||||
return FakeModulusPack()
|
return FakeModulusPack()
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ Some unit tests for the ssh2 protocol in Transport.
|
||||||
import unittest
|
import unittest
|
||||||
from tests.loop import LoopSocket
|
from tests.loop import LoopSocket
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Hash import SHA, HMAC
|
from Crypto.Hash import SHA
|
||||||
from paramiko import Message, Packetizer, util
|
from paramiko import Message, Packetizer, util
|
||||||
from paramiko.common import byte_chr, zero_byte
|
from paramiko.common import byte_chr, zero_byte
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ x1f = byte_chr(0x1f)
|
||||||
|
|
||||||
class PacketizerTest (unittest.TestCase):
|
class PacketizerTest (unittest.TestCase):
|
||||||
|
|
||||||
def test_1_write (self):
|
def test_1_write(self):
|
||||||
rsock = LoopSocket()
|
rsock = LoopSocket()
|
||||||
wsock = LoopSocket()
|
wsock = LoopSocket()
|
||||||
rsock.link(wsock)
|
rsock.link(wsock)
|
||||||
|
@ -56,7 +56,7 @@ class PacketizerTest (unittest.TestCase):
|
||||||
self.assertEqual(44, len(data))
|
self.assertEqual(44, len(data))
|
||||||
self.assertEqual(b'\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0', data[:16])
|
self.assertEqual(b'\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0', data[:16])
|
||||||
|
|
||||||
def test_2_read (self):
|
def test_2_read(self):
|
||||||
rsock = LoopSocket()
|
rsock = LoopSocket()
|
||||||
wsock = LoopSocket()
|
wsock = LoopSocket()
|
||||||
rsock.link(wsock)
|
rsock.link(wsock)
|
||||||
|
|
|
@ -23,7 +23,8 @@ Some unit tests for public/private key objects.
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
import unittest
|
import unittest
|
||||||
from paramiko import RSAKey, DSSKey, ECDSAKey, Message, util
|
from paramiko import RSAKey, DSSKey, ECDSAKey, Message, util
|
||||||
from paramiko.common import rng, StringIO, byte_chr, b, bytes
|
from paramiko.py3compat import StringIO, byte_chr, b, bytes
|
||||||
|
from paramiko.common import rng
|
||||||
from tests.util import test_path
|
from tests.util import test_path
|
||||||
|
|
||||||
# from openssh's ssh-keygen
|
# from openssh's ssh-keygen
|
||||||
|
|
|
@ -32,7 +32,8 @@ import unittest
|
||||||
from tempfile import mkstemp
|
from tempfile import mkstemp
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
from paramiko.common import PY2, b, u, StringIO, o777, o600
|
from paramiko.py3compat import PY2, b, u, StringIO
|
||||||
|
from paramiko.common import o777, o600, o666, o644
|
||||||
from tests.stub_sftp import StubServer, StubSFTPServer
|
from tests.stub_sftp import StubServer, StubSFTPServer
|
||||||
from tests.loop import LoopSocket
|
from tests.loop import LoopSocket
|
||||||
from tests.util import test_path
|
from tests.util import test_path
|
||||||
|
@ -554,6 +555,7 @@ class SFTPTest (unittest.TestCase):
|
||||||
with open(localname, 'wb') as f:
|
with open(localname, 'wb') as f:
|
||||||
f.write(text)
|
f.write(text)
|
||||||
saved_progress = []
|
saved_progress = []
|
||||||
|
|
||||||
def progress_callback(x, y):
|
def progress_callback(x, y):
|
||||||
saved_progress.append((x, y))
|
saved_progress.append((x, y))
|
||||||
sftp.put(localname, FOLDER + '/bunny.txt', progress_callback)
|
sftp.put(localname, FOLDER + '/bunny.txt', progress_callback)
|
||||||
|
@ -663,6 +665,7 @@ class SFTPTest (unittest.TestCase):
|
||||||
with open(localname, 'w') as f:
|
with open(localname, 'w') as f:
|
||||||
f.write(text)
|
f.write(text)
|
||||||
saved_progress = []
|
saved_progress = []
|
||||||
|
|
||||||
def progress_callback(x, y):
|
def progress_callback(x, y):
|
||||||
saved_progress.append((x, y))
|
saved_progress.append((x, y))
|
||||||
res = sftp.put(localname, FOLDER + '/bunny.txt', progress_callback, False)
|
res = sftp.put(localname, FOLDER + '/bunny.txt', progress_callback, False)
|
||||||
|
|
|
@ -23,19 +23,14 @@ a real actual sftp server is contacted, and a new folder is created there to
|
||||||
do test file operations in (so no existing files will be harmed).
|
do test file operations in (so no existing files will be harmed).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import threading
|
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import paramiko
|
|
||||||
from paramiko.common import o660
|
from paramiko.common import o660
|
||||||
from tests.stub_sftp import StubServer, StubSFTPServer
|
|
||||||
from tests.loop import LoopSocket
|
|
||||||
from tests.test_sftp import get_sftp
|
from tests.test_sftp import get_sftp
|
||||||
|
|
||||||
FOLDER = os.environ.get('TEST_FOLDER', 'temp-testing000')
|
FOLDER = os.environ.get('TEST_FOLDER', 'temp-testing000')
|
||||||
|
|
|
@ -23,17 +23,16 @@ Some unit tests for the ssh2 protocol in Transport.
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
import select
|
import select
|
||||||
import socket
|
import socket
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import unittest
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from paramiko import Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, \
|
from paramiko import Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, \
|
||||||
SSHException, BadAuthenticationType, InteractiveQuery, ChannelException
|
SSHException, ChannelException
|
||||||
from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL
|
from paramiko import AUTH_FAILED, AUTH_SUCCESSFUL
|
||||||
from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
|
from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
|
||||||
from paramiko.common import MSG_KEXINIT, MSG_CHANNEL_WINDOW_ADJUST, b, bytes
|
from paramiko.common import MSG_KEXINIT, cMSG_CHANNEL_WINDOW_ADJUST
|
||||||
|
from paramiko.py3compat import bytes
|
||||||
from paramiko.message import Message
|
from paramiko.message import Message
|
||||||
from tests.loop import LoopSocket
|
from tests.loop import LoopSocket
|
||||||
from tests.util import ParamikoTest, test_path
|
from tests.util import ParamikoTest, test_path
|
||||||
|
|
|
@ -23,11 +23,10 @@ Some unit tests for utility functions.
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
import unittest
|
|
||||||
from Crypto.Hash import SHA
|
from Crypto.Hash import SHA
|
||||||
import paramiko.util
|
import paramiko.util
|
||||||
from paramiko.util import lookup_ssh_host_config as host_config
|
from paramiko.util import lookup_ssh_host_config as host_config
|
||||||
from paramiko.py3compat import StringIO, byte_ord, b
|
from paramiko.py3compat import StringIO, byte_ord
|
||||||
|
|
||||||
from tests.util import ParamikoTest
|
from tests.util import ParamikoTest
|
||||||
|
|
||||||
|
@ -338,4 +337,4 @@ AddressFamily inet
|
||||||
IdentityFile something_%l_using_fqdn
|
IdentityFile something_%l_using_fqdn
|
||||||
"""
|
"""
|
||||||
config = paramiko.util.parse_ssh_config(StringIO(test_config))
|
config = paramiko.util.parse_ssh_config(StringIO(test_config))
|
||||||
assert config.lookup('meh') # will die during lookup() if bug regresses
|
assert config.lookup('meh') # will die during lookup() if bug regresses
|
||||||
|
|
Loading…
Reference in New Issue