Package paramiko :: Module channel
[frames] | no frames]

Source Code for Module paramiko.channel

   1  # Copyright (C) 2003-2007  Robey Pointer <robey@lag.net> 
   2  # 
   3  # This file is part of paramiko. 
   4  # 
   5  # Paramiko is free software; you can redistribute it and/or modify it under the 
   6  # terms of the GNU Lesser General Public License as published by the Free 
   7  # Software Foundation; either version 2.1 of the License, or (at your option) 
   8  # any later version. 
   9  # 
  10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
  11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
  12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
  13  # details. 
  14  # 
  15  # You should have received a copy of the GNU Lesser General Public License 
  16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
  17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
  18   
  19  """ 
  20  Abstraction for an SSH2 channel. 
  21  """ 
  22   
  23  import binascii 
  24  import sys 
  25  import time 
  26  import threading 
  27  import socket 
  28  import os 
  29   
  30  from paramiko.common import * 
  31  from paramiko import util 
  32  from paramiko.message import Message 
  33  from paramiko.ssh_exception import SSHException 
  34  from paramiko.file import BufferedFile 
  35  from paramiko.buffered_pipe import BufferedPipe, PipeTimeout 
  36  from paramiko import pipe 
  37   
  38   
  39  # lower bound on the max packet size we'll accept from the remote host 
  40  MIN_PACKET_SIZE = 1024 
  41   
  42   
