U
    ÓZjfk  ã                
   @   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 d\ZZzddlZW n& ek
r’ Z zeZW 5 dZ[X Y nX ddlmZmZ d	ZG d
d„ deƒZdd„ ZG dd„ deƒZG dd„ deƒZdS )z2
Configuration file (aka ``ssh_config``) support.
é    N)Úsha1)Úpartialé   )ÚStringIO)NN)ÚCouldNotCanonicalizeÚConfigParseErroré   c                   @   s
  e Zd ZdZe d¡Zddddddd	d
gdgdddddd
d	gdddd	gddd	gdddddddd	d
g	dœZdd„ Ze	dd„ ƒZ
e	dd„ ƒZe	dd„ ƒZdd„ Zdd„ Zd4d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d0d1„ Zd2d3„ ZdS )5Ú	SSHConfigaƒ  
    Representation of config information as stored in the format used by
    OpenSSH. Queries can be made via `lookup`. The format is described in
    OpenSSH's ``ssh_config`` man page. This class is provided primarily as a
    convenience to posix users (since the OpenSSH format is a de-facto
    standard on posix) but should work fine on Windows too.

    .. versionadded:: 1.6
    z(\w+)(?:\s*=\s*|\s+)(.+)ú%Cú%hú%lú%Lú%nú%pú%rú%uú~ú%d)ZcontrolpathÚhostnameÚidentityfileÚproxycommandZ	proxyjumpú
match-execc                 C   s
   g | _ dS )a†  
        Create a new OpenSSH config object.

        Note: the newer alternate constructors `from_path`, `from_file` and
        `from_text` are simpler to use, as they parse on instantiation. For
        example, instead of::

            config = SSHConfig()
            config.parse(open("some-path.config")

        you could::

            config = SSHConfig.from_file(open("some-path.config"))
            # Or more directly:
            config = SSHConfig.from_path("some-path.config")
            # Or if you have arbitrary ssh_config text from some other source:
            config = SSHConfig.from_text("Host foo\n\tUser bar")
        N)Ú_config)Úself© r   úR/var/www/html/TRUCKING_PROJECT/venv/lib/python3.8/site-packages/paramiko/config.pyÚ__init__I   s    zSSHConfig.__init__c                 C   s   |   t|ƒ¡S )zg
        Create a new, parsed `SSHConfig` from ``text`` string.

        .. versionadded:: 2.7
        )Ú	from_filer   )ÚclsÚtextr   r   r   Ú	from_text^   s    zSSHConfig.from_textc              
   C   s*   t |ƒ�}|  |¡W  5 Q R £ S Q R X dS )zr
        Create a new, parsed `SSHConfig` from the file found at ``path``.

        .. versionadded:: 2.7
        N)Úopenr   )r   ÚpathÚflor   r   r   Ú	from_pathg   s    
zSSHConfig.from_pathc                 C   s   | ƒ }|  |¡ |S )zp
        Create a new, parsed `SSHConfig` from file-like object ``flo``.

        .. versionadded:: 2.7
        )Úparse)r   r#   Úobjr   r   r   r   q   s    
zSSHConfig.from_filec                 C   sR  dgi dœ}|D �].}|  ¡ }|r| d¡r.qt | j|¡}|sNtd |¡ƒ‚| d¡ ¡ }| d¡}|dkrª| j	 
|¡ di i}|d	krš|  |¡|d	< n|  |¡|d
< q|dkrÌ| ¡ dkrÌd|d |< q| d¡rì| d¡rì|dd… }|dk�r(||d k�r|d |  
|¡ n|g|d |< q||d kr||d |< q| j	 
|¡ dS )zŽ
        Read an OpenSSH config from the given file object.

        :param file_obj: a file-like object to read the config file from
        Ú*)ÚhostÚconfigú#zUnparsable line {}r   é   )r(   Úmatchr)   r(   Úmatchesr   ÚnoneNú"éÿÿÿÿ)r   ZlocalforwardZremoteforward)ÚstripÚ
