85.1.42. pepsi-sendmail¶
submit mail locally through the Sendmail interface
- Section du manuel:
1
85.1.42.1.1. Nom¶
pepsi-sendmail - remettre à Pepsi un message écrit localement, en fournissant l’interface traditionnelle /usr/sbin/sendmail.
85.1.42.1.2. Synopsis¶
sendmail [-t] [-i] [-f SENDER] [-F NAME] [-v] [-N NOTIFY] [-R RET] [-V ENVID] [-c CONFIG] [RECIPIENT …]
mailq
newaliases
85.1.42.1.3. Description¶
pepsi-sendmail lit un message sur l’entrée standard et le soumet à pepsi-ingress via une socket de domaine UNIX locale. Il existe afin que les logiciels qui attendent d’un MTA qu’il fournisse /usr/sbin/sendmail — cron, mail(1), git send-email, logwatch, la fonction mail() de PHP — puissent envoyer du courrier à travers Pepsi sans être reconfigurés.
Le paquet Debian l’installe sous les chemins que la Charte Debian §11.6 exige d’un agent de transport de courrier, chacun étant un lien symbolique vers le binaire unifié pepsi — sauf /usr/lib/sendmail, qui pointe vers /usr/sbin/sendmail — qui aiguille selon le nom sous lequel il a été invoqué :
Chemin |
Se comporte comme |
|---|---|
|
le client de soumission décrit ici |
|
le même (chemin historique) |
|
|
|
|
|
le client de soumission (remise UUCP) |
Une installation depuis les sources ne revendique pas ces chemins, car ils appartiennent au MTA que le système possède déjà ; passez INSTALL_MTA_LINKS=yes à make install pour les reprendre délibérément.
85.1.42.1.4. Authentification¶
pepsi-sendmail ne détient aucun privilège et n’affirme aucune identité. Il n’est ni setuid ni setgid, et il n’a besoin d’aucune entrée dans MYNETWORKS.
À la place, pepsi-ingress lit auprès du noyau l’identifiant d’utilisateur du processus qui se connecte (SO_PEERCRED, activé par listener avec AUTH_PEERCRED), le résout en un login via la base passwd, et recherche ce login dans USERNAME_MAP exactement comme il le ferait d’un nom d’utilisateur SASL arrivant sur le port de soumission. Les règles RFC 6409 §6/§8.1 s’appliquent alors inchangées : un programme local ne peut utiliser qu’un expéditeur d’enveloppe et un From: auxquels son propre compte est mappé, et un compte mappé à aucune adresse est refusé d’emblée.
Deux conséquences en découlent :
La socket peut être accessible en écriture par tout le monde. Pouvoir l’ouvrir n’accorde rien, car cela ne détermine pas au nom de qui vous pouvez envoyer. Refusez un compte en le mappant à aucune adresse dans
USERNAME_MAP, non en ajustant les permissions.Rien sur le réseau n’acquiert de droits. C’est là la différence de fond avec le fait de faire confiance à l’interface loopback dans
MYNETWORKS, qui authentifie une position réseau plutôt qu’un utilisateur : dans une telle configuration, n’importe quel processus local peut envoyer au nom de n’importe qui, et un message que cet hôte se relaie à lui-même y réapparaît comme une nouvelle soumission locale, ce qui peut boucler.
Comme les soumissions sont authentifiées, elles sont enregistrées avec state.local_origin positionné, de sorte que le pipeline les traite comme le courrier propre de cet hôte — en les signant en DKIM au nom du domaine de l’auteur et en leur permettant d’être relayées.
85.1.42.1.5. Le message¶
Les producteurs locaux écrivent les messages comme on écrit un fichier texte, aussi le client les met-il au propre avant que quoi que ce soit d’autre ne les regarde :
Chaque LF nu devient CRLF. SMTP est encadré en CRLF et
pepsi-ingressl’impose (un LF nu dansDATAest refusé par500 5.6.0 invalid line framing), cela ne peut donc pas être laissé au serveur.Un champ
From:est ajouté en tête lorsque le message n’en a aucun, construit à partir de -F et de l’expéditeur d’enveloppe ; un nom d’affichage contenant des caractères spéciaux au sens de la RFC 5322 est mis entre guillemets.Chaque champ
Bcc:est retiré, que -t ait été utilisé ou non — le laisser révélerait les destinataires en copie invisible à tous les autres figurant sur l’enveloppe.Un destinataire sans
@— leTo: rootdecron— est complété avec[pepsi-sendmail] DEFAULT_DOMAIN, avant que les doublons ne soient écartés (sans tenir compte de la casse), de sorte que la même adresse donnée deux fois n’est soumise qu’une fois.
La transaction elle-même est le minimum dont a besoin une socket sur l’hôte : lire la salutation, EHLO, MAIL FROM (avec BODY=8BITMIME lorsque le message contient des octets 8 bits et que le serveur a annoncé 8BITMIME, et avec les paramètres -R/-V seulement s’il a annoncé DSN), un RCPT TO par destinataire (portant -N sous la même condition), DATA avec le bourrage de points de la RFC 5321 §4.5.2 appliqué, et un QUIT au mieux — un échec à dire au revoir ne peut pas transformer un message accepté en erreur. Pas de STARTTLS, pas de SASL et pas de MTA-STS : le pair est une socket du système de fichiers sur cet hôte, le transport ne peut pas être observé, et l’authentification est l’affaire du noyau.
85.1.42.1.6. Options¶
- -t
Lire les destinataires dans les en-têtes
To:,Cc:etBcc:du message. Ils sont ajoutés aux destinataires donnés sur la ligne de commande (comme Postfix), et une adresse déjà présente sur la ligne de commande n’est pas répétée. Les en-têtesBcc:sont retirés du message dans les deux cas, avec ou sans -t.- -f SENDER, -r SENDER
Définir l’expéditeur d’enveloppe. Soumis à
USERNAME_MAP: le serveur rejette un expéditeur auquel le compte appelant n’a pas droit. En son absence, on utilise le login du compte appelant qualifié par[pepsi-sendmail] DEFAULT_DOMAIN(et le littéralnobody@suivi de ce domaine si le login ne peut pas être résolu). C’est une valeur par défaut de courtoisie, non une prétention : le serveur redérive de toute façon l’identité depuis les identifiants du pair.- -F NAME
Nom d’affichage pour un en-tête
From:généré lorsque le message n’en a pas.- -i, -oi
Ne pas traiter une ligne ne contenant qu’un point comme une fin d’entrée. Accepté par compatibilité ; l’entrée est toujours lue jusqu’à la fin de fichier.
- -v
Afficher le dialogue SMTP sur la sortie d’erreur standard, et rétablir la sortie de journalisation ordinaire de Pepsi. Sans cette option, le programme ne journalise que les avertissements et les erreurs : un binaire
sendmails’exécute depuiscronet depuis des scripts qui capturent la sortie d’erreur standard et la renvoient par courrier, de sorte que le bavardage informatif habituel transformerait chaque message réussi en un second message.- -c CONFIG, –config CONFIG
Lire la configuration Pepsi depuis CONFIG au lieu de l’emplacement habituel (voir pepsi.conf(5)). C’est une extension Pepsi, qui ne fait pas partie de la grammaire
sendmail; la valeur peut être accolée (-c/etc/pepsi/pepsi.conf) ou séparée.Sans danger à honorer bien qu’il s’agisse de l’interface de soumission locale, car le programme ne détient aucun privilège d’aucune sorte : le pointer vers une autre configuration ne change que la socket à laquelle il se connecte, et le serveur dérive toujours l’identité de l’expéditeur de l’uid de l’appelant via
SO_PEERCRED. Il s’écrit-cplutôt que le-Cde sendmail parce que-Cdésigne déjà unsendmail.cfde remplacement, ce qui est autre chose, et est refusé (voir ci-dessous).- -N NOTIFY, -R RET, -V ENVID
Paramètres de notification d’état de remise (DSN) RFC 3461, transmis au serveur lorsqu’il annonce l’extension
DSN. Voir pepsi-stage-bounce(1).NOTIFY vaut
NEVERou une liste, séparée par des virgules, deSUCCESS,FAILUREetDELAY(RFC 3461 §4.1) ; RET vautFULLouHDRS(§4.3). Toute autre valeur est une erreur d’utilisation plutôt qu’un501du serveur. ENVID est encodé enxtextsur le fil (§4.4) et tronqué aux 100 caractères que la grammaire autorise.
Une valeur donnée à -f, -F, -N, -R ou -V, ou un destinataire, qui contient un caractère de contrôle est refusée avec EX_USAGE. Ces valeurs sont interpolées dans les lignes de commande SMTP et dans un champ From: généré, et les commandes SMTP sont délimitées par CRLF (RFC 5321 §4.1.1) : un retour chariot ou un saut de ligne dans l’une d’elles injecterait donc une commande supplémentaire — un destinataire que l’appelant n’a jamais déclaré — ou un champ d’en-tête supplémentaire. Cela compte surtout pour un appelant qui transmet directement une entrée utilisateur, comme une application web utilisant -f.
- -bm
Lire et soumettre un message. Le comportement par défaut.
- -bp
Afficher la file d’attente. La file de Pepsi réside dans la base de données plutôt que dans un répertoire de spool, et la lire exige un rôle qu’un utilisateur ordinaire ne détient pas : ceci affiche donc une indication sur la sortie d’erreur standard et quitte avec
70; utilisez pepsi-queue(1) pour la file elle-même et pepsi-status(1) pour un résumé. Note pour la supervision :mailq« échoue » donc toujours sur une installation Pepsi saine.- -bi
Reconstruire la base d’alias. La table d’alias de Pepsi est un simple fichier texte que pepsi-stage-aliases(1) relit dès que son heure de modification change, il n’y a donc rien à reconstruire et ceci se termine avec succès sans rien faire — avant même que le fichier de configuration ne soit cherché, puisque les scripts de mainteneur de paquet exécutent
newaliasessans condition et que cela ne doit pas échouer sur un hôte dont la configuration est illisible ou pas encore écrite.- -I
Synonyme de -bi : une opération sans effet qui réussit, comme newaliases.
- -h N, -L TAG, -X FILE, -B TYPE, -p PROTOCOL, -O NAME=VALUE
Acceptées et ignorées, comme les accepte le
sendmail(1) de Postfix. Elles décrivent des compteurs de sauts, de la journalisation et des décisions d’ordonnancement de remise que le pipeline prend lui-même ; chacune consomme sa valeur, qu’elle soit attachée ou séparée, afin que la valeur ne soit pas prise pour un destinataire. Seuls les indicateurs de gestion de file et de démon sont refusés, car ils donneraient une fausse idée de ce que fait le programme.- -m, -U, -n, -s, -G, -Ac, -Am, -oX, -d…
Acceptées et ignorées, ne prenant aucune valeur propre.
-oX est l’orthographe d’option à l’ancienne quecronémet encore (-odi,-oem), et-dest l’indicateur de débogage de sendmail, dont le niveau lui est attaché.- -bs, -bv
Acceptées par l’analyseur mais non prises en charge : chacune affiche pourquoi sur la sortie d’erreur standard et quitte avec
70.-bs(parler SMTP sur l’entrée standard) n’a aucun objet ici — connectez-vous directement à la socket de soumission.-bv(vérification d’adresse) ne peut recevoir de réponse sans les tables d’acheminement, et inventer une réponse serait pire que de décliner.- -bd, -bD, -q…
Refusées au moment de l’analyse. Le serveur en écoute de Pepsi est pepsi-ingress(1) et sa file d’attente est vidée en continu par pepsi-dispatch(1) ; les accepter silencieusement laisserait croire à un démon ou à un passage de file qui n’existent pas.
-C est refusée plutôt que traitée comme -c : dans la grammaire sendmail, elle désigne un sendmail.cf de remplacement, qui n’a pas d’équivalent ici, et lire discrètement une configuration Pepsi depuis un chemin destiné à autre chose serait pire que de décliner. L’orthographe Pepsi est -c/--config, documentée ci-dessus ; sans l’une ni l’autre, le fichier de configuration est localisé de la manière habituelle (voir pepsi.conf(5)).
85.1.42.1.7. Configuration¶
[pepsi-sendmail]
- SOCKET
Chemin de la socket de soumission de domaine UNIX de
pepsi-ingress. Par défaut/run/pepsi/submission.sock. pepsi-ingress lit cette même option pour décider ce qu’il sert, de sorte que les deux extrémités ne peuvent pas être dirigées vers des chemins différents et qu’aucune section de listener n’est nécessaire.La valeur spéciale
nonedésactive entièrement la soumission locale : le serveur ne lie aucune socket et ce programme refuse de s’exécuter.- EHLO_NAME
Nom annoncé dans
EHLO. Par défaut[pepsi-ingress] HOSTNAME, oulocalhostsi celui-ci n’est pas défini. Cosmétique : le serveur authentifie le pair par ses identifiants, non par ce nom.- DEFAULT_DOMAIN
Domaine ajouté à une adresse nue, non qualifiée — le
rootque cron et les outils système remettent àsendmailsans@. Vaut par défaut[pepsi-ingress] HOSTNAME, oulocalhostsi celui-ci n’est pas défini.C’est aussi le domaine de l’expéditeur d’enveloppe par défaut lorsque -f est omis (
<login>@<DEFAULT_DOMAIN>), qui est le repli que la propre table d’identités de soumission du serveur applique à un nom d’utilisateur pour lequel elle n’a pas d’entrée — de sorte que sansUSERNAME_MAPles deux s’accordent par construction. Cela ne concerne toujours que la manière dont le message est adressé : de qui il peut provenir découle de l’uid du pair viaSO_PEERCREDet de laUSERNAME_MAP, et régler cette option ne peut pas l’élargir.
Le côté serveur correspondant n’a besoin d’aucune configuration. pepsi-ingress sert cette socket inconditionnellement, en lisant exactement la même option SOCKET pour décider ce qu’il lie — de sorte que le client et le serveur ne peuvent pas être dirigés vers des chemins différents, et qu’il n’y a aucune section de listener à écrire, à maintenir en phase, ou à oublier. Le listener qu’il synthétise est figé, parce que rien de tout cela n’est un choix : MODE = plain, SUBMISSION = yes (les corrections d’en-têtes RFC 6409 s’appliquent donc) et AUTH_PEERCRED = yes, sur une socket de mode 0666.
Une section [pepsi-ingress-listener-*] facultative ferait au contraire dépendre la fonctionnalité de l’accord de trois choses distinctes — l’existence de la section, la correspondance de son UNIXPATH avec SOCKET, et le fait que le répertoire d’exécution soit accessible en écriture au serveur —, chacune individuellement facile à rater, avec chaque fois le même symptôme : le courrier de cron s’arrête en silence. D’un hôte faisant tourner un MTA, on attend qu’il fournisse /usr/sbin/sendmail.
Sous systemd, le descripteur est hérité plutôt que lié, lorsque le pepsi-ingress.socket livré porte déjà un ListenStream= pour le même chemin. Ce n’est pas une affaire de privilège — ce n’est pas un port privilégié — mais de répertoire. /run/pepsi est partagé avec pepsi-httpd et la sonnette setup-apply, et systemd attribue un RuntimeDirectory= au User= de l’unité qui le déclare, en le réattribuant à chaque démarrage ; un pepsi-ingress non privilégié qui y créerait sa propre socket échoue dès qu’une autre de ces unités redémarre. Lié par l’unité .socket, le nœud est créé par systemd en tant que root avant le démarrage du service, si bien que le serveur n’a besoin d’aucun accès en écriture au répertoire — et la socket reste disponible pendant que le service redémarre, de sorte qu’un /usr/sbin/sendmail concurrent attend au lieu d’échouer.
Le descripteur est apparié par l’adresse à laquelle il est lié, non par un FD_INDEX. Un index est une position parmi les entrées ListenStream= de l’unité : il change donc dès qu’un port est ajouté ou retiré — une seconde déclaration à maintenir en phase avec un fichier qu’elle ne peut pas voir. Demander au noyau à quoi chaque descripteur transmis est lié n’a pas ce mode de défaillance : ajouter ou retirer un port SMTP ne renumérote rien, un hôte purement sortant qui abandonne le port 25 n’exige aucune modification, et l’unité et la configuration ne peuvent pas être en désaccord sur l’identité de cette socket. Si aucun descripteur transmis ne correspond — pas de systemd, ou un SOCKET que l’unité ne lie pas —, pepsi-ingress lie le chemin lui-même.
Si vous modifiez SOCKET, modifiez le ListenStream= de l’unité en conséquence ou supprimez-le : une entrée sur laquelle rien n’accepte est pire que pas d’entrée du tout, car l’appelant se connecte puis bloque jusqu’à l’expiration de son propre délai de lecture (deux minutes, puis EX_TEMPFAIL) au lieu d’être refusé aussitôt. pepsi-ingress journalise au démarrage un avertissement nommant chaque descripteur transmis qu’aucun listener n’a revendiqué.
Échouer à lier la socket est fatal : pepsi-ingress refuse de démarrer plutôt que de tourner en ne servant qu’une partie de ce qu’on lui a demandé de servir. Un serveur qui tourne avec la soumission locale silencieusement absente est précisément la défaillance que cet arrangement existe pour empêcher, et elle est invisible jusqu’à ce que du courrier se perde.
Écrire votre propre section de listener pour le même chemin est pris en charge, et c’est ainsi que vous donnez à la socket des options différentes — un groupe, un mode plus strict, pas d’identifiants de pair. Une section servant ce chemin remplace le listener intégré plutôt que d’entrer en collision avec lui.
85.1.42.1.8. La désactiver¶
SOCKET = none désactive entièrement la soumission locale : pepsi-ingress ne sert aucune socket, et pepsi-sendmail refuse de s’exécuter (sortie EX_SOFTWARE, avant même de lire le message — une mauvaise configuration permanente, que cron ne doit donc pas réessayer). Les programmes de l’hôte doivent alors s’authentifier sur 587 ou 465 comme n’importe quel autre client. pepsi-setup le signale une fois, car un serveur de messagerie sans chemin de soumission locale est assez inhabituel pour qu’un opérateur qui ne l’a pas voulu en soit informé.
85.1.42.1.9. Code de sortie¶
Les valeurs traditionnelles de sysexits.h, sur lesquelles cron et les autres appelants se fondent :
0 |
le message a été accepté |
64 |
erreur d’utilisation ( |
65 |
le message était inutilisable, par exemple |
66 |
le message n’a pas pu être lu depuis l’entrée standard |
67 |
un destinataire a été rejeté comme inconnu — un statut RFC 3463 |
69 |
tout autre rejet permanent par le serveur ( |
70 |
erreur interne, par exemple la configuration n’a pas pu être analysée, ou |
75 |
échec temporaire — la socket était injoignable, une commande a expiré, le serveur a fermé la connexion ou a répondu du SMTP malformé, ou il a différé avec un |
77 |
le serveur a refusé pour des raisons de politique — un statut RFC 3463 |
Un rejet permanent est classé d’après le code d’état étendu placé au début de la réponse du serveur, jamais en fouillant sa prose : ainsi 550 5.1.1 unknown user (see the 5.7.1 policy page) est signalé comme un destinataire inconnu et non comme un refus de politique.
85.1.42.1.10. Fichiers¶
/run/pepsi/submission.sockLa socket de soumission, à moins que
[pepsi-sendmail] SOCKETne nomme un autre chemin. Les deux extrémités lisent cette même option, de sorte que le client etpepsi-ingressne peuvent pas être en désaccord sur son emplacement.
Lorsque -c/–config n’est pas fourni, la configuration est le premier fichier existant de la liste suivante — la même liste que parcourt chaque composant Pepsi :
$XDG_CONFIG_HOME/pepsi.conf$HOME/.config/pepsi.conf/etc/pepsi/pepsi.conf/etc/pepsi.conf
85.1.42.1.11. Exemples¶
Envoyer un message en prenant les destinataires dans ses en-têtes
printf 'To: ops@example.org\nSubject: nightly\n\nall good\n' | sendmail -t
Observer le dialogue en diagnostiquant un refus
sendmail -v -f alice@example.org bob@example.net < message.eml
85.1.42.1.12. Voir aussi¶
pepsi-ingress(1), pepsi-queue(1), pepsi-status(1), pepsi-stage-aliases(1), pepsi.conf(5)