85.1.43. pepsi-whitelist

manage the sender whitelist, by hand or by mailbox

Section du manuel:

1

85.1.43.1.1. Nom

pepsi-whitelist - ajouter, lister, supprimer et importer des entrées de liste blanche d’expéditeurs.

85.1.43.1.2. Synopsis

pepsi-whitelist [GLOBAL-OPTIONS] add [–no-dkim-required] [–signature-required] [–sealer DOMAIN] NAME REGEX

pepsi-whitelist [GLOBAL-OPTIONS] add-list [–pattern] [–no-dkim-required] [–signature-required] [–sealer DOMAIN] NAME LIST-ID

pepsi-whitelist [GLOBAL-OPTIONS] list [NAME] [–json]

pepsi-whitelist [GLOBAL-OPTIONS] remove NAME REGEX

pepsi-whitelist [GLOBAL-OPTIONS] remove-list [–pattern] NAME LIST-ID

pepsi-whitelist [GLOBAL-OPTIONS] import [IMPORT-OPTIONS] [PATH…]

85.1.43.1.3. Description

pepsi-whitelist est l’outil de l’opérateur pour la table pepsi.whitelist — les ensembles nommés de motifs qui marquent un message comme digne de confiance (non spam). Chaque ligne a un whitelist_name (le groupe auquel elle appartient), un whitelist_regex (une expression régulière étendue POSIX comparée sans tenir compte de la casse, via l’opérateur ~*), un match_field qui nomme ce à quoi cette expression est comparée — l’addr-spec du From: du message ou son List-Id: — et trois conditions : dkim_required, signature_required et sealer_domain. Elles sont décrites dans pepsi-stage-check-whitelist(1), qui est ce qui les évalue.

Chaque motif est vérifié avant d’être stocké, en demandant à PostgreSQL – le moteur qui l’exécutera – de le compiler : add, add-list et import refusent une expression qui ne se compile pas, avec la raison donnée par PostgreSQL, et un import n’écrit rien si l’un de ses motifs est refusé.

La liste blanche est consultée par pepsi-stage-check-whitelist(1) et peuplée automatiquement à partir des destinataires sortants par pepsi-stage-auto-whitelist(1) ; cet outil permet à un administrateur de gérer les lignes directement, et permet à chaque utilisateur de semer sa propre liste blanche à partir du courrier qu’il a déjà envoyé (import). Ce n’est pas une étape. Il se connecte à la même base de données que les autres composants, via la section partagée [pepsi-postgres], et lit la section facultative [pepsi-whitelist] décrite dans pepsi.conf(5).

Contrairement à pepsi-stage-auto-whitelist(1), qui échappe une adresse de destinataire en un motif ancré aux limites, add stocke le whitelist_regex exactement tel qu’il est donné, de sorte que l’opérateur contrôle directement la correspondance. import échappe les adresses qu’il trouve, exactement comme le fait l’étape.

85.1.43.1.3.1. Listes de diffusion

add-list et remove-list gèrent les lignes list-id qui mettent une liste de diffusion entière en liste blanche — chaque message qu’elle relaie, quel qu’en soit l’auteur, ce qu’un motif sur From: ne peut exprimer parce que les messages d’une liste portent des adresses d’expéditeur arbitraires.

Ce sont des sous-commandes distinctes plutôt qu’un indicateur sur add, parce qu’elles prennent un autre type d’argument. add stocke son REGEX verbatim, ce qui convient à un motif qu’un opérateur a composé délibérément ; un identifiant de liste tapé dans cet emplacement serait une expression régulière non ancrée, de sorte que users.example.org correspondrait aussi à users.example.org.attacker.example et mettrait en liste blanche une liste au choix de l’attaquant. add-list prend l’identifiant tel qu’il apparaît dans l’en-tête — chevrons facultatifs, casse et phrase environnante ignorées — et l’ancre lui-même. –pattern est l’échappatoire pour le joker délibéré (toutes les listes d’un domaine), et l’argument est alors de nouveau une expression régulière, comme avec add.

