Betrachten wir erstmal eine Sendmailkonfiguration (wer sich jetzt fragt, wozu, möge einen Blick auf das nächste Kapitel werfen, welches ein Problem der realen Welt löst). Sie enthält typischerweise folgende Teile.
# strip message body to 7 bits on input? O SevenBitInput=False # 8-bit data handling O EightBitMode=pass8
Optionen schalten einfache Verhaltenweisen von Sendmail ein oder aus und setzen Parameter. Daran gibt es nicht kompliziertes, und hier eine Referenz von Sendmail-Optionen zu geben, macht nicht viel Sinn.
Mlocal, P=/usr/lib/sm.bin/sensible-mda, F=lsDFMAw5:/|@qhnPu90, S=10/30, R=20/40,
T=DNS/RFC822/X-Unix,
A=sensible-mda $g $u $h ${client_addr}
Mprog, P=/bin/sh, F=lsDFMoqu90, S=10/30, R=20/40, D=$z:/,
T=X-Unix,
A=sh -c $u
Mit Mailerdefinitionen definiert man Mechanismen zum Transport von
Mail. Ein Mailer ist in Sendmail bereits eingebaut,
IPC zum Versand über SMTP. Oben werden die Mailer
local zum lokalen Zustellen von Mail und prog,
der Mail als Shellskript ausführt. Andere Mechanismen werden in
Form externer Programme realisiert, zum Beispiel für
UUCP.
# Mailer table (overriding domains) Kmailertable hash -o /etc/mail/mailertable
Datenbanken ordnen Schlüsseln Werte zu. Man kann neue Datenbanken definieren und zu nahezu beliebigen Veränderungen an Mailadressen benutzen. Wir werden später eine Datenbank definieren, die Benutzern ihre externen Mailadressen zuordnet.
S90 R$* < $- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
Rulesets sind kleine (funktionale) Programme, die auf Mailadressen angewendet werden. Man kann erstaunlich viel damit erreichen, komplexe Aufgaben erforden aber auch entsprechend unübersichtliche Rulesets. Eine typische Konfiguration enthält bereits über 500 Zeilen solcher Rulesets, die außerdem ziemlichen Spaghetticode bilden. Zum Zeitpunkt des Vortrags hatte ich Sendmail 8.8.8 im Einsatz, wo die Rulesets noch nummeriert sind. Mittlerweile tragen sie aber Namen, was der Lesbarkeit beträchtlich hilft.
Die einfachen Sachen sind leider die am wenigsten interessanten. Die Komplexität der Sendmail-Konfiguration liegt in den Rulesets. Rulesets bieten eine spezialisierte Programmiersprache, die auf vergleichweise einfache Weise erlaubt, Mailadressen umzuschreiben. Als Beispiel soll hier Ruleset 90 dienen, welches Adressen in der Mailertable nachschlägt.
Jede Regel in einem Ruleset besitzt eine linke und eine rechte Seite. Rulesets erhalten als Eingabe eine Email-Adresse. Sie wird in Token (Worte oder Sonderzeichen) zerlegt und mit der linken Regelseite gematcht. Bei einem Match wird die aktuelle Adresse durch die rechte Seite der Regel ersetzt und weitergemacht. Verschiedenste Zeichen haben besondere Bedeutung.
S90 R$* < $- . $+ > $* $: $1$2 < $(mtable .$3 $@ $1$2 $@ $2 $) > $4 R$* <$~[ : $+ > $* $>95 < $2 : $3 > $4 check -- resolved? R$* < . $+ > $* $@ $>90 $1 . <$2> $3 no -- strip & try again R$* < $* > $* $: < $(mtable . $@ $1$2 $) > $3 try "." R< $~[ : $+ > $* $>95 < $1 : $2 > $3 "." found? R< $* > $* $@ $2 no mailertable match
Die drei Spalten sind durch Tabulatoren getrennt, die dritte Spalte enthält einen Kommentar. Aud der linken Seite (dem Muster) bedeuten dabei
$* passen auf beliebig viele (auch Null)
Token.$- passen auf genau ein Token.$+ passen auf beliebig viele, jedoch
mindestens ein Token.Die Tokenfolgen, auf die die Spezialzeichen der linken Seite
paßten, werden $1, $2 usw. zugewiesen.
Man kann sie in der rechten Seite wieder einsetzen.
Auf der rechten Seite bedeuten
$(mtable . $@ $1$2 $) nach. Der erste Parameter ist der
Schlüssel, es folgt das Trennzeichen $@, dann weitere
Parameter, die hier nicht ausgewertet werden, dann wieder
$@ und schließlich ein Defaultwert. Wenn eine Adresse
der Form "< arthur . sax . sub . de > udo < @ arthur . sax
. sub . de >" an dieses Ruleset übergeben wird, so ist
$1 leer, $2 enthält "arthur",
$3 enthält "sax.sub.de". Im Endeffekt wird
also der Schlüssel ".sax.sub.de" in der Mailertable
nachgeschlagen.$: kann das für eine Regel verhindert werden, die
wird dann nur einmal angewendet.$@ eine abbrechende Regel
definieren.$>95 wird also gewissermaßen ein Unterprogramm
aufgerufen, $>90 ist ein rekursiver Aufruf. Letzteres
wird hier benutzt, um den Domainnamen zu kürzen und erneut die
Mailertable zu bemühen. So werden weitere Lookups für
".sub.de." und ".de." ausgeführt, falls
".sax.sub.de." keinen eigenen Eintrag besitzt.
Sendmail ruft die Rulesets nach dem rechts gezeigten Schema
auf. Es ist gar nicht zu übersch&aauml;tzen, was mit diesem System
alles möglich ist. Insbesondere kann man Sendmail damit die Syntax
praktisch jedes Mailers beibringen: RFC 822, UUCP, BitNet, DecNet... Wer
dabei alles außer RFC 822 für überflüssig
hält, möge sich mal den Aufwand vorstellen, alle denkbaren
RFC-Adressen mit einer "normalen" Programmiersprache wie C zu
parsen, mit allen Komplikationen: runde und spitze Klammern,
verschachtelte Klammern, Domainadressen und Bang-Adressen, in Usernamen
kodierte Subaccounts, etc.
Wie das Diagramm zeigt, durchlaufen alle Adressen zuerst Ruleset 3. Ruleset 3 ist reichlich komplex, es setzt alle denkbaren Adressen auf ein einheitliches, internes Format um. Das Ergebnis durchläuft Ruleset 0, dessen Ausgabe ein spezielles Format besitzt, welches den zu verwendenden Mailer und die nächste Station für die betrachtete Mail beschreibt.
Im nächsten Schritt werden Sender- und Empfängeradressen verschieden behandelt, nämlich zuerst von Rulesets 1 und 2, dann von je einem Ruleset, welches von gewählten Mailer abhängt. Hier ist auch der Ansatzpunkt, um Absenderadressen zu "fälschen". Abschließend wandern alle Adressen durch Ruleset 4, welches aus dem internen Format wieder eine ordentlich Adresse formt.
Wie gesagt: 500 Zeilen von diesem Zeug — das versteht kein Mensch. Auch mit dem Fledermausbuch nicht. Auch die Anleitung erklärt zwar alles, aber verstehen kann man es damit nicht.
Zum Glück hat das auch Allman eingesehen: Es gibt M4-Makros, die die meisten Konfigurationen einfacher generieren können. Leider nicht alle, und Pointsysteme ohne Namen gehören nicht dazu. Deswegen der Abstieg auf die unterste Ebene.