Internet Service Dämonen

Übersicht Weiter

Damit ein Client einen entsprechenden Server findet, benötigt er neben Kenntnis der IP-Adresse des Serverrechners auch noch die Portnummer, an der der Dienst wartet.

In den ersten Unix-Systemen mit TCP/IP-Unterstützung wurden bereits während des Systemstarts sämtliche Serverprozesse aktiviert, die ihre Ports initialisierten und auf eintreffende Anforderungen warteten. Traf ein Verbindungswunsch ein, erzeugte ein Server einen Kindprozess, vererbte diesem die geöffnete Verbindung, schloss seinerseits die Verbindung und begab sich selbst erneut in den Wartezustand, um eintreffende Anfragen entgegenzunehmen.

Bald erkannte man, dass die meisten Serverprozesse vollkommen umsonst gestartet wurden, sie wurden im Laufe der Aktivität des Systems nicht oder nur selten in Anspruch genommen. Mit den von den warteten Prozessen in Anspruch genommenen CPU-Zeiten konnte man noch gut leben, denn da sie nichts zu erledigen hatten, erzeugten sie auch nur geringe Rechenlast, aber der ständig reservierte Hauptspeicher, zumal in jenen Zeiten die heutigen RAM-Dimensionen ins Reich der Fantasie gehörten, entpuppte sich bald als Schwachpunkt.

Die Lösung kam, wie so viele Anreize aus jenen Tagen, aus Berkeley und wurde mit dem inetd als erstem »Superserver« mit 4.3BSD veröfentlicht.

Anstelle der Aktivierung sämtlicher Netzwerkdienste wurde nun nur noch der Superserver beim Start des Systems zum Leben erweckt. Dieser entnahm alle zu eröffnenden Portnummern einer Konfigurationsdatei und überwachte diese auf eintreffende Verbindungsanforderungen. Lag irgendwo eine Anfrage an, startete der Superserver den entsprechenden Serverdienst und vermachte ihm die bereits offene Verbindung.

Als Konsequenz hieraus ist die meiste Zeit über stets nur ein Server aktiv und alle weiteren können bei Bedarf nachgeladen und nach Erfüllung der Anforderung auch wieder beendet werden.

Der inetd ist der Standard-Superserver für Linux, jedoch lässt er in Sachen Zugriffssteuerung viele Wünsche offen. So hat sich der xinitd in vergangenen Jahren zu einer ernsthaften Alternative entwickelt.

Der Dämon inetd Zurück Anfang Weiter

Der inetd ist der mit Abstand beliebteste Superdämon. Er ist in der Lage sowohl TCP- als auch UDP-basierte und in aktuellen Versionen sogar RPC-Dienste zu starten. Dazu überwacht er die Ports (oft wird in diesem Zusammenhang auch von Internet Sockets gesprochen) der ihm anvertrauten Server und entscheidet anhand der Portnummer, an der eine Anforderung eintrifft, welcher Netzwerkdienst zu starten ist.

Nicht alle Dienste, die der Rechner im Netzwerk anbieten soll, werden von einem Superserver verwaltet. Einige hochverfügbare Server wird man schon während des Systemstarts aktivieren, man denke nur einen http-Dämonen auf einem frequentierten Webserver. Für welche Dienste sich der inetd letztlich verantwortlich zeichnet, muss ihm deshalb in seiner Konfigurationsdatei /etc/inetd.conf mitgeteilt werden.

Es gibt Dienste, die sind in ihrer Art so einfach, dass es vergebene Mühe wäre, sie in ein eigenes Programm zu packen. Der inetd verfügt deswegen über einige interne Dienste, deren Anforderung er höchst persönlich erfüllt:

chargen

Der »Zeichengenerator«. Trifft ein Verbindungswunsch für diesen Dienst ein, wird mit einem ununterbrochenen Zeichenstrom geantwortet, solange, bis der Client die Verbindung beendet. Der Service kann zur Performance-Messung eingesetzt werden.

daytime

Gibt die Rechnerzeit in einem für den Mensch verständlichen Format wieder

discard

