summaryrefslogtreecommitdiff
path: root/paramiko/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'paramiko/config.py')
-rw-r--r--paramiko/config.py92
1 files changed, 57 insertions, 35 deletions
diff --git a/paramiko/config.py b/paramiko/config.py
index 96ec9ef..20ca4aa 100644
--- a/paramiko/config.py
+++ b/paramiko/config.py
@@ -27,7 +27,6 @@ import re
import socket
SSH_PORT = 22
-proxy_re = re.compile(r"^(proxycommand)\s*=*\s*(.*)", re.I)
class SSHConfig (object):
@@ -41,6 +40,8 @@ class SSHConfig (object):
.. versionadded:: 1.6
"""
+ SETTINGS_REGEX = re.compile(r'(\w+)(?:\s*=\s*|\s+)(.+)')
+
def __init__(self):
"""
Create a new OpenSSH config object.
@@ -53,44 +54,39 @@ class SSHConfig (object):
:param file file_obj: a file-like object to read the config file from
"""
+
host = {"host": ['*'], "config": {}}
for line in file_obj:
line = line.rstrip('\r\n').lstrip()
- if (line == '') or (line[0] == '#'):
+ if not line or line.startswith('#'):
continue
- if '=' in line:
- # Ensure ProxyCommand gets properly split
- if line.lower().strip().startswith('proxycommand'):
- match = proxy_re.match(line)
- key, value = match.group(1).lower(), match.group(2)
- else:
- key, value = line.split('=', 1)
- key = key.strip().lower()
- else:
- # find first whitespace, and split there
- i = 0
- while (i < len(line)) and not line[i].isspace():
- i += 1
- if i == len(line):
- raise Exception('Unparsable line: %r' % line)
- key = line[:i].lower()
- value = line[i:].lstrip()
+ match = re.match(self.SETTINGS_REGEX, line)
+ if not match:
+ raise Exception("Unparsable line %s" % line)
+ key = match.group(1).lower()
+ value = match.group(2)
+
if key == 'host':
self._config.append(host)
- value = value.split()
- host = {key: value, 'config': {}}
- #identityfile, localforward, remoteforward keys are special cases, since they are allowed to be
- # specified multiple times and they should be tried in order
- # of specification.
-
- elif key in ['identityfile', 'localforward', 'remoteforward']:
- if key in host['config']:
- host['config'][key].append(value)
- else:
- host['config'][key] = [value]
- elif key not in host['config']:
- host['config'].update({key: value})
+ host = {
+ 'host': self._get_hosts(value),
+ 'config': {}
+ }
+ else:
+ if value.startswith('"') and value.endswith('"'):
+ value = value[1:-1]
+
+ #identityfile, localforward, remoteforward keys are special cases, since they are allowed to be
+ # specified multiple times and they should be tried in order
+ # of specification.
+ if key in ['identityfile', 'localforward', 'remoteforward']:
+ if key in host['config']:
+ host['config'][key].append(value)
+ else:
+ host['config'][key] = [value]
+ elif key not in host['config']:
+ host['config'][key] = value
self._config.append(host)
def lookup(self, hostname):
@@ -111,8 +107,10 @@ class SSHConfig (object):
:param str hostname: the hostname to lookup
"""
- matches = [config for config in self._config if
- self._allowed(hostname, config['host'])]
+ matches = [
+ config for config in self._config
+ if self._allowed(config['host'], hostname)
+ ]
ret = {}
for match in matches:
@@ -128,7 +126,7 @@ class SSHConfig (object):
ret = self._expand_variables(ret, hostname)
return ret
- def _allowed(self, hostname, hosts):
+ def _allowed(self, hosts, hostname):
match = False
for host in hosts:
if host.startswith('!') and fnmatch.fnmatch(hostname, host[1:]):
@@ -208,6 +206,30 @@ class SSHConfig (object):
config[k] = config[k].replace(find, str(replace))
return config
+ def _get_hosts(self, host):
+ """
+ Return a list of host_names from host value.
+ """
+ i, length = 0, len(host)
+ hosts = []
+ while i < length:
+ if host[i] == '"':
+ end = host.find('"', i + 1)
+ if end < 0:
+ raise Exception("Unparsable host %s" % host)
+ hosts.append(host[i + 1:end])
+ i = end + 1
+ elif not host[i].isspace():
+ end = i + 1
+ while end < length and not host[end].isspace() and host[end] != '"':
+ end += 1
+ hosts.append(host[i:end])
+ i = end
+ else:
+ i += 1
+
+ return hosts
+
class LazyFqdn(object):
"""