Un en-tête List-Id: est un texte non authentifié que tout expéditeur peut recopier d’un message authentique : une règle qui ne repose que sur lui est une règle que n’importe qui peut satisfaire. –sealer DOMAIN est l’autre moitié : la ligne exige alors en outre que le message soit arrivé avec une chaîne ARC ayant validé et que DOMAIN ait été l’un de ses scelleurs, tel que pepsi-stage-arc(1) le note. DOMAIN est normalisé (mis en minuscules, point final retiré) sous la même forme que celle que note l’étape ARC, de sorte que les deux ne peuvent pas diverger. Cela fonctionne aussi sur les lignes add, où cela restreint un motif d’expéditeur au courrier relayé par un redirecteur connu.

85.1.43.1.3.2. Noms de liste blanche et qui peut les utiliser

Un whitelist_name est soit

global — un seul segment tel que correspondents, que seul l’opérateur

peut gérer ; soit

détenu par un utilisateur — <login>/<segment> tel que alice/correspondents, et

alice/lists/rust-lang pour d’autres sous-listes.

Un segment est composé de lettres, de chiffres, de _, de . et de - ; le séparateur est /. Un segment fait uniquement de points est refusé, de sorte que . et .. ne peuvent pas être des segments et qu’un nom de liste blanche ne peut jamais être un chemin relatif. Le point est par ailleurs autorisé parce que le segment propriétaire est le login passwd du compte, et alice.smith est un login ordinaire sur tout déploiement LDAP/SSSD/FreeIPA — tout comme un {localpart} de la forme first.last dans pepsi-stage-check-whitelist(1). / est le séparateur parce qu’aucun système de type POSIX ne l’autorise dans un nom de connexion, alors que -, _, . et un $ final y sont tous légaux et ne pourraient donc pas délimiter sans ambiguïté. (Un login portant un caractère hors de la grammaire des segments ne possède toujours aucun espace de noms ; import –all-users saute un tel compte avec un message plutôt que de faire échouer toute l’exécution.)

Parce que ce programme est installé setuid (voir ci-dessous), tout utilisateur local peut l’exécuter. Un appelant non privilégié ne peut lire et écrire que des noms de son propre espace de noms — le login de l’uid réel, pris dans la base passwd, jamais dans $USER ni dans un argument. Cette restriction couvre aussi list : la liste blanche partagée de l’opérateur est un relevé de qui l’organisation fréquente, et ce programme ne doit pas le livrer à chaque compte de l’hôte. root, ainsi que les comptes pepsi, pepsi-owner et pepsi-whitelist, peuvent gérer toutes les listes blanches.

Pour qu’une liste blanche par utilisateur ait le moindre effet, une étape doit la consulter ; voir les marqueurs {localpart} et {login} de WHITELIST_NAME dans pepsi-stage-check-whitelist(1).

85.1.43.1.3.3. Le modèle setuid

Gérer la table partagée pepsi.whitelist nécessite une identité de base de données que les utilisateurs ordinaires n’ont pas, alors que parcourir la boîte aux lettres d’un utilisateur nécessite son identité. Le programme est donc installé setuid vers le compte pepsi-whitelist (mode 4755) et abaisse immédiatement ses ids effectifs vers l’utilisateur appelant, ne conservant le propriétaire que dans le set-user-id sauvegardé. Il les relève de nouveau pendant les quelques millisecondes où il dialogue avec PostgreSQL — l’authentification peer se fonde sur l’uid effectif — et pour rien d’autre.

C’est ce même mécanisme qui permet à root d’utiliser l’outil. Les autres commandes de l’opérateur — pepsi-queue(1), pepsi-status(1), pepsi-settings(1), pepsi-tlsrpt(1), pepsi-failure-bouncer(1) — deviennent simplement le compte de service pepsi lorsqu’elles sont démarrées en tant que root, définitivement, car elles n’ont rien à faire en tant que root. Celle-ci, si : import –user et –all-users exécutent le helper de parcours sous les identifiants d’un autre utilisateur, ce que seul root peut organiser. Elle conserve donc l’identité appelante, root compris, et ne bascule que ses ids effectifs — vers le compte pepsi-whitelist, dont le rôle de base de données n’a de droits que sur la table de liste blanche — le temps de chaque appel à la base, pour revenir ensuite à root.

