85.1.55. pepsi-helper-maildir-writer¶
drop a message into a local user’s Maildir/new/ as root
- Handbuchabschnitt:
1
85.1.55.1.1. Name¶
pepsi-helper-maildir-writer - privilegierter Helper für die lokale Zustellung, der eine einzelne Nachricht von der Standardeingabe in das Maildir/new/ eines Zielbenutzers schreibt.
85.1.55.1.2. Übersicht¶
pepsi-helper-maildir-writer [OPTIONS] TARGET-UID < message
pepsi-helper-maildir-writer measure [OPTIONS] TARGET-UID
85.1.55.1.3. Beschreibung¶
pepsi-helper-maildir-writer ist ein minimaler, sicherheitsgehärteter Helper, der genau eine Nachricht in das Maildir eines lokalen Benutzers zustellt. Er existiert, damit ein vertrauenswürdiger, aber unprivilegierter Aufrufer (ein Mitglied der pepsi-maildir-Gruppe) Mail in das Postfach jedes lokalen Benutzers ablegen kann — und nichts anderes.
Der Helper wird setuid-root installiert, im Besitz von root:pepsi-maildir mit Modus 4750 (rwxr-x--- plus dem setuid-Bit). Folglich dürfen nur Mitglieder der pepsi-maildir-Gruppe ihn ausführen; wenn sie es tun, führt der Kernel ihn mit einer effektiven uid von root aus.
Gegeben die numerische uid des Zielbenutzers und die rohe Nachricht auf der Standardeingabe, tut der Helper Folgendes:
löst den passwd-Eintrag des Zielbenutzers auf (sein Home-Verzeichnis und seine primäre Gruppe) und verweigert uid
0sowie jede uid unterhalb von/etc/login.defsUID_MIN(Standardwert1000, falls nicht lesbar) — Systemkonten sind nie gültige Zustellziele;legt Privilegien vollständig und unwiderruflich von
rootauf den Zielbenutzer ab — reale, effektive und gespeicherte uid und gid — indem es zuerst alle ergänzenden Gruppen, dann die gid, dann die uid ablegt, und stellt sicher, dass root nicht wiedererlangt werden kann. Alles danach handelt mit der Identität des Zielbenutzers, sodass jede von ihm erstellte Datei diesem Benutzer gehört;erstellt das Standard-Maildir-Layout (
tmp,newundcur, Modus0700) unter~/Maildir, falls es nicht bereits existiert;erstellt eine eindeutig benannte Datei in
Maildir/tmp/mitO_CREAT|O_EXCL(sodass er ausschließliche Kontrolle über die Datei hat und nie die Datei einer anderen Zustellung stört), Modus0600, gemäß der Maildir-Namenskonvention<seconds>.M<microseconds>P<pid>Q<sequence>.<hostname>;kopiert die Nachricht von der Standardeingabe in diese Datei, mit
splice(2), wenn die Deskriptoren es erlauben (der häufige Fall, wenn stdin eine Pipe ist), und andernfalls einer einfachen Lese-/Schreibschleife, und zählt dabei die durchlaufenden Bytes;fsync(2)t die Datei und entscheidet — wenn eine Quota durchgesetzt wird und--measureangegeben war —, ob das Postfach Platz dafür hat, und bricht die Zustellung mit Exit-Status 3 ab, wenn nicht; undbenennt sie nach
Maildir/new/um, unter einem Namen, der das Maildir++-Kennzeichen,S=size trägt,fsync(2)t dieses Verzeichnis und meldet auf der Standardausgabe, was das Postfach nun enthält.
Der Helper liest keine Konfiguration, öffnet keine Netzwerkverbindung und kontaktiert keine Datenbank. Die Quota-Richtlinie wird vom Aufrufer entschieden und als Argumente übergeben, denn zu dem Zeitpunkt, zu dem der Helper etwas lesen könnte, ist er der Zielbenutzer, der seine eigene Quota nicht wählen darf.
85.1.55.1.4. Postfach-Quota¶
Der Helper ist der einzige Teil von Pepsi, der sehen kann, wie voll ein Postfach ist: Ein Maildir hat den Modus 0700, und dies ist der eine Prozess, der zum Benutzer wird. Alles andere — die Entscheidungen der Zustell-Stage, die Ablehnung von pepsi-ingress(1) bei RCPT, der Bericht von pepsi-status(1) — arbeitet mit Zahlen, die dieser Helper gemeldet hat.
Er misst nur, wenn er darum gebeten wird (--measure). Der Aufrufer führt eine laufende Schätzung in pepsi.mailbox_quota und bittet um eine Messung, wenn diese Schätzung nahelegt, dass das Konto nahe an seiner Grenze sein könnte; da die Schätzung nur zu hoch zählen kann (nichts sagt ihr, wenn ein Benutzer Mail über IMAP löscht), ist „keine Messung nötig“ ein Beweis, dass Platz ist. Eine gewöhnliche Zustellung in ein Postfach, das weit davon entfernt ist, voll zu sein, kostet daher ein kleines Anhängen und keinen Verzeichnisdurchlauf.
Drei Abrechnungsschichten werden zusammen verwendet, die billigste zuerst:
maildirsizeDie Maildir++-Größendatei im Wurzelverzeichnis des Postfachs, im Format von Courier (eine Quota-Definitionszeile, danach angehängte
<bytes> <messages>-Deltas). Dovecotsquota = maildir:-Backend, Courier und Eximsmaildir_use_size_filelesen und schreiben alle dieselbe Datei, sodass ein Standort, der eines davon für IMAP und Pepsi für die Zustellung betreibt, einen Satz Zahlen führt. Aus diesem Grund wird ein vorhandenesmaildirsizevon jeder Zustellung aktuell gehalten, auch wenn Pepsi selbst keine Quota durchsetzt — sonst würde der Zähler des anderen Agenten stillschweigend alles zu niedrig ausweisen, was Pepsi zustellt. Ohne geltende Quota wird eines nie erzeugt, wo keines existiert. Es wird verwendet, wenn es aktuell ist, und aus einem vollständigen Durchlauf neu geschrieben, wenn es fehlt, sich nicht parsen lässt, gegen andere Grenzen berechnet wurde oder ein langes Delta-Journal angesammelt hat.Das Neuschreiben geschieht, anders als das angehängte Delta, nur solange eine Grenze in Kraft ist —
[pepsi] MAILBOX_QUOTA,MAILBOX_QUOTA_COUNToder einpepsi.mailbox_quota-Datensatz für das Konto —, weil es die Quota-Definitionszeile am Kopf der Datei ersetzt, die ein anderer Agent zu schreiben hat, wenn Pepsi nichts durchsetzt. Sie liegt im eigenen Verzeichnis des Benutzers und ist daher nur beratend: Ein Benutzer kann sein eigenesmaildirsizeneu schreiben.- Ein vollständiger Baumdurchlauf
new/undcur/der INBOX und jedes Maildir++-Ordners (.Sent,.Trash, …) — der ganze Baum, den der Benutzer „mein Postfach“ nennt.tmp/wird nicht mitgezählt (eine Datei dort ist eine Zustellung in Bearbeitung). Der Durchlauf ist einreaddir(3) je Ordner und keinestat(2)-Aufrufe, weil Maildir++ die Größe jeder Nachricht in ihrem Dateinamen kodiert (,S=n) — genau deshalb kennzeichnet dieser Helper die von ihm geschriebenen Dateien. Eine von einem anderen Agenten ungekennzeichnet gelassene Nachricht wird einzelnstatet.quotactl(2)Mit
--fs-quotawird zusätzlich die Abrechnung des Kernels herangezogen. Das ist die einzige manipulationssichere Schicht, und ihre Grenze verschärft die wirksame: Platz zu versprechen, denEDQUOTverweigern würde, hilft niemandem. Es funktioniert unprivilegiert, weilQ_GETQUOTAeinem Aufrufer erlaubt ist, der nach seiner eigenen uid fragt, und zu diesem Zeitpunkt ist der Helper unwiderruflich dieser Benutzer geworden. Beachten Sie, dass der Kernel jeden Block zählt, der dem Benutzer auf diesem Dateisystem gehört, nicht nur seine Mail, sodass seine Zahlen getrennt gemeldet werden, statt die Postfachmessung zu ersetzen. Ein Dateisystem, das nicht antwortet (XFS-Projekt-Quotas, ZFS, keine Quota-Unterstützung), liefert schlicht nichts, und die anderen Schichten gelten weiterhin.
Da die Größe der Nachricht unbekannt ist, bis die Standardeingabe geleert wurde, wird die Nachricht in tmp/ gepuffert (was nicht auf die Quota zählt), bevor die Entscheidung fällt, und wieder entfernt, wenn sie nicht hineinpasst. Die Standardeingabe wird in jedem Fall geleert: Ein Helper, der vorzeitig endete, ließe seinen Aufrufer in eine kaputte Pipe schreiben, was als Transportfehler gemeldet würde statt als die saubere Ablehnung, die es ist.
Zwei gleichzeitig laufende Zustellungen können beide Platz sehen und beide schreiben und die Grenze so um bis zu je eine Nachricht überschreiten. Jede Implementierung der Maildir++-Quota nimmt das hin; die Kernel-Quota-Schicht schließt diese Lücke dort, wo ein Standort sie hat, genau.
85.1.55.1.5. Argumente¶
- TARGET-UID
Die numerische Benutzer-ID des lokalen Benutzers, in dessen
Maildir/new/die Nachricht zugestellt wird. Sie muss eine positive Ganzzahl mit einem passenden passwd-Eintrag sein; uid0(root) sowie jede uid unterhalb von/etc/login.defsUID_MINwerden verweigert.measureVermisst das Postfach und meldet das Ergebnis, ohne etwas zuzustellen. Die Standardeingabe wird nicht gelesen. Wird von
measureundreconcilevon pepsi-quota(1) verwendet.--measureErmittelt vor dem Schreiben die tatsächliche Größe des Postfachs und setzt die durch
--quota-bytes/--quota-countgegebene Quota dagegen durch. Ohne dieses Flag stellt der Helper bedingungslos zu und meldet nur, was er hinzugefügt hat.--fs-quotaZieht zusätzlich
quotactl(2) heran, meldet die Zahlen des Kernels und lässt die Grenze des Kernels die wirksame verschärfen. Wird von der Zustell-Stage aus[pepsi] MAILBOX_FS_QUOTAgesetzt, wonach pepsi-setup(1) sucht.--quota-bytesNDie durchzusetzende Byte-Grenze.
0oder fehlend bedeutet keine Grenze.--quota-countNDie durchzusetzende Nachrichtengrenze.
0oder fehlend bedeutet keine Grenze.
Die zuzustellende Nachricht wird vollständig von der Standardeingabe gelesen.
85.1.55.1.6. Ausgabe¶
Auf der Standardausgabe schreibt der Helper je Zeile einen gekennzeichneten, tabulatorgetrennten Datensatz. Ein unbekanntes Kennzeichen wird vom Aufrufer ignoriert statt als Fehler behandelt, sodass ein neuerer Helper einem älteren Aufrufer mehr melden kann.
uTABbytesTABmessagesGemessene Belegung des gesamten Maildir++-Baums, einschließlich der soeben zugestellten Nachricht. Der Aufrufer speichert dies als Belegung des Kontos und setzt seine Seit-der-Messung-Zähler zurück.
fTABusedTABlimitTABinodesTABinode-limitDie
quotactl(2)-Zahlen, mit0, wo der Kernel keine Grenze durchsetzt.dTABbytesBytes, die dieser Lauf hinzugefügt hat, gemeldet anstelle von
u, wenn keine Messung vorgenommen wurde, sodass der Aufrufer zu seiner Schätzung addiert, statt sie zu ersetzen.sTAB(fsquota|maildirsize|scan)Wie die
u-Zahl ermittelt wurde.wTABtextEin nicht fataler Fehler (ein nicht lesbarer Ordner, ein
maildirsize, das nicht aktualisiert werden konnte). Nie fatal für die Zustellung.
Ein Bericht wird auch dann geschrieben, wenn die Zustellung mangels Platz abgelehnt wurde — gerade dann, denn eine frische Messung ist es, die pepsi-ingress(1) erlaubt, die nächste Nachricht in der SMTP-Sitzung abzulehnen, statt sie anzunehmen, nur um sie zu bouncen.
85.1.55.1.7. Installation¶
Das Binärprogramm muss setuid-root und gruppenbeschränkt installiert sein:
chown root:pepsi-maildir pepsi-helper-maildir-writer
chmod 4750 pepsi-helper-maildir-writer
make install tut dies automatisch (sein install-helper-Schritt), sofern es als root ausgeführt wird und die pepsi-maildir-Gruppe existiert; andernfalls gibt es die genauen, von Hand auszuführenden Befehle aus. Wird der Helper auf einem mit nosuid eingehängten Dateisystem abgelegt, wird das setuid-Bit zur Laufzeit ignoriert und der Helper verweigert die Ausführung (er kann root nicht erlangen); installieren Sie ihn daher auf einem normalen Dateisystem.
85.1.55.1.8. Exit-Status¶
Der Exit-Code sagt der aufrufenden Stage, ob eine Wiederholung überhaupt helfen kann, sodass eine Nachricht weder gebounct wird, während sie noch zugestellt werden könnte, noch tagelang für ein Postfach eingereiht bleibt, das sie nie annehmen wird. Eine Diagnose wird immer auf die Standardfehlerausgabe geschrieben, und pepsi-stage-relay-to-maildir(1) protokolliert sie und nimmt sie in den von ihm erzeugten Bounce auf.
- 0
Die Nachricht wurde in das
Maildir/new/des Zielbenutzers geschrieben und auf die Festplatte synchronisiert.- 1
Vorübergehender Fehler: Ein späterer Versuch kann gelingen, daher behält der Aufrufer die Nachricht in der Warteschlange und versucht es mit Back-off erneut. Das deckt eine volle Platte (
ENOSPC), einen E/A-Fehler, ein schreibgeschütztes Dateisystem und einen Helfer ab, der (noch) nicht setuid-root installiert ist — alles Dinge, die ein Administrator unter einer wartenden Nachricht reparieren kann. Es deckt außerdem jeden Fehler ab, bevor das Postfach berührt wird, welcheserrnoer auch trägt: eine passwd-Abfrage, die fehlschlägt oder keinen Eintrag für die uid findet (ein Verzeichnis-Backend, das nur zeitweise antwortet, da die Stage die uid einen Moment zuvor aufgelöst hat), und einen Wechsel zum Benutzer (setgroups,setgid,setuid), den der Kernel verweigert. Diese melden ebenfallsEPERModerENOENT, und bei ihnen zu bouncen hieße, jeden lokalen Empfänger wegen eines Host-Fehlers zu bouncen.- 2
Permanenter Fehler: Das Postfach ist unbrauchbar, und keine Wiederholung wird daran etwas ändern, bis ein Administrator das Konto repariert; daher bounct der Aufrufer die Nachricht sofort. Das deckt ein
Maildirab, das kein Verzeichnis ist (eine alte mbox-Datei), einen Eigentümer oder einen Modus, der den Benutzer aus seinem eigenenMaildiraussperrt (EACCES/EPERM), ein fehlendes Home-Verzeichnis (ENOENT), ein nicht absolutes Home-Verzeichnis und eine uid unterhalb vonUID_MIN. Dieerrno-Werte zählen nur für Operationen am Postfach selbst, nach dem Wechsel zum Benutzer.- 3
Das Postfach ist über der Quota, die Nachricht wurde also nicht geschrieben. Bewusst weder transient noch permanent: Ob es sich lohnt, auf ein volles Postfach zu warten, ist Standortrichtlinie (
[pepsi] MAILBOX_OVER_QUOTA), und der Helper ist nicht in der Lage zu wissen, ob dieser Benutzer sein Postfach täglich leert oder es vor einem Jahr aufgegeben hat. Er meldet die Tatsache; pepsi-stage-relay-to-maildir(1) wendet die Richtlinie an.EDQUOTvom Kernel wird genauso gemeldet — eine volle Platte ist das Problem des Administrators und wird unter einer eingereihten Nachricht behoben, während ein volles Postfach das des Empfängers ist und es vielleicht nie wird.
Wenn es von einem Benutzer aufgerufen wird, der kein Mitglied der pepsi-maildir-Gruppe ist, weigert sich der Kernel, das Binärprogramm überhaupt auszuführen (Permission denied); der Helper selbst läuft nie.
85.1.55.1.9. Sicherheit¶
Der Helper vertraut darauf, dass sein Aufrufer autorisiert ist (die Mitgliedschaft in der pepsi-maildir-Gruppe ist die Zugriffskontroll-Schranke), und stellt an jeden regulären lokalen Benutzer zu (uid ≥ UID_MIN, nie ein Systemkonto). Er legt die ergänzenden Gruppen ab, bevor er die uid ändert, und wirft dann root vollständig ab (reale, effektive und gespeicherte IDs), stellt sicher, dass root nicht wiedererlangt werden kann, bevor er irgendeine Datei-E/A durchführt, und erstellt die Zustelldatei exklusiv, sodass er nie dazu verleitet werden kann, über eine Datei zu schreiben, die ihm nicht gehört.
85.1.55.1.10. Siehe auch¶
pepsi-stage-relay-to-maildir(1), pepsi-ingress(1), pepsi-dispatch(1), pepsi.conf(5), maildir(5)
85.1.55.1.11. Fehler¶
Melden Sie Fehler an den Pepsi-Issue-Tracker.