Der Dienst basiert auf dem Initial Connection Protocol und anwortet bei eintreffendem Verbindungswunsch mit dem Aufbau einer Verbindung in die Gegenrichtung. Anschließend wartet discard auf eine Anwort und leitet diese nach /dev/null. Ist die Anwort »verarbeitet«, beendet sich der Prozess. Der Dienst wird zu Testzwecken eingesetzt.

echo

Der Dienst sendet die empfangenen Daten unverändert an den Absender zurück.

time

Gibt die Rechnerzeit in einem maschinenlesbaren Format wieder

»time« und »daytime« werden bei einem Zeitserver benötigt, die anderen Dienste sollten nur temporär für Testzwecke geöffnet werden, da sie von außen zum Erzeugen unnötiger Rechenlast missbraucht werden können.

Die Datei /etc/inetd.conf

Alle Dienste, die der inetd starten soll, müssen in dessen Konfigurationsdatei /etc/inetd.conf aufgeführt sein. Beginnt eine Zeile mit dem Doppelkreuz, so handelt es sich um einen Kommentar, alle anderen Zeilen bestehen aus 6 Feldern:

Dienstbezeichnung

Name des Serverdienstes, so wie er in der Datei /etc/services eingetragen ist. Im Falle eines RPC-Dienstes muss zusätzlich dessen Versionsnummer angegeben werden. Der RPC-Dienstname steht in der Datei /etc/rpc, ein gültiger Eintrag lautet dann <RPC-Dienst>/<Version>.

Sockettyp

Die Art des Sockets muss hier angegeben werden. Als Schlüsselwörter sind zulässig: stream, dgram, raw, rdm und seqpacket. stream ist dabei ein Socket, in dem ein Datenfluss (»streaming«) eintrifft, so wie sie das Transportprotokoll TCP implementiert. dgram ist der »Telegrammtyp« und korrespondiert mit dem UDP-Protokoll. raw sind Rohdaten, also Daten, die nicht in einemTransportprotokoll verpackt sind; sie werden direkt an die Anwendung weitergereicht. rdm (reliably delivered message) sind »sicher verteilte« Daten, so dass in den oberen Schichten des TCP-Protokollstacks von ihrer Unversehrtheit ausgegangen werden kann. seqpacket ist eine Sequenz von Paketen.

Protokoll

Ist der Name des Protokolls, über den der Dienst arbeitet, in den meisten Fällen wird es sich um tcp oder udp handeln. Im Falle eines RPC-Dienste steht hier z.B. »rpc/tcp« oder »rpc/udp«.

[no]wait

Eines der Schlüsselworte ist immer anzugeben, wobei die Angabe sich einzig auf das UDP-Protokoll auswirkt. wait bewirkt, dass der inetd nach dem Verbindungsaufbau neue Anforderungen erst entgegennimmt, wenn der UDP-Dienst seine Arbeit beendet hat. Mit nowait wird unverzüglich auf neue Anforderungen gewartet.

Benutzerkennung

Name des Benutzers, in dessen Auftrag der Dienst gestartet wird.

Dienstname

Vollständiger Programmname des Dienstes (inklusive Pfad und Optionen).

Eine Datei »/etc/inetd.conf« könnte dann wir folgt aussehen (Auszüge):

user@sonne> cat /etc/inetd.conf
# <service_name> <sock_type> <proto> <flags> <user> <server_path> <args>
#
# echo  stream  tcp     nowait  root    internal
# echo  dgram   udp     wait    root    internal
# discard       stream  tcp     nowait  root    internal
# discard       dgram   udp     wait    root    internal

daytime       stream  tcp     nowait  root    internal
daytime       dgram   udp     wait    root    internal
# chargen       stream  tcp     nowait  root    internal
# chargen       dgram   udp     wait    root    internal

time    stream  tcp     nowait  root    internal
time    dgram   udp     wait    root    internal
#
# These are standard services.
#
# ftp   stream  tcp     nowait  root    /usr/sbin/tcpd  wu.ftpd -a

ftp     stream  tcp     nowait root    /usr/sbin/tcpd  in.ftpd
#
# If you want telnetd not to "keep-alives" (e.g. if it runs over a ISDN
# uplink), add "-n". See 'man telnetd' for more deatails.

