blob: d7a72febcd13d8695bca8de9c0dade431153de03 [file] [log] [blame]
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
# See LICENSE for details.
#
"""
Parser for inetd.conf files
Maintainer: Andrew Bennetts
Future Plans: xinetd configuration file support?
"""
# Various exceptions
class InvalidConfError(Exception):
"""Invalid configuration file"""
class InvalidInetdConfError(InvalidConfError):
"""Invalid inetd.conf file"""
class InvalidServicesConfError(InvalidConfError):
"""Invalid services file"""
class InvalidRPCServicesConfError(InvalidConfError):
"""Invalid rpc services file"""
class UnknownService(Exception):
"""Unknown service name"""
class SimpleConfFile:
"""Simple configuration file parser superclass.
Filters out comments and empty lines (which includes lines that only
contain comments).
To use this class, override parseLine or parseFields.
"""
commentChar = '#'
defaultFilename = None
def parseFile(self, file=None):
"""Parse a configuration file
If file is None and self.defaultFilename is set, it will open
defaultFilename and use it.
"""
if file is None and self.defaultFilename:
file = open(self.defaultFilename,'r')
for line in file.readlines():
# Strip out comments
comment = line.find(self.commentChar)
if comment != -1:
line = line[:comment]
# Strip whitespace
line = line.strip()
# Skip empty lines (and lines which only contain comments)
if not line:
continue
self.parseLine(line)
def parseLine(self, line):
"""Override this.
By default, this will split the line on whitespace and call
self.parseFields (catching any errors).
"""
try:
self.parseFields(*line.split())
except ValueError:
raise InvalidInetdConfError, 'Invalid line: ' + repr(line)
def parseFields(self, *fields):
"""Override this."""
class InetdService:
"""A simple description of an inetd service."""
name = None
port = None
socketType = None
protocol = None
wait = None
user = None
group = None
program = None
programArgs = None
def __init__(self, name, port, socketType, protocol, wait, user, group,
program, programArgs):
self.name = name
self.port = port
self.socketType = socketType
self.protocol = protocol
self.wait = wait
self.user = user
self.group = group
self.program = program
self.programArgs = programArgs
class InetdConf(SimpleConfFile):
"""Configuration parser for a traditional UNIX inetd(8)"""
defaultFilename = '/etc/inetd.conf'
def __init__(self, knownServices=None):
self.services = []
if knownServices is None:
knownServices = ServicesConf()
knownServices.parseFile()
self.knownServices = knownServices
def parseFields(self, serviceName, socketType, protocol, wait, user,
program, *programArgs):
"""Parse an inetd.conf file.
Implemented from the description in the Debian inetd.conf man page.
"""
# Extract user (and optional group)
user, group = (user.split('.') + [None])[:2]
# Find the port for a service
port = self.knownServices.services.get((serviceName, protocol), None)
if not port and not protocol.startswith('rpc/'):
# FIXME: Should this be discarded/ignored, rather than throwing
# an exception?
try:
port = int(serviceName)
serviceName = 'unknown'
except:
raise UnknownService, "Unknown service: %s (%s)" \
% (serviceName, protocol)
self.services.append(InetdService(serviceName, port, socketType,
protocol, wait, user, group, program,
programArgs))
class ServicesConf(SimpleConfFile):
"""/etc/services parser
@ivar services: dict mapping service names to (port, protocol) tuples.
"""
defaultFilename = '/etc/services'
def __init__(self):
self.services = {}
def parseFields(self, name, portAndProtocol, *aliases):
try:
port, protocol = portAndProtocol.split('/')
port = long(port)
except:
raise InvalidServicesConfError, 'Invalid port/protocol:' + \
repr(portAndProtocol)
self.services[(name, protocol)] = port
for alias in aliases:
self.services[(alias, protocol)] = port
class RPCServicesConf(SimpleConfFile):
"""/etc/rpc parser
@ivar self.services: dict mapping rpc service names to rpc ports.
"""
defaultFilename = '/etc/rpc'
def __init__(self):
self.services = {}
def parseFields(self, name, port, *aliases):
try:
port = long(port)
except:
raise InvalidRPCServicesConfError, 'Invalid port:' + repr(port)
self.services[name] = port
for alias in aliases:
self.services[alias] = port