85.1.13. pepsi-stage-dot-forward

process per-user ~/.forward files

Section du manuel:

1

85.1.13.1.1. Nom

pepsi-stage-dot-forward - l’étape de traitement de ~/.forward du pipeline Pepsi.

85.1.13.1.2. Synopsis

pepsi-stage-dot-forward [GLOBAL-OPTIONS] worker

85.1.13.1.3. Description

pepsi-stage-dot-forward est un programme d’étape exécuté par pepsi-dispatch(1). Pour chaque destinataire d’enveloppe qui se résout en un compte local, il exécute le fichier ~/.forward de cet utilisateur — le mécanisme sendmail/Postfix classique par lequel un titulaire de compte redirige son propre courrier. La localité est décidée exactement comme dans pepsi-stage-relay-to-maildir(1) : le domaine du destinataire doit être dans LOCAL_DOMAINS, son nom de boîte aux lettres (local-part, sous-adresse après RECIPIENT_DELIMITER retirée, mise en minuscules) doit se résoudre en une entrée passwd, et cet uid doit être permis par TARGETS. Un destinataire qui n’est pas local est laissé intact et avance vers NEXT_STAGE. Une consultation passwd qui échoue (un backend LDAP ou sssd en panne) n’est pas interprétée comme « non local » : le message est réessayé, plutôt que remis en contournant le ~/.forward de l’utilisateur.