telnet  stream  tcp     nowait  root    /usr/sbin/tcpd  in.telnetd
nntp  stream  tcp     nowait  news    /usr/sbin/tcpd  /usr/sbin/leafnode
smtp    stream  tcp     nowait  root    /usr/sbin/sendmail  sendmail -bs
# printer       stream  tcp     nowait  root    /usr/sbin/tcpd  /usr/bin/lpd -i
# Shell, login, exec and talk are BSD protocols.
# The option "-h" permits ``.rhosts'' files for the superuser. Please look at
# man-page of rlogind and rshd to see more configuration possibilities about
# .rhosts files.
# shell  stream  tcp nowait  root    /usr/sbin/tcpd  in.rshd -L
# shell  stream  tcp     nowait  root    /usr/sbin/tcpd  in.rshd -aL
#

login   stream  tcp     nowait  root    /usr/sbin/tcpd  in.rlogind
# login stream  tcp     nowait  root    /usr/sbin/tcpd  in.rlogind -a
# exec  stream  tcp     nowait  root    /usr/sbin/tcpd  in.rexecd

talk    dgram   udp     wait    root    /usr/sbin/tcpd  in.talkd
ntalk   dgram   udp     wait    root    /usr/sbin/tcpd  in.talkd

finger  stream  tcp     nowait  nobody  /usr/sbin/tcpd in.fingerd -w
# systat        stream  tcp     nowait  nobody  /usr/sbin/tcpd  /bin/ps -auwwx
# netstat       stream  tcp     nowait  root    /usr/sbin/tcpd  /bin/netstat
# identd is now started at boot time, the following is not longer necessary.
# ident stream  tcp     wait    nobody  /usr/sbin/in.identd  in.identd -w -e

# swat is the Samba Web Administration Tool

swat   stream  tcp    nowait.400      root    /usr/sbin/swat  swat

Der einigen Diensten vorgeschaltete TCP-Wrapper »/usr/sbin/tcpd« implementiert eine dedizierte Zugangskontrolle für den jeweiligen Netzwerkdienst. Er ist eine relevante Komponente der Netzwerksicherheit und wird im Kapitel Netzwerk-Sicherheit TCP-Wrapper vorgestellt.

Der Dämon xinetd Zurück Anfang

Im vergangenen Abschnitt lernten Sie den inetd kennen. Die Bemerkungen zur nichtvorhandenen Zugangskontrolle sollten Ihnen ebenso wenig entgangen sein, wie der Kompromiss des TCP-Wrappers, der die Sicherheitsmängel des inetd teilweise beheben kann. Dennoch kann die Vorgehensweise des »alles ist erlaubt, solange es nicht explizit verboten wurde« bei halbherziger Konfiguration schnell zu unbemerkten Sicherheitslöchern führen.

Der xinetd ist ein vollwertiger Ersatz für den inetd. Das »x« deutet hier nicht etwa ein X-Window-Programm an, sondern steht für »extended« (erweitert). Er implementiert dieselben internen Dienste wie der »inetd« (chargen, daytime, discard, echo, time). Des Weiteren ermöglicht der xinetd die Protokollierung aller Zugriffe.

Die Datei /etc/xinetd.conf

Konfiguriert wird der xinetd mittels der Datei /etc/xinetd.conf. Er kennt zwei Typen von Einträgen. Zum einen handelt es sich um den optionalen »default«-Eintrag, der auf alle anderen Einträge angewandt wird, insofern diese die Optionen nicht selbst definieren. Dieser default-Eintrag besitzt folgende Struktur:

default
  {
     <Schlüssel><Operator><Parameter><Parameter>...
...
  }

Die weiteren Einträge betreffen die einzelnen Dienste:

service <Dienstbezeichnung>
  {
     <Schlüssel><Operator><Parameter><Parameter>...
...
  }

Als Operatoren sind zulässig: die normale Zuweisung mit »=«, das Hinzufügen eines weiteren Schlüssels mit »+=« und das Entfernen eines Schlüssels mit »-=«. Die Verwendung der Operatoren »+=« und »-=« macht vor allem in Verbindung mit dem »default«-Eintrag Sinn.

