85.1.42. pepsi-sendmail¶
submit mail locally through the Sendmail interface
- Handbuchabschnitt:
1
85.1.42.1.1. Name¶
pepsi-sendmail - eine lokal verfasste Nachricht an Pepsi übergeben und dabei die traditionelle /usr/sbin/sendmail-Schnittstelle bereitstellen.
85.1.42.1.2. Übersicht¶
sendmail [-t] [-i] [-f SENDER] [-F NAME] [-v] [-N NOTIFY] [-R RET] [-V ENVID] [-c CONFIG] [RECIPIENT …]
mailq
newaliases
85.1.42.1.3. Beschreibung¶
pepsi-sendmail liest eine Nachricht von der Standardeingabe und liefert sie über einen lokalen UNIX-Domain-Socket bei pepsi-ingress ein. Es existiert, damit Software, die von einem MTA die Bereitstellung von /usr/sbin/sendmail erwartet — cron, mail(1), git send-email, logwatch, PHPs mail() —, Mail über Pepsi versenden kann, ohne umkonfiguriert zu werden.
Das Debian-Paket installiert es unter den Pfaden, die Debian Policy §11.6 von einem Mail Transport Agent verlangt, jeweils als Symlink auf das vereinheitlichte pepsi-Binärprogramm — außer /usr/lib/sendmail, das auf /usr/sbin/sendmail zeigt —, das anhand des Namens verzweigt, unter dem es aufgerufen wurde:
Pfad |
Verhält sich wie |
|---|---|
|
der hier beschriebene Submission-Client |
|
dasselbe (historischer Pfad) |
|
|
|
|
|
der Submission-Client (UUCP-Zustellung) |
Eine Quellinstallation beansprucht diese Pfade nicht, weil sie demjenigen MTA gehören, den das System bereits hat; übergeben Sie INSTALL_MTA_LINKS=yes an make install, um sie bewusst zu übernehmen.
85.1.42.1.4. Authentifizierung¶
pepsi-sendmail hält kein Privileg und behauptet keine Identität. Es ist weder setuid noch setgid, und es benötigt keinen Eintrag in MYNETWORKS.
Stattdessen liest pepsi-ingress die Benutzer-ID des sich verbindenden Prozesses vom Kernel (SO_PEERCRED, pro Listener mit AUTH_PEERCRED aktiviert), löst sie über die passwd-Datenbank zu einem Login auf und schlägt dieses Login in USERNAME_MAP genau so nach, wie es einen am Submission-Port eintreffenden SASL-Benutzernamen nachschlagen würde. Die Regeln aus RFC 6409 §6/§8.1 gelten dann unverändert: Ein lokales Programm darf nur einen Umschlagabsender und ein From: verwenden, auf die sein eigenes Konto abgebildet ist, und ein Konto, das auf keine Adresse abgebildet ist, wird rundweg abgewiesen.
Daraus folgen zwei Dinge:
Der Socket darf für alle beschreibbar sein. Ihn öffnen zu können, gewährt nichts, denn es entscheidet nicht darüber, als wer Sie senden können. Verweigern Sie einem Konto den Zugang, indem Sie es in
USERNAME_MAPauf keine Adresse abbilden, nicht durch Anpassen der Berechtigungen.Nichts im Netzwerk erhält irgendwelche Rechte. Das ist der wesentliche Unterschied dazu, dem Loopback-Interface in
MYNETWORKSzu vertrauen, was eine Netzwerkposition statt eines Benutzers authentifiziert: Bei jener Anordnung kann jeder lokale Prozess als beliebiger Absender senden, und eine Nachricht, die dieser Host an sich selbst weiterleitet, tritt erneut als frische lokale Submission ein, was in eine Schleife münden kann.
Weil Submissions authentifiziert sind, werden sie mit gesetztem state.local_origin gespeichert, sodass die Pipeline sie als eigene Mail dieses Hosts behandelt — sie mit der Domain des Autors DKIM-signiert und ihre Weiterleitung erlaubt.
85.1.42.1.5. Die Nachricht¶
Lokale Erzeuger schreiben Nachrichten so, wie eine Textdatei geschrieben wird, daher räumt der Client sie auf, bevor irgendetwas anderes sie zu sehen bekommt:
Jedes bloße LF wird zu CRLF. SMTP ist CRLF-gerahmt und
pepsi-ingresssetzt das durch (ein bloßes LF inDATAwird mit500 5.6.0 invalid line framingabgelehnt), das kann also nicht dem Server überlassen werden.Ein
From:-Feld wird vorangestellt, wenn die Nachricht keines hat, gebaut aus -F und dem Umschlagabsender; ein Anzeigename, der RFC-5322-Sonderzeichen enthält, wird in Anführungszeichen gesetzt.Jedes
Bcc:-Feld wird entfernt, ob -t verwendet wurde oder nicht — es stehen zu lassen würde die verdeckten Empfänger allen anderen auf dem Umschlag offenbaren.Ein Empfänger ohne
@— dasTo: rootvoncron— wird mit[pepsi-sendmail] DEFAULT_DOMAINvervollständigt, bevor Duplikate (ohne Rücksicht auf Groß-/Kleinschreibung) entfernt werden, sodass dieselbe zweimal angegebene Adresse einmal eingeliefert wird.
Die Transaktion selbst ist das Minimum, das ein Socket auf demselben Host braucht: die Begrüßung lesen, EHLO, MAIL FROM (mit BODY=8BITMIME, wenn die Nachricht 8-Bit-Bytes enthält und der Server 8BITMIME angekündigt hat, und mit den -R/-V-Parametern nur, wenn er DSN angekündigt hat), ein RCPT TO je Empfänger (das -N unter derselben Bedingung mitführt), DATA mit angewandtem Dot-Stuffing nach RFC 5321 §4.5.2 und ein QUIT nach bestem Bemühen — ein misslungener Abschied kann eine angenommene Nachricht nicht in einen Fehler verwandeln. Kein STARTTLS, kein SASL und kein MTA-STS: Die Gegenstelle ist ein Dateisystem-Socket auf diesem Host, der Transport kann nicht beobachtet werden, und die Authentifizierung ist Sache des Kernels.
85.1.42.1.6. Optionen¶
- -t
Liest die Empfänger aus den
To:-,Cc:- undBcc:-Headern der Nachricht. Sie werden zu allen auf der Kommandozeile angegebenen Empfängern hinzugefügt (wie bei Postfix), und eine bereits auf der Kommandozeile stehende Adresse wird nicht wiederholt.Bcc:-Header werden so oder so aus der Nachricht entfernt, mit oder ohne -t.- -f SENDER, -r SENDER
Setzt den Umschlagabsender. Unterliegt
USERNAME_MAP: Der Server weist einen Absender zurück, zu dem das aufrufende Konto nicht berechtigt ist. Weggelassen, wird das Login des aufrufenden Kontos verwendet, qualifiziert mit[pepsi-sendmail] DEFAULT_DOMAIN(und das wörtlichenobody@dieser Domain, wenn das Login nicht aufgelöst werden kann). Es ist ein Standardwert aus Höflichkeit und keine Behauptung: Der Server leitet die Identität ohnehin aus den Peer-Zugangsdaten neu ab.- -F NAME
Anzeigename für einen
From:-Header, der erzeugt wird, wenn die Nachricht keinen hat.- -i, -oi
Eine Zeile, die nur einen Punkt enthält, nicht als Ende der Eingabe behandeln. Aus Kompatibilitätsgründen akzeptiert; die Eingabe wird immer bis zum Dateiende gelesen.
- -v
Gibt den SMTP-Dialog auf der Standardfehlerausgabe aus und stellt die gewöhnliche Pepsi-Log-Ausgabe wieder her. Ohne ihn protokolliert das Programm nur Warnungen und Fehler: Ein
sendmail-Binärprogramm läuft auscronund aus Skripten heraus, die die Standardfehlerausgabe einfangen und per Mail zurückschicken, sodass das übliche informative Geplauder jede erfolgreiche Nachricht in eine zweite Nachricht verwandeln würde.- -c CONFIG, –config CONFIG
Liest die Pepsi-Konfiguration aus CONFIG statt vom üblichen Ort (siehe pepsi.conf(5)). Eine Pepsi-Erweiterung, nicht Teil der
sendmail-Grammatik; der Wert darf angehängt (-c/etc/pepsi/pepsi.conf) oder getrennt stehen.Gefahrlos zu beachten, obwohl dies die lokale Submission-Schnittstelle ist, denn das Programm hält keinerlei Privileg: Es auf eine andere Konfiguration zu richten ändert nur, mit welchem Socket es sich verbindet, und der Server leitet die Identität des Absenders weiterhin über
SO_PEERCREDaus der uid des Aufrufers ab. Es wird-cgeschrieben und nicht wie in sendmail-C, weil-Cbereits eine alternativesendmail.cfbezeichnet, was etwas anderes ist und abgelehnt wird (siehe unten).- -N NOTIFY, -R RET, -V ENVID
Parameter für Zustellungsstatusbenachrichtigungen nach RFC 3461, die an den Server übergeben werden, wenn er die
DSN-Erweiterung ankündigt. Siehe pepsi-stage-bounce(1).NOTIFY ist
NEVERoder eine kommagetrennte Liste ausSUCCESS,FAILUREundDELAY(RFC 3461 §4.1); RET istFULLoderHDRS(§4.3). Alles andere ist ein Benutzungsfehler und kein501vom Server. ENVID wird auf dem Drahtxtext-kodiert (§4.4) und auf die 100 Zeichen gekürzt, die die Grammatik erlaubt.
Ein Wert für -f, -F, -N, -R oder -V — oder ein Empfänger —, der ein Steuerzeichen enthält, wird mit EX_USAGE abgelehnt. Diese Werte werden in SMTP-Befehlszeilen und in ein erzeugtes From:-Feld eingesetzt, und SMTP-Befehle sind durch CRLF getrennt (RFC 5321 §4.1.1), sodass ein Wagenrücklauf oder Zeilenvorschub darin einen zusätzlichen Befehl — einen Empfänger, den der Aufrufer nie angegeben hat — oder ein zusätzliches Header-Feld einschleusen würde. Das wiegt am schwersten bei einem Aufrufer, der Benutzereingaben direkt durchreicht, etwa einer Webanwendung, die -f verwendet.
- -bm
Liest eine Nachricht und liefert sie ein. Der Standardwert.
- -bp
Gibt die Warteschlange aus. Pepsis Warteschlange liegt in der Datenbank statt in einem Spool-Verzeichnis, und sie zu lesen erfordert eine Rolle, die ein gewöhnlicher Benutzer nicht hält; daher gibt dies einen Hinweis auf der Standardfehlerausgabe aus und endet mit
70; verwenden Sie pepsi-queue(1) für die Warteschlange selbst und pepsi-status(1) für eine Zusammenfassung. Hinweis für die Überwachung:mailq„scheitert“ auf einer gesunden Pepsi-Installation daher immer.- -bi
Baut die Alias-Datenbank neu auf. Pepsis Alias-Map ist eine einfache Textdatei, die pepsi-stage-aliases(1) immer dann neu liest, wenn sich ihre Änderungszeit ändert, also gibt es nichts neu aufzubauen, und dies beendet sich erfolgreich, ohne etwas zu tun — noch bevor überhaupt nach der Konfigurationsdatei gesucht wird, denn Betreuerskripte von Paketen führen
newaliasesbedingungslos aus, und es darf auf einem Host nicht fehlschlagen, dessen Konfiguration unlesbar oder noch nicht geschrieben ist.- -I
Synonym für -bi: eine erfolgreiche Nulloperation, wie es auch newaliases ist.
- -h N, -L TAG, -X FILE, -B TYPE, -p PROTOCOL, -O NAME=VALUE
Werden angenommen und ignoriert, so wie Postfix‘
sendmail(1) sie annimmt. Sie beschreiben Hop-Zähler, Logging und Entscheidungen zur Einplanung der Zustellung, die die Pipeline für sich selbst trifft; jede verbraucht ihren Wert, ob angehängt oder getrennt, sodass der Wert nicht für einen Empfänger gehalten wird. Nur Flags zur Warteschlangenverwaltung und Daemon-Flags werden abgelehnt, weil sie falsch darstellen würden, was das Programm tut.- -m, -U, -n, -s, -G, -Ac, -Am, -oX, -d…
Werden angenommen und ignoriert und nehmen keinen eigenen Wert.
-oX ist die Optionsschreibweise im alten Stil, diecronweiterhin ausgibt (-odi,-oem), und-dist sendmails Debug-Flag, dessen Stufe daran angehängt ist.- -bs, -bv
Vom Parser angenommen, aber nicht unterstützt: Jedes gibt auf der Standardfehlerausgabe aus, warum, und endet mit
70.-bs(SMTP auf der Standardeingabe sprechen) hat hier keinen Zweck — verbinden Sie sich direkt mit dem Submission-Socket.-bv(Adressverifikation) lässt sich ohne die Routing-Tabellen nicht beantworten, und eine Antwort zu erfinden wäre schlimmer als abzulehnen.- -bd, -bD, -q…
Wird beim Parsen abgelehnt. Pepsis lauschender Server ist pepsi-ingress(1), und seine Warteschlange wird fortlaufend von pepsi-dispatch(1) geleert; diese stillschweigend anzunehmen würde einen Daemon oder einen Warteschlangenlauf suggerieren, den es nicht gibt.
-C wird abgelehnt, statt wie -c behandelt zu werden: In der sendmail-Grammatik benennt es eine alternative sendmail.cf, die hier kein Gegenstück hat, und eine Pepsi-Konfiguration stillschweigend aus einem Pfad zu lesen, der für etwas anderes gedacht ist, wäre schlimmer als abzulehnen. Die Pepsi-Schreibweise ist -c/--config, oben dokumentiert; ohne beides wird die Konfigurationsdatei auf dem üblichen Weg gefunden (siehe pepsi.conf(5)).
85.1.42.1.7. Konfiguration¶
[pepsi-sendmail]
- SOCKET
Pfad des UNIX-Domain-Submission-Sockets von
pepsi-ingress. Standardwert/run/pepsi/submission.sock. pepsi-ingress liest dieselbe Option, um zu entscheiden, was es bedient, sodass die beiden Enden nicht auf verschiedene Pfade gerichtet werden können und kein Listener-Abschnitt nötig ist.Der Sonderwert
noneschaltet die lokale Submission vollständig ab: Der Server bindet keinen Socket, und dieses Programm verweigert die Ausführung.- EHLO_NAME
Der in
EHLOangekündigte Name. Standardwert ist[pepsi-ingress] HOSTNAME, oderlocalhost, wenn dieser nicht gesetzt ist. Kosmetisch: Der Server authentifiziert die Gegenstelle anhand ihrer Zugangsdaten, nicht anhand dieses Namens.- DEFAULT_DOMAIN
Domain, die an eine nackte, unqualifizierte Adresse angehängt wird — das
root, das cron und Systemwerkzeuge ohne@ansendmailübergeben. Standardwert ist[pepsi-ingress] HOSTNAME, oderlocalhost, falls das nicht gesetzt ist.Sie ist auch die Domain des voreingestellten Umschlagabsenders, wenn -f weggelassen wird (
<login>@<DEFAULT_DOMAIN>) — der Rückfall, den die eigene Einlieferungs-Identitätsabbildung des Servers auf einen Benutzernamen anwendet, für den sie keinen Eintrag hat, sodass die beiden ohneUSERNAME_MAPschon von der Konstruktion her übereinstimmen. Das ist immer noch nur, wie die Nachricht adressiert wird: Von wem sie sein darf, ergibt sich aus der uid der Gegenstelle überSO_PEERCREDund dieUSERNAME_MAP, und diese Option zu setzen kann das nicht ausweiten.
Die zugehörige Serverseite braucht überhaupt keine Konfiguration. pepsi-ingress bedient diesen Socket bedingungslos und liest genau dieselbe SOCKET-Option, um zu entscheiden, was es bindet — sodass Client und Server nicht auf verschiedene Pfade gerichtet werden können und es keinen Listener-Abschnitt zu schreiben, im Gleichschritt zu halten oder zu vergessen gibt. Der von ihm synthetisierte Listener liegt fest, denn nichts daran ist eine Wahl: MODE = plain, SUBMISSION = yes (sodass die RFC-6409-Header-Korrekturen greifen) und AUTH_PEERCRED = yes, auf einem Socket mit Modus 0666.
Ein optionaler [pepsi-ingress-listener-*]-Abschnitt würde die Einrichtung stattdessen davon abhängig machen, dass drei verschiedene Dinge übereinstimmen — dass der Abschnitt existiert, dass sein UNIXPATH zu SOCKET passt und dass das Laufzeitverzeichnis für den Server beschreibbar ist —, jedes einzelne leicht falsch zu machen und jedes Mal mit demselben Symptom: Cron-Mail hört stillschweigend auf. Von einem Host, auf dem ein MTA läuft, wird erwartet, dass er /usr/sbin/sendmail bereitstellt.
Unter systemd wird der Deskriptor geerbt statt gebunden, wenn das ausgelieferte pepsi-ingress.socket bereits ein ListenStream= für denselben Pfad trägt. Dabei geht es nicht um Privilegien — dies ist kein privilegierter Port —, sondern um das Verzeichnis. /run/pepsi wird mit pepsi-httpd und der Setup-Apply-Türklingel geteilt, und systemd gibt ein RuntimeDirectory= dem User= der deklarierenden Unit und ändert bei jedem Start dessen Eigentümer; ein unprivilegiertes pepsi-ingress, das dort seinen eigenen Socket anlegt, scheitert, sobald eine andere dieser Units neu startet. Von der .socket-Unit gebunden, wird der Knoten von systemd als root angelegt, bevor der Dienst startet, sodass der Server überhaupt keinen Schreibzugriff auf das Verzeichnis braucht — und der Socket bleibt verfügbar, während der Dienst neu startet, sodass ein gleichzeitiges /usr/sbin/sendmail wartet, statt zu scheitern.
Der Deskriptor wird über die Adresse, an die er gebunden ist, zugeordnet, nicht über einen FD_INDEX. Ein Index ist eine Position unter den ListenStream=-Einträgen der Unit, ändert sich also, sobald ein Port hinzukommt oder wegfällt — eine zweite Deklaration, die mit einer Datei im Gleichschritt zu halten wäre, die sie nicht sehen kann. Den Kernel zu fragen, woran jeder übergebene Deskriptor gebunden ist, hat diesen Fehlermodus nicht: Einen SMTP-Port hinzuzufügen oder zu entfernen nummeriert nichts um, ein nur ausgehender Host, der Port 25 weglässt, braucht keine Änderung, und die Unit und die Konfiguration können sich nicht darüber uneins sein, welcher Socket dies ist. Passt kein übergebener Deskriptor — kein systemd, oder ein SOCKET, das die Unit nicht bindet —, bindet pepsi-ingress den Pfad selbst.
Wenn Sie SOCKET ändern, ändern Sie das ListenStream= der Unit entsprechend oder entfernen Sie es: Ein Eintrag, auf dem nichts annimmt, ist schlimmer als keiner, denn der Aufrufer verbindet sich und blockiert dann, bis sein eigener Lese-Timeout abläuft (zwei Minuten, dann EX_TEMPFAIL), statt sofort abgewiesen zu werden. pepsi-ingress schreibt beim Start eine Warnung ins Journal, die jeden übergebenen Deskriptor nennt, den kein Listener beansprucht hat.
Das Binden des Sockets zu verfehlen ist fatal: pepsi-ingress verweigert den Start, statt hochzukommen und nur einen Teil dessen zu bedienen, worum es gebeten wurde. Ein Server, der mit stillschweigend fehlender lokaler Submission läuft, ist genau der Fehler, den diese Anordnung verhindern soll, und er ist unsichtbar, bis Mail verloren geht.
Einen eigenen Listener-Abschnitt für denselben Pfad zu schreiben wird unterstützt und ist der Weg, dem Socket andere Optionen zu geben — eine Gruppe, einen strengeren Modus, keine Peer-Zugangsdaten. Ein Abschnitt, der diesen Pfad bedient, ersetzt den eingebauten Listener, statt mit ihm zu kollidieren.
85.1.42.1.8. Abschalten¶
SOCKET = none deaktiviert die lokale Submission vollständig: pepsi-ingress bedient keinen Socket, und pepsi-sendmail verweigert die Ausführung (Exit EX_SOFTWARE, bevor es die Nachricht liest — eine dauerhafte Fehlkonfiguration, die cron also nicht wiederholen darf). Programme auf dem Host müssen sich dann wie jeder andere Client auf 587 oder 465 authentifizieren. pepsi-setup meldet dies einmal, denn ein Mailserver ohne lokalen Submission-Weg ist ungewöhnlich genug, dass ein Operator, der das nicht beabsichtigt hat, davon erfahren sollte.
85.1.42.1.9. Exit-Status¶
Die traditionellen sysexits.h-Werte, auf die cron und andere Aufrufer reagieren:
0 |
die Nachricht wurde angenommen |
64 |
Benutzungsfehler ( |
65 |
die Nachricht war unbrauchbar, z. B. fand |
66 |
die Nachricht konnte nicht von der Standardeingabe gelesen werden |
67 |
ein Empfänger wurde als unbekannt zurückgewiesen — ein RFC-3463-Status |
69 |
jede andere dauerhafte Zurückweisung durch den Server ( |
70 |
interner Fehler, z. B. konnte die Konfiguration nicht geparst werden, oder |
75 |
vorübergehender Fehler — der Socket war nicht erreichbar, ein Befehl lief in eine Zeitüberschreitung, der Server hat die Verbindung geschlossen oder fehlerhaftes SMTP geantwortet, oder er hat mit einem |
77 |
der Server hat aus Richtliniengründen abgelehnt — ein RFC-3463-Status |
Eine dauerhafte Zurückweisung wird anhand des erweiterten Statuscodes am Anfang der Antwort des Servers klassifiziert, nie durch Durchsuchen ihrer Prosa, sodass 550 5.1.1 unknown user (see the 5.7.1 policy page) als unbekannter Empfänger gemeldet wird und nicht als Ablehnung aus Richtliniengründen.
85.1.42.1.10. Dateien¶
/run/pepsi/submission.sockDer Einlieferungs-Socket, sofern nicht
[pepsi-sendmail] SOCKETeinen anderen Pfad benennt. Beide Enden lesen diese eine Option, sodass der Client undpepsi-ingresssich nicht darüber uneinig sein können, wo er liegt.
Wenn -c/–config nicht angegeben ist, ist die Konfiguration die erste existierende Datei aus der folgenden Liste — dieselbe Liste, die jede Pepsi-Komponente durchsucht:
$XDG_CONFIG_HOME/pepsi.conf$HOME/.config/pepsi.conf/etc/pepsi/pepsi.conf/etc/pepsi.conf
85.1.42.1.11. Beispiele¶
Eine Nachricht versenden und die Empfänger aus ihren Headern nehmen:
printf 'To: ops@example.org\nSubject: nightly\n\nall good\n' | sendmail -t
Den Dialog beobachten, während eine Ablehnung diagnostiziert wird:
sendmail -v -f alice@example.org bob@example.net < message.eml
85.1.42.1.12. Siehe auch¶
pepsi-ingress(1), pepsi-queue(1), pepsi-status(1), pepsi-stage-aliases(1), pepsi.conf(5)