
    Iij                         S r SSKrSSKrSSKrSSKrSSKrSSKrSSKJr  SSK	J
r
  SSKJr  Su  rr SSKrSSKJrJr  S	r " S
 S5      rS r " S S5      r " S S\5      rg! \ a  r\r SrCN:SrCff = f)z2
Configuration file (aka ``ssh_config``) support.
    N)sha1)StringIO)partial)NN   )CouldNotCanonicalizeConfigParseError   c                       \ rS rSrSr\R                  " S5      r/ SQS// SQ/ SQ/ SQ/ S	QS
.rS r	\
S 5       r\
S 5       r\
S 5       rS rS rSS jrS rS rS rS rS rS rS rS rS rS rSrg)	SSHConfig.   ag  
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                     / U l         g)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    5/venv/lib/python3.13/site-packages/paramiko/config.py__init__SSHConfig.__init__H   s    &     c                 6    U R                  [        U5      5      $ )zO
Create a new, parsed `SSHConfig` from ``text`` string.

.. versionadded:: 2.7
)	from_filer   )clstexts     r!   	from_textSSHConfig.from_text]   s     }}Xd^,,r$   c                 p    [        U5       nU R                  U5      sSSS5        $ ! , (       d  f       g= f)zZ
Create a new, parsed `SSHConfig` from the file found at ``path``.

.. versionadded:: 2.7
N)openr&   )r'   pathflos      r!   	from_pathSSHConfig.from_pathf   s#     $Z3==% ZZs   '
5c                 6    U " 5       nUR                  U5        U$ )zX
Create a new, parsed `SSHConfig` from file-like object ``flo``.

