ϪfcdZddlZddlZddlZddlmZddlmZm Z ddl m Z ddl m Z ddlmZmZGdd e j"Zd Zd Zd Zd ZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%iZ&e'jQjSD]\Z*Z+e*dddk(se*e&e+<eejXejZzZ.e/de0dDZ1e&e_2y)z This module contains the implementation of the ssh-connection service, which allows access to the shell and port-forwarding. Maintainer: Paul Swartz N)error)commonservice)defer)Logger) nativeString networkStringceZdZdZdZeZdZdZdZ dZ dZ dZ d Z d Zd Zd Zd ZdZdZdZdZdZdZdZdZdZd#dZd$dZd#dZdZdZdZ dZ!dZ"dZ#d Z$d!Z%y")% SSHConnectionao An implementation of the 'ssh-connection' service. It is used to multiplex multiple channels over the single SSH connection. @ivar localChannelID: the next number to use as a local channel ID. @type localChannelID: L{int} @ivar channels: a L{dict} mapping a local channel ID to C{SSHChannel} subclasses. @type channels: L{dict} @ivar localToRemoteChannel: a L{dict} mapping a local channel ID to a remote channel ID. @type localToRemoteChannel: L{dict} @ivar channelsToRemoteChannel: a L{dict} mapping a C{SSHChannel} subclass to remote channel ID. @type channelsToRemoteChannel: L{dict} @ivar deferreds: a L{dict} mapping a local channel ID to a C{list} of C{Deferreds} for outstanding channel requests. Also, the 'global' key stores the C{list} of pending global request C{Deferred}s. sssh-connectionc\d|_i|_i|_i|_dgi|_d|_y)Nrglobal)localChannelIDlocalToRemoteChannelchannelschannelsToRemoteChannel deferreds transportselfs >/usr/lib/python3/dist-packages/twisted/conch/ssh/connection.py__init__zSSHConnection.__init__/s5$&! ')$#Bcht|jdr||jj_yy)Navatar)hasattrrrconnrs rserviceStartedzSSHConnection.serviceStarted=s' 4>>8 ,)-DNN ! ! & -rcpt|jjD]}|j||jra|jj \}}|j tjjj|jra|jy)z8 Called when the connection is stopped. N) listrkeys channelClosedrpopitem openFailedtwistedinternetrConnectionLost_cleanupGlobalDeferreds)rchannel_s rserviceStoppedzSSHConnection.serviceStoppedAs D88==?@ (G   w ' (mm==002LQ   w//55DDF Gmm $$&rc|jdD]&}|jtjd(|jddd=y)z All pending requests that have returned a deferred must be errbacked when this service is stopped, otherwise they might be left uncalled and uncallable. r zConnection stopped.N)rerrbackr ConchError)rds rr'z%SSHConnection._cleanupGlobalDeferredsPsE ) ?A IIe&&'<= > ? NN8 $Q 'rctj|\}}t|dd|dd}}|j||}|rHt}d}|r!t }t |ttfr|d}|jj||yy)z The other side has made a global request. Payload:: string request type bool want reply This dispatches to self.gotGlobalRequest. rNr) rgetNSordgotGlobalRequestMSG_REQUEST_FAILUREMSG_REQUEST_SUCCESS isinstancetuplerr sendPacket)rpacket requestTyperest wantReplyretreplydatas rssh_GLOBAL_REQUESTz SSHConnection.ssh_GLOBAL_REQUEST[s#LL0 Td1Qi.$qr(4 ##K6 'ED+cE4=1q6D NN % %eT 2 rc|jjd|jdjdj |y)z Our global request succeeded. Get the appropriate Deferred and call it back with the packet we received. zglobal request successr rN)_logdebugrpopcallbackrr9s rssh_REQUEST_SUCCESSz!SSHConnection.ssh_REQUEST_SUCCESSps7 01 x $$Q'008rc|jjd|jdjdj t j d|y)z~ Our global request failed. Get the appropriate Deferred and errback it with the packet we received. zglobal request failurer rzglobal request failedN)rBrCrrDr,rr-rFs rssh_REQUEST_FAILUREz!SSHConnection.ssh_REQUEST_FAILURExsH 01 x $$Q'//   4f = rc tj|\}}tjd|dd\}}}|dd} |j ||||}|j }|xj dz c_||_||j|<||j|<||j|<tjd|||j|j|jz} |jjt | |j#|y#t$$r} |j&j)dt+| t,j.r$| j0\} } t+| t2r | | } } nt4} d} |jjt6tjd|| tj8t;| ztj8d zYd} ~ yd} ~ wwxYw) a The other side wants to get a channel. Payload:: string channel name uint32 remote channel number uint32 remote window size uint32 remote maximum packet size We get a channel from self.getChannel(), give it a local channel number and notify the other side. Then notify the channel by calling its channelOpen method. >3LN r0>4Lzchannel open failedzunknown failure>2Lr)rr1structunpack getChannelridrrrpacklocalWindowSizelocalMaxPacket specificDatarr8MSG_CHANNEL_OPEN_CONFIRMATION channelOpen ExceptionrBfailurer6rr-argsintOPEN_CONNECT_FAILEDMSG_CHANNEL_OPEN_FAILURENSr ) rr9 channelTyper; senderChannel windowSize maxPacketr( localChannelopenConfirmPackete textualInforeasons rssh_CHANNEL_OPENzSSHConnection.ssh_CHANNEL_OPENs#LL0 T/5}}UD"I/N, z9bc# ook:y&QG..L   1 $ %GJ*1DMM, '4AD ( ( 16CD % %l 3 ! ++** &&'  NN % %&CEV W    '  II  3 4!U--.&'ff# Vk3/*0+K,/ NN % %( E=&9))M+678))C.!   sCD G/C G**G/ctjd|dd\}}}}|dd}|j|}||_||j|<||j |<||_||_|j|y)a The other side accepted our MSG_CHANNEL_OPEN request. Payload:: uint32 local channel number uint32 remote channel number uint32 remote window size uint32 remote maximum packet size Find the channel using the local channel number and notify its channelOpen method. rMN) rOrPrrrrremoteWindowLeftremoteMaxPacketrX)rr9rd remoteChannelrbrcrVr(s rssh_CHANNEL_OPEN_CONFIRMATIONz+SSHConnection.ssh_CHANNEL_OPEN_CONFIRMATIONs@F}} 6#2;@ <}j)bc{ -- - 2?!!,/0=$$W-#- "+L)rctjd|dd\}}tj|ddd}|j|}|j|=||_t j||}|j|y)a; The other side did not accept our MSG_CHANNEL_OPEN request. Payload:: uint32 local channel number uint32 reason code string reason description Find the channel using the local channel number and notify it by calling its openFailed() method. rNNr) rOrPrr1rrrr-r#)rr9rd reasonCode reasonDescr(rhs rssh_CHANNEL_OPEN_FAILUREz&SSHConnection.ssh_CHANNEL_OPEN_FAILUREsy$*==r #C j\\&*-a0 -- - MM, ' !!*j96"rc|tjd|dd\}}|j|}|j|y)z The other side is adding bytes to its window. Payload:: uint32 local channel number uint32 bytes to add Call the channel's addWindowBytes() method to add new bytes to the remote window. rNNrq)rOrPraddWindowBytes)rr9rd bytesToAddr(s rssh_CHANNEL_WINDOW_ADJUSTz'SSHConnection.ssh_CHANNEL_WINDOW_ADJUSTs;$*==r #C j-- -z*rctjd|dd\}}|j|}||jkDs||jkDr-|j j d|j|ytj|ddd}|xj|zc_|j|jdzkr)|j||j|jz |j|y)a The other side is sending us data. Payload:: uint32 local channel number string data Check to make sure the other side hasn't sent too much data (more than what's in the window, or more than the maximum packet size). If they have, close the channel. Otherwise, decrease the available window and pass the data to the channel's dataReceived(). rNNrqz too much datar) rOrPrlocalWindowLeftrUrBr sendCloserr1rT adjustWindow dataReceived)rr9rd dataLengthr(r?s rssh_CHANNEL_DATAzSSHConnection.ssh_CHANNEL_DATAs$*==r #C j-- - 00 0JAWAW4W IIOOO , NN7 # ||F12J'*:-  " "W%<%<%A A   0073J3JJ  T"rctjd|dd\}}}|j|}||jkDs||jkDr-|j j d|j|ytj|ddd}|xj|zc_|j|jdzkr)|j||j|jz |j||y)a The other side is sending us exteneded data. Payload:: uint32 local channel number uint32 type code string data Check to make sure the other side hasn't sent too much data (more than what's in the window, or than the maximum packet size). If they have, close the channel. Otherwise, decrease the available window and pass the data and type code to the channel's extReceived(). rKNrLztoo much extdatarqrr{) rOrPrr|rUrBrr}rr1rTr~ extReceived)rr9rdtypeCoderr(r?s rssh_CHANNEL_EXTENDED_DATAz'SSHConnection.ssh_CHANNEL_EXTENDED_DATA s.4]]5&"+-N* h -- - // /:@V@V3V IIOO. / NN7 # ||F12J'*:-  " "W%<%<%A A   0073J3JJ  Hd+rcztjd|ddd}|j|}|jy)z The other side is not sending any more data. Payload:: uint32 local channel number Notify the channel by calling its eofReceived() method. >LNrzr)rOrPr eofReceivedrr9rdr(s rssh_CHANNEL_EOFzSSHConnection.ssh_CHANNEL_EOF&s9}}T6"1:6q9 -- -rctjd|ddd}|j|}|jd|_|j r|jr|j |yyy)a1 The other side is closing its end; it does not want to receive any more data. Payload:: uint32 local channel number Notify the channnel by calling its closeReceived() method. If the channel has also sent a close message, call self.channelClosed(). rNrzrT)rOrPr closeReceived remoteClosed localClosedr!rs rssh_CHANNEL_CLOSEzSSHConnection.ssh_CHANNEL_CLOSE1sh}}T6"1:6q9 -- -#   7#7#7   w '$8 rcltjd|ddd}tj|dd\}}t |dd}|j |}t j|j||dd}|r:|j|j||j|j||Sy)ay The other side is sending a request to a channel. Payload:: uint32 local channel number string request name bool want reply Pass the message to the channel's requestReceived method. If the other side wants a reply, add callbacks which will send the reply. rNrzrr0) rOrPrr1r2rr maybeDeferredrequestReceived addCallback_cbChannelRequest addErrback_ebChannelRequest)rr9rdr:r;r<r(r.s rssh_CHANNEL_REQUESTz!SSHConnection.ssh_CHANNEL_REQUESTAs}}T6"1:6q9 "LL4 TQq N -- -    7 7d12h O  MM$00, ? LL// >H rc|stjd|jjtt j d|j|y)a) Called back if the other side wanted a reply to a channel request. If the result is true, send a MSG_CHANNEL_SUCCESS. Otherwise, raise a C{error.ConchError} @param result: the value returned from the channel's requestReceived() method. If it's False, the request failed. @type result: L{bool} @param localChannel: the local channel ID of the channel to which the request was made. @type localChannel: L{int} @raises ConchError: if the result is False. zfailed requestrN)rr-rr8MSG_CHANNEL_SUCCESSrOrSrrresultrds rrzSSHConnection._cbChannelRequestWsG""#34 4 !!  KKd77 E F rc|jjttjd|j |y)a? Called if the other wisde wanted a reply to the channel requeset and the channel request failed. @param result: a Failure, but it's not used. @param localChannel: the local channel ID of the channel to which the request was made. @type localChannel: L{int} rN)rr8MSG_CHANNEL_FAILURErOrSrrs rrzSSHConnection._ebChannelRequestls2 !!  KKd77 E F rctjd|ddd}|jj|r0|j|j d}|j dyy)z Our channel request to the other side succeeded. Payload:: uint32 local channel number Get the C{Deferred} out of self.deferreds and call it back. rNrzr)rOrPrgetrDrErr9rdr.s rssh_CHANNEL_SUCCESSz!SSHConnection.ssh_CHANNEL_SUCCESS{sZ}}T6"1:6q9 >>  l +|,003A JJrN ,rctjd|ddd}|jj|rC|j|j d}|j t jdyy)z Our channel request to the other side failed. Payload:: uint32 local channel number Get the C{Deferred} out of self.deferreds and errback it with a C{error.ConchError}. rNrzrzchannel request failed)rOrPrrrDr,rr-rs rssh_CHANNEL_FAILUREz!SSHConnection.ssh_CHANNEL_FAILUREsg}}T6"1:6q9 >>  l +|,003A IIe&&'?@ A ,rc|jjttj||xrdxsdz|z|r4t j }|jdj||Sy)a  Send a global request for this connection. Current this is only used for remote->local TCP forwarding. @type request: L{bytes} @type data: L{bytes} @type wantReply: L{bool} @rtype: C{Deferred}/L{None} r N) rr8MSG_GLOBAL_REQUESTrr_rDeferredrappend)rrequestr?r<r.s rsendGlobalRequestzSSHConnection.sendGlobalRequestsk !!  IIg )"7"B7 Cd J   A NN8 $ + +A .H rc |jjd|j|j|j|j j ttj|jtjd|j|j|jz|z|j|_ ||j|j<|xjdz c_y)z Open a new channel on this connection. @type channel: subclass of C{SSHChannel} @type extra: L{bytes} z>8 ,>>((66ZDD&//@K,{";;DdD)A}Y5 <""#46OP PDIKrc |jjd|t|jdr&|jjj ||St |jdd}t|d|zd}|sy||S) a We got a global request. pretty much, this is just used by the client to request that we forward a port from the server to the client. Returns either: - 1: request accepted - 1, : request accepted with request specific data - 0: request denied By default, this dispatches to a method 'global_requestType' with -'s in requestType replaced with _'s. The found method is passed data. If this method cannot be found, this method returns 0. Otherwise, it returns the return value of that method. @type requestType: L{bytes} @type data: L{bytes} @rtype: L{int}/L{tuple} z got global {requestType} requestrr-_z global_%sNr) rBrCrrrr3rreplacer)rr:r?rs rr3zSSHConnection.gotGlobalRequestYs}$ : T 4>>8 ,>>((99+tL L";#6#6tT#BC D+ 3T :wrcr||jvrdx|_|_|j|j=|j |j=|j|=|j j|jgD]&}|jtjd(|jyy)a; Called when a channel is closed. It clears the local state related to the channel, and calls channel.closed(). MAKE SURE YOU CALL THIS METHOD, even if you subclass L{SSHConnection}. If you don't, things will break mysteriously. @type channel: L{SSHChannel} TzChannel closed.N) rrrrrRrrrDr,rr-closed)rr(r.s rr!zSSHConnection.channelClosedus d22 29= =G '"6))'**5 gjj),,W5^^'' B7 ? %**+<=> ? NN  3rN)r)r)&__name__ __module__ __qualname____doc__rrrBrrr*r'r@rGrIrirortrxrrrrrrrrrrrrr~rrrr}rQr3r!rrr r s( D 8D . '(3*9 3j*0#$ +#:,6 ( , *    B&!82.(   $  ("&P8rr PQRZ[\]^_`abcdr0r{rzMSG_c#FK|]}|tvr|n tdyw)r)N) alphanumsr2).0is r rsNaQ)^S9Ns!)3rstringrOtwisted.internet.errorr$ twisted.conchrtwisted.conch.sshrrtwisted.internetrtwisted.loggerrtwisted.python.compatrr SSHServicer rr5r4rrWr^rrrrrrrr OPEN_ADMINISTRATIVELY_PROHIBITEDr]rOPEN_RESOURCE_SHORTAGEEXTENDED_DATA_STDERRmessageslocalscopyitemsrvalue ascii_lettersdigitsrbytesrangerprotocolMessagesrrrrs%  -"!=o G&&o d "#$  8==?((*KD% BQx6 &..> ? N5:NN!) r