[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_BANNER = range(50, 54)
|
||||
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_WINDOW_ADJUST, MSG_CHANNEL_DATA, MSG_CHANNEL_EXTENDED_DATA, \
|
||||
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
|
||||
|
|
|
@ -243,6 +243,8 @@ class Message (object):
|
|||
return self.add_mpint(i)
|
||||
else:
|
||||
return self.add_int(i)
|
||||
elif type(i) is bool:
|
||||
return self.add_boolean(i)
|
||||
elif type(i) == types.ListType:
|
||||
return self.add_list(i)
|
||||
else:
|
||||
|
|
|
@ -307,7 +307,7 @@ class BaseTransport (threading.Thread):
|
|||
@type filename: string
|
||||
@return: True if a moduli file was successfully loaded; False
|
||||
otherwise.
|
||||
@rtype: boolean
|
||||
@rtype: bool
|
||||
|
||||
@since: doduo
|
||||
|
||||
|
@ -364,7 +364,7 @@ class BaseTransport (threading.Thread):
|
|||
Return true if this session is active (open).
|
||||
|
||||
@return: True if the session is still active (open); False if the session is closed.
|
||||
@rtype: boolean
|
||||
@rtype: bool
|
||||
"""
|
||||
return self.active
|
||||
|
||||
|
@ -454,7 +454,7 @@ class BaseTransport (threading.Thread):
|
|||
|
||||
@return: True if the renegotiation was successful, and the link is
|
||||
using new keys; False if the session dropped during renegotiation.
|
||||
@rtype: boolean
|
||||
@rtype: bool
|
||||
"""
|
||||
self.completion_event = threading.Event()
|
||||
self._send_kex_init()
|
||||
|
@ -466,6 +466,44 @@ class BaseTransport (threading.Thread):
|
|||
break
|
||||
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):
|
||||
"""
|
||||
I{(subclass override)}
|
||||
|
@ -496,6 +534,36 @@ class BaseTransport (threading.Thread):
|
|||
"""
|
||||
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):
|
||||
try:
|
||||
self.lock.acquire()
|
||||
|
@ -1081,6 +1149,34 @@ class BaseTransport (threading.Thread):
|
|||
desc = m.get_string()
|
||||
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):
|
||||
chanid = m.get_int()
|
||||
server_chanid = m.get_int()
|
||||
|
@ -1187,6 +1283,9 @@ class BaseTransport (threading.Thread):
|
|||
|
||||
_handler_table = {
|
||||
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_FAILURE: _parse_channel_open_failure,
|
||||
MSG_CHANNEL_OPEN: _parse_channel_open,
|
||||
|
|
Loading…
Reference in New Issue