| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
| 2 # See LICENSE for details. | |
| 3 | |
| 4 # | |
| 5 """ | |
| 6 Parser for inetd.conf files | |
| 7 | |
| 8 Maintainer: U{Andrew Bennetts<mailto:spiv@twistedmatrix.com>} | |
| 9 | |
| 10 Future Plans: xinetd configuration file support? | |
| 11 """ | |
| 12 | |
| 13 # Various exceptions | |
| 14 class InvalidConfError(Exception): | |
| 15 """Invalid configuration file""" | |
| 16 | |
| 17 | |
| 18 class InvalidInetdConfError(InvalidConfError): | |
| 19 """Invalid inetd.conf file""" | |
| 20 | |
| 21 | |
| 22 class InvalidServicesConfError(InvalidConfError): | |
| 23 """Invalid services file""" | |
| 24 | |
| 25 | |
| 26 class InvalidRPCServicesConfError(InvalidConfError): | |
| 27 """Invalid rpc services file""" | |
| 28 | |
| 29 | |
| 30 class UnknownService(Exception): | |
| 31 """Unknown service name""" | |
| 32 | |
| 33 | |
| 34 class SimpleConfFile: | |
| 35 """Simple configuration file parser superclass. | |
| 36 | |
| 37 Filters out comments and empty lines (which includes lines that only | |
| 38 contain comments). | |
| 39 | |
| 40 To use this class, override parseLine or parseFields. | |
| 41 """ | |
| 42 | |
| 43 commentChar = '#' | |
| 44 defaultFilename = None | |
| 45 | |
| 46 def parseFile(self, file=None): | |
| 47 """Parse a configuration file | |
| 48 | |
| 49 If file is None and self.defaultFilename is set, it will open | |
| 50 defaultFilename and use it. | |
| 51 """ | |
| 52 if file is None and self.defaultFilename: | |
| 53 file = open(self.defaultFilename,'r') | |
| 54 | |
| 55 for line in file.readlines(): | |
| 56 # Strip out comments | |
| 57 comment = line.find(self.commentChar) | |
| 58 if comment != -1: | |
| 59 line = line[:comment] | |
| 60 | |
| 61 # Strip whitespace | |
| 62 line = line.strip() | |
| 63 | |
| 64 # Skip empty lines (and lines which only contain comments) | |
| 65 if not line: | |
| 66 continue | |
| 67 | |
| 68 self.parseLine(line) | |
| 69 | |
| 70 def parseLine(self, line): | |
| 71 """Override this. | |
| 72 | |
| 73 By default, this will split the line on whitespace and call | |
| 74 self.parseFields (catching any errors). | |
| 75 """ | |
| 76 try: | |
| 77 self.parseFields(*line.split()) | |
| 78 except ValueError: | |
| 79 raise InvalidInetdConfError, 'Invalid line: ' + repr(line) | |
| 80 | |
| 81 def parseFields(self, *fields): | |
| 82 """Override this.""" | |
| 83 | |
| 84 | |
| 85 class InetdService: | |
| 86 """A simple description of an inetd service.""" | |
| 87 name = None | |
| 88 port = None | |
| 89 socketType = None | |
| 90 protocol = None | |
| 91 wait = None | |
| 92 user = None | |
| 93 group = None | |
| 94 program = None | |
| 95 programArgs = None | |
| 96 | |
| 97 def __init__(self, name, port, socketType, protocol, wait, user, group, | |
| 98 program, programArgs): | |
| 99 self.name = name | |
| 100 self.port = port | |
| 101 self.socketType = socketType | |
| 102 self.protocol = protocol | |
| 103 self.wait = wait | |
| 104 self.user = user | |
| 105 self.group = group | |
| 106 self.program = program | |
| 107 self.programArgs = programArgs | |
| 108 | |
| 109 | |
| 110 class InetdConf(SimpleConfFile): | |
| 111 """Configuration parser for a traditional UNIX inetd(8)""" | |
| 112 | |
| 113 defaultFilename = '/etc/inetd.conf' | |
| 114 | |
| 115 def __init__(self, knownServices=None): | |
| 116 self.services = [] | |
| 117 | |
| 118 if knownServices is None: | |
| 119 knownServices = ServicesConf() | |
| 120 knownServices.parseFile() | |
| 121 self.knownServices = knownServices | |
| 122 | |
| 123 def parseFields(self, serviceName, socketType, protocol, wait, user, | |
| 124 program, *programArgs): | |
| 125 """Parse an inetd.conf file. | |
| 126 | |
| 127 Implemented from the description in the Debian inetd.conf man page. | |
| 128 """ | |
| 129 # Extract user (and optional group) | |
| 130 user, group = (user.split('.') + [None])[:2] | |
| 131 | |
| 132 # Find the port for a service | |
| 133 port = self.knownServices.services.get((serviceName, protocol), None) | |
| 134 if not port and not protocol.startswith('rpc/'): | |
| 135 # FIXME: Should this be discarded/ignored, rather than throwing | |
| 136 # an exception? | |
| 137 try: | |
| 138 port = int(serviceName) | |
| 139 serviceName = 'unknown' | |
| 140 except: | |
| 141 raise UnknownService, "Unknown service: %s (%s)" \ | |
| 142 % (serviceName, protocol) | |
| 143 | |
| 144 self.services.append(InetdService(serviceName, port, socketType, | |
| 145 protocol, wait, user, group, program, | |
| 146 programArgs)) | |
| 147 | |
| 148 | |
| 149 class ServicesConf(SimpleConfFile): | |
| 150 """/etc/services parser | |
| 151 | |
| 152 @ivar services: dict mapping service names to (port, protocol) tuples. | |
| 153 """ | |
| 154 | |
| 155 defaultFilename = '/etc/services' | |
| 156 | |
| 157 def __init__(self): | |
| 158 self.services = {} | |
| 159 | |
| 160 def parseFields(self, name, portAndProtocol, *aliases): | |
| 161 try: | |
| 162 port, protocol = portAndProtocol.split('/') | |
| 163 port = long(port) | |
| 164 except: | |
| 165 raise InvalidServicesConfError, 'Invalid port/protocol:' + \ | |
| 166 repr(portAndProtocol) | |
| 167 | |
| 168 self.services[(name, protocol)] = port | |
| 169 for alias in aliases: | |
| 170 self.services[(alias, protocol)] = port | |
| 171 | |
| 172 | |
| 173 class RPCServicesConf(SimpleConfFile): | |
| 174 """/etc/rpc parser | |
| 175 | |
| 176 @ivar self.services: dict mapping rpc service names to rpc ports. | |
| 177 """ | |
| 178 | |
| 179 defaultFilename = '/etc/rpc' | |
| 180 | |
| 181 def __init__(self): | |
| 182 self.services = {} | |
| 183 | |
| 184 def parseFields(self, name, port, *aliases): | |
| 185 try: | |
| 186 port = long(port) | |
| 187 except: | |
| 188 raise InvalidRPCServicesConfError, 'Invalid port:' + repr(port) | |
| 189 | |
| 190 self.services[name] = port | |
| 191 for alias in aliases: | |
| 192 self.services[alias] = port | |
| 193 | |
| 194 | |
| OLD | NEW |