U
    ccVV                     @   s   d Z ddlZddlZddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZmZmZmZmZmZmZ ddlmZmZ ddlmZmZ ddlmZ d	d
 ZG dd deZdd ZG dd deZ dS )z
Packet handling
    N)HMAC)util)linefeed_bytecr_byte_valueasbytes	MSG_NAMESDEBUG	xffffffff	zero_byte)ubyte_ord)SSHExceptionProxyCommandFailure)Messagec                 C   s   t | || S N)r   digest)keymessageZdigest_class r   3/tmp/pip-unpacked-wheel-rglolp_m/paramiko/packet.pycompute_hmac.   s    r   c                   @   s   e Zd ZdZdS )NeedRekeyExceptionz1
    Exception indicating a rekey is needed.
    N)__name__
__module____qualname____doc__r   r   r   r   r   2   s   r   c                 C   s.   d }t | jtkr*t| jdkr*| jd }|S )Nr   )typeargstuplelen)eargr   r   r   	first_arg:   s    
r"   c                   @   s"  e Zd ZdZeddZeddZeddZeddZdd Z	e
dd Zdd	 Zd>ddZd?ddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd@d)d*Zd+d, Zd-d. Zd/d0 Zd1d2 Z d3d4 Z!d5d6 Z"d7d8 Z#d9d: Z$d;d< Z%d=S )A
Packetizerz9
    Implementation of the base SSH packet protocol.
          c                 C   s   || _ d | _d| _d| _d| _d| _t | _d| _d| _	d| _
d| _d| _d| _d| _d| _d| _d| _d | _d | _d| _d | _d | _t | _t | _d | _d | _d| _d| _d| _d| _t  | _!d| _"t## | _$d | _%d | _&d| _'d| _(d S )NFr      ))_Packetizer__socket_Packetizer__logger_Packetizer__closed_Packetizer__dump_packets_Packetizer__need_rekey_Packetizer__init_countbytes_Packetizer__remainder_Packetizer__sent_bytes_Packetizer__sent_packets_Packetizer__received_bytes_Packetizer__received_packets$_Packetizer__received_bytes_overflow&_Packetizer__received_packets_overflow_Packetizer__block_size_out_Packetizer__block_size_in_Packetizer__mac_size_out_Packetizer__mac_size_in_Packetizer__block_engine_out_Packetizer__block_engine_in_Packetizer__sdctr_out_Packetizer__mac_engine_out_Packetizer__mac_engine_in_Packetizer__mac_key_out_Packetizer__mac_key_in _Packetizer__compress_engine_out_Packetizer__compress_engine_in _Packetizer__sequence_number_out_Packetizer__sequence_number_in_Packetizer__etm_out_Packetizer__etm_in	threadingRLock_Packetizer__write_lock_Packetizer__keepalive_intervaltime_Packetizer__keepalive_last_Packetizer__keepalive_callback_Packetizer__timer_Packetizer__handshake_complete_Packetizer__timer_expired)selfsocketr   r   r   __init__Q   sJ    

zPacketizer.__init__c                 C   s   | j S r   )r)   rP   r   r   r   closed   s    zPacketizer.closedc                 C   s
   || _ dS )z?
        Set the Python log object to use for logging.
        N)r(   )rP   logr   r   r   set_log   s    zPacketizer.set_logFc                 C   s^   || _ || _|| _|| _|| _|| _d| _d| _|| _|  j	dO  _	| j	dkrZd| _	d| _
dS )zd
        Switch outbound data cipher.
        :param etm: Set encrypt-then-mac from OpenSSH
        r         FN)r9   r;   r5   r<   r7   r>   r/   r0   rD   r,   r+   )rP   block_engine
