
    7gj                        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	 ddlZn# e$ rZeZY dZ[ndZ[ww xY wddlmZmZ d	Z G d
 d          Zd Z G d d          Z G d de          ZdS )z2
Configuration file (aka ``ssh_config``) support.
    N)sha1)StringIO)partial)NN   )CouldNotCanonicalizeConfigParseError   c                       e Zd ZdZ ej        d          Zg ddgg dg dg dg dd	Zd
 Ze	d             Z
e	d             Ze	d             Zd Zd ZddZd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdS )	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%ur   )r   ~%dr   r   r   r   )r   r   r   r   )r   r   r   )	r   r   r   r   r   r   r   r   r   )controlpathhostnameidentityfileproxycommand	proxyjump
match-execc                     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)selfs    I/var/www/html/syslog/venv/lib/python3.11/site-packages/paramiko/config.py__init__zSSHConfig.__init__H   s    &     c                 F    |                      t          |                    S )zg
        Create a new, parsed `SSHConfig` from ``text`` string.

        .. versionadded:: 2.7
        )	from_filer   )clstexts     r   	from_textzSSHConfig.from_text]   s     }}Xd^^,,,r!   c                 ~    t          |          5 }|                     |          cddd           S # 1 swxY w Y   dS )zr
        Create a new, parsed `SSHConfig` from the file found at ``path``.

        .. versionadded:: 2.7
        N)openr#   )r$   pathflos      r   	from_pathzSSHConfig.from_pathf   s     $ZZ 	&3==%%	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	&s   266c                 D     |             }|                     |           |S )zp
        Create a new, parsed `SSHConfig` from file-like object ``flo``.

        .. versionadded:: 2.7
        )parse)r$   r*   objs      r   r#   zSSHConfig.from_filep   s#     cee		#
r!   c                    dgi d}|D ]}|                                 }|r|                    d          r/t          j        | j        |          }|s"t          d                    |                    |                    d                                          }|                    d          }|dv rW| j	        
                    |           di i}|d	k    r|                     |          |d	<   |                     |          |d
<   |dk    r%|                                dk    rd|d         |<   /|                    d          r|                    d          r
|dd         }|dv r;||d         v r#|d         |         
                    |           |g|d         |<   ||d         vr||d         |<   | 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      )r1   matchr2   r1   matchesr   noneN")r   localforwardremoteforward)strip