.. versionadded:: 2.7
)parse)r'   r.   objs      r!   r&   SSHConfig.from_filep   s     e		#
r$   c                    S/0 S.nU GH  nUR                  5       nU(       a  UR                  S5      (       a  M3  [        R                  " U R                  U5      nU(       d  [        SR                  U5      5      eUR                  S5      R                  5       nUR                  S5      nUS;   aQ  U R                  R                  U5        S0 0nUS	:X  a  U R                  U5      US	'   M  U R                  U5      US
'   M  US:X  a  UR                  5       S:X  a  SUS   U'   GM!  UR                  S5      (       a  UR                  S5      (       a  USS nUS;   a.  XRS   ;   a  US   U   R                  U5        GMz  U/US   U'   GM  XRS   ;  d  GM  XbS   U'   GM     U R                  R                  U5        g)zv
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      )r7   matchr8   r7   matchesr   noneN")r   localforwardremoteforward)strip
startswithrer;   SETTINGS_REGEXr   formatgrouplowerr   append
_get_hosts_get_matchesendswith)r    file_objcontextliner;   keyvalues          r!   r2   SSHConfig.parse{   s     5B/D ::<D4??3// HHT00$7E&';'B'B4'HII++a.&&(CKKNE ''##G,#R.&= '+ooe&<GFO)-):):5)AGI&&5;;=F+B *.!#& ##C((U^^C-@-@!!BKE
 KKh//)#.55e<27)#. 11-2H%c*_ b 	G$r$   c                 j   U R                  US9nSU;  a  XS'   UR                  SS5      S;   n[        UR                  SS5      5      nU(       aQ  UR                  S5      U::  a<  US	   R	                  5       nU R                  XU5      nXS'   U R                  XS
S
S9nU$ U R                  XSS
S9nU$ )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!   lookupSSHConfig.lookup   s    T ,,,1 W$"*J2D9=NNgkk"7;<X^^C(G3 01779G((GDH"*JllT # G  llU$ # G r$   Nc                   ^^ Tc
  [        5       mU R                   H  nU R                  UR                  S/ 5      U5      (       d,  U R	                  UR                  S/ 5      UUUT5      (       d  MV  US   R                  5        HB  u  mnTT;  a  Ub  US S  OUTT'   M  TS:X  d  M#  TT   R                  UU4S jU 5       5        MD     M     U(       a  U R                  TU5      mT$ )Nr7   r<   r8   r   c              3   <   >#    U  H  oTT   ;  d  M  Uv   M     g 7fN ).0xrP   rb   s     r!   	<genexpr>$SSHConfig._lookup.<locals>.<genexpr>  s      (#(aWS\,A5s   	)SSHConfigDictr   _pattern_matchesr]   _does_matchitemsextend_expand_variables)r    r   rb   rZ   r[   rN   rQ   rP   s     `    @r!   r\   SSHConfig._lookup   s    ?#oG ||G%%gkk&"&=xHH##KK	2.  %h/557
Ug%
 05/@58eGCLN*CL'' (#((  8 $.  ,,Wh?Gr$   c                     SnU HJ  nSR                  X5      n[        Xb5      nUb  US   nO [        R                  " U5      nU(       d  MH  Us  $    UR                  SS5      S:X  a  U$ [        U5      e! [        R                   a     NHf = f)a/  
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{}.{}r   canonicalizefallbacklocalrU   )rF   _addressfamily_host_lookupsocketgethostbynamegaierrorr]   r   )r    r   rb   re   founddomain	candidatefamily_specifics           r!   ra   SSHConfig.canonicalize  s     Fx8I8LO* (*"00;E u ! % , ;;2E:eCO #8,,  s   A66BBc                 h    [        5       nU R                   H  nUR                  US   5        M     U$ )zo
Return the set of literal hostnames defined in the SSH config (both
explicit hostnames and wildcard entries).
r7   )setr   update)r    hostsentrys      r!   get_hostnamesSSHConfig.get_hostnamesE  s.    
 \\ELLv' "r$   c                 
   [        US5      (       a  UR                  S5      nSnU HX  nUR                  S5      (       a   [        R                  " X$SS  5      (       a    g[        R                  " X$5      (       d  MV  SnMZ     U$ )Nr`   ,F!r   T)hasattrr`   rC   fnmatch)r    patternstargetr;   patterns        r!   rq   SSHConfig._pattern_matchesO  sx    8W%%~~c*HG!!#&&7??, ,  11   r$   c                    / nUS S  n[         R                  " 5       nU(       Ga_  UR                  S5      n	S n
UR                  SS 5      nUR                  SS 5      nU	S   U	S   pUS:X  a  U R	                  X95      (       a  gUS:X  a  Un
OUS	:X  a  g
US:X  a  U=(       d    UnU R                  X5      n
OUS:X  a  U R                  X5      n
OUS:X  a  U=(       d    UnU R                  UU5      n
O^US:X  a  U R                  X5      n
OFUS:X  a@  U R                  XRSU5      n[        c  [        e[        R                  " USS
S9R                  n
U
b  U R	                  X5      (       a  gUR                  U	5        U(       a  GM_  U$ )Nr   r   usertypeparamrZ   Fr[   allTr7   originalhost	localuserexecr   stdout)hidewarn)getpassgetuserpopr]   _should_failrq   	_tokenizeinvokeinvoke_import_errorrunokrI   )r    
match_listtarget_hostnamerZ   r[   rb   matched
candidateslocal_usernamer   passedconfigured_hostconfigured_usertype_r   hostvalr   exec_cmds                     r!   rr   SSHConfig._does_match`  s    ]
 *"q)IF &kk*d;O%kk&$7O$V,i.@5 #$$Y::  % &)<_..u>.(..uF&&8...ud;+%..uE&>>lE
 >--H8$GJJ!d&7&7&J&JNN9%] j` r$   c                 (    US   (       a  U$ U(       + $ )Nnegaterk   )r    
would_passr   s      r!   r   SSHConfig._should_fail  s    &x0zD*nDr$   c                    U R                  U5      nU(       d  U$ UnUS:w  a  UR                  SU5      nSU;   a  US   nO[        n[        R                  " 5       nSU;   a  US   n	OUn	[
        R                  " 5       R                  S5      S   n
[        X5      n[        R                  R                  S5      nX-   [        U5      -   U	-   n[        UR                  5       5      R                  5       UUU
UUUU	UUS.
nUnUR!                  5        H)  u  nnUU;  a  M  UR#                  U[%        U5      5      nM+     U$ )aL  
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   rX   r   r   )
r   r   r   r   r   r   r   r   r   r   )_allowed_tokensr]   SSH_PORTr   r   rz   gethostnamer`   LazyFqdnosr-   
expanduserreprr   encode	hexdigestrs   replacestr)r    r8   r   rP   rQ   allowed_tokensconfigured_hostnamer   r   
remoteuserlocal_hostname
local_fqdnhomedirtohashreplacements	tokenizedfindr   s                     r!   r   SSHConfig._tokenize  sL    --c2L .*"(**Z9L"MV&>DD VJJ++-33C8;f5
''$$S)1DJ>K v}}'113%  "
$ 	)//1MD'>)!))$G=I 2
 r$   c                 :    U R                   R                  U/ 5      $ )a  
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_KEYr]   r    rP   s     r!   r   SSHConfig._allowed_tokens  s     ((,,S"55r$   c                     U Hi  nX   c  M
  [        U R                  XU5      n[        X   [        5      (       a%  [	        X   5       H  u  pVU" U5      X   U'   M     M]  U" X   5      X'   Mk     U$ )a  
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    r8   r   k	tokenizerirQ   s          r!   ru   SSHConfig._expand_variables  st     Ay KI&)T** )&) 4HA#,U#3FIaL !5 &fi0	  r$   c                      [         R                  " U5      $ ! [         a    [        SR	                  U5      5      ef = f)z.
Return a list of host_names from host value.
zUnparsable host {})shlexr`   
ValueErrorr   rF   )r    r7   s     r!   rJ   SSHConfig._get_hosts  s?    	F;;t$$ 	F"#7#>#>t#DEE	Fs    %=c                   ^
 / n[         R                  " U5      nU(       a  SSSS.nUR                  S5      nUR                  S5      (       a
  SUS'   USS nXAS	'   US
;   a  UR	                  U5        M[  U(       d  [        SR                  U5      5      eUR                  S5      US'   UR	                  U5        U(       a  M  U Vs/ s H  oUS	   PM	     nnSU;   a  Sm
[        [        U
4S jU5      5      [        [        U
4S jU5      5      pSn	[        U5      (       a  Sn	O,SU;   a&  UR                  S5      UR                  S5      :  a  Sn	U	b  [        U	5      eU$ s  snf )zw
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   rZ   r[   z'Missing parameter to Match '{}' keywordr   r   )r   rZ   c                    > U T;   $ rj   rk   rm   	allowables    r!   <lambda>(SSHConfig._get_matches.<locals>.<lambda>"  s	    a9nr$   c                    > U T;  $ rj   rk   r   s    r!   r   r   #  s
    ay&8r$   z>Match does not allow 'all' mixed with anything but 'canonical'rZ   z-Match does not allow 'all' before 'canonical')r   r`   r   rC   rI   r   rF   r   filteranyindex)r    r;   r<   tokensr   rm   keywordsr   baderrr   s             @r!   rK   SSHConfig._get_matches  sZ    U#!DEBEJJqME$$"&hab	!&M55u%&=DDUK  $ZZ]E'NNN5!# f( (//w!fIw/H,IV4h?@V8(CD  C3xxV"rxx'<rxx'NE&s++ 0s   E"r   )NFF)__name__
__module____qualname____firstlineno____doc__rD   compilerE   r   r"   classmethodr)   r/   r&   r2   rf   r\   ra   r   rq   rr   r   r   r   ru   rJ   rK   __static_attributes__rk   r$   r!   r   r   .   s     ZZ ;<N
 HFA/' M	* - - & &  :%x@D!F'-R"6pE<|	6*F*r$   r   c                 \   UR                  SS5      R                  5       nUS:X  a  g [        R                  nUS:X  a  [        R                  n[        R
                  " U SU[        R                  [        R                  [        R                  5      $ ! [        R                   a     gf = f)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)
r]   rH   rz   AF_INET6AF_INETgetaddrinfo
SOCK_DGRAM
IPPROTO_IPAI_CANONNAMEr|   )r   rb   address_familyfamilys       r!   ry   ry   /  s    $ [[%8>>@NV#^^F!!
 	
 ?? s   A*B B+*B+c                   (    \ rS rSrSrSS jrS rSrg)r   iT  z/
Returns the host's fqdn on request as string.
Nc                 *    S U l         Xl        X l        g rj   )fqdnr8   r7   )r    r8   r7   s      r!   r"   LazyFqdn.__init__Y  s    		r$   c                     U R                   ce  S n[        U R                  U R                  5      nUb"  U H  nUu  pEpgnU(       d  M  SU;   d  M  Un  O   Uc  [        R
                  " 5       nXl         U R                   $ )NrX   )r  ry   r7   r8   rz   getfqdn)	r    r  resultsresafsocktypeproto	canonnamesas	            r!   __str__LazyFqdn.__str__^  sy    99 D0DKKHG""C9<6B%B ySI%5(	 # |~~'Iyyr$   )r8   r  r7   rj   )r   r   r   r   r   r"   r  r   rk   r$   r!   r   r   T  s    
r$   r   c                   $    \ rS rSrSrS rS rSrg)rp   iz  ac  
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                 ^    X   n[        U[        5      (       a  U$ UR                  5       S:H  $ )ar  
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
rU   )r   boolrH   )r    rP   vals      r!   as_boolSSHConfigDict.as_bool  s.     ic4  Jyy{e##r$   c                     [        X   5      $ )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
)r^   r   s     r!   as_intSSHConfigDict.as_int  s     49~r$   rk   N)r   r   r   r   r   r  r  r   rk   r$   r!   rp   rp   z  s    B$&	r$   rp   )r   r   r   r   rD   r   rz   hashlibr   ior   	functoolsr   r   r   ImportErroressh_exceptionr   r   r   r   ry   r   dictrp   rk   r$   r!   <module>r     s   (   	 	     (  B ~ ~B"J# #L>D >k  s   A$ $A6*A11A6