block_size
mac_enginemac_sizemac_keyZsdctretmr   r   r   set_outbound_cipher   s    
zPacketizer.set_outbound_cipherc                 C   sd   || _ || _|| _|| _|| _d| _d| _d| _d| _|| _	|  j
dO  _
| j
dkr`d| _
d| _dS )zc
        Switch inbound data cipher.
        :param etm: Set encrypt-then-mac from OpenSSH
        r   r$   rX   FN)r:   r6   r=   r8   r?   r1   r2   r3   r4   rE   r,   r+   )rP   rY   rZ   r[   r\   r]   r^   r   r   r   set_inbound_cipher   s    
zPacketizer.set_inbound_cipherc                 C   s
   || _ d S r   )r@   rP   Z
compressorr   r   r   set_outbound_compressor   s    z"Packetizer.set_outbound_compressorc                 C   s
   || _ d S r   )rA   ra   r   r   r   set_inbound_compressor   s    z!Packetizer.set_inbound_compressorc                 C   s   d| _ | j  d S NT)r)   r'   closerS   r   r   r   re      s    zPacketizer.closec                 C   s
   || _ d S r   r*   )rP   Zhexdumpr   r   r   set_hexdump   s    zPacketizer.set_hexdumpc                 C   s   | j S r   rf   rS   r   r   r   get_hexdump   s    zPacketizer.get_hexdumpc                 C   s   | j S r   )r8   rS   r   r   r   get_mac_size_in   s    zPacketizer.get_mac_size_inc                 C   s   | j S r   )r7   rS   r   r   r   get_mac_size_out   s    zPacketizer.get_mac_size_outc                 C   s   | j S )z
        Returns ``True`` if a new set of keys needs to be negotiated.  This
        will be triggered during a packet read or write, so it should be
        checked after every read or write, or at least after every few.
        r+   rS   r   r   r   
need_rekey   s    zPacketizer.need_rekeyc                 C   s   || _ || _t | _dS )z
        Turn on/off the callback keepalive.  If ``interval`` seconds pass with
        no data read from or written to the socket, the callback will be
        executed and the timer will be reset.
        N)rI   rL   rJ   rK   )rP   intervalcallbackr   r   r   set_keepalive   s    zPacketizer.set_keepalivec                 C   s
   d| _ d S rd   )rO   rS   r   r   r   
read_timer   s    zPacketizer.read_timerc                 C   s(   | j s$tt|| j| _ | j   dS )z
        Tells `Packetizer` that the handshake process started.
        Starts a book keeping timer that can signal a timeout in the
        handshake process.

        :param float timeout: amount of seconds to wait before timing out
        N)rM   rF   Timerfloatrp   start)rP   timeoutr   r   r   start_handshake   s    zPacketizer.start_handshakec                 C   s   | j s
dS | jrdS | jS )aR  
        Checks if the handshake has timed out.

        If `start_handshake` wasn't called before the call to this function,
        the return value will always be `False`. If the handshake completed
        before a timeout was reached, the return value will be `False`

        :return: handshake time out status, as a `bool`
        F)rM   rN   rO   rS   r   r   r   handshake_timed_out   s
    
zPacketizer.handshake_timed_outc                 C   s    | j r| j   d| _d| _dS )zF
        Tells `Packetizer` that the handshake has completed.
        FTN)rM   cancelrO   rN   rS   r   r   r   complete_handshake  s    
zPacketizer.complete_handshakec              
   C   sF  t  }t| jdkr>| jd| }| j|d | _|t|8 }|dkrBd}|  rZt z6| j|}t|dkrzt ||7 }|t|8 }W nr tjk
r   d}Y nZ tj	k
r } z8t
|}|tjkrd}n|tjkrn| jrt n W 5 d}~X Y nX |r>| jrt |r8t|dkr8| jr8t |   q>|S )a&  
        Read as close to N bytes as possible, blocking as long as necessary.

        :param int n: number of bytes to read
        :return: the data read, as a `str`

        :raises:
            ``EOFError`` -- if the socket was closed before all the bytes could
            be read
        r   NFT)r-   r   r.   rv   EOFErrorr'   recvrQ   rt   errorr"   errnoEAGAINEINTRr)   r+   r   _check_keepalive)rP   ncheck_rekeyoutZgot_timeoutxr    r!   r   r   r   read_all  sB    



zPacketizer.read_allc              
   C   s(  t   | _d}t|dkr$d}z| j|}W n tjk
rJ   d}Y nz tjk
r } z0t|}|t	j
krtd}n|t	jkrd}nd}W 5 d }~X Y n, tk
r    Y n tk
r   d}Y nX |rd}| jrd}n|dkr|dkrd}|d7 }|dk rt |t|krq$||d  }qd S )Nr   FT
   rW   )rJ   rK   r   r'   sendrQ   rt   r{   r"   r|   r}   r~   r   	Exceptionr)   ry   )rP   r   Z#iteration_with_zero_as_return_valueZretry_writer   r    r!   r   r   r   	write_allJ  s@    




zPacketizer.write_allc                 C   sr   | j }t|kr|| |7 }q|t}||d d | _ |d| }t|dkrj|d tkrj|dd }t|S )z
        Read a line from the socket.  We assume no data is pending after the
        line, so it's okay to attempt large reads.
        rW   Nr   r   )r.   r   _read_timeoutindexr   r   r   )rP   rt   bufr   r   r   r   readlineu  s    
zPacketizer.readlinec                 C   s  t |}t|d }|tkr&t| }n
d|}t|}| j  zp| jdk	rZ| |}| 	|}| j
r| td|| | tt|d | jdk	r| jr|dd | j|dd  }q| j|}n|}| jdk	r td| j}|| jr|n| }|t| j|| jd| j 7 }| jd t@ | _| | |  jt|7  _|  jd7  _| j| jkpr| j| jk}	|	r| jsd	}
| t|
| j| j d| _ d| _!| "  W 5 | j  X dS )
zR
        Write a block of data using the current cipher, as an SSH block.
        r   ${:x}NzWrite packet <{}>, length {}zOUT:    >IrW   z(Rekeying (hit {} packets, {} bytes sent))#r   r   r   formatr   rH   acquirereleaser@   _build_packetr*   _logr   r   format_binaryr9   rD   updatestructpackrB   r   r>   r<   r7   r	   r   r/   r0   REKEY_PACKETSREKEY_BYTESr+   r3   r4   _trigger_rekey)rP   datacmdcmd_nameZorig_lenpacketr   packedpayloadZsent_too_muchmsgr   r   r   send_message  sj    








  

 zPacketizer.send_messagec                 C   s  | j | jdd}| jrtd|dd d }|| j d }|dd | j |dd }| j | jdd}td| j|| }t| j	|| j
d| j }t||std	|}| jdk	r| j|}| jr| tt|d
 | jr|}ntd|dd d }|dd }|t| | j dkr,td|  || j t| }	|	d|t|  }|	|t| d }
| jdk	r| j|}|| }| jr| tt|d
 | jdkr| js|
d| j }td| j|| }t| j	|| j
d| j }t||std	t|d }|d||  }| jrF| td|| | jdk	r\| |}t|dd }| j|_| jd t@ | _|| j d }|  j|7  _|  jd7  _| jr|  j|7  _|  jd7  _| j| j ks| j| j!krDtdnL| j| j"ks| j| j#krDd}| t|| j| j d| _d| _| $  t|d }|t%krdt%| }n
d|}| jr| td|t| ||fS )z
        Only one thread should ever be in this function (no other locking is
        done).

        :raises: `.SSHException` -- if the packet is mangled
        :raises: `.NeedRekeyException` -- if the transport should rekey
        T)r   r   Nr   r   Fz>IIzMismatched MACzIN: zInvalid packet blockingrW   z"Got payload ({} bytes, {} padding)z+Remote transport is ignoring rekey requestsz,Rekeying (hit {} packets, {} bytes received)r   zRead packet <{}>, length {})&r   r6   rE   r   unpackr8   r   rC   r   r?   r=   r   Zconstant_time_bytes_eqr   r:   r   r*   r   r   r   r   r   r   rA   r   Zseqnor	   r1   r2   r+   r3   r4   REKEY_PACKETS_OVERFLOW_MAXREKEY_BYTES_OVERFLOW_MAXr   r   r   r   )rP   headerZpacket_size	remainingr   macZmac_payloadZmy_macleftoverr   Zpost_packetpaddingr   r   Zraw_packet_sizeerrr   r   r   r   r   read_message  s      
   





zPacketizer.read_messagec                 C   sH   | j d krd S tt|tr6|D ]}| j || q n| j || d S r   )r(   
issubclassr   listrU   )rP   levelr   mr   r   r   r   E  s    
zPacketizer._logc                 C   s@   | j r| jr| jrd S t }|| j| j  kr<|   || _d S r   )rI   r9   r+   rJ   rK   rL   )rP   nowr   r   r   r   N  s    zPacketizer._check_keepalivec              
   C   s   t   }z&| jd}t|dkr(t W qW nH tjk
rD   Y n4 tk
rv } zt|t	j
krdn W 5 d }~X Y nX | jrt t   }|| |krt q|S )N   r   )rJ   r'   rz   r   ry   rQ   rt   EnvironmentErrorr"   r|   r~   r)   )rP   rt   rs   r   r    r   r   r   r   r   [  s$    
zPacketizer._read_timeoutc                 C   s~   | j }| jrdnd}d| t|| |  }tdt|| d |}||7 }| js^| jd krl|t| 7 }n|t	|7 }|S )Nr   r&   rX   z>IBrW   )
r5   rD   r   r   r   r;   r9   r
   osurandom)rP   r   ZbsizeZaddlenr   r   r   r   r   r   q  s    zPacketizer._build_packetc                 C   s
   d| _ d S rd   rk   rS   r   r   r   r     s    zPacketizer._trigger_rekeyN)FF)F)F)&r   r   r   r   powr   r   r   r   rR   propertyrT   rV   r_   r`   rb   rc   re   rg   rh   ri   rj   rl   ro   rp   ru   rv   rx   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r#   A   sL   



0
  
% 

	
3+? 	r#   )!r   r|   r   rQ   r   rF   rJ   hmacr   Zparamikor   Zparamiko.commonr   r   r   r   r   r	   r
   Zparamiko.py3compatr   r   Zparamiko.ssh_exceptionr   r   Zparamiko.messager   r   r   r   r"   objectr#   r   r   r   r   <module>   s    $	