Le ~/.forward lui-même est lu et exécuté par le helper privilégié pepsi-helper-dot-forward(1), qui commence par abandonner ses privilèges au profit de l’utilisateur cible. Le code de sortie du helper indique à l’étape ce qu’est devenu ce destinataire :

  • pas de ~/.forward — le destinataire est un passthrough : il reste sur le message, qui avance vers NEXT_STAGE (typiquement la remise locale, puis un smarthost). Un destinataire conservé par sa propre entrée \name avance aussi vers NEXT_STAGE, mais, chaque fois que le message est scindé, sur une ligne sœur qui lui est propre, afin qu’aucun réessai de cette étape n’exécute son ~/.forward une seconde fois.

  • redirigé — le destinataire est remplacé par les adresses que le ~/.forward a nommées. Celles-ci redémarrent le pipeline à RESTART_STAGE (par défaut init) sur une nouvelle ligne sœur pending, de sorte que les destinataires réécrits sont réauthentifiés et réacheminés comme du courrier neuf. Une liste d’adresses vide (le message a été entièrement consommé par des directives |pipe//file) supprime simplement le destinataire.

  • échoué — le helper a refusé ou échoué pour ce destinataire (code de sortie 2) : une commande de tube a quitté avec un code non nul, un fichier n’a pu être écrit, ou une directive désactivée a été demandée. Le destinataire est acheminé vers BOUNCE_STAGE de sorte qu’un DSN d’échec soit généré (en honorant le NOTIFY de l’expéditeur). Un message qui est lui-même un rebond (expéditeur nul) n’est jamais renvoyé en rebond.

  • problème d’hôte — le helper a signalé un échec opérationnel (code de sortie 3 : il n’est pas installé setuid-root, la consultation passwd a échoué, le compte est refusé, ou le répertoire personnel ou le ~/.forward n’appartient pas exclusivement à l’utilisateur — il n’en est pas propriétaire, ou le fichier est accessible en écriture au groupe ou à tous ; le helper vérifie le répertoire personnel avant de chercher un ~/.forward, ce qui refuse donc aussi les comptes qui n’en ont pas), une |command a demandé à être réessayée (elle a quitté avec 75, EX_TEMPFAIL, ou a manqué de temps), ou le helper n’a pas pu être exécuté du tout, a été tué par un signal, ou a quitté avec un statut qu’il ne documente pas. Aucun de ces cas n’est un verdict sur le destinataire, donc rien ne rebondit : le message est réessayé (une minute, doublée jusqu’à une heure, jusqu’à MAX_LIFETIME ; voir pepsi-dispatch(1)).

    Les destinataires traités plus tôt dans la même passe ont été pris en charge — leurs tubes ont été exécutés, leurs fichiers écrits — si bien qu’avant le réessai ils sont validés avec leur issue (redirigé, conservé, rebondi) et le message est réduit aux destinataires que le helper n’a pas atteints. Un réessai n’exécute donc jamais deux fois le ~/.forward d’un destinataire. La seule exception est le destinataire dont le propre ~/.forward a différé en cours de route : les directives situées au-dessus de celle qui a différé ont agi, et agissent de nouveau.

Un même message peut présenter un mélange de ces issues selon ses destinataires ; les adresses redirigées, les rebonds par destinataire et les destinataires conservés (passthrough) sont réconciliés en une seule scission du message, suivie de son terminal (dans la même instruction lorsqu’aucun destinataire ne reste sur le message). Le jeton de chaque ligne sœur est dérivé du destinataire ou du login de redirection qu’elle porte, de sorte qu’une passe réessayée ne peut jamais entrer en collision avec une ligne créée par une passe antérieure.

85.1.13.1.4. Boucles de redirection

Comme un message redirigé redémarre tout le pipeline, deux utilisateurs se redirigeant l’un vers l’autre (~bob → alice, ~alice → bob) boucleraient. Pour empêcher cela, chaque ligne redirigée porte sa chaîne de redirection dans state["dot-forwarders"] (voir pepsi.state(7)) : la chaîne de la ligne depuis laquelle elle a été redirigée, plus le login dont le ~/.forward l’a redirigée. Un destinataire dont l’utilisateur figure déjà dans la chaîne de sa ligne n’est pas remis et le helper n’est pas appelé (un avertissement est journalisé), de sorte que la chaîne se termine. Le destinataire est acheminé vers BOUNCE_STAGE comme n’importe quel autre échec de ~/.forward, afin que l’expéditeur soit informé (la RFC 5321 §6.1 exige une notification une fois le message accepté) ; un message qui est lui-même un rebond, ou une étape sans BOUNCE_STAGE, le supprime à la place.

La chaîne appartient à un chemin de redirection, pas au message : lorsque plusieurs destinataires d’un même message redirigent, les adresses de chacun partent sur une ligne sœur à part, qui ne porte que la chaîne de ce destinataire, de sorte que le ~/.forward d’un destinataire ne fait jamais passer pour une boucle un saut ultérieur par celui d’un autre. Une adresse vers laquelle plusieurs d’entre eux redirigent est remise une seule fois, sur la ligne du premier destinataire qui l’a nommée.

85.1.13.1.5. Arguments et sous-commandes

worker

Exécuté comme un worker persistant de pepsi-dispatch(1), lisant les identifiants de message sur l’entrée standard et écrivant une ligne de statut pour chacun. C’est ainsi que le dispatcher exécute l’étape en production.

85.1.13.1.6. Configuration

Lu depuis la section [stage-<stage>] du message :

PROGRAM

Doit être pepsi-stage-dot-forward.

RESTART_STAGE

L’étape à laquelle un message redirigé avec succès redémarre. Par défaut init (réexécutant tout le pipeline entrant, y compris l’authentification). Réglez-la sur une étape ultérieure (par exemple srs) pour sauter la réauthentification d’un message redirigé en interne. Doit nommer une étape existante.

ALLOW_PIPE

Si les directives |command dans un ~/.forward sont honorées (le message est envoyé par tube à la commande, exécutée en tant que l’utilisateur). Par défaut yes.

ALLOW_FILE

Si les directives /path (ajouter le message à un fichier) sont honorées. Par défaut yes. Lorsque ALLOW_PIPE et ALLOW_FILE sont tous deux no, l’étape n’envoie pas du tout le corps du message au helper par tube (le helper n’a besoin que de lire les adresses de redirection).

TARGETS, LOCAL_DOMAINS, RECIPIENT_DELIMITER

La sélection de compte local, de signification identique à pepsi-stage-relay-to-maildir(1). TARGETS vaut par défaut la plage d’uid ordinaires (non système) de /etc/login.defs, et pepsi-helper-dot-forward(1) refuse tout uid inférieur à UID_MIN quoi qu’elle indique (pepsi-setup(1) avertit d’un jeton qui descend en dessous) ; LOCAL_DOMAINS vaut par défaut [pepsi-ingress] ACCEPTED_DOMAINS ; RECIPIENT_DELIMITER vaut par défaut [pepsi] RECIPIENT_DELIMITER et, à défaut, + (none désactive le retrait de sous-adresse).

HELPER

Le helper de ~/.forward privilégié à exécuter. Par défaut pepsi-helper-dot-forward (résolu sur le $PATH) ; indiquez un chemin absolu pour le redéfinir.

NEXT_STAGE

Où les destinataires passthrough (pas de ~/.forward) avancent. Obligatoire, car la plupart des destinataires n’ont pas de ~/.forward. L’étape est normalement placée juste avant la remise locale, de sorte que NEXT_STAGE est l’étape de remise locale.

BOUNCE_STAGE

L’étape de génération de DSN vers laquelle un destinataire est acheminé lorsque l’exécution de son ~/.forward échoue.

85.1.13.1.7. Un fichier ~/.forward

Le helper interprète chaque ligne non vide et non commentaire (#) du ~/.forward de l’utilisateur comme l’une des lignes suivantes :

  • une adresse e-mail — collectée et utilisée comme nouveau destinataire ;

  • \name — le marqueur sendmail « remettre à name et ne pas l’étendre davantage ». L’adresse n’est pas redémarrée à RESTART_STAGE : si elle nomme le compte du destinataire lui-même (le \bob canonique dans ~bob/.forward, la façon dont un utilisateur garde une copie locale tout en redirigeant), ce destinataire reste simplement sur le message et avance vers NEXT_STAGE ; tout autre \name — un nom seul est qualifié par le domaine du destinataire — devient une ligne sœur à NEXT_STAGE. Comme un tel destinataire ne repasse jamais par cette étape, le marqueur ne peut pas créer de boucle non bornée. Notez qu’il contourne aussi le ~/.forward de cet utilisateur, ce qui est précisément le sens de « ne pas étendre davantage » ;

  • |command — lorsque ALLOW_PIPE est activé, le message est envoyé par tube à /bin/sh -c command exécuté en tant que l’utilisateur ;

  • /absolute/path — lorsque ALLOW_FILE est activé, le message est ajouté à ce fichier (style mbox) en tant que l’utilisateur.

Les adresses de redirection devraient être pleinement qualifiées (user@domain) ; un nom local seul est renvoyé tel quel et peut ne pas se résoudre à nouveau comme local.

Une |command dispose de 300 secondes pour se terminer, après quoi tout son groupe de processus est tué et le destinataire est réessayé comme pour une commande qui a quitté avec 75 (un agent de remise lent ne dit rien du destinataire ; le faire rebondir jetait du courrier qui aurait été accepté une minute plus tard). L’étape à son tour abandonne et tue un helper qui n’a pas fini au bout de 330 secondes, ce qu’elle signale comme une erreur réessayable plutôt que comme un rebond. Les deux limites sont des constantes de compilation, et non de la configuration : elles existent pour qu’un |sleep infinity d’un seul compte — ou une directive de fichier nommant une FIFO — ne puisse pas accaparer définitivement un worker du dispatcher, et que PARALLELISM d’entre eux ne puissent pas arrêter l’étape. Une directive de fichier doit nommer un fichier ordinaire ; une FIFO, un périphérique ou un lien symbolique est refusé.

85.1.13.1.8. Installation et privilèges

Pour atteindre le helper setuid-root, pepsi-stage-dot-forward doit lui-même être installé set-group-id au groupe pepsi-forward (mode 2550, propriétaire pepsi:pepsi-forward — exécutable par le propriétaire et non par tous, car le bit setgid est la barrière devant le helper setuid-root ; le droit d’exécution ne peut pas non plus venir des bits de groupe, pepsi n’étant délibérément pas membre du groupe, il vient donc du propriétaire). pepsi-dispatch(1) exécute l’étape en tant qu’utilisateur de service pepsi non privilégié ; le bit setgid donne au worker un gid effectif de pepsi-forward, ce qui est exactement ce qui lui permet d’exécuter le pepsi-helper-dot-forward(1) restreint au groupe — et rien d’autre sur l’hôte n’obtient cette capacité. make install met cela en place (son étape install-forward-stage), à condition d’être exécuté en tant que root et que le groupe pepsi-forward existe ; sinon il imprime les commandes exactes à exécuter à la main.

Le bit setgid étant cette barrière, le programme énonce lui-même la même règle : à moins que l’utilisateur réel ne soit root ou le compte de service pepsi, il sort en erreur avant qu’aucune configuration ne soit lue et — comme les étapes de cryptographie setuid — il retire les variables d’environnement qui pilotent le chargement de la configuration (HOME, XDG_CONFIG_HOME, PG*, TALER_*, PEPSI_*) et fixe PATH à une valeur par défaut sûre. Un mode de fichier est un fait de déploiement et ceci est un fait de programme ; ni l’un ni l’autre n’est censé tenir seul.

85.1.13.1.9. Voir aussi

pepsi-helper-dot-forward(1), pepsi-stage-relay-to-maildir(1), pepsi-stage-aliases(1), pepsi-stage-bounce(1), pepsi-dispatch(1), pepsi.conf(5), pepsi.state(7)

85.1.13.1.10. Bogues

Signalez les bogues au gestionnaire de tickets de Pepsi.