Ce compte n’est délibérément pas le compte de service pepsi : pepsi-setup(1) accorde à son rôle de base de données SELECT, INSERT et DELETE sur la table pepsi.whitelist et rien de plus, de sorte que la compromission d’un binaire que chaque utilisateur local peut exécuter ne peut atteindre ni la file d’attente de messages, ni les statistiques, ni les clés de signature.

L’analyse de la boîte aux lettres — la seule partie qui lit des données contrôlées par un attaquant, à savoir chaque message que quiconque a jamais envoyé à l’utilisateur — n’a pas lieu dans ce processus du tout. Elle s’exécute dans pepsi-helper-mailbox-scan(1), lancé avec setresuid positionnant les ids réel, effectif et sauvegardé sur l’utilisateur cible, de sorte que ce processus ne conserve nulle part dans ses identifiants un id privilégié et ne peut pas devenir pepsi-whitelist, même en principe.

Parce qu’un programme setuid ne doit pas être dirigé vers un fichier de configuration choisi par l’appelant, -c/–config est rejeté pour les appelants non privilégiés, et les variables d’environnement qui redirigeraient autrement la recherche de configuration (HOME, XDG_CONFIG_HOME), l’expansion de ${DATADIR} (PATH) ou la connexion à la base de données (PG*) sont retirées avant que la configuration ne soit lue.

85.1.43.1.4. Commandes

add [–no-dkim-required] [–signature-required] [–sealer DOMAIN] NAME REGEX

Insérer une entrée from stockant REGEX sous la liste blanche NAME. L’insertion est idempotente sur la contrainte UNIQUE(whitelist_name, match_field, whitelist_regex) : ré-ajouter un triplet existant est sans effet et laisse ses conditions inchangées.

–no-dkim-required

Effacer l’indicateur dkim_required de la ligne. Par défaut il est positionné, de sorte qu’une correspondance ne compte que si la signature DKIM ou ARC de l’expéditeur s’est vérifiée.

–signature-required

Positionner l’indicateur signature_required de la ligne. Par défaut il est effacé. Lorsqu’il est positionné, une correspondance ne compte que si la signature du message s’est vérifiée.

–sealer DOMAIN

Définir le sealer_domain de la ligne. Par défaut il est vide (n’importe quel chemin). Lorsqu’il est défini, une correspondance ne compte que si le message est arrivé avec une chaîne ARC ayant validé et que DOMAIN a été l’un de ses scelleurs. DOMAIN est mis en minuscules et débarrassé d’un point final, en accord avec ce que note pepsi-stage-arc(1).

add-list [–pattern] [CONDITION-OPTIONS] NAME LIST-ID

Insérer une entrée list-id sous la liste blanche NAME, correspondant à tout message dont l’en-tête List-Id: porte l’identifiant LIST-ID. L’identifiant peut être donné entre chevrons ou nu, dans n’importe quelle casse, avec ou sans phrase descriptive ; il est réduit à sa forme nue en minuscules et ancré, de sorte qu’il corresponde à cette liste et à aucune autre. Prend les mêmes options de condition que add, et l’associer à –sealer est vivement conseillé — voir Listes de diffusion ci-dessus.

–pattern

Traiter LIST-ID comme une expression régulière étendue POSIX à stocker verbatim, plutôt que comme un identifiant unique à ancrer. Pour le cas du joker délibéré (toutes les listes d’un domaine) ; une expression non ancrée correspond à tout identifiant qui la contient, écrivez donc les ancres vous-même.

list [NAME] [–json]

Lister les entrées ordonnées par nom, champ de correspondance, puis regex. Avec NAME, seul ce groupe de liste blanche est affiché.

–json

Émettre un tableau JSON d’objets (whitelist_id, whitelist_name, whitelist_regex, match_field, dkim_required, signature_required, sealer_domain) au lieu de la table lisible par un humain.

remove NAME REGEX

Supprimer l’entrée from dont le whitelist_name est NAME et dont le whitelist_regex est exactement REGEX. Une ligne list-id portant le même texte de motif est une entrée différente et est laissée intacte ; employez remove-list pour elle.

remove-list [–pattern] NAME LIST-ID

Supprimer l’entrée list-id que add-list aurait créée pour LIST-ID, de sorte que l’identifiant qui a ajouté une liste la retire également. –pattern a le même sens que dans add-list, et doit être donné s’il l’a été alors.

