U q`j @sdZddlZddlZddlZddlZddlZddlZddlmZddl m Z d\Z Z z ddl Z Wn&e k rZzeZ W5dZ[XYnXddlmZmZdZGd d d eZd d ZGd ddeZGdddeZdS)z2 Configuration file (aka ``ssh_config``) support. N)partial)StringIO)NN)CouldNotCanonicalizeConfigParseErrorc @seZdZdZedZddddddd gdgd d ddd dgd dddgd ddddddd gd Zd dZe ddZ e ddZ e ddZ ddZ ddZd3ddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2ZdS)4 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+)(.+)%h%l%L%n%p%r%u~%d)Z controlpathhostname identityfile proxycommand 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-nv4zd3e_/lib/python/paramiko/config.py__init__GszSSHConfig.__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_pathes zSSHConfig.from_pathcCs|}|||S)zp Create a new, parsed `SSHConfig` from file-like object ``flo``. .. versionadded:: 2.7 )parse)rr!objrrrros 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#zs6       zSSHConfig.parsecCs|j|d}d|kr||d<|dddk}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.lookupNFcsdkrt|jD]}||dg|sF||dg||sFq|dD]T\}kr|dk rv|ddn|<qRdkrRfdd|DqRq||dkrЈddkrЈd=S)Nr&r+r'rc3s|]}|kr|VqdSNr.0xr<rHrr s z$SSHConfig._lookup..r) SSHConfigDictr_pattern_matchesrC _does_matchitemsextend_expand_variables)rrrHrAr:r=rrOrrBs0    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>)r3_addressfamily_host_lookupsocket gethostbynamegaierrorrCr)rrrHrIfounddomain candidateZfamily_specificrrrrGs     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)NrF,F!rT)hasattrrFr0fnmatch)rpatternstargetr*patternrrrrREs    zSSHConfig._pattern_matchescCs |||SrK)rR)rr`rrrr_allowedWszSSHConfig._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| }tdkr ttj |dd dj } | dk r:|| |r:dS| |q|S)NrrusertypeparamrAFallTr&Z originalhostZ localuserexecrstdout)Zhidewarn) getpassgetuserpoprC _should_failrR _tokenizeinvokeinvoke_import_errorrunokr6)rZ match_listtarget_hostnamerArHmatched candidatesZlocal_usernamer]ZpassedZconfigured_hostZconfigured_usertype_rmZhostvalrkZexec_cmdrrrrSZsL        zSSHConfig._does_matchcCs|dr |S| S)Nnegater)rZ would_passr]rrrruszSSHConfig._should_failc Cs||}|s|S|}|dkr*|d|}d|kr<|d}nt}t}d|krZ|d} n|} tdd} t|| } t j d} | || | ||| || 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. rportrkr@rr) rr r r r r rrr)_allowed_tokensrCSSH_PORTrrrsrX gethostnamerFLazyFqdnosr expanduserrTreplacestr)rr'r{r<r=Zallowed_tokensZconfigured_hostnamerrkZ remoteuserZlocal_hostnameZ local_fqdnhomedir replacementsZ tokenizedfindrrrrrvs@      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_KEYrCrr<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)rrv isinstancelist enumerate)rr'r{k tokenizerir=rrrrVs  zSSHConfig._expand_variablescCs4z t|WStk r.td|YnXdS)z> Return a list of host_names from host value. zUnparsable host {}N)shlexrF ValueErrorrr3)rr&rrrr7s zSSHConfig._get_hostsc s$g}t|}|rdddd}|d}|drFd|d<|dd}||d <|d krb||q|sttd ||d|d <||qd d|D}d|kr d ttfdd|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)rlrmrrrdTrrrl)rnrAz'Missing parameter to Match '{}' keywordrmcSsg|] }|dqS)rlrrLrrr sz*SSHConfig._get_matches..rncs|kSrKrrNZ allowablerrz(SSHConfig._get_matches..cs|kSrKrrrrrrrz>Match does not allow 'all' mixed with anything but 'canonical'rAz-Match does not allow 'all' before 'canonical') rrFrtr0r6rr3rfilteranyindex) rr*r+tokensr~keywordsrzbaderrrrrr8s@          zSSHConfig._get_matches)NF)__name__ __module__ __qualname____doc__r1compiler2rr classmethodrr"rr#rJrBrGrbrRrjrSrurvrrVr7r8rrrrr.s:      =: !) 4=  rcCsh|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) rCr5rXAF_INET6AF_INET getaddrinfo SOCK_DGRAM IPPROTO_IP AI_CANONNAMErZ)rrHaddress_familyfamilyrrrrW$s"rWc@s"eZdZdZdddZddZdS)rz7 Returns the host's fqdn on request as string. NcCsd|_||_||_dSrK)fqdnr'r&)rr'r&rrrrNszLazyFqdn.__init__c Csl|jdkrfd}t|j|j}|dk rP|D]&}|\}}}}}|r(d|kr(|}qPq(|dkr`t}||_|jS)Nr@)rrWr&r'rXgetfqdn) rrresultsresafsocktypeproto canonnamesarrr__str__Ss  zLazyFqdn.__str__)N)rrrrrrrrrrrIs rcs0eZdZdZfddZddZddZZS)rQa 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||dSrK)superrQr)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>)rboolr5)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 )rDrrrras_ints zSSHConfigDict.as_int)rrrrrrr __classcell__rrrrrQos! rQ)rrfrrrr1rrX functoolsrZ py3compatrrwrx ImportErroreZ ssh_exceptionrrrobjectrrWrdictrQrrrrs,   y%&