Von den nachfolgend beschriebenen Schlüsseln sind im Falle des default-Eintrags nicht alle sinnvoll. Erlaubt sind hier »log_type«, »log_on_success«, »log_on_failure«, »only_from«, »no_access«, »passenv«, »instances« und »disabled«. »disabled« kann nur im »default«-Eintrag stehen und sperrt den Zugang zu den angegebenen Diensten.

id

Jeder Dienst muss eindeutig identifiziert werden können, die Angabe ist für Mulit-Protokoll-Dienste notwendig. Fehlt sie, so wird der Name des Dienstes (»Dienstbezeichnung«) als ID angenommen.

type

Kombination aus »RPC« (RPC-Dienst), »INTERNAL« (interner Dienst) oder »UNLISTED« (Dienst, der nicht in den Dateien »/etc/rpc« oder »/etc/services« eingetragen ist).

flags

Von den möglichen Einträgen ist »IDONLY« der Interessanteste. Eine Anforderung wird dann nur zugelassen, wenn der entfernte Benutzer identifiziert werden kann.

socket_type

Die Typen sind »stream«, »dgram«, »raw« und »seqpacket« und besitzen dieselbe Bedeutung wie beim inetd beschrieben wurde.

protocol

Name des Protokolls, über das der Dienst arbeitet. Fehlt die Angabe, wird das »übliche« Protokoll des Dienstes angenommen.

wait

Steht hier »yes«, wartet der xinitd nach einem Verbindungsaufbau auf das Ende des Servers, bevor er neue Anforderungen entgegen nimmt. Mit »no«, startet er ggf. weitere Serverprozesse.

user

Die Nutzerkennung, unter der der Serverprozess gestartet wird.

group

Die Gruppenkennung, unter der der Serverprozess gestartet wird.

instances

Maximal mögliche Anzahl Prozesse, die den Dienst zu einer Zeit ausführen dürfen. Neben der Zahl darf auch »UNLIMITED« stehen.

nice

Priorität des Serverprozesses.

server

Programmname des Servers (inklusive Pfad)

server_args

Argumente des Serverprogrammes

only_from

Liste von Rechnern, von denen der Zugang erlaubt ist. Die Angabe kann eine IP-Adresse, ein Rechnername, eine Netzwerkadresse oder ein Adressbereich sein (192.168.100.12/100 erlaubt den Zugriff von den Rechner 192.168.100.12 bis 192.168.100.100)

no_access

Rechner, denen der Zugriff verwehrt wird. Die Angaben erfolgen wie unter »only_from«, wobei bei Mehrfachnennung die »bessere« Übereinstimmung gilt (wurde der Zugriff den Rechern eines Netzwerks erlaubt und ist nun ein konkreter Rechner aus jedem Netzwerk in der verbotenen Liste enthalten, so wird ihm der Zugang verwehrt).

access_times

Tageszeit, zu der der Zugriff erlaubt ist

log_type

Wo und wie soll protokolliert werden? Mit »SYSLOG Herkunft [Level]« wird die Protokollierung an den syslogd weitergereicht; mit »FILE Datei [soft_limit [hardlimit]]« erfolgt sie in der angegebenen Datei. Die beiden Limits sind die Schranken, wie größ eine Datei maximal werden kann, somit wird ein Volllaufen des Dateisystems ausgeschlossen.

log_on_success

Was wird protokolliert, falls der Server erfolgreich startet? Mögliche Einträge sind: Prozessnummer des Servers »PID«, Rechnername, von dem die Anforderung kam »HOST«, Benutzernummer, von dem die Anforderung kam »USERID«, der Exit-Status des Servers »EXIT« und die Dauer des Serverlaufs »DURATION«.

log_on_failure

Was wird protokolliert, falls der Server nicht gestartet werden konnte? Neben »HOST« und »USERID« (wie oben) sind möglich »ATTEMPT«, das die Tatsache des fehlgeschlagenen Starts notiert und »RECORD«, das weiterführende Informationen (sofern ermittelbar) vom entfernten Aufruf protokolliert.

rpc_version

Versionsnummer des RPC-Dienstes