startswithÚrer,   ÚSETTINGS_REGEXr   ÚformatÚgroupÚlowerr   ÚappendÚ
_get_hostsÚ_get_matchesÚendswith)r   Zfile_objÚcontextÚliner,   ÚkeyÚvaluer   r   r   r%   |   s6    


zSSHConfig.parsec                 C   s„   | j |d�}d|kr||d< | dd¡dk}t| dd¡ƒ}|r€| d¡|kr€|d	  ¡ }|  |||¡}||d< | j ||d
d�}|S )aÂ  
        Return a dict (`SSHConfigDict`) of config options for a given hostname.

        The host-matching rules of OpenSSH's ``ssh_config`` man page are used:
        For each parameter, the first obtained value will be used.  The
        configuration files contain sections separated by ``Host`` and/or
        ``Match`` specifications, and that section is only applied for hosts
        which match the given patterns or keywords

        Since the first obtained value for each parameter is used, more host-
        specific declarations should be given near the beginning of the file,
        and general defaults at the end.

        The keys in the returned dict are all normalized to lowercase (look for
        ``"port"``, not ``"Port"``. The values are processed according to the
        rules for substitution variable expansion in ``ssh_config``.

        Finally, please see the docs for `SSHConfigDict` for deeper info on
        features such as optional type conversion methods, e.g.::

            conf = my_config.lookup('myhost')
            assert conf['passwordauthentication'] == 'yes'
            assert conf.as_bool('passwordauthentication') is True

        .. note::
            If there is no explicitly configured ``HostName`` value, it will be
            set to the being-looked-up hostname, which is as close as we can
            get to OpenSSH's behavior around that particular option.

        :param str hostname: the hostname to lookup

        .. versionchanged:: 2.5
            Returns `SSHConfigDict` objects instead of dict literals.
        .. versionchanged:: 2.7
            Added canonicalization support.
        .. versionchanged:: 2.7
            Added ``Match`` support.
        )r   r   ZcanonicalizehostnameN)ÚyesÚalwaysZcanonicalizemaxdotsr   Ú.ZcanonicaldomainsT)Ú	canonical)Ú_lookupÚgetÚintÚcountÚsplitÚcanonicalize)r   r   ÚoptionsZcanonZmaxdotsÚdomainsr   r   r   Úlookup¹   s    (zSSHConfig.lookupNFc                    sÔ   ˆd krt ƒ ‰| jD ]”}|  | dg ¡|¡sF|  | dg ¡||ˆ¡sFq|d  ¡ D ]T\‰ }ˆ ˆkr€|d k	rv|d d … n|ˆˆ < qRˆ dkrRˆˆ   ‡ ‡fdd„|D ƒ¡ qRq|  ˆ|¡‰dˆkrÐˆd d krÐˆd= ˆS )Nr(   r-   r)   r   c                 3   s   | ]}|ˆˆ  kr|V  qd S ©Nr   ©Ú.0Úx©r>   rJ   r   r   Ú	<genexpr>	  s     z$SSHConfig._lookup.<locals>.<genexpr>r   )ÚSSHConfigDictr   Ú_pattern_matchesrE   Ú_does_matchÚitemsÚextendÚ_expand_variables)r   r   rJ   rC   r<   r?   r   rQ   r   rD   ó   s0    
ÿ
   ÿþÿzSSHConfig._lookupc              	   C   sˆ   d}|D ]^}d  ||¡}t||ƒ}|dk	r4|d }n&zt |¡}W n tjk
rX   Y nX |r|  S q| dd¡dkr||S t|ƒ‚dS )ag  
        Return canonicalized version of ``hostname``.

        :param str hostname: Target hostname.
        :param options: An `SSHConfigDict` from a previous lookup pass.
        :param domains: List of domains (e.g. ``["paramiko.org"]``).

        :returns: A canonicalized hostname if one was found, else ``None``.

        .. versionadded:: 2.7
        Fz{}.{}Nr   Zcanonicalizefallbacklocalr@   )r5   Ú_addressfamily_host_lookupÚsocketÚgethostbynameÚgaierrorrE   r   )r   r   rJ   rK   ÚfoundÚdomainÚ	candidateZfamily_specificr   r   r   rI     s    


