U vfj @sdZddlZddlZddlZddlZddlZddlZddlmZddl m Z ddl m Z d\Z Zz ddl Z Wn&ek rZzeZW5dZ[XYnXddlmZmZd ZGd d d Zd d ZGdddZGdddeZdS)z2 Configuration file (aka ``ssh_config``) support. N)sha1)StringIO)partial)NN)CouldNotCanonicalizeConfigParseErrorc@seZdZdZedZddddddd d gdgdd d ddd d gd ddd gddd gdd dddddd d g d ZddZe ddZ e ddZ e ddZ ddZ ddZd2ddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1ZdS)3 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 controlpathhostname identityfile proxycommandZ proxyjump match-execcCs g|_dS)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)selfr@/opt/alt/python38/lib/python3.8/site-packages/paramiko/config.py__init__HszSSHConfig.__init__cCs|t|S)zg Create a new, parsed `SSHConfig` from ``text`` string. .. versionadded:: 2.7 ) from_filer)clstextrrr from_text]szSSHConfig.from_textc Cs*t|}||W5QRSQRXdS)zr Create a new, parsed `SSHConfig` from the file found at ``path``. .. versionadded:: 2.7 N)openr)rpathflorrr from_pathfs zSSHConfig.from_pathcCs|}|||S)zp Create a new, parsed `SSHConfig` from file-like object ``flo``. .. versionadded:: 2.7 )parse)rr#objrrrrps zSSHConfig.from_filecCsRdgid}|D].}|}|r|dr.qt|j|}|sNtd||d}|d}|dkr|j |dii}|d kr| ||d <n| ||d <q|d kr|d krd |d|<q|dr| dr|dd}|dkr(||dkr|d| |n|g|d|<q||dkr||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 *)hostconfig#zUnparsable line {}r)r(matchr)r(matchesrnoneN")rZ localforwardZ remoteforward)strip startswithrer,SETTINGS_REGEXrformatgrouplowerrappend _get_hosts _get_matchesendswith)rZfile_objcontextliner,keyvaluerrrr%{s6       zSSHConfig.parsecCs|j|d}d|kr||d<|dddk}t|dd}|r|d|kr|d }||||}||d<|j||d d d }n|j||d 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. )rrZcanonicalizehostnameN)yesalwaysZcanonicalizemaxdotsr.ZcanonicaldomainsT) canonicalfinalF)_lookupgetintcountsplit canonicalize)rroptionsZcanonZmaxdotsdomainsrrrlookups,*  zSSHConfig.lookupNFcsdkrt|jD]}||dg|sH||dg|||sHq|dD]T\}kr|dk rx|ddn|<qTdkrTfdd|DqTq|r||S)Nr(r-r)rc3s|]}|kr|VqdSNr.0xr>rKrr s z$SSHConfig._lookup..) SSHConfigDictr_pattern_matchesrF _does_matchitemsextend_expand_variables)rrrKrCrDr<r?rrRrrEs0     zSSHConfig._lookupc Csd}|D]^}d||}t||}|dk r4|d}n&zt|}Wntjk rXYnX|r|Sq|dddkr||St|dS)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{}.{}NrZcanonicalizefallbacklocalr@)r5_addressfamily_host_lookupsocket gethostbynamegaierrorrFr)rrrKrLfounddomain candidateZfamily_specificrrrrJs     zSSHConfig.canonicalizecCs$t}|jD]}||dq |S)z Return the set of literal hostnames defined in the SSH config (both explicit hostnames and wildcard entries). r()setrupdate)rhostsentryrrr get_hostnamesEs zSSHConfig.get_hostnamescCsZt|dr|d}d}|D]8}|drDt||ddrDdSt||rd}q|S)NrI,F!rT)hasattrrIr2fnmatch)rpatternstargetr,patternrrrrUOs    zSSHConfig._pattern_matchescCsVg}|dd}t}|rR|d} d} |dd} |dd} | d| d} }| dkrn||| rndS| dkr||} n| d krd S| d kr| p|}|||} n| d kr|||} nn| dkr| p|}|||} nP| d kr|||} n:| dkr*|||d|}tdkrttj |dd dj } | dk rF|| | rFdS| | q|S)NrrusertypeparamrCFrDallTr(Z originalhostZ localuserexecrstdout)Zhidewarn) getpassgetuserpoprF _should_failrU _tokenizeinvokeinvoke_import_errorrunokr8)rZ match_listtarget_hostnamerCrDrKZmatched candidatesZlocal_usernamer`ZpassedZconfigured_hostZconfigured_usertype_roZhostvalrmZexec_cmdrrrrV`sP        zSSHConfig._does_matchcCs|dr |S| S)Nnegater)rZ would_passr`rrrrwszSSHConfig._should_failc Cs||}|s|S|}|dkr*|d|}d|kr<|d}nt}t}d|krZ|d} n|} tdd} t|| } t j d} | |t || } t | | || | ||| || d }|}|D]"\}}||krq||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. rportrmrBrr) r rr r r rrrrr)_allowed_tokensrFSSH_PORTrtrur[ gethostnamerILazyFqdnosr" expanduserreprrencode hexdigestrWreplacestr)rr)r}r>r?Zallowed_tokensZconfigured_hostnamerrmZ remoteuserZlocal_hostnameZ local_fqdnhomedirZtohashZ replacementsZ tokenizedfindrrrrrxsD      zSSHConfig._tokenizecCs|j|gS)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_KEYrFrr>rrrrs zSSHConfig._allowed_tokenscCsr|D]h}||dkrqt|j|||}t||tr\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)rrx isinstancelist enumerate)rr)r}kZ tokenizerir?rrrrYs  zSSHConfig._expand_variablescCs4z t|WStk r.td|YnXdS)z> Return a list of host_names from host value. zUnparsable host {}N)shlexrI ValueErrorrr5)rr(rrrr9s zSSHConfig._get_hostsc s$g}t|}|rdddd}|d}|drFd|d<|dd}||d <|d krb||q|sttd ||d|d <||qd d|D}d|kr dttfdd|ttfdd|}}d}t |rd}n$d|kr| d| dkrd}|dk 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)rnrorrrgTrrrn)rprCrDz'Missing parameter to Match '{}' keywordrocSsg|] }|dqS)rnrrOrrr sz*SSHConfig._get_matches..rp)rprCcs|kSrNrrQZ allowablerr"z(SSHConfig._get_matches..cs|kSrNrrrrrr#rz>Match does not allow 'all' mixed with anything but 'canonical'rCz-Match does not allow 'all' before 'canonical') rrIrvr2r8rr5rfilteranyindex) rr,r-tokensrkeywordsr|baderrrrrr:s@          zSSHConfig._get_matches)NFF)__name__ __module__ __qualname____doc__r3compiler4rr classmethodr r$rr%rMrErJrerUrVrwrxrrYr9r:rrrrr .s:      <B #) 8>  r cCsh|dd}|dkrdSz0tj}|dkr2tj}t|d|tjtjtjWStj k rbYnXdS)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 addressfamilyrNZinet) rFr7r[AF_INET6AF_INET getaddrinfo SOCK_DGRAM IPPROTO_IP AI_CANONNAMEr])rrKaddress_familyfamilyrrrrZ/s"rZc@s"eZdZdZdddZddZdS)rz7 Returns the host's fqdn on request as string. NcCsd|_||_||_dSrN)fqdnr)r()rr)r(rrrrYszLazyFqdn.__init__c Csl|jdkrfd}t|j|j}|dk rP|D]&}|\}}}}}|r(d|kr(|}qPq(|dkr`t}||_|jS)NrB)rrZr(r)r[getfqdn) rrresultsresafsocktypeproto canonnamesarrr__str__^s  zLazyFqdn.__str__)N)rrrrrrrrrrrTs rc@s eZdZdZddZddZdS)rTa 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 cCs"||}t|tr|S|dkS)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@)rboolr7)rr>valrrras_bools zSSHConfigDict.as_boolcCs 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 )rGrrrras_ints zSSHConfigDict.as_intN)rrrrrrrrrrrTzs!rT)rrirtrr3rr[hashlibrior functoolsrryrz ImportErroreZ ssh_exceptionrrrr rZrdictrTrrrrs0    %&