[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-39]
add global request mechanism add transport.global_request() to make a global-style request (usually an extension to the protocol -- like keepalives) and handle requests from the remote host. incoming requests are now handled and responded to correctly, which should make openssh-style keepalives work. (before, we would silently ignore them, which was wrong.)
This commit is contained in:
parent
c9d301b782
commit
70faf02f3e
|
@ -28,6 +28,7 @@ MSG_KEXINIT, MSG_NEWKEYS = range(20, 22)
|
||||||
MSG_USERAUTH_REQUEST, MSG_USERAUTH_FAILURE, MSG_USERAUTH_SUCCESS, \
|
MSG_USERAUTH_REQUEST, MSG_USERAUTH_FAILURE, MSG_USERAUTH_SUCCESS, \
|
||||||
MSG_USERAUTH_BANNER = range(50, 54)
|
MSG_USERAUTH_BANNER = range(50, 54)
|
||||||
MSG_USERAUTH_PK_OK = 60
|
MSG_USERAUTH_PK_OK = 60
|
||||||
|
MSG_GLOBAL_REQUEST, MSG_REQUEST_SUCCESS, MSG_REQUEST_FAILURE = range(80, 83)
|
||||||
MSG_CHANNEL_OPEN, MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, \
|
MSG_CHANNEL_OPEN, MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, \
|
||||||
MSG_CHANNEL_WINDOW_ADJUST, MSG_CHANNEL_DATA, MSG_CHANNEL_EXTENDED_DATA, \
|
MSG_CHANNEL_WINDOW_ADJUST, MSG_CHANNEL_DATA, MSG_CHANNEL_EXTENDED_DATA, \
|
||||||
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
|
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
|
||||||
|
|
|
@ -243,6 +243,8 @@ class Message (object):
|
||||||
return self.add_mpint(i)
|
return self.add_mpint(i)
|
||||||
else:
|
else:
|
||||||
return self.add_int(i)
|
return self.add_int(i)
|
||||||
|
elif type(i) is bool:
|
||||||
|
return self.add_boolean(i)
|
||||||
elif type(i) == types.ListType:
|
elif type(i) == types.ListType:
|
||||||
return self.add_list(i)
|
return self.add_list(i)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -307,7 +307,7 @@ class BaseTransport (threading.Thread):
|
||||||
@type filename: string
|
@type filename: string
|
||||||
@return: True if a moduli file was successfully loaded; False
|
@return: True if a moduli file was successfully loaded; False
|
||||||
otherwise.
|
otherwise.
|
||||||
@rtype: boolean
|
@rtype: bool
|
||||||
|
|
||||||
@since: doduo
|
@since: doduo
|
||||||
|
|
||||||
|
@ -364,7 +364,7 @@ class BaseTransport (threading.Thread):
|
||||||
Return true if this session is active (open).
|
Return true if this session is active (open).
|
||||||
|
|
||||||
@return: True if the session is still active (open); False if the session is closed.
|
@return: True if the session is still active (open); False if the session is closed.
|
||||||
@rtype: boolean
|
@rtype: bool
|
||||||
"""
|
"""
|
||||||
return self.active
|
return self.active
|
||||||
|
|
||||||
|
@ -454,7 +454,7 @@ class BaseTransport (threading.Thread):
|
||||||
|
|
||||||
@return: True if the renegotiation was successful, and the link is
|
@return: True if the renegotiation was successful, and the link is
|
||||||
using new keys; False if the session dropped during renegotiation.
|
using new keys; False if the session dropped during renegotiation.
|
||||||
@rtype: boolean
|
@rtype: bool
|
||||||
"""
|
"""
|
||||||
self.completion_event = threading.Event()
|
self.completion_event = threading.Event()
|
||||||
self._send_kex_init()
|
self._send_kex_init()
|
||||||
|
@ -466,6 +466,44 @@ class BaseTransport (threading.Thread):
|
||||||
break
|
break
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def global_request(self, kind, data=None, wait=True):
|
||||||
|
"""
|
||||||
|
Make a global request to the remote host. These are normally
|
||||||
|
extensions to the SSH2 protocol.
|
||||||
|
|
||||||
|
@param kind: name of the request.
|
||||||
|
@type kind: string
|
||||||
|
@param data: an optional tuple containing additional data to attach
|
||||||
|
to the request.
|
||||||
|
@type data: tuple
|
||||||
|
@param wait: C{True} if this method should not return until a response
|
||||||
|
is received; C{False} otherwise.
|
||||||
|
@type wait: bool
|
||||||
|
@return: a L{Message} containing possible additional data if the
|
||||||
|
request was successful (or an empty L{Message} if C{wait} was
|
||||||
|
C{False}); C{None} if the request was denied.
|
||||||
|
@rtype: L{Message}
|
||||||
|
"""
|
||||||
|
if wait:
|
||||||
|
self.completion_event = threading.Event()
|
||||||
|
m = Message()
|
||||||
|
m.add_byte(chr(MSG_GLOBAL_REQUEST))
|
||||||
|
m.add_string(kind)
|
||||||
|
m.add_boolean(wait)
|
||||||
|
if data is not None:
|
||||||
|
for item in data:
|
||||||
|
m.add(item)
|
||||||
|
self._send_message(m)
|
||||||
|
if not wait:
|
||||||
|
return True
|
||||||
|
while True:
|
||||||
|
self.completion_event.wait(0.1)
|
||||||
|
if not self.active:
|
||||||
|
return False
|
||||||
|
if self.completion_event.isSet():
|
||||||
|
break
|
||||||
|
return self.global_response
|
||||||
|
|
||||||
def check_channel_request(self, kind, chanid):
|
def check_channel_request(self, kind, chanid):
|
||||||
"""
|
"""
|
||||||
I{(subclass override)}
|
I{(subclass override)}
|
||||||
|
@ -496,6 +534,36 @@ class BaseTransport (threading.Thread):
|
||||||
"""
|
"""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def check_global_request(self, kind, msg):
|
||||||
|
"""
|
||||||
|
I{(subclass override)}
|
||||||
|
Handle a global request of the given C{kind}. This method is called
|
||||||
|
in server mode and client mode, whenever the remote host makes a global
|
||||||
|
request. If there are any arguments to the request, they will be in
|
||||||
|
C{msg}.
|
||||||
|
|
||||||
|
There aren't any useful global requests defined, aside from port
|
||||||
|
forwarding, so usually this type of request is an extension to the
|
||||||
|
protocol.
|
||||||
|
|
||||||
|
If the request was successful and you would like to return contextual
|
||||||
|
data to the remote host, return a tuple. Items in the tuple will be
|
||||||
|
sent back with the successful result. (Note that the items in the
|
||||||
|
tuple can only be strings, ints, longs, or bools.)
|
||||||
|
|
||||||
|
The default implementation always returns C{False}, indicating that it
|
||||||
|
does not support any global requests.
|
||||||
|
|
||||||
|
@param kind: the kind of global request being made.
|
||||||
|
@type kind: string
|
||||||
|
@param msg: any extra arguments to the request.
|
||||||
|
@type msg: L{Message}
|
||||||
|
@return: C{True} or a tuple of data if the request was granted;
|
||||||
|
C{False} otherwise.
|
||||||
|
@rtype: bool
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
def accept(self, timeout=None):
|
def accept(self, timeout=None):
|
||||||
try:
|
try:
|
||||||
self.lock.acquire()
|
self.lock.acquire()
|
||||||
|
@ -1081,6 +1149,34 @@ class BaseTransport (threading.Thread):
|
||||||
desc = m.get_string()
|
desc = m.get_string()
|
||||||
self._log(INFO, 'Disconnect (code %d): %s' % (code, desc))
|
self._log(INFO, 'Disconnect (code %d): %s' % (code, desc))
|
||||||
|
|
||||||
|
def _parse_global_request(self, m):
|
||||||
|
kind = m.get_string()
|
||||||
|
want_reply = m.get_boolean()
|
||||||
|
ok = self.check_global_request(kind, m)
|
||||||
|
extra = ()
|
||||||
|
if type(ok) is tuple:
|
||||||
|
extra = ok
|
||||||
|
ok = True
|
||||||
|
if want_reply:
|
||||||
|
msg = Message()
|
||||||
|
if ok:
|
||||||
|
msg.add_byte(chr(MSG_REQUEST_SUCCESS))
|
||||||
|
for item in extra:
|
||||||
|
msg.add(item)
|
||||||
|
else:
|
||||||
|
msg.add_byte(chr(MSG_REQUEST_FAILURE))
|
||||||
|
self._send_message(msg)
|
||||||
|
|
||||||
|
def _parse_request_success(self, m):
|
||||||
|
self.global_response = m
|
||||||
|
if self.completion_event is not None:
|
||||||
|
self.completion_event.set()
|
||||||
|
|
||||||
|
def _parse_request_failure(self, m):
|
||||||
|
self.global_response = None
|
||||||
|
if self.completion_event is not None:
|
||||||
|
self.completion_event.set()
|
||||||
|
|
||||||
def _parse_channel_open_success(self, m):
|
def _parse_channel_open_success(self, m):
|
||||||
chanid = m.get_int()
|
chanid = m.get_int()
|
||||||
server_chanid = m.get_int()
|
server_chanid = m.get_int()
|
||||||
|
@ -1187,6 +1283,9 @@ class BaseTransport (threading.Thread):
|
||||||
|
|
||||||
_handler_table = {
|
_handler_table = {
|
||||||
MSG_NEWKEYS: _parse_newkeys,
|
MSG_NEWKEYS: _parse_newkeys,
|
||||||
|
MSG_GLOBAL_REQUEST: _parse_global_request,
|
||||||
|
MSG_REQUEST_SUCCESS: _parse_request_success,
|
||||||
|
MSG_REQUEST_FAILURE: _parse_request_failure,
|
||||||
MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success,
|
MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success,
|
||||||
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,
|
||||||
|
|
Loading…
Reference in New Issue