zSSHConfig.canonicalizec                 C   s$   t ƒ }| jD ]}| |d ¡ q|S )z‡
        Return the set of literal hostnames defined in the SSH config (both
        explicit hostnames and wildcard entries).
        r(   )Úsetr   Úupdate)r   ÚhostsÚentryr   r   r   Úget_hostnames=  s    
zSSHConfig.get_hostnamesc                 C   sZ   t |dƒr| d¡}d}|D ]8}| d¡rDt ||dd … ¡rD dS t ||¡rd}q|S )NrH   ú,Fú!r   T)ÚhasattrrH   r2   Úfnmatch)r   ÚpatternsÚtargetr,   Úpatternr   r   r   rT   G  s    

 
ÿzSSHConfig._pattern_matchesc                 C   s   |   ||¡S rM   )rT   )r   rb   r   r   r   r   Ú_allowedY  s    zSSHConfig._allowedc                 C   sJ  g }|d d … }t  ¡ }|�rF| d¡}d }	| dd ¡}
| dd ¡}|d |d  }}|dkrp|  ||¡rndS n®|dkr|d	S |d
krš|
pŠ|}|  ||¡}	n„|dkr°|  ||¡}	nn|dkrÎ|p¾|}|  ||¡}	nP|dkrä|  ||¡}	n:|dk�r|  ||d|¡}td k�rt‚tj	|dd	d�j
}	|	d k	�r:|  |	|¡�r:dS | |¡ q|S )Nr   r   ÚuserÚtypeÚparamrC   FÚallTr(   ZoriginalhostZ	localuserÚexecr   Ústdout)ZhideÚwarn)ÚgetpassÚgetuserÚpoprE   Ú_should_failrT   Ú	_tokenizeÚinvokeÚinvoke_import_errorÚrunÚokr8   )r   Z
match_listÚtarget_hostnamerC   rJ   ZmatchedÚ
candidatesZlocal_usernamer_   ZpassedZconfigured_hostZconfigured_userÚtype_ro   Zhostvalrm   Zexec_cmdr   r   r   rU   \  sL    

   ÿ
zSSHConfig._does_matchc                 C   s   |d r|S | S )NÚnegater   )r   Z
would_passr_   r   r   r   rw   �  s    zSSHConfig._should_failc                 C   sô   |   |¡}|s|S |}|dkr*| d|¡}d|kr<|d }nt}t ¡ }d|krZ|d }	n|}	t ¡  d¡d }
t||
ƒ}t	j
 d¡}|
| t|ƒ |	 }t| ¡ ƒ ¡ |||
||||	||dœ
}|}| ¡ D ]"\}}||krÞqÌ| |t|ƒ¡}qÌ|S )a„  
        Tokenize a string based on current config/hostname data.

        :param config: Current config data.
        :param target_hostname: Original target connection hostname.
        :param key: Config key being tokenized (used to filter token list).
        :param value: Config value being tokenized.

        :returns: The tokenized version of the input ``value`` string.
        r   Úportrm   rB   r   r   )
r
   r   r   r   r   r   r   r   r   r   )Ú_allowed_tokensrE   ÚSSH_PORTrt   ru   rZ   ÚgethostnamerH   ÚLazyFqdnÚosr"   Ú
expanduserÚreprr   ÚencodeÚ	hexdigestrV   ÚreplaceÚstr)r   r)   r}   r>   r?   Zallowed_tokensZconfigured_hostnamer�   rm   Z
remoteuserZlocal_hostnameZ
local_fqdnÚhomedirZtohashZreplacementsZ	tokenizedÚfindr‹   r   r   r   rx   “  sD    