startswithrer5   SETTINGS_REGEXr   formatgrouplowerr   append
_get_hosts_get_matchesendswith)r   file_objcontextliner5   keyvalues          r   r-   zSSHConfig.parse{   s     5B// /	3 /	3D ::<<D 4??3//  HT0$77E J&';'B'B4'H'HIII++a..&&((CKKNNE '''##G,,,#R.&== '+ooe&<&<GFOO)-):):5)A)AGI&&&&5;;==F+B+B *.!#&& ##C(( (U^^C-@-@ (!!B$KE
 KKKgh///)#.55e<<<<27)#.. 111-2GH%c*G$$$$$r!   c                    |                      |          }d|vr||d<   |                    dd          dv }t          |                    dd                    }|ri|                    d          |k    rP|d	                                         }|                     |||          }||d<   |                      ||d
d
          }n|                      ||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.
        .. versionchanged:: 3.3
            Added ``Match final`` support.
        )r   r   canonicalizehostnameN)yesalwayscanonicalizemaxdotsr   .canonicaldomainsT)	canonicalfinalF)_lookupgetintcountsplitcanonicalize)r   r   optionscanonmaxdotsdomainss         r   lookupzSSHConfig.lookup   s
   T ,,,11 W$$"*GJ2D99=NNgkk"7;;<< 	X^^C((G33 017799G((7GDDH"*GJll'T #  GG ll'U$ #  G r!   NFc                    t                      | j        D ]}|                     |                    dg           |          s.|                     |                    dg           |||          sZ|d                                         D ]I\  }vr|
|d d          n|<   dk    r(                             fd|D                        J|r|                     |          S )Nr1   r6   r2   r   c              3   0   K   | ]}|         v|V  d S N ).0xrJ   r[   s     r   	<genexpr>z$SSHConfig._lookup.<locals>.<genexpr>  s:       ( (AWS\,A,A,A,A,A,A( (r!   )SSHConfigDictr   _pattern_matchesrV   _does_matchitemsextend_expand_variables)r   r   r[   rS   rT   rH   rK   rJ   s     `    @r   rU   zSSHConfig._lookup   sQ   ?#ooG | 	 	G%%gkk&"&=&=xHH
##KK	2.. 
 %h/5577 
 

Ug%%
 05/@588eGCLLN**CL'' ( ( ( ( (#(( ( (   
  	@ ,,Wh??Gr!   c                 *   d}|D ]d}d                     ||          }t          ||          }|	|d         }n+	 t          j        |          }n# t          j        $ r Y nw xY w|r|c S e|                    dd          dk    r|S t          |          )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   canonicalizefallbacklocalrN   )r@   _addressfamily_host_lookupsocketgethostbynamegaierrorrV   r   )r   r   r[   r^   founddomain	candidatefamily_specifics           r   rZ   zSSHConfig.canonicalize  s      	! 	!Fx88I8GLLO* (*"0;;EE   D ! !   ! ;;2E::eCCO #8,,,s   AA A c                 l    t                      }| j        D ]}|                    |d                    |S )z
        Return the set of literal hostnames defined in the SSH config (both
        explicit hostnames and wildcard entries).
        r1   )setr   update)r   hostsentrys      r   get_hostnameszSSHConfig.get_hostnamesE  s<    
 \ 	( 	(ELLv''''r!   c                     t          |d          r|                    d          }d}|D ]N}|                    d          r t          j        ||dd                    r dS t          j        ||          rd}O|S )NrY   ,F!r   T)hasattrrY   r=   fnmatch)r   patternstargetr5   patterns        r   rh   zSSHConfig._pattern_matchesO  s    8W%% 	+~~c**H 		 		G!!#&& 7?, ,  uu 11 r!   c                 :   g }|d d          }t          j                    }|rx|                    d          }	d }
|                    dd           }|                    dd           }|	d         |	d         }}|dk    r|                     ||	          rdS |dk    r|}
n|d	k    rd
S |dk    r|p|}|                     ||          }
n|dk    r|                     ||          }
n|dk    r|p|}|                     ||          }
ne|dk    r|                     ||          }
nH|dk    rB|                     ||d|          }t          t          t          j	        |dd
          j
        }
|
|                     |
|	          rdS |                    |	           |x|S )Nr   r   usertypeparamrS   FrT   allTr1   originalhost	localuserexecr   stdout)hidewarn)getpassgetuserpoprV   _should_failrh   	_tokenizeinvokeinvoke_import_errorrunokrC   )r   
match_listtarget_hostnamerS   rT   r[   matched
candidateslocal_usernameru   passedconfigured_hostconfigured_usertype_r   hostvalr   exec_cmds                     r   ri   zSSHConfig._does_match`  s    ]
 ** .	&"q))IF &kk*d;;O%kk&$77O$V,i.@5E ##$$Y	:: ! 5 %t &)<_..ug>>.((..uoFF&&8...ud;;+%%..unEE&>>_lE 
 >--H8$GGGJ!d&7&7	&J&J!uNN9%%%]  .	&` r!   c                     |d         r|n| S )Nnegaterc   )r   
would_passru   s      r   r   zSSHConfig._should_fail  s    &x0Dzz*nDr!   c                    |                      |          }|s|S |}|dk    r|                    d|          }d|v r	|d         }nt          }t          j                    }d|v r	|d         }	n|}	t          j                                        d          d         }
t          ||
          }t          j
                            d          }|
|z   t          |          z   |	z   }t          |                                                                          |||
||||	||d
}|}|                                D ]-\  }}||vr
|                    |t%          |                    }.|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   portr   rQ   r   r   )
r   r   r   r   r   r   r   r   r   r   )_allowed_tokensrV   SSH_PORTr   r   rp   gethostnamerY   LazyFqdnosr)   
expanduserreprr   encode	hexdigestrj   replacestr)r   r2   r   rJ   rK   allowed_tokensconfigured_hostnamer   r   
remoteuserlocal_hostname
local_fqdnhomedirtohashreplacements	tokenizedfindr   s                     r   r   zSSHConfig._tokenize  s    --c22 	L .*"(**Z9L"M"MV&>DDD  VJJJ+--33C88;fn55
'$$S))/1DJJ>K v}}''1133%  "
 
$ 	)//11 	> 	>MD'>))!))$G==IIr!   c                 8    | 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_KEYrV   r   rJ   s     r   r   zSSHConfig._allowed_tokens  s     (,,S"555r!   c                    |D ]}||         t          | j        |||          }t          ||         t                    r0t	          ||                   D ]\  }} ||          ||         |<   m |||                   ||<   |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
        )r   r   
isinstancelist	enumerate)r   r2   r   k	tokenizerirK   s          r   rl   zSSHConfig._expand_variables  s      	1 	1Aay KKI&)T** 1 )&) 4 4 4 4HAu#,9U#3#3F1IaLL4 &IfQi00q		r!   c                     	 t          j        |          S # t          $ r# t          d                    |                    w xY w)z>
        Return a list of host_names from host value.
        zUnparsable host {})shlexrY   
ValueErrorr   r@   )r   r1   s     r   rD   zSSHConfig._get_hosts  sT    	F;t$$$ 	F 	F 	F"#7#>#>t#D#DEEE	Fs	    -Ac                   	 g }t          j        |          }|rdddd}|                    d          }|                    d          rd|d<   |dd         }||d	<   |d
v r|                    |           `|s"t          d                    |                    |                    d          |d<   |                    |           |d |D             }d|v rd	t          t          	fd|                    t          t          	fd|                    }}d}t          |          rd}n2d|v r.|
                    d          |
                    d          k    rd}|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)r   r   r   r   r   Tr   r   r   )r   rS   rT   z'Missing parameter to Match '{}' keywordr   c                     g | ]
}|d          S )r   rc   )rd   re   s     r   
<listcomp>z*SSHConfig._get_matches.<locals>.<listcomp>  s    ///!AfI///r!   r   )r   rS   c                     | v S rb   rc   re   	allowables    r   <lambda>z(SSHConfig._get_matches.<locals>.<lambda>"  s    a9n r!   c                     | vS rb   rc   r   s    r   r   z(SSHConfig._get_matches.<locals>.<lambda>#  s    ay&8 r!   z>Match does not allow 'all' mixed with anything but 'canonical'rS   z-Match does not allow 'all' before 'canonical')r   rY   r   r=   rC   r   r@   r   filteranyindex)
r   r5   r6   tokensr   keywordsr   baderrr   s
            @r   rE   zSSHConfig._get_matches  s    U## 	"!DEBBEJJqMME$$ ""&habb	!E&M555u%%% &=DDUKK   $ZZ]]E'NNN5!!!#  	"( 0/w///H,IV4444h??@@V8888(CCDD B C3xx FV""rxx'<'<rxx'N'NE&s+++r!   )NFF)__name__
