o bc@s"dZddlZddlZddlZddlmZddlmZm Z ddl m Z ddl m Z ddlmZmZGdd d e jZd Zd Zd Zd ZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%iZ&e'()D]\Z*Z+e*dddkrxe*e&e+<qheej,ej-Z.e/dde0dDZ1e&e_2dS) 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 networkStringc@seZdZdZdZeZddZddZddZ d d Z d d Z d dZ ddZ ddZddZddZddZddZddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*ZdDd,d-ZdEd/d0ZdDd1d2Zd3d4Zd5d6Zd7d8Z d9d:Z!d;d<Z"d=d>Z#d?d@Z$dAdBZ%dCS)F 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-connectioncCs,d|_i|_i|_i|_dgi|_d|_dS)Nrglobal)localChannelIDlocalToRemoteChannelchannelschannelsToRemoteChannel deferreds transportselfr>/usr/lib/python3/dist-packages/twisted/conch/ssh/connection.py__init__/s   zSSHConnection.__init__cCst|jdr ||jj_dSdS)Navatar)hasattrrrconnrrrrserviceStarted=s zSSHConnection.serviceStartedcCsVt|jD]}||q|jr%|j\}}|tjj |js| dS)z8 Called when the connection is stopped. N) listrkeys channelClosedr popitem openFailedtwistedinternetrConnectionLost_cleanupGlobalDeferreds)rchannel_rrrserviceStoppedAs  zSSHConnection.serviceStoppedcCs4|jdD] }|tdq|jddd=dS)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)rdrrrr"Psz%SSHConnection._cleanupGlobalDeferredscCsxt|\}}t|dd|dd}}|||}|r:t}d}|r1t}t|ttfr1|d}|j ||dSdS)z The other side has made a global request. Payload:: string request type bool want reply This dispatches to self.gotGlobalRequest. rN) rgetNSordgotGlobalRequestMSG_REQUEST_FAILUREMSG_REQUEST_SUCCESS isinstancetuplerr sendPacket)rpacket requestTyperest wantReplyretreplydatarrrssh_GLOBAL_REQUEST[s  z SSHConnection.ssh_GLOBAL_REQUESTcCs&|jd|jdd|dS)z Our global request succeeded. Get the appropriate Deferred and call it back with the packet we received. zglobal request successr rN)_logdebugrpopcallbackrr3rrrssh_REQUEST_SUCCESSps z!SSHConnection.ssh_REQUEST_SUCCESScCs.|jd|jddtd|dS)z~ Our global request failed. Get the appropriate Deferred and errback it with the packet we received. zglobal request failurer rzglobal request failedN)r;r<rr=r&rr'r?rrrssh_REQUEST_FAILURExs  z!SSHConnection.ssh_REQUEST_FAILUREc CsNt|\}}td|dd\}}}|dd}zA|||||}|j}|jd7_||_||j|<||j|<||j |<t d|||j |j |j } |jt| ||WdSty} z?|jdt| tjr| j\} } t| tr~| | } } nt} d} |jtt d|| tt| td WYd} ~ dSd} ~ ww) 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 r)>4Lzchannel open failedzunknown failure>2Lr*)rr+structunpack getChannelr idr rr packlocalWindowSizelocalMaxPacket specificDatarr2MSG_CHANNEL_OPEN_CONFIRMATION channelOpen Exceptionr;failurer0rr'argsintOPEN_CONNECT_FAILEDMSG_CHANNEL_OPEN_FAILURENSr) rr3 channelTyper5 senderChannel windowSize maxPacketr# localChannelopenConfirmPackete textualInforeasonrrrssh_CHANNEL_OPENsT             zSSHConnection.ssh_CHANNEL_OPENcCsftd|dd\}}}}|dd}|j|}||_||j|<||j|<||_||_||dS)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. rDN) rFrGr rr rremoteWindowLeftremoteMaxPacketrO)rr3r[ remoteChannelrYrZrMr#rrrssh_CHANNEL_OPEN_CONFIRMATIONs     z+SSHConnection.ssh_CHANNEL_OPEN_CONFIRMATIONcCs`td|dd\}}t|ddd}|j|}|j|=||_t||}||dS)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. rENr) rFrGrr+r rrr'r)rr3r[ reasonCode reasonDescr#r_rrrssh_CHANNEL_OPEN_FAILUREs   z&SSHConnection.ssh_CHANNEL_OPEN_FAILUREcCs0td|dd\}}|j|}||dS)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. rENrf)rFrGr addWindowBytes)rr3r[ bytesToAddr#rrrssh_CHANNEL_WINDOW_ADJUSTs z'SSHConnection.ssh_CHANNEL_WINDOW_ADJUSTcCstd|dd\}}|j|}||jks||jkr(|jd||dSt |ddd}|j|8_|j|j dkrL| ||j |j| |dS)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(). rENrfz too much datar) rFrGr localWindowLeftrLr;r sendCloserr+rK adjustWindow dataReceived)rr3r[ dataLengthr#r9rrrssh_CHANNEL_DATAs    zSSHConnection.ssh_CHANNEL_DATAcCstd|dd\}}}|j|}||jks||jkr)|jd||dSt |ddd}|j|8_|j|j dkrM| ||j |j| ||dS)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(). rBNrCztoo much extdatarfrrn) rFrGr rorLr;rrprr+rKrq extReceived)rr3r[typeCodersr#r9rrrssh_CHANNEL_EXTENDED_DATA s    z'SSHConnection.ssh_CHANNEL_EXTENDED_DATAcCs.td|ddd}|j|}|dS)z The other side is not sending any more data. Payload:: uint32 local channel number Notify the channel by calling its eofReceived() method. >LNrmr)rFrGr eofReceivedrr3r[r#rrrssh_CHANNEL_EOF&s  zSSHConnection.ssh_CHANNEL_EOFcCsRtd|ddd}|j|}|d|_|jr%|jr'||dSdSdS)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(). rxNrmrT)rFrGr closeReceived remoteClosed localClosedrrzrrrssh_CHANNEL_CLOSE1s  zSSHConnection.ssh_CHANNEL_CLOSEcCstd|ddd}t|dd\}}t|dd}|j|}t|j||dd}|rB| |j || |j ||SdS)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. rxNrmrr)) rFrGrr+r,r r maybeDeferredrequestReceived addCallback_cbChannelRequest addErrback_ebChannelRequest)rr3r[r4r5r6r#r(rrrssh_CHANNEL_REQUESTAs  z!SSHConnection.ssh_CHANNEL_REQUESTcCs.|std|jttd|j|dS)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 requestrxN)rr'rr2MSG_CHANNEL_SUCCESSrFrJr rresultr[rrrrWs  zSSHConnection._cbChannelRequestcCs |jttd|j|dS)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} rxN)rr2MSG_CHANNEL_FAILURErFrJr rrrrrls zSSHConnection._ebChannelRequestcCsFtd|ddd}|j|r!|j|d}|ddSdS)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. rxNrmr)rFrGrgetr=r>rr3r[r(rrrssh_CHANNEL_SUCCESS{s  z!SSHConnection.ssh_CHANNEL_SUCCESScCsLtd|ddd}|j|r$|j|d}|tddSdS)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}. rxNrmrzchannel request failed)rFrGrrr=r&rr'rrrrssh_CHANNEL_FAILUREs  z!SSHConnection.ssh_CHANNEL_FAILURErcCsH|jtt||r dp d||r"t}|jd||SdS)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) rr2MSG_GLOBAL_REQUESTrrVrDeferredrappend)rrequestr9r6r(rrrsendGlobalRequests zSSHConnection.sendGlobalRequestr*c Csp|jjd|j|j|jd|jtt |j t d|j|j|j||j|_ ||j|j<|jd7_dS)z Open a new channel on this connection. @type channel: subclass of C{SSHChannel} @type extra: L{bytes} z: 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) r;r<rrrr-rreplacer)rr4r9rrrrr-Ys zSSHConnection.gotGlobalRequestcCsh||jvr2d|_|_|j|j=|j|j=|j|=|j|jgD] }|t dq!| dSdS)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) rr~r}r rIr rr=r&rr'closed)rr#r(rrrrus    zSSHConnection.channelClosedN)r)r*)&__name__ __module__ __qualname____doc__rrr;rrr%r"r:r@rAr`rerirlrtrwr{rrrrrrrrrrqrrrrprHr-rrrrrr sF  5      ( r PQRZ[\]^_`abcdr)rnrmMSG_ccs$|] }|tvr |ntdVqdS)r$N) alphanumsr,).0irrr s"r)3rstringrFtwisted.internet.errorr twisted.conchrtwisted.conch.sshrrtwisted.internetrtwisted.loggerrtwisted.python.compatrr SSHServicer rr/r.rrNrUrrrrrrrr OPEN_ADMINISTRATIVELY_PROHIBITEDrTrOPEN_RESOURCE_SHORTAGEEXTENDED_DATA_STDERRmessageslocalscopyitemsrvalue ascii_lettersdigitsrbytesrangerprotocolMessagesrrrrsR   v