ñzSSHConfig._tokenizec                 C   s   | j  |g ¡S )aJ  
        Given config ``key``, return list of token strings to tokenize.

        .. note::
            This feels like it wants to eventually go away, but is used to
            preserve as-strict-as-possible compatibility with OpenSSH, which
            for whatever reason only applies some tokens to some config keys.
        )ÚTOKENS_BY_CONFIG_KEYrE   ©r   r>   r   r   r   r‚   Ñ  s    	zSSHConfig._allowed_tokensc                 C   sr   |D ]h}|| dkrqt | j|||ƒ}t|| tƒr\t|| ƒD ]\}}||ƒ|| |< q@q||| ƒ||< q|S )aA  
        Return a dict of config options with expanded substitutions
        for a given original & current target hostname.

        Please refer to :doc:`/api/config` for details.

        :param dict config: the currently parsed config
        :param str hostname: the hostname whose config is being looked up
        N)r   rx   Ú
isinstanceÚlistÚ	enumerate)r   r)   r}   ÚkÚ	tokenizerÚir?   r   r   r   rX   Ü  s    
zSSHConfig._expand_variablesc                 C   s4   zt  |¡W S  tk
r.   td |¡ƒ‚Y nX dS )z>
        Return a list of host_names from host value.
        zUnparsable host {}N)ÚshlexrH   Ú
ValueErrorr   r5   )r   r(   r   r   r   r9   ñ  s    zSSHConfig._get_hostsc           	         s$  g }t  |¡}|rŽddddœ}| d¡}| d¡rFd|d< |dd… }||d	< |d
krb| |¡ q|sttd |¡ƒ‚| d¡|d< | |¡ qdd„ |D ƒ}d|k�r d
‰ tt‡ fdd„|ƒƒtt‡ fdd„|ƒƒ }}d}t	|ƒrêd}n$d|k�r| 
d¡| 
d¡k�rd}|dk	�r t|ƒ‚|S )z�
        Parse a specific Match config line into a list-of-dicts for its values.

        Performs some parse-time validation as well.
        NF)rn   ro   r€   r   rf   Tr€   r   rn   )rp   rC   z'Missing parameter to Match '{}' keywordro   c                 S   s   g | ]}|d  ‘qS )rn   r   rN   r   r   r   Ú
<listcomp>  s     z*SSHConfig._get_matches.<locals>.<listcomp>rp   c                    s   | ˆ kS rM   r   ©rP   ©Z	allowabler   r   Ú<lambda>  ó    z(SSHConfig._get_matches.<locals>.<lambda>c                    s   | ˆ kS rM   r   rš   r›   r   r   rœ     r�   z>Match does not allow 'all' mixed with anything but 'canonical'rC   z-Match does not allow 'all' before 'canonical')r—   rH   rv   r2   r8   r   r5   r’   ÚfilterÚanyÚindex)	r   r,   r-   Útokensr   Úkeywordsr|   ÚbadÚerrr   r›   r   r:   ú  s@    



ÿ
þ 
zSSHConfig._get_matches)NF)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r3   Úcompiler4   r�   r   Úclassmethodr    r$   r   r%   rL   rD   rI   rd   rT   rl   rU   rw   rx   r‚   rX   r9   r:   r   r   r   r   r	   /   s<   


ø

	

=:
!)
4>	r	   c                 C   sh   |  dd¡ ¡ }|dkrdS z0tj}|dkr2tj}t | d|tjtjtj¡W S  tj	k
rb   Y nX dS )a  
    Try looking up ``hostname`` in an IPv4 or IPv6 specific manner.

    This is an odd duck due to needing use in two divergent use cases. It looks
    up ``AddressFamily`` in ``options`` and if it is ``inet`` or ``inet6``,
    this function uses `socket.getaddrinfo` to perform a family-specific
    lookup, returning the result if successful.

    In any other situation -- lookup failure, or ``AddressFamily`` being
    unspecified or ``any`` -- ``None`` is returned instead and the caller is
    expected to do something situation-appropriate like calling
    `socket.gethostbyname`.

    :param str hostname: Hostname to look up.
    :param options: `SSHConfigDict` instance w/ parsed options.
    :returns: ``getaddrinfo``-style tuples, or ``None``, depending.
    ZaddressfamilyrŸ   NZinet)