import [OPTIONS] [PATH…]

Semer une liste blanche à partir des destinataires du courrier que l’utilisateur a envoyé.

Une boîte aux lettres est parcourue à la recherche des messages envoyés par l’utilisateur, et les adresses To:, Cc: et Bcc: de ces messages deviennent des entrées de liste blanche, de sorte que lorsque ces personnes répondent, leurs réponses sont reconnues. Les destinataires à un domaine local sont sautés — les expéditeurs locaux ne passent jamais par la barrière entrante.

Un message compte comme envoyé par l’utilisateur lorsque son From: (ou son Sender:) est à l’un des domaines locaux et que son bloc d’en-têtes ne porte aucun champ Received:, Return-Path:, Delivered-To: ni X-Original-To:. Les deux moitiés sont nécessaires : From: n’est pas authentifié, c’est donc à lui seul une affirmation que n’importe qui peut faire, et un inconnu qui vous envoie un message portant votre propre adresse dans From: et la sienne dans To: verrait sinon cette adresse insérée dans votre liste blanche par le prochain import — c’est-à-dire précisément la barrière que la liste blanche ouvre. Exiger une signature ne la referme pas, car le faussaire signe le courrier de son propre domaine. Les quatre champs ci-dessus sont écrits par un MTA ou un MDA de réception et jamais par un client de messagerie qui compose un message : leur absence est donc la preuve que le message a été classé ici plutôt que remis ici.

Le courrier reçu est donc ignoré, comme tout ce qui est arrivé. –include-delivered désactive ce test ; lisez ci-dessous avant de l’employer.

L’endroit où un message est classé n’a toujours pas d’importance : un parcours de Maildir traverse tout l’arbre, de sorte que ~/Maildir couvre .Sent et chaque dossier d’archive en une seule exécution. Seul le bloc d’en-têtes de chaque message est lu, jamais le corps.

PATH… sont des fichiers de boîte aux lettres ou des répertoires Maildir. Sans aucun, ~/Maildir est parcouru s’il existe, sinon /var/mail/<login> ; [pepsi-whitelist] MAILBOX redéfinit cette valeur par défaut. Notez que /var/mail/<login> est un spool de remise et ne contient que du courrier reçu : sur un hôte sans Maildir, la valeur par défaut ne trouve donc rien et un dossier Sent doit être nommé explicitement.

–name NAME

Liste blanche à semer. Par défaut <login>/correspondents (ou le correspondents global pour un appelant privilégié).

–include-delivered

Compter un message comme envoyé sur la seule foi de son From:, en abandonnant le test de trace de remise ci-dessus. Dangereux sur toute boîte aux lettres qui contient du courrier reçu — un From: falsifié suffit alors à planter une entrée de liste blanche. Cela existe pour le magasin inhabituel dont les copies envoyées sont réellement passées par la remise, et ne devrait être pointé que vers ce dossier Sent, jamais vers une boîte de réception.

–format auto|mbox|maildir

Forcer le format de boîte aux lettres au lieu de le détecter par chemin (un répertoire est une Maildir, un fichier une mbox).

–auto-wildcard

Proposer de remplacer les adresses individuelles d’un domaine par une seule entrée *@domain lorsqu’au moins N adresses distinctes y ont été vues (N est --threshold, par défaut [pepsi-whitelist] WILDCARD_THRESHOLD, 10).

Les propositions sont imprimées et confirmées une à une sur un terminal ; en refuser une garde simplement les adresses de ce domaine individuelles. Avec –yes, toutes sont acceptées ; sans terminal et sans –yes, toutes sont refusées, de sorte qu’une exécution sans surveillance ne peut jamais élargir d’elle-même une liste blanche à un domaine entier.

Les hébergeurs e-mail publics ne sont jamais proposés, quel que soit le nombre de correspondants que l’utilisateur y a : « tout le monde chez gmail.com » n’est pas un ensemble de personnes que l’utilisateur connaît. La liste de ces domaines est [pepsi-whitelist] HOSTERS_FILE (/usr/share/pepsi/hosters.txt).

–threshold N

Nombre d’adresses distinctes à un même domaine avant qu’un joker ne soit proposé.