__module____qualname____doc__r>   compiler?   r   r    classmethodr&   r+   r#   r-   r_   rU   rZ   r|   rh   ri   r   r   r   rl   rD   rE   rc   r!   r   r   r   .   s          RZ ;<<N
 HGGFAAA///''' MLL	 	  * - - [- & & [&   [:% :% :%x@ @ @D! ! ! !F'- '- '-R    "6 6 6pE E E< < <|	6 	6 	6  *F F F* * * * *r!   r   c                 :   |                     dd                                          }|dk    rdS 	 t          j        }|dk    rt          j        }t          j        | d|t          j        t          j        t          j                  S # t          j	        $ r Y dS w xY w)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.
    addressfamilyr   Ninet)
rV   rB   rp   AF_INET6AF_INETgetaddrinfo
SOCK_DGRAM
IPPROTO_IPAI_CANONNAMErr   )r   r[   address_familyfamilys       r   ro   ro   /  s    $ [[%88>>@@NV##^F!
 
 	
 ?   s   AB BBc                        e Zd ZdZddZd ZdS )r   z7
    Returns the host's fqdn on request as string.
    Nc                 0    d | _         || _        || _        d S rb   )fqdnr2   r1   )r   r2   r1   s      r   r    zLazyFqdn.__init__Y  s    				r!   c                     | j         Qd }t          | j        | j                  }||D ]}|\  }}}}}|rd|v r|} n|t	          j                    }|| _         | j         S )NrQ   )r   ro   r1   r2   rp   getfqdn)	r   r   resultsresafsocktypeproto	canonnamesas	            r   __str__zLazyFqdn.__str__^  s    9 D0DKHHG""  C9<6B%B  SI%5%5(|~''DIyr!   rb   )r   r   r   r   r    r   rc   r!   r   r   r   T  sA            
    r!   r   c                       e Zd ZdZd Zd ZdS )rg   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                 p    | |         }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
        rN   )r   boolrB   )r   rJ   vals      r   as_boolzSSHConfigDict.as_bool  s7     3ic4   	Jyy{{e##r!   c                 ,    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
        )rW   r   s     r   as_intzSSHConfigDict.as_int  s     49~~r!   N)r   r   r   r   r   r   rc   r!   r   rg   rg   z  s=         B$ $ $&	 	 	 	 	r!   rg   )r   r   r   r   r>   r   rp   hashlibr   ior   	functoolsr   r   r   ImportErroressh_exceptionr   r   r   r   ro   r   dictrg   rc   r!   r   <module>r     s  (    				 				                    ( MMMM    B A A A A A A A ~ ~ ~ ~ ~ ~ ~ ~B" " "J# # # # # # # #L> > > > >D > > > > >s   8 A	AA	