1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 L{SSHConfig}.
21 """
22
23 import fnmatch
24
25
27 """
28 Representation of config information as stored in the format used by
29 OpenSSH. Queries can be made via L{lookup}. The format is described in
30 OpenSSH's C{ssh_config} man page. This class is provided primarily as a
31 convenience to posix users (since the OpenSSH format is a de-facto
32 standard on posix) but should work fine on Windows too.
33
34 @since: 1.6
35 """
36
38 """
39 Create a new OpenSSH config object.
40 """
41 self._config = [ { 'host': '*' } ]
42
43 - def parse(self, file_obj):
44 """
45 Read an OpenSSH config from the given file object.
46
47 @param file_obj: a file-like object to read the config file from
48 @type file_obj: file
49 """
50 configs = [self._config[0]]
51 for line in file_obj:
52 line = line.rstrip('\n').lstrip()
53 if (line == '') or (line[0] == '#'):
54 continue
55 if '=' in line:
56 key, value = line.split('=', 1)
57 key = key.strip().lower()
58 else:
59
60 i = 0
61 while (i < len(line)) and not line[i].isspace():
62 i += 1
63 if i == len(line):
64 raise Exception('Unparsable line: %r' % line)
65 key = line[:i].lower()
66 value = line[i:].lstrip()
67
68 if key == 'host':
69 del configs[:]
70
71 for host in value.split():
72
73 matches = [c for c in self._config if c['host'] == host]
74 if len(matches) > 0:
75 configs.append(matches[0])
76 else:
77 config = { 'host': host }
78 self._config.append(config)
79 configs.append(config)
80 else:
81 for config in configs:
82 config[key] = value
83
85 """
86 Return a dict of config options for a given hostname.
87
88 The host-matching rules of OpenSSH's C{ssh_config} man page are used,
89 which means that all configuration options from matching host
90 specifications are merged, with more specific hostmasks taking
91 precedence. In other words, if C{"Port"} is set under C{"Host *"}
92 and also C{"Host *.example.com"}, and the lookup is for
93 C{"ssh.example.com"}, then the port entry for C{"Host *.example.com"}
94 will win out.
95
96 The keys in the returned dict are all normalized to lowercase (look for
97 C{"port"}, not C{"Port"}. No other processing is done to the keys or
98 values.
99
100 @param hostname: the hostname to lookup
101 @type hostname: str
102 """
103 matches = [x for x in self._config if fnmatch.fnmatch(hostname, x['host'])]
104
105 matches.sort(lambda x,y: cmp(len(x['host']), len(y['host'])))
106 ret = {}
107 for m in matches:
108 ret.update(m)
109 del ret['host']
110 return ret
111