–hosters FILE

Utiliser FILE comme liste d’hébergeurs publics au lieu de celle configurée.

–no-hosters

N’exclure aucun domaine de la mise en joker.

–dry-run

Signaler ce qui serait ajouté et ne rien changer.

-y, –yes

Accepter chaque proposition de joker sans demander.

–max-entries N

Nombre maximal de lignes que cet import peut ajouter (par défaut [pepsi-whitelist] MAX_ENTRIES, 5000). Chaque ligne d’une liste blanche est comparée au From: de chaque message entrant qui la consulte, de sorte qu’un import non borné est un coût permanent par message.

–max-messages N

Examiner au plus N messages. Cela plafonne le nombre de messages analysés et classés, pas la portion de la boîte aux lettres qui est lue : le fichier, l’arbre ou le compte IMAP est tout de même parcouru jusqu’au bout.

–own-address ADDRESS

Ne considérer comme appartenant à l’utilisateur que le courrier envoyé depuis cette adresse exacte, au lieu de tout expéditeur à un domaine local. Répétable.

–imap URL

Parcourir un magasin de courrier qui n’est pas sur ce système de fichiers, p. ex. imaps://alice@mail.example.com/. imaps:// est du TLS implicite (port 993), imap:// du STARTTLS (port 143) ; un composant de chemin est un motif de boîte aux lettres (par défaut *, toutes les boîtes). Les boîtes aux lettres sont ouvertes en lecture seule (EXAMINE) et seuls les blocs d’en-têtes sont récupérés, de sorte qu’un parcours ne marque rien comme \Seen.

LMTP ne peut pas faire cela — c’est un protocole de remise sans aucun verbe qui liste ou récupère quoi que ce soit — ce qui explique pourquoi IMAP est l’option réseau.

–imap-user NAME

Le login IMAP, s’il n’est pas dans l’URL.

–imap-password-file FILE

Lire le mot de passe sur la première ligne de FILE au lieu de le demander. Gardez-le en mode 0600 : ce chemin lit le fichier lui-même et ne vérifie pas ses permissions, contrairement à l’option du même nom de pepsi-helper-mailbox-scan(1), qui refuse un fichier que tout autre utilisateur peut lire. Le mot de passe n’est jamais passé sur une ligne de commande, où tous les autres utilisateurs pourraient le lire dans ps.

–doveadm

Lire un magasin Dovecot local via doveadm, pour les formats qu’aucun scanner de fichiers ne peut analyser (mdbox/sdbox). doveadm est exécuté par ce programme (il a besoin de privilèges) et sa sortie est redirigée vers le helper de parcours non privilégié.

–doveadm-path PATH

Le binaire doveadm à utiliser.

–user LOGIN

Importer pour un autre utilisateur, dans son espace de noms. Nécessite un appelant privilégié ; le helper de parcours est abaissé aux identifiants de cet utilisateur.

–all-users

Importer pour chaque compte local que [pepsi-whitelist] TARGETS autorise, chacun dans son propre <login>/correspondents. Nécessite un appelant privilégié. Seuls les comptes du fichier passwd local sont trouvés ; nommez un compte de service d’annuaire avec –user.

–no-dkim-required, –signature-required

Comme pour add, appliqué à chaque ligne que l’import ajoute.

85.1.43.1.5. Options globales

Ces options globales précèdent la sous-commande (un indicateur placé à la fin est rejeté).

-c FILE, –config FILE

Lit la configuration depuis FILE au lieu de parcourir les emplacements par défaut. Rejeté pour les appelants non privilégiés lorsque ce programme est installé setuid : la configuration décide de la connexion à la base de données, de sorte qu’un processus setuid n’en lit qu’une qui appartient à root.

-L LOGLEVEL, –log LOGLEVEL

Règle la verbosité de journalisation. LOGLEVEL est l’un de error, warn, info, debug ou trace (par défaut : info).

-v, –verbose

Affiche les messages de journal de toutes les sources, y compris les bibliothèques tierces.

-h, –help

Affiche un résumé d’utilisation et quitte.

-V, –version

Affiche la version et quitte.

85.1.43.1.6. Code de sortie

0

Achèvement réussi.

