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