a bfk @sdZddlZddlZddlZddlZddlZddlZddlmZddl m Z ddl m Z d\Z Zz ddl Z Wn(eyZzeZWYdZ[n dZ[00ddlmZmZd ZGd d d eZd d ZGdddeZGdddeZdS)z2 Configuration file (aka ``ssh_config``) support. N)sha1)partial)StringIO)NN)CouldNotCanonicalizeConfigParseErrorc@seZdZdZedZgddggdgdgdgdd Zd d Ze d d Z e ddZ e ddZ ddZ ddZd0ddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/ZdS)1 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 rr)rr rr)r rr) r rr r r rrrr)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)selfr6/tmp/pip-target-98j97qn4/lib/python/paramiko/config.py__init__IszSSHConfig.__init__cCs|t|S)zg Create a new, parsed `SSHConfig` from ``text`` string. .. versionadded:: 2.7 ) from_filer)clstextrrr from_text^szSSHConfig.from_textcCs6t|}||WdS1s(0YdS)zr Create a new, parsed `SSHConfig` from the file found at ``path``. .. versionadded:: 2.7 N)openr)rpathflorrr from_pathgs zSSHConfig.from_pathcCs|}|||S)zp Create a new, parsed `SSHConfig` from file-like object ``flo``. .. versionadded:: 2.7 )parse)rr#objrrrrqs zSSHConfig.from_filecCsRdgid}|D].}|}|r|dr.qt|j|}|sNtd||d}|d}|dvr|j |dii}|d kr| ||d <n| ||d <q|d kr|d krd |d|<q|dr| dr|dd}|dvr(||dvr|d| |n|g|d|<q||dvr||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|vr||d<|dddv}t|dd}|r|d|kr|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. )rrZcanonicalizehostnameN)yesalwaysZcanonicalizemaxdotsr.ZcanonicaldomainsT) canonical)_lookupgetintcountsplit canonicalize)rroptionsZcanonZmaxdotsdomainsrrrlookups(  zSSHConfig.lookupNFcsdurt|jD]}||dg|sF||dg||sFq|dD]T\}vr|durv|ddn|<qRdkrRfdd|DqRq||dvrЈddurЈd=S)Nr(r-r)rc3s|]}|vr|VqdSNr.0xr>rJrr sz$SSHConfig._lookup..r) SSHConfigDictr_pattern_matchesrE _does_matchitemsextend_expand_variables)rrrJrCr<r?rrQrrDs*   zSSHConfig._lookupc Csd}|D]\}d||}t||}|dur4|d}n$zt|}WntjyVYn0|r|Sq|dddkrz|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 gethostbynamegaierrorrEr)rrrJrKfounddomain candidateZfamily_specificrrrrIs     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_hostnames=s zSSHConfig.get_hostnamescCsZt|dr|d}d}|D]8}|drDt||ddrDdSt||rd}q|S)NrH,F!rT)hasattrrHr2fnmatch)rpatternstargetr,patternrrrrTGs    zSSHConfig._pattern_matchescCs |||SrM)rT)rrbrrrr_allowedYszSSHConfig._allowedcCsJg}|dd}t}|rF|d}d} |dd} |dd} |d|d} } | dkrp|||rndSn| dkr|d S| d kr| p|}|| |} n| d kr|| |} nn| dkr| p|}|| |} nP| d kr|| |} n:| d kr|||d| }tdur ttj |dd dj } | dur:|| |r:dS| |q|S)NrrusertypeparamrCFallTr(Z originalhostZ localuserexecrstdout)hidewarn) getpassgetuserpoprE _should_failrT _tokenizeinvokeinvoke_import_errorrunokr8)rZ match_listtarget_hostnamerCrJmatched candidatesZlocal_usernamer_ZpassedZconfigured_hostZconfigured_usertype_roZhostvalrmZexec_cmdrrrrU\sF        zSSHConfig._does_matchcCs|dr |S| S)Nnegater)rZ would_passr_rrrrxszSSHConfig._should_failc Cs||}|s|S|}|dkr*|d|}d|vr<|d}nt}t}d|vrZ|d} n|} tdd} t|| } t j d} | |t || } t | | || | ||| || d }|}|D]"\}}||vrq||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_tokensrESSH_PORTrurvrZ gethostnamerHLazyFqdnosr" expanduserreprrencode hexdigestrVreplacestr)rr)r~r>r?Zallowed_tokensZconfigured_hostnamerrmZ remoteuserZlocal_hostnameZ local_fqdnhomedirZtohash replacementsZ tokenizedfindrrrrrysD      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_KEYrErr>rrrrs zSSHConfig._allowed_tokenscCsr|D]h}||durqt|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)rry isinstancelist enumerate)rr)r~k tokenizerir?rrrrXs  zSSHConfig._expand_variablescCs2z t|WSty,td|Yn0dS)z> Return a list of host_names from host value. zUnparsable host {}N)shlexrH ValueErrorrr5)rr(rrrr9s  zSSHConfig._get_hostsc s$g}t|}|rdddd}|d}|drFd|d<|dd}||d <|d vrb||q|sttd ||d|d <||qd d|D}d|vr d ttfdd|ttfdd|}}d}t |rd}n$d|vr| d| dkrd}|dur 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)rnrorrrfTrrrn)rprCz'Missing parameter to Match '{}' keywordrocSsg|] }|dqS)rnrrNrrr z*SSHConfig._get_matches..rpcs|vSrMrrPZ allowablerrrz(SSHConfig._get_matches..cs|vSrMrrrrrrrz>Match does not allow 'all' mixed with anything but 'canonical'rCz-Match does not allow 'all' before 'canonical') rrHrwr2r8rr5rfilteranyindex) rr,r-tokensrkeywordsr}baderrrrrr:s@          zSSHConfig._get_matches)NF)__name__ __module__ __qualname____doc__r3compiler4rr classmethodr r$rr%rLrDrIrdrTrlrUrxryrrXr9r:rrrrr /s<     =: !) 4>  r cCsf|dd}|dkrdSz0tj}|dkr2tj}t|d|tjtjtjWStj y`Yn0dS)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) rEr7rZAF_INET6AF_INET getaddrinfo SOCK_DGRAM IPPROTO_IP AI_CANONNAMEr\)rrJaddress_familyfamilyrrrrY's"rYc@s"eZdZdZdddZddZdS)rz7 Returns the host's fqdn on request as string. NcCsd|_||_||_dSrM)fqdnr)r()rr)r(rrrrQszLazyFqdn.__init__c Csl|jdurfd}t|j|j}|durP|D]&}|\}}}}}|r(d|vr(|}qPq(|dur`t}||_|jS)NrB)rrYr(r)rZgetfqdn) rrresultsresafsocktypeproto canonnamesarrr__str__Vs  zLazyFqdn.__str__)N)rrrrrrrrrrrLs rcs0eZdZdZfddZddZddZZS)rSa 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 cstt|j|i|dSrM)superrSr)rargskwargs __class__rrrszSSHConfigDict.__init__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 )rFrrrras_ints zSSHConfigDict.as_int)rrrrrrr __classcell__rrrrrSrs! rS)rrhrurr3rrZhashlibr functoolsrZ py3compatrrzr{ ImportErroreZ ssh_exceptionrrrobjectr rYrdictrSrrrrs.    {%&