1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
=== modified file 'paramiko/channel.py'
--- paramiko/channel.py 2006-05-11 01:11:40 +0000
+++ paramiko/channel.py 2006-10-23 00:02:25 +0000
@@ -150,6 +150,55 @@
self.transport._send_user_message(m)
self._wait_for_event()
+ def request_x11(self, want_reply=0, single_connection=0,
+ x11_auth_proto=None,
+ x11_auth_cookie=None,
+ x11_screen_number=0):
+ """
+ Request an x11 session on this channel. If the server allows it,
+ further x11 requests can be made from the server to the client,
+ when an x11 application is run in a shell session.
+
+ From the RFC4254:
+ It is RECOMMENDED that the 'x11 authentication cookie' that is sent
+ be a fake, random cookie, and that the cookie be checked and replaced
+ by the real cookie when a connection request is received.
+
+ X11 connection forwarding should stop when the session channel is
+ closed. However, already opened forwardings should not be
+ automatically closed when the session channel is closed.
+
+ @param want_reply: if an ACK is needed (openssh do not set it)
+ @type want_reply: bool
+ @param single_connection: if True, only a single connection should be
+ forwarded. No more connections will be forwarded after the first,
+ or after the session channel has been closed
+ @type single_connection: bool
+ @param x11_auth_proto: the name of the X11 authentication method used,
+ e.g., "MIT-MAGIC-COOKIE-1"
+ @type x11_auth_proto: string
+ @param x11_auth_cookie: MUST be hexadecimal encoded
+ @type x11_auth_cookie: string
+ @param x11_screen_number: the number of the x11 screen
+ @type x11_screen_number: int
+ """
+ if self.closed or self.eof_received or self.eof_sent or not self.active:
+ raise SSHException('Channel is not open')
+
+ m = Message()
+ m.add_byte(chr(MSG_CHANNEL_REQUEST))
+ m.add_int(self.remote_chanid)
+ m.add_string('x11-req')
+ m.add_boolean(want_reply)
+ m.add_boolean(single_connection)
+ m.add_string(x11_auth_proto)
+ m.add_string(x11_auth_cookie)
+ m.add_int(x11_screen_number)
+ self.event.clear()
+ self.transport._send_user_message(m)
+ if want_reply:
+ self._wait_for_event()
+
def invoke_shell(self):
"""
Request an interactive shell session on this channel. If the server
@@ -905,8 +954,15 @@
ok = server.check_channel_window_change_request(self, width, height, pixelwidth,
pixelheight)
else:
- self._log(DEBUG, 'Unhandled channel request "%s"' % key)
- ok = False
+ # support for unhandled channels in the server
+ if server is None or not hasattr(server,
+ 'check_unhandled_channel_request'):
+ ok = False
+ else:
+ ok = server.check_unhandled_channel_request(self, key,
+ want_reply, m)
+ if not ok:
+ self._log(DEBUG, 'Unhandled channel request "%s"' % key)
if want_reply:
m = Message()
if ok:
=== modified file 'paramiko/transport.py'
--- paramiko/transport.py 2006-10-15 01:56:28 +0000
+++ paramiko/transport.py 2006-10-22 23:36:06 +0000
@@ -589,6 +589,22 @@
"""
return self.open_channel('session')
+ def open_x11_channel(self, src_addr=None):
+ """
+ Request a new channel to the client, of type C{"x11"}. This
+ is just an alias for C{open_channel('x11', src_addr=src_addr)}.
+
+ @param src_addr: the source address of the x11 server (port is the
+ x11 port, ie. 6010)
+ @type src_addr: (str, int)
+ @return: a new L{Channel}
+ @rtype: L{Channel}
+
+ @raise SSHException: if the request is rejected or the session ends
+ prematurely
+ """
+ return self.open_channel('x11', src_addr=src_addr)
+
def open_channel(self, kind, dest_addr=None, src_addr=None):
"""
Request a new channel to the server. L{Channel}s are socket-like
@@ -634,6 +650,9 @@
m.add_int(dest_addr[1])
m.add_string(src_addr[0])
m.add_int(src_addr[1])
+ elif (kind == 'x11'):
+ m.add_string(src_addr[0])
+ m.add_int(src_addr[1])
self.channels[chanid] = chan = Channel(chanid)
self.channel_events[chanid] = event = threading.Event()
self.channels_seen[chanid] = True
@@ -1781,7 +1800,33 @@
initial_window_size = m.get_int()
max_packet_size = m.get_int()
reject = False
- if not self.server_mode:
+ if kind == 'x11' and hasattr(self, 'client_object'):
+ # handle x11 requests comming from the server
+ # an attribute client_object must be set
+ # the client_object must have a method named
+ # check_x11_channel_request(chanid, orig_addr, orig_port)
+ # where chanid is the newly created channel identifier,
+ # orig_addr and orig_port are the parameters passed from
+ # the x11 server (see open_x11_channel for details)
+ # the client_object must also have a method new_x11_channel()
+ # (see ~55 lines below)
+ self.lock.acquire()
+ try:
+ my_chanid = self.channel_counter
+ while my_chanid in self.channels:
+ self.channel_counter = (self.channel_counter + 1) & 0xffffff
+ my_chanid = self.channel_counter
+ self.channel_counter = (self.channel_counter + 1) & 0xffffff
+ finally:
+ self.lock.release()
+ origin_addr = m.get_string()
+ origin_port = m.get_int()
+ reason = self.client_object.check_x11_channel_request(my_chanid,
+ origin_addr, origin_port)
+ if reason != OPEN_SUCCEEDED:
+ self._log(DEBUG, 'Rejecting "%s" channel request from client.' % kind)
+ reject = True
+ elif not self.server_mode:
self._log(DEBUG, 'Rejecting "%s" channel request from server.' % kind)
reject = True
reason = OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
@@ -1816,6 +1861,10 @@
chan._set_transport(self)
chan._set_window(self.window_size, self.max_packet_size)
chan._set_remote_channel(chanid, initial_window_size, max_packet_size)
+ if kind == 'x11' and hasattr(self, 'client_object'):
+ # if the channel creation is OK, notify the client
+ # by calling its new_x11_channel() method
+ self.client_object.new_x11_channel(chan)
finally:
self.lock.release()
m = Message()
|