rE   r7   rZ   ÚAF_INET6ÚAF_INETÚgetaddrinfoÚ
SOCK_DGRAMÚ
IPPROTO_IPÚAI_CANONNAMEr\   )r   rJ   Úaddress_familyÚfamilyr   r   r   rY   '  s"    úrY   c                   @   s"   e Zd ZdZddd„Zdd„ ZdS )r…   z7
    Returns the host's fqdn on request as string.
    Nc                 C   s   d | _ || _|| _d S rM   )Úfqdnr)   r(   )r   r)   r(   r   r   r   r   Q  s    zLazyFqdn.__init__c           	      C   sl   | j d krfd }t| j| jƒ}|d k	rP|D ]&}|\}}}}}|r(d|kr(|} qPq(|d kr`t ¡ }|| _ | j S )NrB   )r³   rY   r(   r)   rZ   Úgetfqdn)	r   r³   ÚresultsÚresÚafÚsocktypeÚprotoÚ	canonnameÚsar   r   r   Ú__str__V  s    
zLazyFqdn.__str__)N)r¥   r¦   r§   r¨   r   r¼   r   r   r   r   r…   L  s   
r…   c                       s0   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Z‡  ZS )rS   aÃ  
    A dictionary wrapper/subclass for per-host configuration structures.

    This class introduces some usage niceties for consumers of `SSHConfig`,
    specifically around the issue of variable type conversions: normal value
    access yields strings, but there are now methods such as `as_bool` and
    `as_int` that yield casted values instead.

    For example, given the following ``ssh_config`` file snippet::

        Host foo.example.com
            PasswordAuthentication no
            Compression yes
            ServerAliveInterval 60

    the following code highlights how you can access the raw strings as well as
    usefully Python type-casted versions (recalling that keys are all
    normalized to lowercase first)::

        my_config = SSHConfig()
        my_config.parse(open('~/.ssh/config'))
        conf = my_config.lookup('foo.example.com')

        assert conf['passwordauthentication'] == 'no'
        assert conf.as_bool('passwordauthentication') is False
        assert conf['compression'] == 'yes'
        assert conf.as_bool('compression') is True
        assert conf['serveraliveinterval'] == '60'
        assert conf.as_int('serveraliveinterval') == 60

    .. versionadded:: 2.5
    c                    s   t t| ƒj||Ž d S rM   )ÚsuperrS   r   )r   ÚargsÚkwargs©Ú	__class__r   r   r   ”  s    zSSHConfigDict.__init__c                 C   s"   | | }t |tƒr|S | ¡ dkS )aº  
        Express given key's value as a boolean type.

        Typically, this is used for ``ssh_config``'s pseudo-boolean values
        which are either ``"yes"`` or ``"no"``. In such cases, ``"yes"`` yields
        ``True`` and any other value becomes ``False``.

        .. note::
            If (for whatever reason) the stored value is already boolean in
            nature, it's simply returned.

        .. versionadded:: 2.5
        r@   )r‘   Úboolr7   )r   r>   Úvalr   r   r   Úas_bool˜  s    
zSSHConfigDict.as_boolc                 C   s   t | | ƒS )zí
        Express given key's value as an integer, if possible.

        This method will raise ``ValueError`` or similar if the value is not
        int-appropriate, same as the builtin `int` type.

        .. versionadded:: 2.5
        )rF   r�   r   r   r   Úas_int«  s    	zSSHConfigDict.as_int)r¥   r¦   r§   r¨   r   rÄ   rÅ   Ú__classcell__r   r   rÀ   r   rS   r  s   !rS   )r¨   rh   rt   r†   r3   r—   rZ   Úhashlibr   Ú	functoolsr   Z	py3compatr   ry   rz   ÚImportErrorÚeZssh_exceptionr   r   rƒ   Úobjectr	   rY   r…   ÚdictrS   r   r   r   r   Ú<module>   s.      {%&