env

Hier lassen sich zu einem Server zusätzliche Umgebungsvariablen angeben

passenv

Liste der Umgebungsvariablen, die der xinetd dem Server vererbt

port

Portnummer, an der der Server wartet, diese muss mit dem Eintrag in der Datei /etc/services (soweit vorhanden) übereinstimmen

redirect

Eine Anforderung wird an den angegebenen Rechner weitergeleitet. Dies ist nur bei TCP-Diensten möglich

bind

Bindet einen Dienst an ein spezielles Device. So kann z.B. bei einem Rechner mit zwei Netzwerkkarten sicher gestellt werden, dass der Dienst nur über die eine Karte zugänglich ist

banner

Enthält einen Dateinamen, deren Inhalt auf dem zugreifenden Rechner angezeigt wird, falls ihm der Zugang verwehrt wird.

Bevor wir uns den Beispielen zuwenden, sind noch einige Anwendungen zu den vom xinetd akzeptierten Signalen notwendig. Bislang konnten Sie nahezu jeden Prozess mit dem Signal SIGHUP (1) zum erneuten Einlesen seiner Konfigurationsdateien bewegen. Im Falle des xinetd erreichen Sie damit allerdings nur, dass dieser sich mit einem Speicherabzug verabschiedet. Aus Sicherheitsgründen reagiert der xinetd auf einige Signale anders als gewohnt:

SIGUSR1 (10)

Einlesen der Konfigurationsdatei. Aktive Dienste bleiben aktiv.

SIGUSR2 (12)

Einlesen der Konfigurationsdatei. Aktive Dienste werden sofort beendet.

SIGQUIT (3)

Programmende, ohne laufende Dienste zu beenden

SIGTERM (15)

Programmende, laufende Dienste werden zuvor beendet

SIGHUP (1)

Anlegen eines Speicherauszugs und Programmende

SIGIO (29)

Interne Konsitenzprüfung des xinetd

Beispiel 1: Mit dem default-Eintrag spezifizieren wir einige Voreinstellungen, die für alle Dienste gelten, in denen sie nicht explizit überschrieben werden.

default
   {
    log_type       = FILE /var/lo/xinetd.log
    log_on_success = HOST
    log_on_failure = HOST USERID
    instance       = 5
    disabled       = finger
   }

Beispiel 2: »telnet« soll nur von Rechnern des Netzwerkes 192.168.100 möglich sein, wobei die Rechner mit den Endnummern 56-192 ausgenommen werden sollen. Alle fehlgeschlagenen Kontaktversuche sollen über den Syslog-Mechanismus protokolliert werden, wobei die Herkunft den Sicherheitdiensten (auth) zugeordnet werden soll und die Meldung das Level »Warnung« erhält:

service telnet
   {
    socket_type = stream
    protocol    = tcp
    wait        = no
    user        = root
    server      = /usr/sbin/in.telnetd
    only_from   = 192.168.100.0
    no_access   = 192.158.100.56/192
    flags       = IDONLY
    log_on_failure += RECORD
    log_type    = SYSLOG auth warn
   }

Beispiel 3: »ftp« soll nur in den Nachtstunden erlaubt sein. Gleichzeitig werden 4 Zugriffe zugelassen.

service ftp
   {
    socket_type = stream
    wait        = no
    user        = root
    server      = /usr/sbin/wu.ftpd
    server_flags = -a
    log_on_success += DURATION
    access_times = 20:00-06:00
    instance    = 4
   }

Beispiel 4: Von den internen Diensten soll »time« sowohl über »udp« als auch über »tcp« bereitgestellt werden:

service time
   {
    id          = time_dgram
    socket_type = dgram
    wait        = no
    user        = root
   }

service time
   {
    id          = time_stream
    socket_type = stream
    wait        = no
    user        = root
   }

Beispiel 5: Zuletzt noch ein Beispiel zu einem RPC-Dienst:

service rstatd
   {
    type        = RPC
    socket_type = dgram
    wait        = yes
    user        = root
    server      = /usr/etc/rpc.rstatd
    rpc_version = 2-4
    env         = LD_LIBRARY_PATH=/etc/securelib
   }