43 -class Channel (object):
44 """ 45 A secure tunnel across an SSH L{Transport}. A Channel is meant to behave 46 like a socket, and has an API that should be indistinguishable from the 47 python socket API. 48 49 Because SSH2 has a windowing kind of flow control, if you stop reading data 50 from a Channel and its buffer fills up, the server will be unable to send 51 you any more data until you read some of it. (This won't affect other 52 channels on the same transport -- all channels on a single transport are 53 flow-controlled independently.) Similarly, if the server isn't reading 54 data you send, calls to L{send} may block, unless you set a timeout. This 55 is exactly like a normal network socket, so it shouldn't be too surprising. 56 """ 57
58 - def __init__(self, chanid):
59 """ 60 Create a new channel. The channel is not associated with any 61 particular session or L{Transport} until the Transport attaches it. 62 Normally you would only call this method from the constructor of a 63 subclass of L{Channel}. 64 65 @param chanid: the ID of this channel, as passed by an existing 66 L{Transport}. 67 @type chanid: int 68 """ 69 self.chanid = chanid 70 self.remote_chanid = 0 71 self.transport = None 72 self.active = False 73 self.eof_received = 0 74 self.eof_sent = 0 75 self.in_buffer = BufferedPipe() 76 self.in_stderr_buffer = BufferedPipe() 77 self.timeout = None 78 self.closed = False 79 self.ultra_debug = False 80 self.lock = threading.Lock() 81 self.out_buffer_cv = threading.Condition(self.lock) 82 self.in_window_size = 0 83 self.out_window_size = 0 84 self.in_max_packet_size = 0 85 self.out_max_packet_size = 0 86 self.in_window_threshold = 0 87 self.in_window_sofar = 0 88 self.status_event = threading.Event() 89 self._name = str(chanid) 90 self.logger = util.get_logger('paramiko.transport') 91 self._pipe = None 92 self.event = threading.Event() 93 self.combine_stderr = False 94 self.exit_status = -1 95 self.origin_addr = None
96
97 - def __del__(self):
98 try: 99 self.close() 100 except: 101 pass
102
103 - def __repr__(self):
104 """ 105 Return a string representation of this object, for debugging. 106 107 @rtype: str 108 """ 109 out = '<paramiko.Channel %d' % self.chanid 110 if self.closed: 111 out += ' (closed)' 112 elif self.active: 113 if self.eof_received: 114 out += ' (EOF received)' 115 if self.eof_sent: 116 out += ' (EOF sent)' 117 out += ' (open) window=%d' % (self.out_window_size) 118 if len(self.in_buffer) > 0: 119 out += ' in-buffer=%d' % (len(self.in_buffer),) 120 out += ' -> ' + repr(self.transport) 121 out += '>' 122 return out
123
124 - def get_pty(self, term='vt100', width=80, height=24):
125 """ 126 Request a pseudo-terminal from the server. This is usually used right 127 after creating a client channel, to ask the server to provide some 128 basic terminal semantics for a shell invoked with L{invoke_shell}. 129 It isn't necessary (or desirable) to call this method if you're going 130 to exectue a single command with L{exec_command}. 131 132 @param term: the terminal type to emulate (for example, C{'vt100'}) 133 @type term: str 134 @param width: width (in characters) of the terminal screen 135 @type width: int 136 @param height: height (in characters) of the terminal screen 137 @type height: int 138 139 @raise SSHException: if the request was rejected or the channel was 140 closed 141 """ 142 if self.closed or self.eof_received or self.eof_sent or not self.active: 143 raise SSHException('Channel is not open') 144 m = Message() 145 m.add_byte(chr(MSG_CHANNEL_REQUEST)) 146 m.add_int(self.remote_chanid) 147 m.add_string('pty-req') 148 m.add_boolean(True) 149 m.add_string(term) 150 m.add_int(width) 151 m.add_int(height) 152 # pixel height, width (usually useless) 153 m.add_int(0).add_int(0) 154 m.add_string('') 155 self.event.clear() 156 self.transport._send_user_message(m) 157 self._wait_for_event()
158
159 - def invoke_shell(self):
160 """ 161 Request an interactive shell session on this channel. If the server 162 allows it, the channel will then be directly connected to the stdin, 163 stdout, and stderr of the shell. 164 165 Normally you would call L{get_pty} before this, in which case the 166 shell will operate through the pty, and the channel will be connected 167 to the stdin and stdout of the pty. 168 169 When the shell exits, the channel will be closed and can't be reused. 170 You must open a new channel if you wish to open another shell. 171 172 @raise SSHException: if the request was rejected or the channel was 173 closed 174 """ 175 if self.closed or self.eof_received or self.eof_sent or not self.active: 176 raise SSHException('Channel is not open') 177 m = Message() 178 m.add_byte(chr(MSG_CHANNEL_REQUEST)) 179 m.add_int(self.remote_chanid) 180 m.add_string('shell') 181 m.add_boolean(1) 182 self.event.clear() 183 self.transport._send_user_message(m) 184 self._wait_for_event()
185
186 - def exec_command(self, command):
187 """ 188 Execute a command on the server. If the server allows it, the channel 189 will then be directly connected to the stdin, stdout, and stderr of 190 the command being executed. 191 192 When the command finishes executing, the channel will be closed and 193 can't be reused. You must open a new channel if you wish to execute 194 another command. 195 196 @param command: a shell command to execute. 197 @type command: str 198 199 @raise SSHException: if the request was rejected or the channel was 200 closed 201 """ 202 if self.closed or self.eof_received or self.eof_sent or not self.active: 203 raise SSHException('Channel is not open') 204 m = Message() 205 m.add_byte(chr(MSG_CHANNEL_REQUEST)) 206 m.add_int(self.remote_chanid) 207 m.add_string('exec') 208 m.add_boolean(True) 209 m.add_string(command) 210 self.event.clear() 211 self.transport._send_user_message(m) 212 self._wait_for_event()
213
214 - def invoke_subsystem(self, subsystem):
215 """ 216 Request a subsystem on the server (for example, C{sftp}). If the 217 server allows it, the channel will then be directly connected to the 218 requested subsystem. 219 220 When the subsystem finishes, the channel will be closed and can't be 221 reused. 222 223 @param subsystem: name of the subsystem being requested. 224 @type subsystem: str 225 226 @raise SSHException: if the request was rejected or the channel was 227 closed 228 """ 229 if self.closed or self.eof_received or self.eof_sent or not self.active: 230 raise SSHException('Channel is not open') 231 m = Message() 232 m.add_byte(chr(MSG_CHANNEL_REQUEST)) 233 m.add_int(self.remote_chanid) 234 m.add_string('subsystem') 235 m.add_boolean(True) 236 m.add_string(subsystem) 237 self.event.clear() 238 self.transport._send_user_message(m) 239 self._wait_for_event()
240
241 - def resize_pty(self, width=80, height=24):
242 """ 243 Resize the pseudo-terminal. This can be used to change the width and 244 height of the terminal emulation created in a previous L{get_pty} call. 245 246 @param width: new width (in characters) of the terminal screen 247 @type width: int 248 @param height: new height (in characters) of the terminal screen 249 @type height: int 250 251 @raise SSHException: if the request was rejected or the channel was 252 closed 253 """ 254 if self.closed or self.eof_received or self.eof_sent or not self.active: 255 raise SSHException('Channel is not open') 256 m = Message() 257 m.add_byte(chr(MSG_CHANNEL_REQUEST)) 258 m.add_int(self.remote_chanid) 259 m.add_string('window-change') 260 m.add_boolean(True) 261 m.add_int(width) 262 m.add_int(height) 263 m.add_int(0).add_int(0) 264 self.event.clear() 265 self.transport._send_user_message(m) 266 self._wait_for_event()
267
268 - def exit_status_ready(self):
269 """ 270 Return true if the remote process has exited and returned an exit 271 status. You may use this to poll the process status if you don't 272 want to block in L{recv_exit_status}. Note that the server may not 273 return an exit status in some cases (like bad servers). 274 275 @return: True if L{recv_exit_status} will return immediately 276 @rtype: bool 277 @since: 1.7.3 278 """ 279 return self.closed or self.status_event.isSet()
280
281 - def recv_exit_status(self):
282 """ 283 Return the exit status from the process on the server. This is 284 mostly useful for retrieving the reults of an L{exec_command}. 285 If the command hasn't finished yet, this method will wait until 286 it does, or until the channel is closed. If no exit status is 287 provided by the server, -1 is returned. 288 289 @return: the exit code of the process on the server. 290 @rtype: int 291 292 @since: 1.2 293 """ 294 while True: 295 if self.closed or self.status_event.isSet(): 296 break 297 self.status_event.wait(0.1) 298 return self.exit_status
299
300 - def send_exit_status(self, status):
301 """ 302 Send the exit status of an executed command to the client. (This 303 really only makes sense in server mode.) Many clients expect to 304 get some sort of status code back from an executed command after 305 it completes. 306 307 @param status: the exit code of the process 308 @type status: int 309 310 @since: 1.2 311 """ 312 # in many cases, the channel will not still be open here. 313 # that's fine. 314 m = Message() 315 m.add_byte(chr(MSG_CHANNEL_REQUEST)) 316 m.add_int(self.remote_chanid) 317 m.add_string('exit-status') 318 m.add_boolean(False) 319 m.add_int(status) 320 self.transport._send_user_message(m)
321
322 - def request_x11(self, screen_number=0, auth_protocol=None, auth_cookie=None, 323 single_connection=False, handler=None):
324 """ 325 Request an x11 session on this channel. If the server allows it, 326 further x11 requests can be made from the server to the client, 327 when an x11 application is run in a shell session. 328 329 From RFC4254:: 330 331 It is RECOMMENDED that the 'x11 authentication cookie' that is 332 sent be a fake, random cookie, and that the cookie be checked and 333 replaced by the real cookie when a connection request is received. 334 335 If you omit the auth_cookie, a new secure random 128-bit value will be 336 generated, used, and returned. You will need to use this value to 337 verify incoming x11 requests and replace them with the actual local 338 x11 cookie (which requires some knoweldge of the x11 protocol). 339 340 If a handler is passed in, the handler is called from another thread 341 whenever a new x11 connection arrives. The default handler queues up 342 incoming x11 connections, which may be retrieved using 343 L{Transport.accept}. The handler's calling signature is:: 344 345 handler(channel: Channel, (address: str, port: int)) 346 347 @param screen_number: the x11 screen number (0, 10, etc) 348 @type screen_number: int 349 @param auth_protocol: the name of the X11 authentication method used; 350 if none is given, C{"MIT-MAGIC-COOKIE-1"} is used 351 @type auth_protocol: str 352 @param auth_cookie: hexadecimal string containing the x11 auth cookie; 353 if none is given, a secure random 128-bit value is generated 354 @type auth_cookie: str 355 @param single_connection: if True, only a single x11 connection will be 356 forwarded (by default, any number of x11 connections can arrive 357 over this session) 358 @type single_connection: bool 359 @param handler: an optional handler to use for incoming X11 connections 360 @type handler: function 361 @return: the auth_cookie used 362 """ 363 if self.closed or self.eof_received or self.eof_sent or not self.active: 364 raise SSHException('Channel is not open') 365 if auth_protocol is None: 366 auth_protocol = 'MIT-MAGIC-COOKIE-1' 367 if auth_cookie is None: 368 auth_cookie = binascii.hexlify(self.transport.randpool.get_bytes(16)) 369 370 m = Message() 371 m.add_byte(chr(MSG_CHANNEL_REQUEST)) 372 m.add_int(self.remote_chanid) 373 m.add_string('x11-req') 374 m.add_boolean(True) 375 m.add_boolean(single_connection) 376 m.add_string(auth_protocol) 377 m.add_string(auth_cookie) 378 m.add_int(screen_number) 379 self.event.clear() 380 self.transport._send_user_message(m) 381 self._wait_for_event() 382 self.transport._set_x11_handler(handler) 383 return auth_cookie
384
385 - def get_transport(self):
386 """ 387 Return the L{Transport} associated with this channel. 388 389 @return: the L{Transport} that was used to create this channel. 390 @rtype: L{Transport} 391 """ 392 return self.transport
393
394 - def set_name(self, name):
395 """ 396 Set a name for this channel. Currently it's only used to set the name 397 of the channel in logfile entries. The name can be fetched with the 398 L{get_name} method. 399 400 @param name: new channel name 401 @type name: str 402 """ 403 self._name = name
404
405 - def get_name(self):
406 """ 407 Get the name of this channel that was previously set by L{set_name}. 408 409 @return: the name of this channel. 410 @rtype: str 411 """ 412 return self._name
413
414 - def get_id(self):
415 """ 416 Return the ID # for this channel. The channel ID is unique across 417 a L{Transport} and usually a small number. It's also the number 418 passed to L{ServerInterface.check_channel_request} when determining 419 whether to accept a channel request in server mode. 420 421 @return: the ID of this channel. 422 @rtype: int 423 """ 424 return self.chanid
425
426 - def set_combine_stderr(self, combine):
427 """ 428 Set whether stderr should be combined into stdout on this channel. 429 The default is C{False}, but in some cases it may be convenient to 430 have both streams combined. 431 432 If this is C{False}, and L{exec_command} is called (or C{invoke_shell} 433 with no pty), output to stderr will not show up through the L{recv} 434 and L{recv_ready} calls. You will have to use L{recv_stderr} and 435 L{recv_stderr_ready} to get stderr output. 436 437 If this is C{True}, data will never show up via L{recv_stderr} or 438 L{recv_stderr_ready}. 439 440 @param combine: C{True} if stderr output should be combined into 441 stdout on this channel. 442 @type combine: bool 443 @return: previous setting. 444 @rtype: bool 445 446 @since: 1.1 447 """ 448 data = '' 449 self.lock.acquire() 450 try: 451 old = self.combine_stderr 452 self.combine_stderr = combine 453 if combine and not old: 454 # copy old stderr buffer into primary buffer 455 data = self.in_stderr_buffer.empty() 456 finally: 457 self.lock.release() 458 if len(data) > 0: 459 self._feed(data) 460 return old
461 462 463 ### socket API 464 465
466 - def settimeout(self, timeout):