1

Une erreur s’est produite : un fichier de configuration malformé ou une connexion ou requête de base de données échouée. La raison est écrite dans le journal.

85.1.43.1.7. Fichiers

Lorsque –config n’est pas fourni, le premier fichier existant de la liste suivante est utilisé. Chaque composant Pepsi partage le même fichier de configuration, c’est donc la même liste que chacun parcourt :

  • $XDG_CONFIG_HOME/pepsi.conf

  • $HOME/.config/pepsi.conf

  • /etc/pepsi/pepsi.conf

  • /etc/pepsi.conf

${DATADIR}/hosters.txt

La liste d’hébergeurs publics pour lesquels import –auto-wildcard ne propose jamais de joker, installée par make install depuis contrib/hosters.txt (/usr/share/pepsi/hosters.txt sur une installation par défaut). Surchargée par [pepsi-whitelist] HOSTERS_FILE ou, pour une seule exécution, par –hosters.

~/Maildir, /var/mail/login

Les boîtes aux lettres que import parcourt lorsqu’aucun PATH n’est donné, dans cet ordre ; [pepsi-whitelist] MAILBOX remplace la paire.

85.1.43.1.8. Exemples

Mettre un expéditeur en liste blanche (DKIM/ARC requis par défaut)

pepsi-whitelist -c /etc/pepsi/pepsi.conf add trusted-senders '^alice@example\.com$'

Le motif est stocké verbatim, l’ancrer est donc le travail de l’opérateur. Un alice@example\.com non ancré correspond aussi à alice@example.com.attacker.example et à "alice@example.com!"@attacker.example, que l’attaquant peut l’un comme l’autre placer dans un en-tête From:. C’est pour cette raison que les motifs engendrés (import et pepsi-stage-auto-whitelist(1)) ancrent toujours sur ^/$.

Mettre tout un domaine en liste blanche sans exiger de signature

pepsi-whitelist -c /etc/pepsi/pepsi.conf add trusted-senders --no-dkim-required '@example\.org$'

Lister le groupe trusted-senders en JSON

pepsi-whitelist -c /etc/pepsi/pepsi.conf list trusted-senders --json

Supprimer une entrée

pepsi-whitelist -c /etc/pepsi/pepsi.conf remove trusted-senders '@example\.org$'

En tant qu’utilisateur ordinaire, mettre en liste blanche une liste de diffusion à laquelle vous êtes abonné, de sorte que ses messages vous parviennent quels qu’en soient les auteurs, mais seulement lorsque l’ADMD propre à la liste les a scellés

pepsi-whitelist add-list alice/lists users.rust-lang.org \
    --sealer mail.rust-lang.org

Toutes les listes exploitées à un même domaine, ce qui exige d’écrire les ancres à la main

pepsi-whitelist add-list alice/lists --pattern '^[a-z0-9-]+\.lists\.example\.org$' \
    --sealer lists.example.org

Désabonné ; retirer la règle avec l’identifiant qui l’a créée

pepsi-whitelist remove-list alice/lists users.rust-lang.org

En tant qu’utilisateur ordinaire, semer votre propre liste blanche depuis votre boîte aux lettres, en voyant d’abord ce que cela ferait

pepsi-whitelist import --dry-run
pepsi-whitelist import

Idem, mais en regroupant les domaines auxquels vous écrivez largement en une entrée chacun (les hébergeurs publics ne sont jamais regroupés)

pepsi-whitelist import --auto-wildcard

Parcourir seulement votre dossier Sent, et un compte distant via IMAP

pepsi-whitelist import ~/Maildir/.Sent
pepsi-whitelist import --imap imaps://alice@mail.example.com/Sent

En tant que root, semer la liste blanche propre à chaque compte local depuis un magasin Dovecot

pepsi-whitelist import --all-users --doveadm --auto-wildcard --yes

85.1.43.1.9. Voir aussi

pepsi-config(1), pepsi-helper-mailbox-scan(1), pepsi-stage-check-whitelist(1), pepsi-stage-auto-whitelist(1), pepsi-queue(1), pepsi.conf(5), pepsi-setup(1)

85.1.43.1.10. Bogues

Signalez les bogues au gestionnaire de tickets de Pepsi.