L'Internet Rapide et Permanent

SMTP/IMAP en pratique

Christian Caleca

Vous disposez d'une connexion permanente et rapide... et maintenant, vous êtes perdu dans la technique...

Cette série « L'Internet Rapide et Permanent », que Christian Caleca nous a aimablement autorisé à reproduire, est là pour répondre à quelques-unes de ces questions. Cet article parlera de SMTP et de IMAP.

N'hésitez pas à commenter cet article ! Commentez

- Titre : L'Internet Rapide et Permanent

- Auteur : Christian Caleca

- Parution : 18 février 2012

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2012 Christian Caleca. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- 1. Introduction

- 1-1. Avertissement

- 1-2. Problématique

- 1-3. À savoir d'abord

- 1-3-1. Qu'attendons-nous ?

- 1-3-2. Les restrictions imposées

- 1-3-2-1. Blocage du port 25

- 1-3-2-2. Les « BlackLists »

- 1-3-2-3. Adresse de l'émetteur

- 1-3-2-4. Cohérence DNS

- 1-3-2-5. Sender Policy Framework

- 1-3-2-5-1. Le Message est posté localement.

- 1-3-2-5-2. Le message vient du réseau

- 1-3-3. Les messages entrants

- 2. Postfix « deBase »

- 2-1. Ce qui est nécessaire

- 2-2. Anatomie de Postfix

- 2-2-1. Les files d'attente de Postfix

- 2-2-2. Réception d'un e-mail

- 2-2-3. Origine du message

- 2-2-3-1. Traitement du message

- 2-2-3-1-1. Le message n'est pas livrable

- 2-2-3-1-2. Le message est livrable

- 2-2-3-1-2-1. master.cf

- 2-2-3-1-2-2. main.cf

- 2-2-4. Livraison du message

- 2-2-5. Conclusion

- 2-3. Installation et essais

- 2-3-1. Plate-forme de tests

- 2-3-2. Configuration « deBase »

- 2-3-2-1. Envoi local

- 2-3-2-1-1. Les alias

- 2-3-2-1-1-1. Remarque à propos de Bind

- 2-3-2-2. Envoi ailleurs

- 2-4. Bilan

- 2-4-1. Envoi de messages

- 2-4-2. Réception des messages

- 2-4-3. Étape suivante

- 2-4-4. Question philosophique

- 3. Postfix et Dovecot

- 3-1. Configuration de Postfix

- 3-1-1. Passer à Maildir

- 3-1-2. Installation de Dovecot

- 3-1-3. Configuration de Dovecot

- 3-1-3-1. Contenu de dovecot-common

- 3-1-4. Démarrage

- 3-2. Essais IMAP

- 3-3. Plus de BALs...

- 3-3-1. Création du compte

- 3-4. Recevoir du monde

- 3-4-1. Le silence est d'or

- 3-4-1-1. La bannière d'accueil

- 3-4-1-2. La commande « vrfy »

- 3-4-2. La politesse, bordel !

- 3-4-2-1. On se présente...

- 3-4-2-2. Un dialogue « bcbg »

- 3-4-2-2-1. smtpd client restrictions

- 3-4-2-2-2. smtpd sender restrictions

- 3-4-2-2-3. smtpd recipient restrictions

- 3-4-2-3. Vérifions...

- 3-5. Amavis

- 3-5-1. ClamAV et accessoires

- 3-5-2. SpamAssassin

- 3-5-3. amavisd-new

- 3-5-3-1. Configuration d'Amavis

- 3-5-3-1-1. Antivirus et Antispam

- 3-5-3-1-2. Tags artistiques

- 3-5-3-2. Configuration de Postfix

- 3-5-3-2-1. Dans master.cf

- 3-5-3-2-2. Dans main.cf

- 3-5-4. Vérifications

- 3-5-5. Remarque

- 3-6. Relais nomade

- 3-6-1. Configuration de Dovecot

- 3-6-2. Configuration de Postfix

- 3-6-2-1. Sur « main.cf »

- 3-6-2-2. Sur « master.cf »

- 3-6-2-2-1. Vérification (de routine) :

- 3-6-2-2-1-1. Avertissement

- 3-6-2-3. A propos du MDA

- 3-7. Bilan

- 4. Postfix, Dovecot, etc.

- 4-1. Postfix Admin

- 4-1-1. Installation

- 4-1-2. Création de la base

- 4-1-3. Configuration

- 4-1-4. Mise à feu

- 4-1-5. Base de données

- 4-2. Configurer Dovecot

- 4-2-1. Préparatifs

- 4-2-2. Accès à la base

- 4-2-3. Dovecot

- 4-2-4. Vérifications

- 4-3. Configurer Postfix

- 4-3-1. Postfix et MySQL

- 4-3-1-1. Les requêtes SQL

- 4-3-1-1-1. Les domaines virtuels

- 4-3-1-1-2. Les alias

- 4-3-1-1-3. Les boites aux lettres

- 4-3-1-2. le proxy de Postfix

- 4-3-1-3. Vérification

- 4-3-2. Transport dovecot

- 4-4. Plus avec Dovecot

- 4-4-1. Sieve

- 4-4-2. Les quotas

- 4-4-2-1. Philosophie

- 4-4-2-2. Où la mécanique en rajoute

- 4-4-2-3. Le plug-in

- 4-4-2-4. Postfixadmin et les quotas

- 4-5. Bilan d'étape

- 4-5-1. Postfixadmin

- 4-5-2. Dovecot

- 4-5-3. Bonus

- 5. Postfix, Cyrus, etc.

- 5-1. Ce qui existe

- 5-1-1. L'interface graphique

- 5-1-2. Les bases de données

- 5-1-3. Serveurs POP et IMAP

- 5-1-4. Les MTA

- 5-2. Le choix proposé

- 5-3. Web-Cyradm

- 5-3-1. Création de la base

- 5-3-2. Accès à la base

- 5-3-3. Configuration de web-cyradm

- 5-4. S A S L

- 5-4-1. saslauthd

- 5-4-1-1. Installation

- 5-4-1-2. Configuration

- 5-4-2. Et PAM ?

- 5-5. Cyrus-imapd

- 5-5-1. Installation

- 5-5-2. Configuration

- 5-5-2-1. cyrus.conf

- 5-5-2-2. imapd.conf

- 5-5-2-3. Bon. Et PAM ?

- 5-5-3. Vérifications

- 5-5-4. Sieve

- 5-5-5. Note importante

- 5-5-5-1. Suppression d'un message

- 5-6. Postfix avec cyrus

- 5-6-1. Configuration minimale

- 5-6-2. Postfix et MySQL

- 5-6-2-1. Pour « mydestination »

- 5-6-2-2. Pour les alias

- 5-6-2-3. Pour les redirections

- 5-6-2-4. Remarques

- 5-7. Postfix avec SASL

- 5-7-1. Profitons des acquis

- 5-7-2. Et PAM ?

- 5-8. Questions de sécurité

- 5-8-1. Contrôler finement les accès

- 5-8-1-1. Pour imap

- 5-8-1-2. Pour pop

- 5-8-1-3. Pour sieve

- 5-8-1-4. Pour Submission

- 5-8-1-5. Pour les destinataires

- 5-8-2. Restreindre l'utilisateur cyrus

- 5-8-3. Utiliser TLS

- 5-8-3-1. Pour Postfix

- 5-8-3-2. Pour Cyrus-imapd

- 5-8-4. Amavis

- 5-8-5. Interface web

- 5-8-6. limites du système

- 6. Mailing lists

- 6-1. Le principe général

- 6-1-1. Un peu plus de piment ?

- 6-1-2. État des lieux

- 6-1-3. Quelques solutions

- 6-2. Mise en place de Sympa

- 6-2-1. Installation « de base »

- 6-2-2. Vérifications

- 6-2-3. Apache

- 6-2-4. Présentation rapide

- 6-2-5. Et ça marche ?

- 6-2-5-1. Résumé d'intervention

- 6-2-6. C'est tout ?

- 6-3. Domaines virtuels Sympa

- 6-3-1. Le but

- 6-3-2. La méthode

- 6-3-2-1. Étape 1

- 6-3-2-2. Étape 2

- 6-3-2-3. Étape 3

- 6-3-2-4. Étape 4

- 6-3-2-5. Étape 5

- 6-3-2-6. Bilan

- 6-4. Plus loin avec Sympa

- 6-4-1. Versions de Sympa

- 6-4-2. Personnaliser Sympa

- 6-4-2-1. Un « list-subscribe » ?

- 6-4-2-2. Modèles de listes

- 6-4-2-2-1. TT2

- 6-5. Cadeau bonus

- 6-5-1. Les transports

- 6-5-2. Alias virtuels

- 6-5-2-1. Extension d'adresse

- 6-5-2-2. Alias virtuels

- 6-5-3. Transport à la carte

- 6-5-4. Et finalement...

- 6-5-4-1. Avantage

- 6-5-4-2. Inconvénient

- 7. Remerciements Developpez

1 - Introduction

1-1 - Avertissement

Cette suite de chapitres est avant tout destinée à montrer les diverses facettes d'un système de messagerie, de plus en plus complet. Elle n'a pas la prétention de fournir des solutions directement applicables en production, mais plutôt de présenter des pistes de recherche pour obtenir une solution qui réponde aux besoins.

L'étude étant progressive, les derniers chapitres, principalementPostfix, Cyrus, etc. etMailing lists font appel à des notions vues dans les chapitres précédents...

1-2 - Problématique

Mettre en œuvre un système complet de messagerie est une aventure un peu compliquée.

Si l'on souhaite disposer d'un système complet, capable d'envoyer des mails et aussi d'en recevoir pour un ou plusieurs domaines, il faudra également tenir compte des protocoles POP3 et IMAP et installer ce qui va avec.

Il existe dans le monde libre de nombreuses solutions, nous en verrons quelques-unes :

- Postfix pour le SMTP avec un serveur POP/IMAP comme Dovecot, pour gérer un seul domaine ;

- Postfix avec le serveur POP/IMAP nommé Cyrus, pour gérer plusieurs domaines ;

- Qmail, avec Vpopmail et Ezmlm, également pour gérer plusieurs domaines et fournir aussi des listes de diffusion.

Bien sûr, de nombreuses autres combinaisons sont possibles, principalement si l'on doit également tenir compte d'une très forte montée en charge et d'une tolérance de panne très faible.

1-3 - À savoir d'abord

1-3-1 - Qu'attendons-nous ?

Un serveur SMTP en production doit être capable de faire au moins ceci :

- depuis le réseau de son entreprise, nous devons pouvoir envoyer des messages aux comptes de messagerie dont nous avons la gestion ;

- depuis le réseau de son entreprise, nous devons pouvoir envoyer des messages au reste du monde ;

- le reste du monde doit pouvoir envoyer des messages aux comptes de messagerie dont nous avons la gestion ;

- nous ne devons éventuellement servir de relais que dans certains cas bien spécifiques :

- vers des domaines qui nous l'ont expressément demandé ;

- éventuellement, pour des clients qui ont un compte que nous gérons, et qui souhaitent utiliser notre SMTP comme relais. Dans un tel cas, il faut bien entendu mettre en place une stratégie stricte de contrôle des clients autorisés.

En aucun cas nous ne devons pouvoir servir de relais ouvert, c'est-à-dire que n'importe qui puisse utiliser notre service SMTP pour envoyer des messages n'importe où.

1-3-2 - Les restrictions imposées

Si techniquement il est possible de faire tout ceci, le développement du « spam » et les parades qui sont d'usage (plus ou moins pertinent) sur l'Internet vont amener quelques restrictions.

1-3-2-1 - Blocage du port 25

Vous disposez d'un accès que votre fournisseur a bridé. En effet, la solution simple, efficace (et contraire à l'éthique de l'Internet) que votre fournisseur d'accès a mis en place consiste à vous interdire toute connexion TCP vers le port 25, hormis vers le serveur SMTP « officiel » de votre fournisseur.

Dans un tel cas, vous ne pourrez pas faire grand-chose, à part un serveur tampon pour l'envoi de vos messages vers le reste du monde. Si votre fournisseur est dans ce cas et qu'il n'y a pas moyen pour vous de faire débloquer le port 25, abandonnez toute envie de gérer vous-même votre messagerie ou changez de fournisseur.

1-3-2-2 - Les « BlackLists »

Il existe la possibilité, nous le verrons, de créer ou d'utiliser des listes d'exclusions. Ces listes contiennent des adresses IP ou des blocs CIDR d'adresses IP qui sont sensés représenter des SMTP « malpropres ». Certains n'hésitent pas à mettre dans ces listes toutes les adresses IP qui sont utilisées par les fournisseurs d'accès pour leurs clients.

Il n'y a pas de parade. Si l'hébergeur du domaine de messagerie @truc.com utilise une blacklist où vous êtes référencé, vous ne pourrez envoyer par vous-même aucun message @truc.com. Il vous faudra alors passer par le SMTP officiel de votre fournisseur (en priant pour que celui-ci ne soit pas aussi blacklisté).

1-3-2-3 - Adresse de l'émetteur

Une saine précaution (dérisoire toutefois) est de contrôler que l'adresse de l'émetteur (valeur de from: dans le dialogue SMTP) est @unDomaineConnuSurLe.net. Ceci est généralement du ressort de vos utilisateurs qui doivent disposer d'une adresse e-mail valide.

1-3-2-4 - Cohérence DNS

Lors du dialogue entre votre serveur SMTP et celui du destinataire, votre serveur se présente par son nom (valeur helo ou ehlo dans le dialogue SMTP). Le serveur destinataire peut effectuer plusieurs contrôles :

- le domaine annoncé existe-t-il vraiment (contrôle DNS) ?

- le « rdns » (recherche DNS inverse) donne-t-il quelque chose de cohérent ? Autrement dit, si votre serveur se présente comme « smtp.mondomaine.tld » avec l'adresse IP xx.yy.zz.tt, est-ce qu'une recherche rdns aboutit :

- à un nom de machine dans le domaine mondomaine.tld ?

- à un nom de machine égal à smtp.mondomaine.tld ?

- à une machine enregistrée comme MX (Mail Exchanger) pour le domaine mondomaine.tld ?

Si votre fournisseur d'accès vous permet de personnaliser votre rdns, vous pouvez rendre tout cela cohérent.

1-3-2-5 - Sender Policy Framework

Ce très controversé système de contrôle utilise un champ particulier dans les DNS, qui permet d'indiquer quels sont les hôtes autorisés à envoyer des messages pour le domaine dont nous avons la charge. Dans la mesure où vous pouvez créer cette entrée sur vos DNS, faites-le le moins salement possible...

1-3-2-5-1 - Le Message est posté localement.

Le programme Postfix « sendmail » (ne pas confondre avec le MTA concurrent) le dépose dans la file « maildrop » d'où il est retiré par le service « pickup ». Ce service effectue quelques contrôles « sanitaires » dans le but de protéger le reste du système Postfix. Dans le but d'éviter des accidents, les permissions du répertoire contenant « maildrop » sont telles que tout le monde peut y écrire, mais aucun utilisateur ne peut en effacer le contenu.

1-3-2-5-2 - Le message vient du réseau

Le serveur SMTP Postfix reçoit le message et effectue quelques contrôles « sanitaires », toujours dans le but de protéger le reste du système Postfix. Le serveur SMTP peut être configuré pour implémenter des contrôles UCE (Unsollicited Commercial Email) sur la base d'une liste noire locale ou issue du réseau, de vérifications sur les DNS (domaine de l'expéditeur) ou d'autres requêtes sur les informations concernant l'émetteur.

1-3-3 - Les messages entrants

Nous ne devons pas laisser entrer n'importe quoi. Plusieurs cas peuvent se produire :

- nous sommes sur un réseau local ou d'entreprise, le ou les blocs d'adresses IP utilisées sur ce réseau sont connus, nous disposons d'un ou de plusieurs domaines (au sens DNS du terme), les hôtes qui disposent d'une de ces adresses peuvent a priori sans restrictions utiliser notre serveur SMTP pour envoyer des messages à des utilisateurs @nos_domaines, depuis un hôte situé sur notre réseau ;

- les mêmes utilisateurs, lorsqu'ils sont sur notre réseau, doivent pouvoir utiliser notre SMTP pour envoyer des messages au reste du monde ;

- le reste du monde ne doit pouvoir accéder à notre SMTP que pour y déposer des messages à destination de nos domaines ;

- les utilisateurs qui ont un compte de messagerie dans l'un de nos domaines aimeraient pouvoir utiliser notre SMTP pour envoyer des messages au reste du monde, même s'ils ne sont pas connectés sur notre réseau. Ceci ne sera pas forcément possible, ne serait-ce qu'à cause des restrictions que certains fournisseurs (la majorité) mettent sur le port 25 ;

- en aucun cas le monde ne doit pouvoir utiliser notre SMTP pour relayer des messages ailleurs dans le monde.

2 - Postfix « deBase »

Ici, nous allons juste installer un serveur Postfix, qui permettra essentiellement d'envoyer des e-mails depuis notre LAN vers le reste du monde. Nous ne nous occuperons pas trop de la réception, hormis quelques comptes locaux administratifs.

Dans une telle configuration, les utilisateurs qui sont susceptibles de recevoir des messages sont tous titulaires d'un compte local, ce qui simplifie grandement la gestion des boîtes aux lettres et leur accès pour la récupération des messages. À la limite, nous n'aurions même pas besoin d'installer de serveur POP ou IMAP et d'ailleurs, nous ne le ferons pas dans ce chapitre.

2-1 - Ce qui est nécessaire

Pour travailler proprement, nous disposons d'un nom de domaine officiel, enregistré et tout. Par exemple, le domaine « nain-t.net ». Cela sous-entend que nous disposons d'un DNS public qui gère cette zone.

Il nous faut une connexion à l'Internet, avec une adresse IP qui, de préférence, ne change jamais.

Il nous faut enfin une machine pour installer le tout.

2-2 - Anatomie de Postfix

Postfix est un système de messagerie très modulaire. Vous avez ci-dessous le schéma fonctionnel dont  nous allons essayer d'analyser grossièrement le fonctionnement. Tout ce qui suit peut être considéré comme une traduction libre de la documentation officielle du produit. Le site officiel de Postfix se trouve à l'adresse www.postfix.org, avec un site en français qui reprend la quasi-totalité du site officiel.

2-2-1 - Les files d'attente de Postfix

Il y a cinq files d'attente pour les messages :

- « maildrop » qui reçoit les messages postés localement (depuis l'hôte lui-même) ;

- « incoming » qui reçoit aussi bien les messages postés localement que ceux qui arrivent du réseau (lorsque par exemple nous utilisons cet hôte comme serveur smtp pour notre réseau local). Les messages qui arrivent dans cette file ont déjà subi quelques traitements que nous détaillerons plus loin ;

- « active » est la file qui contient les messages en cours d'envoi ;

- « deferred » (différé), contient les messages qui, pour une raison ou une autre, n'ont pu être envoyés. Le protocole SMTP prévoit en effet de ne pas jeter systématiquement les messages qui n'ont pu être envoyés. Les messages classés dans « deferred » subiront plusieurs tentatives d'envoi en étant réinjectés dans « active » ;

- « mailbox » est la file d'attente des messages destinés aux utilisateurs locaux. Nous verrons plus loin son utilité exacte.

Ceux qui souhaitent une description plus détaillée du fonctionnement de Postfix pourront avantageusement se tourner vers « Présentation de l'architecture de Postfix ».

2-2-2 - Réception d'un e-mail

Lorsqu'un message arrive dans le système Postfix, quelle que soit son origine, son premier arrêt se fait dans « incoming ». La figure ci-contre montre les composants qui sont invoqués lors de l'arrivée d'un nouveau message.

2-2-3 - Origine du message

2-2-3-1 - Traitement du message

2-2-3-1-1 - Le message n'est pas livrable

Un e-mail est généré automatiquement par le système Postfix dans le but de renvoyer ce message à son expéditeur. Ce sont les démons « bounce » (rebond) ou « defer » (livraison) qui annoncent la mauvaise nouvelle.

Un e-mail est également généré automatiquement par le système Postfix dans le but de prévenir le responsable de la messagerie en cas de problème. Le système Postfix peut être configuré pour alerter en cas de problème de protocole SMTP, de violation de règles de sécurité UCE, etc. (ce chemin est indiqué sur le graphique par la flèche sans label).

2-2-3-1-2 - Le message est livrable

Le message est transmis par l'agent de livraison local soit par l'intermédiaire d'une entrée de la base de données des « alias » au niveau du système, soit par le fichier « .forward » au niveau de l'utilisateur. Nous reviendrons sur ces notions un peu complexes dans la configuration de Postfix.

Le démon « cleanup » implémente le dernier traitement du message. Il ajoute le champ « Form: » et d'autres en-têtes dans le message, arrange les adresses de réponses dans le format « user@fully.qualified.domain » et optionnellement extrait les adresses des destinataires de l'en-tête. Le démon « cleanup » insère le résultat dans une seule file d'attente : « incoming » et notifie le « queue manager » (qmgr sur le schéma complet) de l'arrivée d'un nouveau message. Le démon « cleanup » peut être configuré pour transformer les adresses sur la base des tables de consultation « canonical » et « virtual ». Nous verrons également cela dans la configuration de Postfix.

Sur la requête du démon « cleanup », le démon « trivial-rewrite » ré-écrit les adresses dans le format standard « user@fully.qualified.domain ».

2-2-3-1-2-1 - master.cf

Ce fichier contient des informations diverses sur le comportement de Postfix et sa façon de faire résider les différents « démons » en mémoire. Nous ne nous en occuperons pas pour l'instant.

2-2-3-1-2-2 - main.cf

Ce fichier contient la configuration principale de Postfix. Dans le cadre de ce que nous voulons faire ici, c'est le seul qu'il nous faudra manipuler dans un premier temps.

Voici ce que nous mettons dans /etc/postfix/main.cf (à peine modifié par rapport à ce que l'on obtient en choisissant le mode « site internet ») :

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:$queue_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${queue_directory}/smtp_scache
myhostname = cyrus.nain-t.net
myorigin = $myhostname
mydestination = $myhostname, localhost
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost =
mynetworks = 127.0.0.0/8 192.168.0.0/24
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

Ce qui est surligné en bleu concerne TLS, ne nous en préoccupons pas pour l'instant, nous n'aurons pas l'occasion de nous en servir ici.

Pour ce qui est surligné en jaune :

- myhostname représente le nom pleinement qualifié du serveur (le nom qui sera utilisé dans le protocole SMTP avec la commande HELO ou EHLO et aussi pour la construction de l'en-tête des messages passant par le MTA) ;

- la valeur de myorigin est ici identique à celle de myhostname ;

- mydestination indique pour quel(s) domaine(s) notre Postfix est le destinataire final. Ici, les adresses considérées comme « locales » seront de la forme @cyrus.nain-t.net ou de la forme @localhost ;

- mynetworks indique quelles sont les adresses IP qui sont autorisées à se connecter à ce MTA. Ici, l'adresse locale et le réseau local (192.168.0.0/24 dans l'exemple).

Pour ce qui est surligné en blanc, le fichier /etc/aliases a son importance, que nous verrons plus tard.

2-2-4 - Livraison du message

Chaque fois qu'un message est déposé dans la file d'attente « incoming », l'étape suivante consiste à le livrer. La figure ci-contre montre les principaux composants de la fonction de livraison de Postfix.

Le gestionnaire de file d'attente est le cœur du système de messagerie Postfix. Il contacte les agents de livraison « local », « smtp » ou « pipe » (les anglophones ont un langage parfois équivoque: faire un « pipe » sur une « queue »...) et envoie une demande de livraison avec le chemin d'accès au fichier qui contient la file d'attente, l'adresse de l'expéditeur, le nom de l'hôte à qui il faut livrer si la destination n'est pas locale, et une où plusieurs adresses de destinataires.

Le gestionnaire maintient une file d'attente « deferred » séparée pour chaque message qui n'a pas pu être livré, de manière à ce qu'un compte rendu de livraison trop volumineux ne vienne pas ralentir l'accès des autres files.

Le gestionnaire maintient une petite file d'attente « active » avec juste quelques messages prêts pour la livraison. « active » agit comme une petite fenêtre sur les files d'attentes « incoming » ou « deferred ». Cette méthode évite au gestionnaire de faire des débordements de mémoire si le serveur est fortement chargé.

Optionnellement, le gestionnaire fait « rebondir » le message pour les destinataires qui sont référencés dans la table « relocated ». Cette table contient des informations sur les utilisateurs qui ont changé d'adresse.

Sur la demande du gestionnaire de file d'attente, le démon « trivial-rewrite » résout les destinations. Par défaut, il fait uniquement la distinction entre les destinations locales ou distantes. Des informations de routage additionnelles peuvent être spécifiées dans la table « transport ».

Sur la demande du gestionnaire de file d'attente, les démons « bounce » et « defer » génèrent des rapports de non-livraison lorsqu'un message ne peut être acheminé, soit à cause d'une erreur non récupérable, soit parce que le destinataire n'est pas joignable pendant une durée trop longue.

L'agent local de la livraison sait gérer les boîtes aux lettres de type UNIX, les bases de données du type « alias » de sendmail (le MTA concurrent), les fichiers de type .forward de l'utilisateur. De multiples agents locaux de livraison peuvent être exécutés en parallèle, mais la livraison en parallèle au même utilisateur est habituellement limitée.

En même temps que l'agent de livraison « sendmail », l'agent de livraison « local » implémente l'interface utilisateur familière de sendmail (le MTA concurrent).

L'agent de la livraison locale a des possibilités pour utiliser d'autres moyens de livraison locale : vous pouvez le configurer pour livrer aux fichiers de boîte aux lettres dans les répertoires locaux d'utilisateur, et vous pouvez même le configurer pour déléguer la livraison de boîte aux lettres à une commande externe telle que le programme populaire « procmail ».

Le client smtp recherche une liste d'échangeurs de courrier pour l'hôte de destination, trie la liste par préférence, et essaye chaque adresse alternativement jusqu'à ce qu'il trouve un serveur qui réponde. Sur un système Postfix chargé, vous verrez plusieurs processus de client de SMTP fonctionner en parallèle.

Le « pipe » est l'interface de sortie vers d'autres transports de courrier (le programme « sendmail » est l'interface d'entrée). Le système de courrier Postfix peut par exemple livrer du courrier par l'intermédiaire du protocole UUCP. Ce protocole vénérable est encore largement répandu. Par défaut, Postfix comprend des adresses de type « bang path » (rassurez-vous, ici on parle de SMTP, pas de UUCP qui n'est plus de mise sur Internet, mais seulement dans des réseaux privés).

2-2-5 - Conclusion

Si vous avez eu le courage de lire cette page jusqu'ici, vous êtes un brave. Si en plus, vous avez tout compris, alors vous êtes remarquable!

Pour résumer la situation, disons que Postfix sait faire les choses suivantes :

- Recevoir du courrier depuis le réseau (cette fonction nous intéresse) ;

- recevoir du courrier depuis l'hôte local (pourquoi ne pas s'en servir?) ;

- acheminer du courrier dont la destination est ailleurs (c'est exactement ce que nous cherchons à faire) ;

- acheminer du courrier localement (pourquoi pas?) ;

- dans tous ces processus, Postfix est capable de modifier quelque peu les en-têtes de messages. Ça n'a pas beaucoup d'intérêt pour nous, sauf dans le cas où nous utiliserons l'hôte de Postfix pour expédier du courrier.

Il y a tout de même un détail qu'il ne faut pas laisser dans l'ombre : Postfix n'est pas un serveur POP ni IMAP. Même s'il sait livrer du courrier local, il ne sait pas gérer les boîtes aux lettres pour des clients distants. Si l'on veut réaliser cette opération, il faudra ajouter un autre logiciel, ce que nous n'allons d'ailleurs pas nous priver de faire...

2-3 - Installation et essais

Nous faisons ici une installation de base, qui sera avant tout destinée à pouvoir envoyer nos e-mails vers le monde et accessoirement gérer quelques boites aux lettres de service, juste pour voir comment Postfix gère les messages entrants. Nous n'attendons pas ici de messages provenant de l'Internet.

2-3-1 - Plate-forme de tests

Nous avons donc une machine nommée cyrus.nain-t.net (vous comprendrez beaucoup plus loin pourquoi elle se nomme comme cela). Elle est animée par une Debian stable (Etch à l'heure où ces lignes sont écrites).

Le domaine nain-t.net est un « vrai » domaine, ne l'oublions pas, ce qui aura son importance par la suite.

aptitude install postfix

Lors du postinstall, vous pouvez laisser Postfix « non configuré », mais le choix de « Site Internet » vous permettra de disposer d'une base de configuration.

2-3-2 - Configuration « deBase »

Il y a deux fichiers importants dans la configuration de Postfix et quelques autres dont l'importance varie en fonction de ce que l'on souhaite faire.

2-3-2-1 - Envoi local

Pour envoyer un message localement, il faut un utilisateur local, qui dispose d'un compte Unix. Nous en créons un qui s'appellera « prof »

adduser prof

Je vous passe les détails de la création de ce compte. Ensuite, il nous faut un outil minimal pour poster un message. mail fait partie du paquet mailx. Donc, si ce n'est déjà fait :

aptitude install mailx

Enfin, « root » va envoyer un message à « prof » :

# mail prof
Subject: test Postfix en local
Bonjour Prof
.
Cc:

Dans le fichier de logs /var/log/mail.info (Sur Debian), nous lisons :

Jun  1 18:09:01 cyrus postfix/pickup[19600]: AF6D367D9E: uid=0 from=<root>
Jun  1 18:09:01 cyrus postfix/cleanup[19681]: AF6D367D9E: message-id=<20080601160901.AF6D367D9E@cyrus.nain-t.net>
Jun  1 18:09:01 cyrus postfix/qmgr[19601]: AF6D367D9E: from=<root@cyrus.nain-t.net>, size=327, nrcpt=1 (queue active)
Jun  1 18:09:01 cyrus postfix/local[19683]: AF6D367D9E: to=<prof@cyrus.nain-t.net>, orig_to=<prof>, relay=local, delay=0.07, delays=0.04/0.01/0/0.01, dsn=2.0.0, status=sent (delivered to mailbox)
Jun  1 18:09:01 cyrus postfix/qmgr[19601]: AF6D367D9E: removed

Les logs disent que tout s'est bien passé. Notez que lors de la manipulation, nous n'avons pas indiqué de domaine de destination (pas de @quelquechose). Postfix en a déduit qu'il s'agissait d'utilisateurs locaux et a donc complété avec le contenu de $myorigin.

Mais où est-ce passé ce message ? Dans /var/mail/ (sur Debian) :

# ls -l /var/mail
total 4
-rw------- 1 prof mail 465 2008-06-01 18:09 prof

Voyons :

# cat /var/mail/prof
From root@cyrus.nain-t.net  Sun Jun  1 18:09:01 2008
Return-Path: <root@cyrus.nain-t.net>
X-Original-To: prof
Delivered-To: prof@cyrus.nain-t.net
Received: by cyrus.nain-t.net (Postfix, from userid 0)
id AF6D367D9E; Sun,  1 Jun 2008 18:09:01 +0200 (CEST)
To: prof@cyrus.nain-t.net
Subject: test Postfix en local
Message-Id: <20080601160901.AF6D367D9E@cyrus.nain-t.net>
Date: Sun,  1 Jun 2008 18:09:01 +0200 (CEST)
From: root@cyrus.nain-t.net (root)

Bonjour Prof

C'est bien lui. Le travail de Postfix pour la livraison locale s'arrête là.

Comme nous sommes curieux, que se passerait-il si root envoyait un message à un compte local qui n'existe pas ?

# mail machin
Subject: test foireux
il n'y a personne ici
.
Cc:

Et voyons les logs :

Jun  1 18:30:54 cyrus postfix/pickup[19719]: 74C0167D9E: uid=0 from=<root>
Jun  1 18:30:54 cyrus postfix/cleanup[19723]: 74C0167D9E: message-id=<20080601163054.74C0167D9E@cyrus.nain-t.net>
Jun  1 18:30:54 cyrus postfix/qmgr[19717]: 74C0167D9E: from=<root@cyrus.nain-t.net>, size=329, nrcpt=1 (queue active)
Jun  1 18:30:54 cyrus postfix/local[19725]: 74C0167D9E: to=<machin@cyrus.nain-t.net>, orig_to=<machin>, relay=local, delay=0.07,delays=0.04/0.01/0/0.01, dsn=5.1.1, status=bounced (unknown user: "machin")
Jun  1 18:30:54 cyrus postfix/cleanup[19723]: 80E9767D9F: message-id=<20080601163054.80E9767D9F@cyrus.nain-t.net>
Jun  1 18:30:54 cyrus postfix/qmgr[19717]: 80E9767D9F: from=<>, size=2093, nrcpt=1 (queue active)
Jun  1 18:30:54 cyrus postfix/bounce[19726]: 74C0167D9E: sender non-delivery notification: 80E9767D9F
Jun  1 18:30:54 cyrus postfix/qmgr[19717]: 74C0167D9E: removed
Jun  1 18:30:54 cyrus postfix/local[19725]: 80E9767D9F: to=<root@cyrus.nain-t.net>, relay=local, delay=0.02, delays=0.01/0/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Jun  1 18:30:54 cyrus postfix/qmgr[19717]: 80E9767D9F: removed

C'est du travail sérieux. Comme le destinataire local n'a pas pu être trouvé par Postfix (par le service « local », en fait), Postfix (le service « bounce », en réalité) a envoyé une notification à l'expéditeur (root). Nous devons nous attendre à trouver un fichier /var/mail/root :

# cat /var/mail/root
From MAILER-DAEMON  Sun Jun  1 18:30:54 2008
Return-Path: <>
X-Original-To: root@cyrus.nain-t.net
Delivered-To: root@cyrus.nain-t.net
Received: by cyrus.nain-t.net (Postfix)
id 80E9767D9F; Sun,  1 Jun 2008 18:30:54 +0200 (CEST)
Date: Sun,  1 Jun 2008 18:30:54 +0200 (CEST)
From: MAILER-DAEMON@cyrus.nain-t.net (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
To: root@cyrus.nain-t.net
Auto-Submitted: auto-replied
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="74C0167D9E.1212337854/cyrus.nain-t.net"
Message-Id: <20080601163054.80E9767D9F@cyrus.nain-t.net>

This is a MIME-encapsulated message.

--74C0167D9E.1212337854/cyrus.nain-t.net
Content-Description: Notification
Content-Type: text/plain; charset=us-ascii

This is the mail system at host cyrus.nain-t.net.

I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.

For further assistance, please send mail to postmaster.

If you do so, please include this problem report. You can
delete your own text from the attached returned message.

The mail system

<machin@cyrus.nain-t.net> (expanded from <machin>): unknown user: "machin"

--74C0167D9E.1212337854/cyrus.nain-t.net
Content-Description: Delivery report
Content-Type: message/delivery-status

Reporting-MTA: dns; cyrus.nain-t.net
X-Postfix-Queue-ID: 74C0167D9E
X-Postfix-Sender: rfc822; root@cyrus.nain-t.net
Arrival-Date: Sun,  1 Jun 2008 18:30:54 +0200 (CEST)

Final-Recipient: rfc822; machin@cyrus.nain-t.net
Original-Recipient: rfc822; machin
Action: failed
Status: 5.1.1
Diagnostic-Code: X-Postfix; unknown user: "machin"

--74C0167D9E.1212337854/cyrus.nain-t.net
Content-Description: Undelivered Message
Content-Type: message/rfc822

Received: by cyrus.nain-t.net (Postfix, from userid 0)
id 74C0167D9E; Sun,  1 Jun 2008 18:30:54 +0200 (CEST)
To: machin@cyrus.nain-t.net
Subject: test foireux
Message-Id: <20080601163054.74C0167D9E@cyrus.nain-t.net>
Date: Sun,  1 Jun 2008 18:30:54 +0200 (CEST)
From: root@cyrus.nain-t.net (root)

il n'y a personne ici

--74C0167D9E.1212337854/cyrus.nain-t.net--

Tout cela appelle deux remarques importantes :

- Le message de notification signale qu'il y a un « postmaster@cyrus.nain-t.net ». Ce compte n'existe pas et il n'est pas forcément bon qu'il existe réellement. Cependant, il faudrait pouvoir traiter les messages pour « postmaster », en les envoyant à quelqu'un d'autre. « root » par exemple ?

- « root » reçoit des messages, c'est bien et c'est mal. root a d'autres choses à faire que d'ouvrir son compte pour lire une messagerie. Nous ne sommes pas ici sous certains systèmes peu sécurisés et l'identité « root », nous le savons, ne doit être utilisée que lorsque c'est absolument nécessaire, certainement pas pour consulter des messages.

Il serait bon que les messages adressés à « root » soient redirigés sur un compte sans privilèges particuliers. Comment réaliser cela ?

2-3-2-1-1 - Les alias

Ici entre en scène le fichier /etc/alias. Ce fichier va expliquer à Postfix que certains destinataires locaux (et seulement locaux) peuvent être redirigés sur d'autres destinataires locaux (ou distants).

Nous allons faire ceci :

- les messages pour « postmaster » seront transmis à « root » ;

- les messages pour « root » seront transmis à « prof » (puisque « prof » n'a pas de privilèges particuliers).

Ainsi, un message envoyé à root sera dirigé sur prof et un message pour postmaster sera dirigé sur root, donc sur prof.

Nous créons (ou modifions) le fichier /etc/aliases comme ceci :

# cat aliases
postmaster: root
root: prof

C'est bien, mais Postfix n'utilisera pas ce fichier. Il lui faudra un fichier formaté comme indiqué dans main.cf :

alias_maps = hash:/etc/aliases

L'utilitaire postalias(1), va le faire pour nous :

# postalias hash:/etc/aliases

Ce qui a créé un fichier /etc/aliases.db, qui n'est pas un simple fichier texte.

Voyons maintenant en envoyant un message à « postmaster » :

# mail postmaster
Subject: essai d'aliases
postmaster -> prof
.
Cc:

Le message est bien envoyé à « postmaster » et dans les logs :

Jun  1 19:33:28 cyrus postfix/pickup[19719]: B43F467D9E: uid=0 from=<root>
Jun  1 19:33:28 cyrus postfix/cleanup[19777]: B43F467D9E: message-id=<20080601173328.B43F467D9E@cyrus.nain-t.net>
Jun  1 19:33:28 cyrus postfix/qmgr[19717]: B43F467D9E: from=<root@cyrus.nain-t.net>, size=333, nrcpt=1 (queue active)
Jun  1 19:33:28 cyrus postfix/local[19779]: B43F467D9E: to=<prof@cyrus.nain-t.net>, orig_to=<postmaster>, relay=local, delay=0.06, delays=0.04/0.01/0/0.01, dsn=2.0.0, status=sent (delivered to mailbox)
Jun  1 19:33:28 cyrus postfix/qmgr[19717]: B43F467D9E: removed

Je vous laisse vérifier dans /var/mail/prof.

Voilà une bonne chose de faite.

2-3-2-1-1-1 - Remarque à propos de Bind

Bind9, le serveur de noms quasi-universellement utilisé sur l'Internet, présente une petite restriction qu'il est important de souligner. En effet, il ne supporte pas que le nom d'hôte indiqué comme MX soit un alias, autrement dit un CNAME.

Évitez donc les ennuis et ne faites pas quelque chose comme :

truc.machin.net.    IN  A      192.168.0.5
cyrus.machin.net.   IN CNAME   truc.machin.net.
machin.net.         IN MX 1    cyrus.machin.net.

Mais plutôt :

cyrus.machin.net.   IN  A      192.168.0.5
truc.machin.net.    IN CNAME   cyrus.machin.net.
machin.net.         IN MX 1    cyrus.machin.net.

2-3-2-2 - Envoi ailleurs

Notre Postfix saurait-il envoyer des messages à des destinataires dans d'autres domaines ? Bien entendu, c'est un vrai serveur SMTP, il sait le faire.

Cependant, lutte antispam obligeant, nous allons rencontrer quelques difficultés. Heureusement, nous avons un « vrai » domaine et la possibilité chez notre fournisseur d'accès de personnaliser le « reverse dns ».

Exemple avant personnalisation :

~$ host cyrus.nain-t.net
lair.nain-t.net has address 82.229.45.192

~$ host 82.229.41.192
192.45.229.82.in-addr.arpa domain name pointer smg13-1-82-229-45-192.fbx.proxad.net.

C'est pas très bon. Il vaudrait bien mieux avoir :

~$ host 82.229.41.132
192.45.229.82.in-addr.arpa domain name pointer cyrus.nain-t.net.

Et nous allons voir pourquoi.

# mail irp@eme-enseignement.fr
Subject: Test distant
Avec de la chance...
on va passer.
.
Cc:

Et dans les logs :

Jun  1 20:00:15 cyrus postfix/pickup[19719]: C736067D9E: uid=0 from=<root>
Jun  1 20:00:15 cyrus postfix/cleanup[19783]: C736067D9E: message-id=<20080601180015.C736067D9E@cyrus.nain-t.net>
Jun  1 20:00:15 cyrus postfix/qmgr[19717]: C736067D9E: from=<root@cyrus.nain-t.net>, size=343, nrcpt=1 (queue active)
Jun  1 20:02:46 cyrus postfix/smtp[19791]: C736067D9E: to=<irp@eme-enseignement.fr>, relay=mx3.ovh.net[213.186.33.73]:25, delay=150, delays=0.01/0.01/60/90, dsn=2.0.0, status=sent (250 ok 1212343362 qp 10101)
Jun  1 20:02:46 cyrus postfix/qmgr[19717]: C736067D9E: removed

C'est passé, mais au bout de 2 minutes 30...

Comme « wireshark » était justement là, nous allons savoir pourquoi :

No.     Time        Source                Destination           Protocol Info
1 0.000000    192.168.0.15          213.186.33.73         TCP      40953 > smtp [SYN] Seq=0 Win=5840 Len=0 MSS=1460 TSV=1433613 TSER=0 WS=5
2 0.056990    213.186.33.73         192.168.0.15          TCP      smtp > 40953 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=48788396 TSER=1433613 WS=9
3 0.057057    192.168.0.15          213.186.33.73         TCP      40953 > smtp [ACK] Seq=1 Ack=1 Win=5856 Len=0 TSV=1433627 TSER=48788396
4 60.158023   213.186.33.73         192.168.0.15          SMTP     Response: 220 mx1.ovh.net mx3.ovh.net mx0.ovh.net. You connect to mail14.ha.ovh.net ESMTP
5 60.158074   192.168.0.15          213.186.33.73         TCP      40953 > smtp [ACK] Seq=1 Ack=82 Win=5856 Len=0 TSV=1448653 TSER=48803421
6 60.158336   192.168.0.15          213.186.33.73         SMTP     Command: EHLO cyrus.nain-t.net
7 60.216044   213.186.33.73         192.168.0.15          TCP      smtp > 40953 [ACK] Seq=82 Ack=27 Win=6144 Len=0 TSV=48803436 TSER=1448653
8 60.216096   213.186.33.73         192.168.0.15          SMTP     Response: 250-mx1.ovh.net mx3.ovh.net mx0.ovh.net. You connect to mail14.ha.ovh.net
9 60.216655   192.168.0.15          213.186.33.73         SMTP     Command: MAIL FROM:<root@cyrus.nain-t.net> SIZE=580
10 60.310846   213.186.33.73         192.168.0.15          TCP      smtp > 40953 [ACK] Seq=268 Ack=115 Win=6144 Len=0 TSV=48803460 TSER=1448667
11 150.278169  213.186.33.73         192.168.0.15          SMTP     Response: 250 ok. I do not like your reverse.
12 150.278436  192.168.0.15          213.186.33.73         SMTP     Command: Received: from [127.0.0.1] (localhost.nain-t.net [127.0.0.1])
13 150.341513  213.186.33.73         192.168.0.15          TCP      smtp > 40953 [ACK] Seq=327 Ack=704 Win=7168 Len=0 TSV=48825967 TSER=1471183
14 150.357314  213.186.33.73         192.168.0.15          SMTP     Response: 250 ok 1212331928 qp 21627
15 150.357489  213.186.33.73         192.168.0.15          SMTP     Response: 221 mx1.ovh.net mx3.ovh.net mx0.ovh.net. You connect to mail14.ha.ovh.net
16 150.357929  192.168.0.15          213.186.33.73         TCP      40953 > smtp [RST, ACK] Seq=704 Ack=431 Win=6912 Len=0 TSV=1471203 TSER=48825971

Après établissement de la connexion TCP (trames 1 à 3) qui se passe normalement, nous voyons que :

- Entre les trames 3 et 4, nous avons 60 secondes d'attente ;

- Entre les trames 10 et 11, nous avons 90 secondes d'attente ;

- Le message de la trame 11 « I do not like your reverse » n'est pas très poli, mais explicite...

Clairement, le MX d'OVH émet quelques doutes sur la légitimité de notre MTA et nous fait perdre du temps volontairement. Le but poursuivi étant le suivant :

Le jeu d'un « spammer », c'est d'envoyer un maximum de messages en un minimum de temps. Si chaque message doit mettre 2 minutes 30 à passer, ce n'est pas intéressant, le spammer laisse tomber.

Nous ne sommes pas des spammers et nous souhaitons ne pas trop perdre de temps dans l'envoi de nos messages. Aussi allons-nous faire ce qu'il faut pour gagner la confiance du MX OVH. Puisque notre nom de domaine existe et que notre fournisseur d'accès nous permet de personnaliser le « rdns », arrangeons-nous pour que la recherche inverse sur notre adresse IP renvoie non pas smg13-1-82-229-45-192.fbx.proxad.net, mais cyrus.nain-t.net.

Nous en profitons pour mettre proprement à jour les informations dns. Nous devons avoir :

- un enregistrement A qui indique l'adresse IP (publique, bien sûr) de notre serveur ;

- un enregistrement MX qui indique le nom de notre MTA. Nous lui mettons la priorité minimale, pour la suite des opérations. Pour l'instant, nous ne gérons pas de boites-aux-lettres @nain-t.net hormis quelques comptes administratifs, donc nous ne devrions rien recevoir de l'Internet (à part du spam, éventuellement).

Une fois le rdsn mis à jour :

Jun  2 09:20:06 cyrus postfix/pickup[3926]: A91E2EEA7: uid=0 from=<root>
Jun  2 09:20:06 cyrus postfix/cleanup[3932]: A91E2EEA7: message-id=<20080602072006.A91E2EEA7@cyrus.nain-t.net>
Jun  2 09:20:06 cyrus postfix/qmgr[3924]: A91E2EEA7: from=<root@cyrus.nain-t.net>, size=319, nrcpt=1 (queue active)
Jun  2 09:20:07 cyrus postfix/smtp[3934]: A91E2EEA7: to=<irp@eme-enseignement.fr>, relay=mx3.ovh.net[213.186.33.73]:25, delay=0.9, delays=0.21/0.1/0.24/0.35, dsn=2.0.0, status=sent (250 ok 1212391203 qp 8008)
Jun  2 09:20:07 cyrus postfix/qmgr[3924]: A91E2EEA7: removed

C'est bien mieux.

2-4 - Bilan

2-4-1 - Envoi de messages

Nous savons envoyer des messages vers le reste du monde, si le reste du monde veut bien accepter notre serveur. Malgré toutes nos précautions, il peut se faire que notre serveur soit rejeté dans certains domaines destinataires. Dans un tel cas, il faudra faire relayer les messages à ce domaine par le serveur SMTP de notre fournisseur d'accès. Cela peut se réaliser en utilisant le paramètre transport_maps. Plus radical, nous pouvons tout faire relayer par le MTA de notre fournisseur d'accès, en l'indiquant avec le paramètre relayhost.

Nous ne gérons pas de boites aux lettres dans notre domaine, hormis le compte administratif qui va collecter les messages émis par les divers services tournant sur notre hôte. Du fait de notre liste d'alias /etc/aliases, tous ces messages doivent se retrouver dans la même boite. Il nous faudra créer des boites aux lettres et installer un moyen d'y accéder à distance.

Nous verrons tout cela dans la prochaine étape.

2-4-2 - Réception des messages

Nous avons vu que ces messages sont stockés au format « mailbox » (tous les messages à la suite, dans un seul fichier). Ce n'est pas terrible, de nos jours où le nombre d'entrées dans les catalogues des systèmes de fichiers n'est plus trop un problème. Il vaudrait mieux exploiter le format Maildir, où chaque message est stocké dans un fichier différent.

Nous n'avons pas installé de serveur POP ni IMAP, ce qui fait que le compte administratif n'est consultable que localement. Il nous faudra prévoir quelque chose de plus souple.

Les boîtes aux lettres nécessitent l'existence d'un compte Unix correspondant. Pas bien pratique et même dangereux, si dans l'avenir nous devons créer de nombreuses boîtes. Ça deviendra même impossible si nous devons gérer plusieurs domaines de messagerie sur le même serveur. Ce serait pas mal que l'on puisse créer des boîtes et les stocker sur la machine, sans pour autant devoir créer un compte Unix. Pour le faire, il faudra que Postfix puisse, d'une manière ou d'une autre, avoir conscience de l'existence de ces boîtes. Il faudra aussi que nos futurs serveurs POP ou IMAP aient un moyen d'identifier ces utilisateurs pour leur donner l'accès à leur boîte.

2-4-3 - Étape suivante

Nous allons passer au format « Maildir », plus sympathique, et installer un serveur POP/IMAP. Nous avons le choix :

- Dovecot est un excellent serveur, plein de possibilités bien qu'encore jeune ;

- la suite Courier propose tout ce qu'il faut pour faire un serveur POP/IMAP de qualité ;

- Cyrus est un peu « usine à gaz », mais propose énormément de fonctionnalités. Nous garderons celui-ci pour la fin.

Dans l'étape suivante, Dovecot fera parfaitement l'affaire.

2-4-4 - Question philosophique

Dans cet exemple très simple d'utilisation de Postfix, 13 lignes suffisent à configurer le MTA, si l'on omet les quelques lignes concernant TLS que nous avons laissées dans la configuration, mais sans les utiliser.

Les étapes suivantes vont nous montrer que Postfix est bien plus configurable et propose bien plus de possibilités, mais au prix d'un fichier de configuration qui va progressivement s'allonger et se compliquer.

Le secret de l'apparente simplicité de cet exemple réside dans les paramètres par défaut de Postfix. Une très grande quantité de paramètres est définie à notre place de façon implicite (invisible dans le fichier de configuration), d'où l'apparente grande simplicité de l'exemple.

L'inconvénient d'une telle approche est que l'on peut acquérir le sentiment que la configuration d'un MTA est facile, ce qui n'est pas du tout le cas. Nous mettons ici une confiance aveugle dans des choix de paramétrage faits à notre place par l'équipe du projet Postfix. Nous pouvons nous le permettre, ce choix étant tout à fait judicieux, mais mieux vaut le savoir. Si nous nous arrêtons ici, nous devons être conscients que nous ne savons encore pratiquement rien de Postfix.

3 - Postfix et Dovecot

Notre postfix « deBase » remplit sa mission d'envoi de messages dans le monde, ne reçoit pas encore de messages venant du monde, mais il est tout de même le destinataire des messages administratifs (ceux qu'envoient les divers services qui tournent sur notre machine).

Pour l'instant, il les stocke au format « mailbox » (tous les messages dans un seul fichier). C'est lourd à gérer, lorsque l'on efface un message on ne fait rien de bien fonctionnel, le fichier garde sa taille. Il faut alors compresser le fichier pour qu'il perde du poids, tout ceci n'est pas très pratique.

De plus nous allons employer surtout IMAP, qui aime le format « Maildir ».

A l'issue de cette installation, nous disposerons d'un système que l'on peut déposer dans un placard (ventilé, tout de même) qui saura envoyer nos messages et sur lequel la boite aux lettres administrative pourra être consultée et gérée à distance. Il sera même possible de créer quelques comptes pour des utilisateurs, mais avec l'ennui que ces derniers devront posséder un compte Unix. Les risques seront éventuellement minimisés en n'attribuant pas de « shell » à ces comptes.

Nous pourrons alors commencer à envisager de recevoir des messages pour ces comptes depuis le monde.

Bien entendu, du moment que l'on attend des messages qui viennent de l'internet, il faudra envisager des mesures de sécurité, de lutte antispam, antivirus, etc.

Enfin, soyons fous, pourquoi ne pas envisager de permettre à notre système de relayer les messages depuis l'internet vers l'internet ? Mais à condition bien sûr que l'utilisateur se soit d'abord authentifié. (Pas de relais ouvert, tout de même...)

3-1 - Configuration de Postfix

3-1-1 - Passer à Maildir

Première chose à faire, passer au format « Maildir ». C'est extrêmement simple, il suffit d'ajouter une ligne à notre /etc/postfix/main.cf :

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:$queue_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${queue_directory}/smtp_scache
myhostname = cyrus.nain-t.net
myorigin = $myhostname
mydestination = $myhostname, localhost
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost =
mynetworks = 127.0.0.0/8 192.168.0.0/24
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
home_mailbox = Maildir/

Essayons :

mail prof
Subject: Test Maildir
Nous passons a Maildir
.
Cc:

Dans les logs :

Jun  3 14:22:58 cyrus postfix/pickup[20275]: 26D4D67D9E: uid=0 from=<root>
Jun  3 14:22:58 cyrus postfix/cleanup[20287]: 26D4D67D9E: message-id=<20080603122258.26D4D67D9E@cyrus.nain-t.net>
Jun  3 14:22:58 cyrus postfix/qmgr[20273]: 26D4D67D9E: from=<root@cyrus.nain-t.net>, size=329, nrcpt=1 (queue active)
Jun  3 14:22:58 cyrus postfix/local[20289]: 26D4D67D9E: to=<prof@cyrus.nain-t.net>, orig_to=<prof>, relay=local, delay=0.05, delays=0.03/0.01/0/0, dsn=2.0.0, status=sent (delivered to maildir)
Jun  3 14:22:58 cyrus postfix/qmgr[20273]: 26D4D67D9E: removed

Tout s'est bien passé. Mais où est allé notre message ? Est-il toujours dans /var/mail/ ? Non. Tout se passe désormais dans le répertoire de l'utilisateur :

# su prof
prof@cyrus:~/Maildir/new$ cd ~

prof@cyrus:~$ ls
Maildir

prof@cyrus:~$ cd Maildir/
prof@cyrus:~/Maildir$ ls
cur  new  tmp

prof@cyrus:~/Maildir$ cd new/
prof@cyrus:~/Maildir/new$ ls
1212495778.V306I7b467M188615.cyrus

prof@cyrus:~/Maildir/new$ cat 1212495778.V306I7b467M188615.cyrus
Return-Path: <root@cyrus.nain-t.net>
X-Original-To: prof
Delivered-To: prof@cyrus.nain-t.net
Received: by cyrus.nain-t.net (Postfix, from userid 0)
id 26D4D67D9E; Tue,  3 Jun 2008 14:22:58 +0200 (CEST)
To: prof@cyrus.nain-t.net
Subject: Test Maildir
Message-Id: <20080603122258.26D4D67D9E@cyrus.nain-t.net>
Date: Tue,  3 Jun 2008 14:22:58 +0200 (CEST)
From: root@cyrus.nain-t.net (root)

Nous passons a Maildir
prof@cyrus:~/Maildir/new$

Dans le « home » de l'utilisateur, Postfix a créé un répertoire Maildir. Dedans, il y a 3 répertoires : cur, new et tmp. C'est dans new que Postfix range les messages entrants, un message par fichier. /var/mail/prof n'a plus de service.

Reste maintenant à installer Dovecot pour permettre d'exploiter à distance le contenu de ~/Maildir, par l'entremise d'IMAP et éventuellement POP3.

3-1-2 - Installation de Dovecot

Dovecot est fourni dans toutes les « bonnes » distributions GNU/Linux (et Debian en est une).

# aptitude search dovecot
p   dovecot-common                 - secure mail server that supports mbox and maildir mailboxes
p   dovecot-imapd                  - secure IMAP server that supports mbox and maildir mailboxes
p   dovecot-pop3d                  - secure POP3 server that supports mbox and maildir mailboxes

Dovecot est donc fourni sous la forme de trois paquets. Nous sommes ici pour être curieux, donc nous allons essayer aussi bien le POP3 que l'IMAP (cependant, vous essayerez tout seul les possibilités de POP3 si le cœur vous en dit) :

# aptitude install dovecot-common dovecot-imapd dovecot-pop3d
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances... Fait
Lecture de l'information d'état étendu
Initialisation de l'état des paquets... Fait
Lecture des descriptions de tâches... Fait
Construction de la base de données des étiquettes... Fait
Les NOUVEAUX paquets suivants vont être automatiquement installés :
dovecot-common libmysqlclient15off libpq4 libsqlite3-0 mysql-common
Les NOUVEAUX paquets suivants vont être installés :
dovecot-common dovecot-imapd dovecot-pop3d libmysqlclient15off libpq4 libsqlite3-0 mysql-common
0 paquets mis à jour, 6 nouvellement installés, 0 à enlever et 0 non mis à jour.
Il est nécessaire de télécharger 3999ko d'archives. Après dépaquetage, 8377ko seront utilisés.
Voulez-vous continuer ? [Y/n/?]
...
Paramétrage de dovecot-common (1.0.rc15-2etch4) ...
adduser : Attention : ce répertoire personnel n'appartient pas à
l'utilisateur que vous êtes en train de créer.
Ajout de l'utilisateur « dovecot » au groupe « mail »...
Terminé.
Creating generic self-signed certificate: /etc/ssl/certs/dovecot.pem
(replace with hand-crafted or authorized one if needed).

Paramétrage de dovecot-imapd (1.0.rc15-2etch4) ...

Bon. Pourquoi des choses qui parlent de mysql, de sqlite et de papier hygiénique ?

Alors... D'abord, libpq n'a rien à voir avec le rouleau de papier, c'est une librairie cliente de PostgreSQL, l'autre base de données populaire dans le monde GNU. Donc, clairement, Dovecot sait utiliser des bases de données SQL (Postfix aussi d'ailleurs). Ici, nous n'en aurons pas besoin, mais l'usage d'une base de données est bien pratique lorsque nous avons plusieurs domaines à gérer ainsi qu'un grand nombre d'utilisateurs qui n'ont pas de compte Unix associé. Il s'agit de la gestion de domaines « virtuels » que nous aborderons dans le chapitre suivant.

3-1-3 - Configuration de Dovecot

3-1-3-1 - Contenu de dovecot-common

C'est dans ce paquets que se trouve la structure de configuration :

# dpkg -L dovecot-common
/.
/etc
/etc/ssl
/etc/ssl/certs
/etc/ssl/private
/etc/dovecot
/etc/dovecot/dovecot.conf
/etc/dovecot/dovecot-ldap.conf
/etc/dovecot/dovecot-sql.conf
/etc/pam.d
/etc/pam.d/dovecot
/etc/init.d
/etc/init.d/dovecot
/usr
/usr/sbin
/usr/sbin/dovecot
/usr/sbin/dovecotpw
/usr/share
...
/usr/share/doc
...
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/maildirmake.dovecot.1.gz
/usr/lib
...
/usr/bin
/usr/bin/maildirmake.dovecot
/var
...

Non seulement nous avons sql, mais il semble bien que ldap soit aussi utilisable...

À vue de nez, c'est /etc/dovecot/dovecot.conf qui va nous être le plus utile pour ce que nous avons à faire. Ce fichier est assez particulier :

- il sert aussi de documentation ;

- il indique assez clairement les paramètres de configuration pris par défaut par les services dovecot.

En réalité, nous aurons très peu de choses à y mettre. Une première lecture rapide nous laisse entendre que :

- il faudra indiquer quels services nous voulons activer (pop3 et imap dans un premier temps) ;

- il faudra donner le chemin aux répertoires Maildir des utilisateurs ;

- il faudra indiquer quelle méthode nous choisissons pour authentifier les utilisateurs.

Peut-être que Debian a déjà fait pas mal de travail à notre place ?

# cat dovecot.conf | egrep -v -e '^[[:blank:]]*#|^$'
protocols =
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_privileged_group = mail
protocol imap {
}

protocol pop3 {
pop3_uidl_format = %08Xu%08Xv
}
auth default {
mechanisms = plain
passdb pam {
}
userdb passwd {
}
user = root
}
dict {
}
plugin {
}

A priori, pour ce que nous avons à faire, c'est presque bon :

- mécanisme d'authentification en texte clair ;

- le système utilisera PAM pour vérifier le mot de passe de l'utilisateur qui se connecte. Dovecot a installé un fichier dovecot dans /etc/pam.d dans ce but ;

- c'est le fichier passwd qui sera utilisé comme base de données des utilisateurs. De ce fait, l'utilisateur sous le compte duquel dovecot va effectuer l'authentification devra ici être root.

Voyez le dovecot.conf d'usine pour tous les détails sur les divers modes d'authentification possibles.

Dans un premier temps, nous n'avons donc qu'à compléter la ligne protocols comme suit :

protocols = pop3 imap

En ce qui concerne l'accès aux ~/Maildir, c'est l'option par défaut, donc pas besoin de le spécifier.

3-1-4 - Démarrage

# /etc/init.d/dovecot restart
Restarting mail server: dovecot.
# netstat -a | grep :pop
tcp        0      0 *:pop3                  *:*                     LISTEN

# netstat -a | grep :imap
tcp        0      0 *:imap2                 *:*                     LISTEN

Il est à l'écoute.

3-2 - Essais IMAP

Une fois débarrassé de ses commentaires, le fichier dovecot.conf semble très simple. Ne nous y trompons pas, il l'est encore une fois à cause des options par défaut (qui sont en très grand nombre ici).

Premier exemple amusant, nous allons tester par telnet (car bien entendu, nous connaissons par cœur les commandes du protocole IMAP), en local, puis à distance.

En local

À distance

~# telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK Dovecot ready.
20 capability
* CAPABILITY IMAP4rev1 SASL-IR SORT THREAD=REFERENCES
MULTIAPPEND UNSELECT LITERAL+ IDLE
CHILDREN NAMESPACE LOGIN-REFERRALS
STARTTLS AUTH=PLAIN
20 OK Capability completed.
40 login prof epikoi
40 OK Logged in.
60 logout
* BYE Logging out
60 OK Logout completed.
Connection closed by foreign host.

chris@pchris2:~$ telnet cyrus.nain-t.net 143
Trying 192.168.0.18...
Connected to cyrus.nain-t.net.
Escape character is '^]'.
* OK Dovecot ready.
20 capability
* CAPABILITY IMAP4rev1 SASL-IR SORT THREAD=REFERENCES
MULTIAPPEND UNSELECT LITERAL+ IDLE
CHILDREN NAMESPACE LOGIN-REFERRALS
STARTTLS LOGINDISABLED
20 OK Capability completed.
40 login prof epikoi
* BAD [ALERT] Plaintext authentication
is disabled, but your client sent
password in plaintext anyway.
If anyone was listening,
the password was exposed.
40 NO Plaintext authentication disabled.
60 logout
* BYE Logging out
60 OK Logout completed.
Connection closed by foreign host.

Par défaut, l'authentification en mode « plaintext » fonctionne en local, mais pas à distance. Bien entendu, il est possible de modifier ce comportement, mais ce n'est pas souhaitable.

Vérifions tout ceci avec Thunderbird sur un poste du réseau. Configurons notre oiseau du tonnerre pour aller lire la boite-aux-lettres de prof sur cyrus.nain-t.net et vérifions que la lecture n'est possible qu'à certaines conditions :

Ben oui, nous étions prévenus. Il est temps de changer ses habitudes et de venir à un système chiffré. IMAP TLS utilise le même port que IMAP, mais envoie la commande STARTTLS pour débuter un chiffrement de la communication, tandis que IMAP SSL utilise un autre port et chiffre tout l'ensemble de la communication. Il s'agit d'un autre service, à part entière, que nous n'avons d'ailleurs pas démarré, il s'agit de IMAPS. Essayons de cocher « TLS, si possible » ou même « TLS » dans les paramètres de sécurité des paramètres du serveur du compte IMAP que nous avons créé dans notre Thunderbird, et voyons :

Ici, ça devient sérieux. Nous sommes en mode chiffré, Cyrus nous envoie son certificat, mais il n'est pas signé par une racine de confiance. Dovecot a créé un certificat autosigné lors de son installation. Voyons ce certificat :

Si nous devions faire du travail de pro, il nous faudrait obtenir un certificat pour Cyrus, signé par une racine de confiance. Nous nous en passerons ici et nous accepterons de façon définitive ce certificat. Par la suite, nous verrons comment réaliser une autorité racine « maison » et signer nos certificats avec. L'interface TinyCA permet avec Openssl de réaliser ces choses assez simplement.

Nous retrouvons bien le message envoyé à « prof » il y a déjà quelques temps.

Nous ne sommes pas ici pour étudier IMAP, c'est déjà fait ailleurs. Il n'est donc pas utile de vérifier que la connexion IMAP est bien chiffrée pour tout ce qui concerne le login et les données, ni que le dialogue IMAP est bien correct. Ça fonctionne, ça nous suffira ici.

C'est du Maildir, nous pouvons créer à distance autant de dossiers dans des dossiers qu'il sera nécessaire pour bien classer nos messages. C'est un vrai serveur IMAP quoi.

Et d'où viennent donc ces certificats utilisés avec STARTTLS ? Des options par défaut... Mais lisez donc le dovecot.conf d'usine !

3-3 - Plus de BALs...

Pour la beauté du geste, et aussi pour constater que ce n'est pas forcément bien pratique, nous allons créer un compte de messagerie pour un utilisateur lambda.

Il faut un compte Unix, mais cet utilisateur lambda n'a pas besoin de shell, il ne doit pas pouvoir lancer de commandes sur cyrus. Il doit juste disposer d'un répertoire dans lequel Postfix déposera la structure Maildir et les messages entrants et dans lequel Dovecot ira récupérer ces messages pour les présenter au client.

3-3-1 - Création du compte

# adduser --shell /bin/false lambda

Nous avons bien dans /etc/passwd :

lambda:x:1002:1002:,,,:/home/lambda:/bin/false

Il n'y a plus qu'à essayer, avec notre oiseau du tonnerre, d'envoyer un message à lambda :

Et dans les logs :

Jun  3 16:41:11 cyrus postfix/smtpd[20702]: connect from unknown[192.168.10.47]
Jun  3 16:41:11 cyrus postfix/smtpd[20702]: 8FB3567D9D: client=unknown[192.168.10.47]
Jun  3 16:41:11 cyrus postfix/cleanup[20707]: 8FB3567D9D: message-id=<48455808.5070500@nain-t.net>
Jun  3 16:41:11 cyrus postfix/qmgr[20273]: 8FB3567D9D: from=<prof@nain-t.net>, size=529, nrcpt=1 (queue active)
Jun  3 16:41:11 cyrus postfix/smtpd[20702]: disconnect from unknown[192.168.10.47]
Jun  3 16:41:11 cyrus postfix/local[20708]: 8FB3567D9D: to=<lambda@cyrus.nain-t.net>, relay=local, delay=0.05, delays=0.03/0.01/0/0.01, dsn=2.0.0, status=sent (delivered to maildir)

C'est passé dirait-on. Vérifions après avoir créé un compte pour lambda dans notre oiseau :

Notez que nous avons dû utiliser l'adresse lambda@cyrus.nain-t.net pour que ça fonctionne. Si nous avions utilisé lambda@nain-t.net, Postfix aurait mal réagi :

Dans les logs :

Jun  3 16:50:40 cyrus postfix/smtpd[20716]: connect from unknown[192.168.10.47]
Jun  3 16:50:40 cyrus postfix/smtpd[20716]: NOQUEUE: reject: RCPT from unknown[192.168.10.47]: 554 5.7.1 <lambda@nain-t.net>: Relay access denied; from=<prof@nain-t.net> to=<lambda@nain-t.net> proto=ESMTP helo=<[192.168.10.47]>
Jun  3 16:51:09 cyrus postfix/smtpd[20716]: disconnect from unknown[192.168.10.47]

Tout simplement parce que notre postfix ne sait pas que tout le domaine nain-t.net fait partie de ses destinations :

mydestination = $myhostname, localhost

Modifions comme ceci :

mydestination = $mydomain, $myhostname, localhost

Et désormais, les adresses lambda@nain-t.net et prof@nain-t.net deviennent des destinations valides pour notre cyrus.

3-4 - Recevoir du monde

Nous pouvons maintenant commencer à envisager de recevoir des messages depuis le monde vers nos comptes @nain-t.net.

Nous devons déjà nous assurer que le DNS qui gère le domaine nain-t.net répond correctement à une requête de type MX :

# host -t MX nain-t.net
nain-t.net mail is handled by 1 cyrus.nain-t.net.

C'est le cas. Il va falloir tout de même prévoir quelques mesures sanitaires en conséquence.

3-4-1 - Le silence est d'or

3-4-1-1 - La bannière d'accueil

Est-il bien nécessaire que notre postfix s'annonce de manière si explicite ? Non. Seul le nom d'hôte est obligatoire. Notre Postfix se présente actuellement comme ceci :

$ telnet cyrus.nain-t.net 25
Trying 192.168.10.7...
Connected to cyrus.nain-t.net.
Escape character is '^]'.
220 cyrus.nain-t.net ESMTP Postfix (Debian/GNU)

Ce n'est pas nécessaire d'indiquer à tout le monde que nous utilisons Postfix sur une Debian. Modifions notre smtp_banner en fonction :

smtpd_banner = $myhostname ESMTP Experimental

Et vérifions :

$ telnet cyrus.nain-t.net 25
Trying 192.168.10.7...
Connected to cyrus.nain-t.net.
Escape character is '^]'.
220 cyrus.nain-t.net ESMTP Experimental

C'est mieux, c'est plus discret, c'est moins extraverti.

3-4-1-2 - La commande « vrfy »

SMTP prévoit la commande vrfy <username> qui permet à un client de savoir si un utilisateur existe ou non dans le domaine :

vrfy lambda
252 2.0.0 lambda
vrfy truc
550 5.1.1 : Recipient address rejected: User unknown in local recipient table

Cette commande est bien utile pour des besoins de mise au point, mais à quoi bon donner aux spammers un moyen simple de trouver ce genre d'informations ?

disable_vrfy_command = yes

va arranger ça :

vrfy lambda
502 5.5.1 VRFY command is disabled

3-4-2 - La politesse, bordel !

3-4-2-1 - On se présente...

SMTP prévoit que les MTA sont polis. Ils se présentent avec la commande EHLO (ou HELO). Il est possible d'éjecter simplement les malpolis en indiquant à Postfix que :

smtpd_helo_required = yes

Voyons :

$ telnet cyrus.nain-t.net 25
Trying 192.168.10.7...
Connected to cyrus.nain-t.net.
Escape character is '^]'.
220 cyrus.nain-t.net ESMTP Experimental
MAIL FROM: <machin@truc.com>
503 5.5.1 Error: send HELO/EHLO first

3-4-2-2 - Un dialogue « bcbg »

Postfix permet de placer des restrictions plus ou moins serrées lors du dialogue SMTP, principalement sur les commandes MAIL FROM: et RCPT TO:, ainsi que sur l'adresse IP du client.

3-4-2-2-1 - smtpd client restrictions

Le paramètre smtpd_client_restrictions permet de contrôler qui se connecte à notre MTA. Par défaut, ce paramètre n'applique aucune restriction.

Nous pouvons vérifier que les clients ne sont pas référencés sur des « blacklists » réputées :

smtpd_client_restrictions =
permit_mynetworks,                                # Nous faisons confiance aux clients de notre réseau
reject_rbl_client blackholes.easynet.nl,          # mais pas à ceux qui sont "blacklistés"
reject_rbl_client cbl.abuseat.org,
reject_rbl_client proxies.blackholes.wirehub.net,
reject_rbl_client bl.spamcop.net,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client dnsbl.njabl.org,
reject_rbl_client list.dsbl.org,
permit

Les règles sont lues de gauche à droite (de haut en bas dans notre façon de l'écrire) et la première règle vérifiée est la bonne. Les autres sont donc ignorées. Ici, les réseaux spécifiés dans $mynetworks sont permis et dans ce cas le filtrage n'ira pas plus loin. En revanche, si le client qui se connecte n'est pas dans $mynetworks, Postfix va vérifier qu'il n'est référencé dans aucune des « blacklists » indiquées avant de lui permettre (permit en fin de liste) de se connecter.

Le principe de ces listes est simple. Postfix va effectuer une requête dns inverse (rdns) à partir de l'adresse IP du client, inversée et apposée au domaine annoncé de la liste noire :

$ host 95.57.127.82.sbl.spamhaus.org

Si la réponse est :

Host 95.57.127.82.sbl.spamhaus.org not found: 3(NXDOMAIN)

C'est que l'adresse 82.127.57.95 n'est pas référencée. Si au contraire, la réponse est :

95.57.127.82.sbl.spamhaus.org has address 82.127.57.95

C'est que l'adresse 82.127.57.95 est référencée. Le client sera alors rejeté.

Nous pouvons utiliser plusieurs blacklists, au détriment des ressources consommées sur le serveur, au risque de voir ces clients rejetés par erreur... Le postmaster doit donc rester attentif.

3-4-2-2-2 - smtpd sender restrictions

La commande MAIL FROM: doit indiquer l'adresse (de messagerie) de l'émetteur du message. Nous pouvons vérifier certaines choses à ce niveau et nous allons le faire, par l'intermédiaire de la directive smtpd_sender_restrictions :

smtpd_sender_restrictions =
permit_mynetworks,                                 # Nous faisons confiance aux clients de notre réseau
reject_non_fqdn_sender,                            # machin@chose ne passera pas
reject_unknown_sender_domain,                      # machin@truc.tld ne passera pas
permit

3-4-2-2-3 - smtpd recipient restrictions

Ces restrictions touchent à ce qu'il y a dans la commande RCPT TO:. La valeur par défaut (permit_mynetworks, reject_unauth_destination) est acceptable, mais il est possible de restreindre d'avantage. Voyez la documentation de Postfix officielle ou sa traduction en français pour plus de détails.

3-4-2-3 - Vérifions...

Nous avons désormais un main.cf qui ressemble à ceci :

smtpd_banner = $myhostname ESMTP Experimental
disable_vrfy_command = yes
smtpd_helo_required = yes
smtpd_sender_restrictions =
permit_mynetworks,
reject_non_fqdn_sender
reject_unknown_sender_domain,
permit

smtpd_client_restrictions =
permit_mynetworks,
reject_rbl_client blackholes.easynet.nl,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client proxies.blackholes.wirehub.net,
reject_rbl_client bl.spamcop.net,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client dnsbl.njabl.org,
permit

biff = no
append_dot_mydomain = no
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${queue_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${queue_directory}/smtp_scache
myhostname = cyrus.nain-t.net
myorigin = $myhostname
mydestination = $mydomain, $myhostname, localhost
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost =
mynetworks = 127.0.0.0/8 192.168.0.0/24
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
home_mailbox = Maildir/

Depuis un client de l'internet, nous allons, en passant par le SMTP du fournisseur de ce client, envoyer un message à lambda@nain-t.net. Observons les logs sur cyrus.nain-t.net :

Jun  4 11:24:54 cyrus postfix/smtpd[21077]: connect from smtp21.orange.fr[80.12.242.49]
Jun  4 11:24:55 cyrus postfix/smtpd[21077]: B230A67D9D: client=smtp21.orange.fr[80.12.242.49]
Jun  4 11:24:55 cyrus postfix/cleanup[21082]: B230A67D9D: message-id=<48465F65.4020809@eme-enseignement.fr>
Jun  4 11:24:55 cyrus postfix/smtpd[21077]: disconnect from smtp21.orange.fr[80.12.242.49]
Jun  4 11:24:55 cyrus postfix/qmgr[21075]: B230A67D9D: from=, size=1243, nrcpt=1 (queue active)
Jun  4 11:24:55 cyrus postfix/local[21083]: B230A67D9D: to=, relay=local, delay=0.98, delays=0.96/0.01/0/0.01, dsn=2.0.0, status=sent (delivered to maildir)
Jun  4 11:24:55 cyrus postfix/qmgr[21075]: B230A67D9D: removed

C'est bon ça.

Allons lire ce message avec notre oiseau du tonnerre, via Dovecot (code source du message) :

Return-Path: <christian.caleca@exe-enxeignexent.fr>
X-Original-To: lambda@nain-t.net
Delivered-To: lambda@nain-t.net
Received: from smtp21.orange.fr (smtp21.orange.fr [80.12.242.49])
by cyrus.nain-t.net (Postfix) with ESMTP id B230A67D9D
for <lambda@nain-t.net>; Wed,  4 Jun 2008 11:24:54 +0200 (CEST)
Received: from me-wanadoo.net (localhost [127.0.0.1])
by mwinf2121.orange.fr (SMTP Server) with ESMTP id 46CF01C004ED
for <lambda@nain-t.net>; Wed,  4 Jun 2008 11:24:54 +0200 (CEST)
Received: from jupiter.eme.org (LSt-Amand-152-32-18-95.w82-127.abo.wanadoo.fr [82.127.57.95])
by mwinf2121.orange.fr (SMTP Server) with ESMTP id 2EDE51C0044A
for <lambda@nain-t.net>; Wed,  4 Jun 2008 11:24:54 +0200 (CEST)
X-ME-UUID: 20080604092454192.2EDE51C0044A@mwinf2121.orange.fr
Received: from [172.16.129.250] (p-caleca.eme.org [172.16.129.250])
by jupiter.eme.org (Postfix) with ESMTP id C61C81E3
for <lambda@nain-t.net>; Wed,  4 Jun 2008 11:24:53 +0200 (CEST)
Message-ID: <48465F65.4020809@eme-enseignement.fr>
Date: Wed, 04 Jun 2008 11:24:53 +0200
From: Christian Caleca <christian.caleca@exe-enxeignexent.fr>
User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
MIME-Version: 1.0
To: lambda@nain-t.net
Subject: Test lointain
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit

Et ça passe. :p

Notre MTA est devenu aussi MX et nous pouvons désormais recevoir des messages depuis le monde.

3-5 - Amavis

Pour river leur clou aux virus et autres spams.

Nous avons déjà pas mal protégé notre serveur, mais tout de même...

- les virus peuvent encore passer ;

- les blacklists ne suffisent pas à limiter le spam.

L'idéal serait de pouvoir connecter notre Postfix à des outils comme ClamAV et SpamAssassin, pour améliorer encore notre bien-être. Amavis est là pour répondre à cette question.

Amavis va servir de glu pour passer les messages entrants à des filtres comme ClamAV et SpamAssassin. Nous allons mettre ClamAV à l'œuvre. Spamassassin.

Le module smtpd va se connecter à Amavis par une connexion TCP sur le port 10024 par défaut. Lorsqu'un message entrera sur smtpd, ce dernier le transmettra au service amavisd.

Celui-ci va filtrer le message en le passant à ClamAV (et à SpamAssassin s'il est en état de fonctionner).

Amavis va alors retransmettre un message à smtpd toujours par une connexion TCP, sur le port 10025 par défaut. Ce message retransmis pourra avoir plusieurs formes suivant le cas :

- le message est sain, il est retransmis tel quel ;

- le message contient un virus. Dans ce cas, Amavis mettra le message en quarantaine, enverra une notification au destinataire pour l'avertir qu'un message vérolé lui a été envoyé et éventuellement une notification à l'envoyeur pour lui signaler que son message n'a pas été remis. L'administrateur du site pourra également être notifié ;

- le message est supposé être un spam, il est alors marqué comme tel, puis remis dans la chaine de distribution. Il est en effet malvenu de détruire ce qui est supposé être un spam, la détection étant toujours approximative (faux positifs). Suivant le « score » que SpamAssassin aura attribué au message, l'attitude pourra tout de même évoluer. Ainsi un message recevant un score sans appel pourra être tout de même détruit.

3-5-1 - ClamAV et accessoires

Debian stable c'est bien, mais ça vieillit parfois assez mal. Ce n'est souvent pas très gênant, sauf pour des applications comme ClamAV ou SpamAssassin. Le dépôt « volatile » est là pour pallier cet inconvénient. Il y a toute une série de miroirs dans le monde, choisissez celui qui vous convient et ajoutez-le à votre source.list.

Il faut installer :

# aptitude search clamav | grep ^i
i   clamav                          - anti-virus utility for Unix - command-line
i A clamav-base                     - anti-virus utility for Unix - base package
i   clamav-daemon                   - anti-virus utility for Unix - scanner daem
i A clamav-freshclam                - anti-virus utility for Unix - virus databa
i   clamav-testfiles                - anti-virus utility for Unix - test files
i A libclamav4                      - anti-virus utility for Unix - library

clamav-testfiles est optionnel, il fournit des fichiers de test.

3-5-2 - SpamAssassin

SpamAssassin mériterait à lui seul tout un chapitre. Nous nous contenterons ici de la configuration par défaut, juste pour vérifier que notre montage fonctionne.

3-5-3 - amavisd-new

Passons à la glu :

~# aptitude install amavisd-new
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances... Fait
Lecture de l'information d'état étendu
Initialisation de l'état des paquets... Fait
Lecture des descriptions de tâches... Fait
Construction de la base de données des étiquettes... Fait
Les NOUVEAUX paquets suivants vont être automatiquement installés :
libarchive-tar-perl libarchive-zip-perl libberkeleydb-perl libcompress-zlib-perl libconvert-binhex-perl
libconvert-tnef-perl libconvert-uulib-perl libio-multiplex-perl libio-stringy-perl libio-zlib-perl
libmailtools-perl libmime-perl libnet-cidr-perl libnet-server-perl libtimedate-perl libunix-syslog-perl
Les NOUVEAUX paquets suivants vont être installés :
amavisd-new libarchive-tar-perl libarchive-zip-perl libberkeleydb-perl libcompress-zlib-perl
libconvert-binhex-perl libconvert-tnef-perl libconvert-uulib-perl libio-multiplex-perl libio-stringy-perl
libio-zlib-perl libmailtools-perl libmime-perl libnet-cidr-perl libnet-server-perl libtimedate-perl
libunix-syslog-perl
0 paquets mis à jour, 17 nouvellement installés, 0 à enlever et 0 non mis à jour.
Il est nécessaire de télécharger 1772ko d'archives. Après dépaquetage, 5468ko seront utilisés.
Voulez-vous continuer ? [Y/n/?]
...

Ce n'est pas parce que c'est installé que ça va coller tout seul. Nous avons un /usr/share/doc/amavisd-new/README.postfix.gz qui va bien nous aider à l'interfacer avec Postfix.

3-5-3-1 - Configuration d'Amavis

La configuration d'amavisd-new sur Debian est une chose finalement assez amusante à faire. Tout est dans /etc/amavis/conf.d

# ls -l /etc/amavis/conf.d/
total 56
-rw-r--r-- 1 root root  1458 2007-02-24 19:30 01-debian
-rw-r--r-- 1 root root   692 2007-02-24 19:30 05-domain_id
-rw-r--r-- 1 root root   235 2007-02-24 19:30 05-node_id
-rw-r--r-- 1 root root 13907 2007-02-24 19:30 15-av_scanners
-rw-r--r-- 1 root root   554 2007-02-24 19:30 15-content_filter_mode
-rw-r--r-- 1 root root  9187 2007-02-24 19:30 20-debian_defaults
-rw-r--r-- 1 root root   573 2007-02-24 19:30 25-amavis_helpers
-rw-r--r-- 1 root root  2130 2007-02-24 19:30 30-template_localization
-rw-r--r-- 1 root root  1223 2008-06-23 14:19 50-user

Bref, il y en a dans tous les coins, à nous de nous y retrouver.

Comme dans toute critique d'un bon roman à « suspense » ou d'un bon jeu d'action, il faut bien se garder de déflorer l'intrigue, aussi vous laisserais-je le soin de vous y retrouver...

Juste un ou deux indices cependant, histoire de ne décourager personne :

- tous les fichiers de configuration sont lus, les uns après les autres, par ordre alphabétique ;

- lorsqu'une directive de configuration est donnée plusieurs fois dans des fichiers différents, c'est la dernière lue qui a raison ;

- le fichier 50-user est, en l'état, le dernier à être lu ;

- tous les autres sont susceptibles d'être modifiés lors d'une mise à jour d'amavisd-new.

Tirez-en les conclusions qui s'imposent.

3-5-3-1-1 - Antivirus et Antispam

En lisant le fichier /etc/amavis/conf.d/15-content_filter_mode, vous comprendrez probablement que pour activer l'appel de l'antivirus et de l'antispam :

use strict;

# You can modify this file to re-enable SPAM checking through spamassassin
# and to re-enable antivirus checking.

#
# Default antivirus checking mode
# Uncomment the two lines below to enable it back
#

#@bypass_virus_checks_maps = (
#   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

#
# Default SPAM checking mode
# Uncomment the two lines below to enable it back
#

#@bypass_spam_checks_maps = (
#   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

1;  # insure a defined return
Nous allons bien nous garder de le faire, mais allons plutôt ajouter ces lignes dans 50-user :
@bypass_virus_checks_maps = (
\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);
@bypass_spam_checks_maps = (
\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

3-5-3-1-2 - Tags artistiques

Il y a un fichier bien intéressant à lire : /etc/amavis/conf.d/20-debian_defaults, car il contient bon nombre de paramètres de configuration d'Amavis. Dans les grandes lignes, mieux vaut garder cette configuration, sauf que :

- si vous désirez que les tags posés par spamassassin soient systématiquement ajoutés dans les en-têtes de messages, ça n'ira pas ;

- si vous voulez que les spams ne soient jamais éliminés, mais simplement marqués comme tels, ça n'ira pas non plus ;

- si par la suite vous souhaitez, comme nous le ferons dans le chapitre suivant, utiliser des domaines « virtuels », vos tags risquent de ne jamais apparaitre.

En effet, amavisd-new ne retranscrit les tags de spamassassin que pour les messages à destination des domaines référencés dans la variable (liste) @local_domains_acl.

De plus, la variable $sa_kill_level_deflt définit le score à partir duquel nous sommes « sûrs » qu'un message est un spam, et la variable $final_spam_destiny indique quoi faire de ce message dans pareil cas.

Dans la configuration par défaut (allez fouiller dans /etc/amavis/conf.d/20-debian_defaults), vous constaterez que si un message obtient un score >= 100, il est « D_BOUNCE », ce qui veut dire qu'il est mis en quarantaine locale et que le destinataire ne reçoit rien. Certes, un score de 100 est assez significatif mais tout de même, peut-être souhaiterez-vous vous montrer plus tolérant.

La variable @local_domains_acl telle qu'elle est configurée devrait faire l'affaire ici, mais n'ira pas dans le cas de domaines virtuels. Vérifiez tout de même, en cas de refus de tags de la part d'Amavis, de vérifier que le problème ne vient pas de là. La configuration suivante :

@local_domains_acl = ( "." );

Permettra d'effectuer le marquage des tags antispam quel que soit le domaine de destination.

Enfin, les variables $sa_tag_level_deflt et $sa_tag2_level_deflt ont leur importance sur la façon dont le message est marqué, de même que $sa_spam_subject_tag a un effet direct sur l'esthétique du message remis.

Voici un exemple de 50-user :

#
# Place your configuration directives here.  They will override those in
# earlier files.
#
# See /usr/share/doc/amavisd-new/ for documentation and examples of
# the directives you can use in this file
#
#@local_domains_acl = ( "." ); # éventuellement, en cas de soucis

@bypass_virus_checks_maps = (
\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

@bypass_spam_checks_maps = (
\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

$sa_tag_level_deflt = -9999;     # note minimale pour ajouter les tags X-Spam... à l'en-tête des emails
# ici, nous sommes à peu près surs que le tag sera toujours présent
$sa_tag2_level_deflt = 5.0;      # note minimale pour ajouter le tag X-Spam-Flag: YES
# et modifier l'objet
$sa_kill_level_deflt = 100;      # note à partir de laquelle les mails sont traités comme définis
# par la variable $final_spam_destiny (ici ils sont acceptés)
$sa_spam_subject_tag = '[SPAM]'; # chaine ajoutée à l'objet de l'email
$final_spam_destiny       = D_PASS;

# Pour ne pas en dire trop sur les armes employées
$X_HEADER_LINE = "spam & virus filtering at $mydomain";

#------------ Do not modify anything below this line -------------
1;  # insure a defined return

3-5-3-2 - Configuration de Postfix

Jusqu'à présent, nous avons pu éviter de toucher à master.cf. Maintenant, il va falloir y aller.

Ce fichier de configuration permet essentiellement de configurer les divers services fournis par Postfix, ainsi que des services annexes que l'on peut lui rattacher. En gros, c'est un outil pour faire de la chirurgie dans l'architecture de Postfix. Il est donc recommandé d'y aller avec précautions.

Nous allons juste faire ce qui est dit dans la documentation d'amavisd-new :

3-5-3-2-1 - Dans master.cf

Il faut ajouter ceci à la fin du fichier :

#
# Amavisd-new
#
smtp-amavis unix -      -       -     -       2  smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20

127.0.0.1:10025 inet n  -       -     -       -  smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=127.0.0.0/8,,[::1]/128
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks

Ces deux paragraphes vont permettre la création des points d'accrochage entre le module smtpd de Postfix et le daeémon amavisd. De plus, il faudra modifier le fichier main.cf pour indiquer à Postfix que smtpd doit se connecter à amavisd.

Les options (-o) indiquées ici surchargeront éventuellement celles qui seraient données dans main.cf pour les services en question, c'est-à-dire d'une part smtp-amavis et d'autre part le service smtpd attaché à amavis sur le port 10025.

3-5-3-2-2 - Dans main.cf

Il y a juste une ligne à ajouter :

content_filter=smtp-amavis:[127.0.0.1]:10024

Enfin, comme le dit la documentation de amavisd-new, il faut ajouter l'utilisateur clamav sous l'identité duquel le service de l'antivirus (clamd) tourne au groupe amavis :

# usermod -a -G amavis clamav

3-5-4 - Vérifications

Après avoir relancé amavis et forcé Postfix à relire sa configuration, vérifions que amavisd-new tourne, Postfix (et Dovecot) aussi :

~# netstat -tap
Connexions Internet actives (serveurs et établies)
Proto Recv-Q Send-Q Adresse locale          Adresse distante        Etat        PID/Program name
tcp        0      0 localhost:10024         *:*                     LISTEN     4280/amavisd (master)
tcp        0      0 localhost:10025         *:*                     LISTEN     2532/master
...
tcp        0      0 *:imap2                 *:*                     LISTEN     3536/dovecot
tcp        0      0 *:smtp                  *:*                     LISTEN     2532/master

Nous envoyons un message à test@nain-t.net et regardons l'en-tête du message reçu :

Return-Path: <machin@chose.truc>
Received: from cyrus.nain-t.net ([unix socket])
by cyrus.nain-t.net (Cyrus v2.2.13-Debian-2.2.13-10) with LMTPA;
Mon, 23 Jun 2008 14:20:47 +0200
X-Sieve: CMU Sieve 2.2
Received: from localhost (localhost [127.0.0.1])
by cyrus.nain-t.net (Postfix) with ESMTP id B1DC080FF274
for <test@nain-t.net>; Mon, 23 Jun 2008 14:20:47 +0200 (CEST)
X-Virus-Scanned: spam & virus filtering at cyrus.nain-t.net
X-Spam-Score: 0.644
X-Spam-Level:
X-Spam-Status: No, score=0.644 tagged_above=-9999 required=5 tests=[AWL=0.644]
Received: from cyrus.nain-t.net ([127.0.0.1])
by localhost (cyrus.nain-t.net [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id D38UlkWl4ypt for <test@nain-t.net>;
Mon, 23 Jun 2008 14:20:40 +0200 (CEST)
Received: from smtp20.orange.fr (smtp20.orange.fr [193.252.22.29])
by cyrus.nain-t.net (Postfix) with ESMTP id 26C1880FF273
for <test@nain-t.net>; Mon, 23 Jun 2008 14:20:39 +0200 (CEST)
Received: from me-wanadoo.net (localhost [127.0.0.1])
by mwinf2018.orange.fr (SMTP Server) with ESMTP id 1DA561C00046
for <test@nain-t.net>; Mon, 23 Jun 2008 14:20:37 +0200 (CEST)
Received: from jupiter.chose.truc (LSt-Amand-152-32-18-95.w82-127.abo.wanadoo.fr [82.127.57.95])
by mwinf2018.orange.fr (SMTP Server) with ESMTP id F39901C000BA
for <test@nain-t.net>; Mon, 23 Jun 2008 14:20:36 +0200 (CEST)
X-ME-UUID: 20080623122036997.F39901C000BA@mwinf2018.orange.fr
Received: from [172.16.129.245] (test-desktop.chose.truc [172.16.129.245])
by jupiter.chose.truc (Postfix) with ESMTP id 8977EEA3
for <test@nain-t.net>; Mon, 23 Jun 2008 14:20:36 +0200 (CEST)
Message-ID: <485F9514.4000807@eme-enseignement.fr>
Date: Mon, 23 Jun 2008 14:20:36 +0200
From: machin <machin@chose.truc>
User-Agent: Thunderbird 2.0.0.14 (X11/20080505)
MIME-Version: 1.0
To: test@nain-t.net
Subject: test des tags
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

ça taggue.

Si nous avions le temps, nous pourrions aussi envoyer un message identique à celui qui est fourni en exemple de spam avec SpamAssassin, pour constater que le travail est bien fait. De même, nous pouvons aussi envoyer un exemple de virus fourni avec ClamAV et constater qu'il est mis en quarantaine et non transmis au destinataire.

Enfin, il faut s'assurer que le dossier de quarantaine ne va pas exploser. Peut-être faut-il écrire un script qui nettoie les messages trop vieux, ou même créer une poubelle sans fond (/dev/null) ?

3-5-5 - Remarque

Il n'y a pas qu'Amavis qui permette l'interaction de Postfix avec des filtres de messages. Il y a aussi MailScanner. Sa méthode de rattachement à Postfix est bien plus simple (peut-être même un peu simpliste), mais pour ce que nous avons fait ici, MailScanner aurait pu suffire.

3-6 - Relais nomade

Il nous manque juste une fonctionnalité intéressante : celle de pouvoir utiliser notre cyrus.nain-t.net pour envoyer nos messages lorsque nous sommes en déplacement.

Les fournisseurs d'accès en effet ont l'habitude (légitime) de réserver leur SMTP à leurs clients. Si bien que lorsque nous sommes en déplacements, nous devons reconfigurer notre MUA en fonction de fournisseur dont on utilise les services. Ce n'est pas bien pratique. Si notre SMTP cyrus pouvait accepter de faire le relais pour nous quel que soit le fournisseur par lequel nous nous connectons, sans pour autant devenir un « open relay », ce serait parfait.

Le RFC 2476 va venir à notre secours. Nous allons ouvrir un MSA (Message Submission Agent) sur notre Postfix qui est prévu pour.

Le principe, assez tortueux, va être le suivant. Nos utilisateurs disposent d'un couple « login/password » pour accéder à leur boite aux lettres via dovecot-imapd. Nous allons utiliser SASL, de manière à faire authentifier les utilisateurs sur le SMTP par le même couple login/password, en s'appuyant sur dovecot-auth. SASL est une grande chose que nous manipulerons de manière plus musclée dans la solution suivante.

Simple Authentication and Security Layer porte assez mal son nom. Nous n'allons que l'effleurer ici en demandant à Dovecot d'assurer le rôle de serveur SASL et à Postfix celui du client. Normalement, Postfix sait parler SASL avec Dovecot :

# postconf -a
cyrus
dovecot

3-6-1 - Configuration de Dovecot

Nous devons avoir dans les méandres de /etc/dovecot/dovecot.conf, au paragraphe auth default, quelque chose comme ceci :

socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = postfix
}
}

Ce qui veut dire que le serveur SASL implémenté dans Dovecot va écouter sur un socket unix placé dans la cage de Postfix (/var/spool/postfix), et que ce socket sera accessible en lecture comme en écriture par l'utilisateur « postfix ».

Pour vous aider à y voir plus clair, voici le fichier complet, débarrassé de ses commentaires :

protocols = pop3 imap
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_privileged_group = mail
protocol imap {
}

protocol pop3 {
pop3_uidl_format = %08Xu%08Xv
}
auth default {
mechanisms = plain login
passdb pam {
}
userdb passwd {
}
user root
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = postfix
}
}
}
dict {
}
plugin {
}

Relancez Dovecot.

3-6-2 - Configuration de Postfix

Il va falloir agir sur les deux fichiers main.cf et master.cf.

3-6-2-1 - Sur « main.cf »

Nous devons préciser le type sasl employé (dovecot), ainsi que l'emplacement du socket du déaemon d'authentification de Dovecot (que nous avons placé dans /var/spool/postfix/private/auth). Ceci se traduit par l'ajout de ces deux lignes :

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

(Le chemin vers le socket est donné de façon relative de manière à ce qu'il soit indépendant du chemin de mise en cage de Postfix).

Nous avons donc finalement :

smtpd_banner = $myhostname ESMTP Experimental
disable_vrfy_command = yes
smtpd_helo_required = yes

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

smtpd_sender_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
permit

smtpd_client_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_rbl_client blackholes.easynet.nl,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client proxies.blackholes.wirehub.net,
reject_rbl_client bl.spamcop.net,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client dnsbl.njabl.org,
permit

content_filter=smtp-amavis:[127.0.0.1]:10024

biff = no
append_dot_mydomain = no
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${queue_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${queue_directory}/smtp_scache
myhostname = cyrus.nain-t.net
myorigin = $myhostname
mydestination = $mydomain, $myhostname, localhost
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost =
mynetworks = 127.0.0.0/8 192.168.0.0/24 192.168.10.0/24
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
home_mailbox = Maildir/

3-6-2-2 - Sur « master.cf »

Nous devons activer la « submission » qui ne l'est pas par défaut, en décommentant les lignes correspondantes et en ajoutant une option :

...
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       -       -       -       smtpd
submission inet n       -       -       -       -       smtpd
-o smtpd_enforce_tls=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
...

Les options transmises au service smtpd vont surcharger pour ce service, dont le nom est « submission » (et celui-ci seulement), celles qui seraient fournies dans main.cf. Nous avons ici 3 options :

- oblige à utiliser TLS (commande STARTTLS) avant l'authentification ;

- active l'authentification en utilisant SASL ;

- seuls les clients authentifiés par SASL peuvent se connecter ;

- surcharge pour la « submission » les options par défaut qui sont : smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination. Postfix n'acceptera de relayer les message que pour les clients authentifiés.

En effet, il ne s'agit pas dans ce cas d'autoriser « my nesworks » mais uniquement les utilisateurs authentifiés par SASL et de rejeter tous les autres, non seulement pour le relais, mais aussi pour les destinations locales. En bref, le MTA ne sera utilisable que pour les personnes qui disposent d'un compte local.

Après avoir relancé Postfix, si nous configurons notre oiseau comme ceci.

Une fois les formalités d'acceptation du certificat du serveur (qui n'est pas toujours pas signé par une racine de confiance) et de fourniture du mot de passe de l'utilisateur « lambda » réglées, cyrus devrait accepter de relayer n'importe où.

3-6-2-2-1 - Vérification (de routine) :

Jun  5 16:22:09 cyrus postfix/smtpd[26816]: connect from LSt-Amand-152-32-18-95.w82-127.abo.wanadoo.fr[82.127.57.95]
Jun  5 16:22:09 cyrus postfix/smtpd[26816]: C92D967DA4: client=LSt-Amand-152-32-18-95.w82-127.abo.wanadoo.fr[82.127.57.95], sasl_method=PLAIN, sasl_username=lambda
Jun  5 16:22:10 cyrus postfix/cleanup[26811]: C92D967DA4: message-id=<4847F690.1020505@eme-enseignement.fr>
Jun  5 16:22:10 cyrus postfix/qmgr[26780]: C92D967DA4: from=, size=590, nrcpt=1 (queue active)
Jun  5 16:22:10 cyrus postfix/smtpd[26813]: connect from localhost[127.0.0.1]
Jun  5 16:22:10 cyrus postfix/smtpd[26813]: 1CC6167DA5: client=localhost[127.0.0.1]
Jun  5 16:22:10 cyrus postfix/smtpd[26816]: disconnect from LSt-Amand-152-32-18-95.w82-127.abo.wanadoo.fr[82.127.57.95]
Jun  5 16:22:10 cyrus postfix/cleanup[26811]: 1CC6167DA5: message-id=<4847F690.1020505@eme-enseignement.fr>
Jun  5 16:22:10 cyrus postfix/smtpd[26813]: disconnect from localhost[127.0.0.1]
Jun  5 16:22:10 cyrus amavis[25917]: (25917-05) Passed CLEAN, [82.127.57.95] [82.127.57.95]  -> , Message-ID: <4847F690.1020505@eme-enseignement.fr>, mail_id: l3UEHAo7xlK9, Hits: -, queued_as: 1CC6167DA5, 130 ms
Jun  5 16:22:10 cyrus postfix/smtp[26812]: C92D967DA4: to=, relay=127.0.0.1[127.0.0.1]:10024, delay=0.46, delays=0.32/0/0.01/0.13, dsn=2.6.0, status=sent (250 2.6.0 Ok, id=25917-05, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 1CC6167DA5)
Jun  5 16:22:10 cyrus postfix/qmgr[26780]: C92D967DA4: removed
Jun  5 16:22:10 cyrus postfix/qmgr[26780]: 1CC6167DA5: from=, size=1038, nrcpt=1 (queue active)
Jun  5 16:22:20 cyrus postfix/smtp[26818]: 1CC6167DA5: to=, relay=mail.grenouille.com[213.186.35.33]:25, delay=10, delays=0.07/0.01/6.8/3.6, dsn=2.0.0, status=sent (250 ok 1212675740 qp 4369)
Jun  5 16:22:20 cyrus postfix/qmgr[26780]: 1CC6167DA5: removed

3-6-2-2-1-1 - Avertissement

Dovecot offre la particularité d'avoir un fichier de configuration particulièrement mouvant. D'une version à l'autre, des paramètres apparaissent et disparaissent régulièrement. Ceci est normal, le logiciel est jeune, la version 1.0 ne date que d'avril 2007, la version 1.1.1 est sortie le 22 juin 2008, et il n'est distribué qu'en version 1.0rc15 sur Debian Etch. Espérons que les choses vont maintenant se stabiliser.

La configuration annoncée ici n'est donc réputée valable que pour Dovecot 1.0 rc15.

Par rapport à la configuration vue au chapitre précédent, nous n'avons pas énormément de modifications à apporter. Dovecot devra principalement :

- trouver les utilisateurs et les identifier à partir des informations de la base de données et non plus du fichier /etc/passwd ;

- il devra également trouver l'emplacement du répertoire Maildir de chaque compte dans la base de données ;

- il devra offrir à Postfix un transport non plus local mais virtuel.

3-6-2-3 - A propos du MDA

Nous avons utilisé ici un MDA interne à Postfix. Nous pouvons aussi utiliser un MDA plus configurable, comme Procmail, qui permet par exemple de créer des règles de filtrage personnalisées pour chaque compte. Procmail peut ainsi déposer directement les messages dans des dossiers IMAP dédiés en fonctions de critères de tri. Il suffit dans ce cas d'ajouter la ligne :

mailbox_command = /usr/bin/procmail -a "$EXTENSION"

à notre main.cf, puis d'écrire des fichiers .procmailrc dans le répertoire des utilisateurs. Procmail dispose d'un langage de script très puissant, mais peu intuitif.

Dovecot propose également un MDA. Dans un cas comme celui que nous traitons ici (sans domaines virtuels), nous aurions pu nous en servir en plaçant dans main.cf la ligne :

mailbox_command = /usr/lib/dovecot/deliver

Dovecot dispose d'un plug-in qui permet alors de filtrer les messages au niveau du MDA en utilisant le langage Sieve(2).

Si c'est ce MDA (nommé aussi LDA dans la documentation Dovecot) qui est utilisé, quelques ajouts doivent être faits dans le fichier de configuration de Dovecot.

Quelques paramètres spécifiques à la configuration de deliver :

protocol lda {
postmaster_address = postmaster@nain-t.net
mail_plugin_dir = /usr/lib/dovecot/modules/lda
sendmail_path = /usr/lib/sendmail
mail_plugins = cmusieve
}

Et une ligne pour spécifier à deliver que l'on souhaite utiliser le format Maildir (en effet, la ligne qui le spécifie dans main.cf de Postfix ne sert plus à rien puisque l'on utilise plus le MDA de Postfix) :

mail_location = maildir:~/Maildir

En ce qui concerne l'emploi de Sieve, Dovecot distribué par Debian ne permet pas à l'utilisateur de placer ses scripts autrement que par FTP ou SSH pour l'instant. Sur ce point, nous verrons que dans l'état actuel (au 26 juin 2008), Cyrus conserve une longueur d'avance.

3-7 - Bilan

Nous disposons d'une solution tout à fait exploitable si nous avons peu de comptes à gérer et un seul domaine de messagerie. Dovecot est un serveur POP/IMAP de bonne facture et qui peut aller bien au-delà de ce que nous lui avons demandé ici. Au train où vont les choses, il pourra sans doute rapidement rivaliser avec le serveur Cyrus que nous verrons dans la solution suivante.

Nous aurions également pu utiliser courier-imap. Il est plus lourd que Dovecot et ne se justifie pas forcément ici, mais la solution n'est pas à écarter.

Il nous manque juste la gestion de comptes de messagerie qui ne nécessite pas de créer un compte unix, et la possibilité de gérer plusieurs domaines de messagerie. C'est ce que nous allons faire dans le chapitre suivant.

4 - Postfix, Dovecot, etc.

Notre solution Postfix + Dovecot fonctionne, mais ne gère qu'un seul domaine de messagerie.

Les utilisateurs titulaires d'un compte de messagerie doivent disposer d'un compte Unix. Même sans shell, cette solution devient vite lourde à gérer.

Nous allons ici ajouter la gestion de comptes virtuels, sans aucun rapport donc avec les comptes Unix. Il y a plusieurs façons de réaliser cette opération, la façon la plus souple étant sans doute de stocker les informations de ces comptes dans une base de données ou un annuaire.

Nous ferons ici appel à MySQL et à une interface de gestion libre : Postfix Admin.

Pour le reste, continuons avec Postfix et Dovecot.

Nous allons utiliser les possibilités qu'offre Postfix pour la gestion des domaines virtuels en s'appuyant sur une base de données MySQL.

Dovecot s'appuiera également sur cette base, proposera un serveur SASL pour Postfix comme nous l'avons vu dans le chapitre précédent, mais il ira chercher les informations dans MySQL et non pas dans les comptes Unix.

Nous utiliserons le MDA de Dovecot pour profiter du langage Sieve pour le filtrage des messages.

4-1 - Postfix Admin

Postfix Admin est une interface en PHP qui permet principalement de gérer une base de données qui contiendra toutes les informations nécessaires à la maintenance de comptes virtuels. Postfix Admin n'impose pas de serveur POP/IMAP spécifique. Dovecot ou Courier-imap Pourront être utilisés, nous continuerons avec Dovecot.

Postfix Admin semble activement maintenu. La version utilisée ici est la 2.2.0 d'avril 2008. Bien que ne faisant à ce jour (17 juillet 2008) pas partie des distributions Debian, il existe sur le site officiel du projet un paquet Debian que nous allons utiliser. Les dépendances sont minimes : Dépend: apache2, libapache2-mod-php5 ou php5-cgi ou php5, mysql-server. Autant de composants dont nous aurons besoin par ailleurs.

4-1-1 - Installation

Suivant les règles Debian, le logiciel s'installe dans /usr/share/postfixadmin, installe dans /etc/apache2/conf.d un fichier nommé postfixadmin réduit à sa plus simple expression :

# BEGIN FOR POSTFIXADMIN
Alias /postfixadmin /usr/share/postfixadmin
# END FOR POSTFIXADMIN

Et dans /etc/postfixadmin le fichier config.inc.php qu'il conviendra de modifier manuellement. Mais avant tout, il faut lire /usr/share/doc/postfixadmin/INSTALL.TXT...

4-1-2 - Création de la base

Nous allons commencer par créer la base de données et l'utilisateur qui va avec :

CREATE DATABASE vmail;
CREATE USER 'vmail'@'localhost' IDENTIFIED BY 'epikoi';
GRANT ALL PRIVILEGES ON `vmail` . * TO 'vmail'@'localhost';

4-1-3 - Configuration

Le fichier /etc/postfixadmin/config.inc.php est assez long, bien documenté et il faut le lire jusqu'au bout...

Voici pour fixer les idées, une version débarrassée de ses commentaires. Ce qui est surligné est particulièrement important, mais encore une fois, prenez le temps de lire (et éventuellement modifier) ce fichier jusqu'au bout.

<?php
if (ereg ("config.inc.php", $_SERVER['PHP_SELF']))
{
header ("Location: login.php");
exit;
}

$CONF['configured'] = true;
$CONF['postfix_admin_url'] = 'http://cyrus.nain-t.net/postfixadmin';
$CONF['postfix_admin_path'] = '/usr/share/postfixadmin';
$CONF['default_language'] = 'fr';
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'vmail';
$CONF['database_password'] = 'epikoi';
$CONF['database_name'] = 'vmail';
$CONF['database_prefix'] = '';
$CONF['database_tables'] = array (
'admin' => 'admin',
'alias' => 'alias',
'config' => 'config',
'domain' => 'domain',
'domain_admins' => 'domain_admins',
'log' => 'log',
'mailbox' => 'mailbox',
'vacation' => 'vacation',
'vacation_notification' => 'vacation_notification',
);

$CONF['admin_email'] = 'sysop@nain-t.net';
$CONF['smtp_server'] = 'localhost';
$CONF['smtp_port'] = '25';
$CONF['encrypt'] = 'md5crypt';
$CONF['min_password_length'] = 5;
$CONF['generate_password'] = 'NO';
$CONF['show_password'] = 'yes';
$CONF['page_size'] = '10';
$CONF['default_aliases'] = array (
'abuse' => 'sysop@nain-t.net',
'hostmaster' => 'sysop@nain-t.net',
'postmaster' => 'sysop@nain-t.net',
'webmaster' => 'sysop@nain-t.net'
);

$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['aliases'] = '0';
$CONF['mailboxes'] = '0';
$CONF['maxquota'] = '2000';
$CONF['quota'] = 'NO';
$CONF['quota_multiplier'] = '1024000';
$CONF['transport'] = 'NO';
$CONF['transport_options'] = array (
'virtual',  // for virtual accounts
'local',    // for system accounts
'relay'     // for backup mx
);

$CONF['transport_default'] = 'virtual';
$CONF['vacation'] = 'NO';
$CONF['vacation_domain'] = 'autoreply.nain-t.net';
$CONF['vacation_control'] ='YES';
$CONF['vacation_control_admin'] = 'YES';
$CONF['alias_control'] = 'NO';
$CONF['alias_control_admin'] = 'NO';
$CONF['special_alias_control'] = 'NO';
$CONF['alias_goto_limit'] = '0';
$CONF['backup'] = 'YES';
$CONF['sendmail'] = 'YES';
$CONF['logging'] = 'YES';
$CONF['fetchmail'] = 'YES';
$CONF['fetchmail_extra_options'] = 'NO';
$CONF['show_header_text'] = 'NO';
$CONF['header_text'] = ':: Postfix Admin ::';
$CONF['user_footer_link'] = "http://cyrus.nain-t.net/postfixadmin";
$CONF['show_footer_text'] = 'YES';
$CONF['footer_text'] = 'Return to nain-t.net';
$CONF['footer_link'] = 'http://nain-t.net';
$CONF['welcome_text'] = <<

Notez les alias qui pointent tous vers sysop@nain-t.net qui est un compte qu'il nous faudra créer et qui sera celui du super-administrateur du site.

4-1-4 - Mise à feu

Il faut maintenant, après avoir demandé à l'Apache de relire sa configuration, ce que le script « postinstall » du paquet postfixadmin n'a pas fait, aller sur l'URL de votre installation. Ici :

http://cyrus.nain-t.net/postfixadmin/setup.php

Afin de corriger les éventuels erreurs constatées, nous allons créer le compte du « super administrateur » et enfin renommer ou détruire le fichier /usr/share/postfixadmin/setup.php.

Postfixadmin devrait être en état de fonctionner, hormis l'envoi de messages puisque nous n'avons pas encore configuré Postfix pour cela.

4-1-5 - Base de données

La base de données a été construite lors du « setup ». Elle contient les tables admin, alias, config, domain, domain_admins, fetchmail, log, mailbox, vacation et vacation_notification.

Créons le domaine nain-t.net et le compte sysop@nain-t.net et regardons un peu :

mysql> select * from alias;
+-----------------------+------------------+------------+---------------------+---------------------+--------+
| address               | goto             | domain     | created             | modified            | active |
+-----------------------+------------------+------------+---------------------+---------------------+--------+
| abuse@nain-t.net      | sysop@nain-t.net | nain-t.net | 2008-07-15 16:15:31 | 2008-07-15 16:15:31 |      1 |
| hostmaster@nain-t.net | sysop@nain-t.net | nain-t.net | 2008-07-15 16:15:31 | 2008-07-15 16:15:31 |      1 |
| postmaster@nain-t.net | sysop@nain-t.net | nain-t.net | 2008-07-15 16:15:31 | 2008-07-15 16:15:31 |      1 |
| webmaster@nain-t.net  | sysop@nain-t.net | nain-t.net | 2008-07-15 16:15:31 | 2008-07-15 16:15:31 |      1 |
| sysop@nain-t.net      | sysop@nain-t.net | nain-t.net | 2008-07-15 16:16:01 | 2008-07-15 16:16:01 |      1 |
+-----------------------+------------------+------------+---------------------+---------------------+--------+

Dans la table alias nous retrouvons les alias définis dans la configuration, et sysop@nain-t.net qui pointe sur lui-même.

mysql> select * from mailbox;
+------------------+------------------------------------+------------------+-------------------+-------+------------+---------------------+---------------------+--------+
| username         | password                           | name             | maildir           | quota | domain     | created             | modified            | active |
+------------------+------------------------------------+------------------+-------------------+-------+------------+---------------------+---------------------+--------+
| sysop@nain-t.net | $1$b05611fa$K.98vXKRWNG5Xr97dlkcp1 | sysop            | nain-t.net/sysop/ |     0 | nain-t.net | 2008-07-15 16:16:01 | 2008-07-15 16:16:01 |      1 |
+------------------+------------------------------------+------------------+-------------------+-------+------------+---------------------+---------------------+--------+

Dans la table mailbox, nous trouvons pas mal de choses :

- username contient l'adresse du compte ;

- name contient la partie gauche de l'adresse ;

- domain contient le nom du domaine virtuel (partie droite de l'adresse) ;

- password contient le mot de passe chiffré en MD5-CRYPT ;

- maildir contient le chemin relatif du répertoire Maildir de l'utilisateur.

mysql> select * from domain;
+------------+----------------+---------+-----------+----------+-------+-----------+----------+---------------------+---------------------+--------+
| domain     | description    | aliases | mailboxes | maxquota | quota | transport | backupmx | created             | modified            | active |
+------------+----------------+---------+-----------+----------+-------+-----------+----------+---------------------+---------------------+--------+
| ALL        |                |       0 |         0 |        0 |     0 | NULL      |        0 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |      1 |
| nain-t.net | Domaine public |       0 |         0 |        0 |     0 | virtual   |        0 | 2008-07-15 16:15:31 | 2008-07-15 16:15:31 |      1 |
+------------+----------------+---------+-----------+----------+-------+-----------+----------+---------------------+---------------------+--------+

La table « domain » contient essentiellement la liste des domaines virtuels créés.

4-2 - Configurer Dovecot

4-2-1 - Préparatifs

Commençons par créer un groupe et un utilisateur vmail, sans shell, qui disposera d'un répertoire /home/virtual/mail. Les UID et GID = 500 peuvent prendre une autre valeur disponible. Nous aurons besoin de cette valeur plus tard.

groupadd -g 500 vmail
useradd -g vmail -u 500 vmail -d /home/virtual/mail -s /bin/false -m

4-2-2 - Accès à la base

Il y a dans /etc/dovecot un fichier abondamment documenté qui s'appelle dovecot-sql.conf. Nous devons commencer par celui-ci.

Fichier /etc/dovecot/dovecot-sql.conf débarrassé de ses commentaires :

driver =  mysql
connect = host=localhost dbname=vmail user=vmail password=epikoi
default_pass_scheme = MD5
password_query = SELECT password FROM mailbox WHERE username = '%u'

- driver permet d'indiquer le type de la base.

- connect donne les indications nécessaires pour se connecter à cette base.

- default_pass_scheme indique le mode de chiffrement des mots de passe. MD5 pour la version 1.0rc15, mais attention, c'est MD5-CRYPT à partir de la version 1.0rc16 et jusqu'à la prochaine fois.

- password_query permet de récupérer le mot de passe de l'utilisateur %u.

4-2-3 - Dovecot

Le fichier dovecot.conf, débarrassé de ses commentaires, devrait ressembler à ceci :

protocols = imap imaps pop3 pop3s
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = maildir:/home/virtual/mail/%d/%n/Maildir

protocol imap {
}

protocol pop3 {
pop3_uidl_format = %08Xu%08Xv
}
protocol lda {
postmaster_address = sysop@nain-t.net
hostname = cyrus.nain-t.net
mail_plugin_dir = /usr/lib/dovecot/modules/lda
sendmail_path = /usr/lib/sendmail
auth_socket_path = /var/run/dovecot/auth-master
mail_plugins = cmusieve
}
auth default {
mechanisms = plain
passdb pam {
}
passdb sql {
args = /etc/dovecot/dovecot-sql.conf
}
userdb passwd {
}
userdb static {
args = uid=vmail gid=vmail home=/home/virtual/mail/%d/%n
}

user = root
socket listen {
master {
path = /var/run/dovecot/auth-master
mode = 0600
user = vmail
group = vmail
}
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = vmail
}
}
}
dict {
}
plugin {
}

Nous avons essentiellement ajouté ce qu'il fallait pour que Dovecot sache reconstituer le chemin absolu des Maildir et utilise les requêtes SQL décrites dans dovecot-sql.conf pour trouver le mot de passe.

Le paragraphe userdb static permet de définir de façon statique (c'est notre mode de fonctionnement) les UID et GID de l'utilisateur virtuel (vmail), ainsi qu'un répertoire home.

Notez que nous aurons ainsi :

- le répertoire Maildir, celui où les messages vont venir se stocker, défini comme /home/virtual/mail/%d/%n/Maildir ;

- le répertoire home du compte sera quant à lui /home/virtual/mail/%d/%n, ce qui est une structure similaire à celle que nous avions avec des « vrais » comptes Unix.

Le paragraphe master dans socket listen définit un « socket » qui sera nécessaire par la suite, lorsque nous utiliserons le deliver de Dovecot pour le transport virtuel.

4-2-4 - Vérifications

Nous devrions déjà vérifier que l'utilisateur sysop@nain-t.net peut se connecter en IMAP et être authentifié :

# telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK Dovecot ready.
10 login sysop@nain-t.net epikoi
10 OK Logged in.
20 logout
* BYE Logging out
20 OK Logout completed.
Connection closed by foreign host.

Et dans les logs /var/log/mail.info :

Jul 15 18:30:22 cyrus dovecot: Dovecot v1.0.rc15 starting up
Jul 15 18:30:23 cyrus dovecot: auth-worker(default): mysql: Connected to localhost (vmail)
Jul 15 18:30:45 cyrus dovecot: ssl-build-param: SSL parameters regeneration completed
Jul 15 18:31:05 cyrus dovecot: imap-login: Login: user=<sysop@nain-t.net>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, secured
Jul 15 18:31:50 cyrus dovecot: IMAP(sysop@nain-t.net): Disconnected: Logged out

Une bonne chose de faite.

Allons faire un tour dans /home/virtual/mail :

cyrus:/home/virtual/mail# ls -l
total 0
drwx------ 3 vmail vmail 18 2008-07-15 18:40 nain-t.net

Ce répertoire, c'est Dovecot qui l'a créé lorsque sysop s'est connecté pour la première fois. Il est fort ce Dovecot. Mais voyons plus loin :

cyrus:/home/virtual/mail# cd nain-t.net/
cyrus:/home/virtual/mail/nain-t.net# ls -l
total 0
drwx------ 5 vmail vmail 36 2008-07-15 18:40 sysop

Et encore plus loin :

cyrus:/home/virtual/mail/nain-t.net# cd sysop/Maildir
cyrus:/home/virtual/mail/nain-t.net/sysop/Maildir# ls -l
total 0
drwx------ 2 vmail vmail 6 2008-07-15 18:40 cur
drwx------ 2 vmail vmail 6 2008-07-15 18:40 new
drwx------ 2 vmail vmail 6 2008-07-15 18:40 tmp

Toute la structure a été construite. Notez que le tout appartient à vmail.

4-3 - Configurer Postfix

Pour Postfix, ça va être un peu plus compliqué. Nous avons vu jusqu'ici des configurations assez simples de Postfix, principalement grâce à ses paramètres par défaut. La liste des paramètres de Postfix est assez impressionnante. Pour s'en convaincre, un postconf montrera tous ces paramètres avec leurs valeurs par défaut si elles n'ont pas été surchargées dans main.cf. Il y a actuellement pas moins de 525 paramètres...

Nous allons surtout nous intéresser aux paramètres spécifiques à la configuration « virtuelle ». En effet Postfix est conçu pour gérer les domaines virtuels. Il n'y a que 15 paramètres spécifiques, qui commencent tous par le mot virtual :

virtual_alias_domains = $virtual_alias_maps
virtual_alias_expansion_limit = 1000
virtual_alias_maps = $virtual_maps
virtual_alias_recursion_limit = 1000
virtual_destination_concurrency_limit = $default_destination_concurrency_limit
virtual_destination_recipient_limit = $default_destination_recipient_limit
virtual_gid_maps =
virtual_mailbox_base =
virtual_mailbox_domains = $virtual_mailbox_maps
virtual_mailbox_limit = 51200000
virtual_mailbox_lock = fcntl
virtual_mailbox_maps =
virtual_minimum_uid = 100
virtual_transport = virtual
virtual_uid_maps =

- virtual_uid_maps et virtual_gid_maps représentent respectivement l'UID et le GID de l'utilisateur qui doit accéder à ces boites virtuelles, vmail (500:500) dans notre cas ;

- virtual_minimum_uid est l'UID minimum à utiliser lorsque l'on utilise plusieurs identités pour la remise du courrier. Nous ne ferons pas aussi compliqué, tous nos comptes virtuels sont gérés par l'utilisateur vmail et la valeur 500 conviendra parfaitement ;

- virtual_transport indique le LDA (MDA) utilisé pour la remise du courrier virtuel. Comme pour la remise locale, Postfix possède un agent de livraison, mais nous utiliserons celui de Dovecot ;

- virtual_mailbox_base indique la base du chemin d'accès aux répertoires des comptes virtuels. Chez nous : /home/virtual/mail ;

- virtual_mailbox_domain donnera la liste des domaines virtuels gérés, à récupérer dans MySQL ;

- virtual_mailbox_maps fournit le chemin relatif au Maildir (à ajouter à virtual_mailbox_base) à récupérer dans MySQL ;

- virtual_alias_maps, les alias, à récupérer dans MySQL.

4-3-1 - Postfix et MySQL

Pour que Postfix puisse causer à MySQL et réciproquement, il y a plusieurs choses à faire :

- apprendre à Postfix le langage SQL ;

- trouver un lieu où les deux interlocuteurs peuvent communiquer. Postfix est en cage et MySQL non. Il y a trois façons de contourner ce problème :

- placer le socket Unix de MySQL dans la cage de Postfix, mais ce n'est pas une très bonne solution. MySQL ne communiquera pas qu'avec Postfix ;

- utiliser non pas un socket Unix mais un socket réseau. Ça fonctionne, mais peut-être pas de façon aussi rapide qu'un socket Unix ;

- utiliser le service proxy de Postfix, qui est justement là pour permettre de passer des informations entre la cage de Postfix et le reste du système.

4-3-1-1 - Les requêtes SQL

Tout d'abord, il faut installer le paquet postfix-mysql :

aptitude install postfix-mysql

Ensuite, il faut rédiger des fichiers qui permettront à Postfix d'interroger MySQL sur les domaines, les alias et les boites aux lettres qu'il a en charge.

4-3-1-1-1 - Les domaines virtuels

Dans la table domains, nous avons la liste des domaines virtuels à gérer. Postfixadmin prévoit divers drapeaux :

l> select * from domain;
+------------+----------------+---------+-----------+----------+-------+-----------+----------+---------------------+---------------------+--------+
| domain     | description    | aliases | mailboxes | maxquota | quota | transport | backupmx | created             | modified            | active |
+------------+----------------+---------+-----------+----------+-------+-----------+----------+---------------------+---------------------+--------+
| ALL        |                |       0 |         0 |        0 |     0 | NULL      |        0 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |      1 |
| nain-t.net | Domaine public |       0 |         0 |        0 |     0 | virtual   |        0 | 2008-07-15 16:15:31 | 2008-07-15 16:15:31 |      1 |
+------------+----------------+---------+-----------+----------+-------+-----------+----------+---------------------+---------------------+--------+

- backupmx permet de savoir si le serveur doit agir pour ce domaine en tant que destination (valeur 0) ou en tant que relais, c'est-à-dire en MX de « backup » (valeur 1) ;

- active permet de désactiver (valeur 0) un domaine sans pour autant le détruire.

Nous créons un fichier /etc/postfix/db/mysql_virtual_domains_maps.cf qui permettra à Postfix d'interroger MySQL sur ce point et qui sera de la forme :

user = vmail
password = epikoi
hosts = localhost
dbname = vmail
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'

4-3-1-1-2 - Les alias

De la même manière, créons un fichier /etc/postfix/db/mysql_virtual_alias_maps.cf dont le contenu sera le suivant :

user = vmail
password = epikoi
hosts = localhost
dbname = vmail
query = SELECT goto FROM alias WHERE address='%s' and active = '1'

4-3-1-1-3 - Les boites aux lettres

Enfin, les chemins d'accès aux répertoires Maildir. Un fichier /etc/postfix/db/mysql_virtual_mailbox_maps.cf :

user = vmail
password = epikoi
hosts = localhost
dbname = vmail
query = SELECT CONCAT(maildir, 'Maildir/') FROM mailbox WHERE username='%s' and active = '1'

4-3-1-2 - le proxy de Postfix

Le service proxy de Postfix s'utilise assez simplement. Il faut cependant l'informer des lectures de paramètres qu'il doit prendre en charge. Commençons par voir quelle est sa configuration par défaut :

proxy_read_maps = $local_recipient_maps,
$mydestination,
$virtual_alias_maps,
$virtual_alias_domains,
$virtual_mailbox_maps,
$virtual_mailbox_domains,
$relay_recipient_maps,
$relay_domains,
$canonical_maps,
$sender_canonical_maps,
$recipient_canonical_maps,
$relocated_maps,
$transport_maps $mynetworks

Nous allons donc maintenant modifier dans /etc/postfix/main.cf les trois paramètres qui nous concernent :

virtual_alias_maps = proxy:mysql:/etc/postfix/db/mysql_virtual_alias_maps.cf
virtual_mailbox_domains = proxy:mysql:/etc/postfix/db/mysql_virtual_domains_maps.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/db/mysql_virtual_mailbox_maps.cf

Sans oublier les UID et GID de l'utilisateur vmail :

virtual_minimum_uid = 500
virtual_uid_maps = static:500
virtual_gid_maps = static:500

Ni la partie commune du chemin d'accès aux Maildirs :

virtual_mailbox_base = /home/virtual/mail

4-3-1-3 - Vérification

Nous allons utiliser l'agent de livraison virtual de Postfix pour faire un essai. C'est possible avec Dovecot. virtual est même capable de créer un Maildir qui n'existe pas encore.

Nous envoyons un message à sysop@nain-t.net :

~# mail sysop@nain-t.net
Subject: test postfix virtuel
c'est bon
.
Cc:

Tout en observant les logs :

Jul 16 10:29:02 cyrus postfix/pickup[2953]: F186C4006BF: uid=0 from=<root>
Jul 16 10:29:02 cyrus postfix/cleanup[2982]: F186C4006BF: message-id=<20080716082901.F186C4006BF@cyrus.nain-t.net>
Jul 16 10:29:02 cyrus postfix/qmgr[2954]: F186C4006BF: from=<root@cyrus.nain-t.net>, size=320, nrcpt=1 (queue active)
Jul 16 10:29:05 cyrus postfix/smtpd[2990]: connect from localhost[127.0.0.1]
Jul 16 10:29:05 cyrus postfix/smtpd[2990]: 609494012E5: client=localhost[127.0.0.1]
Jul 16 10:29:05 cyrus postfix/cleanup[2982]: 609494012E5: message-id=<20080716082901.F186C4006BF@cyrus.nain-t.net>
Jul 16 10:29:05 cyrus postfix/smtpd[2990]: disconnect from localhost[127.0.0.1]
Jul 16 10:29:05 cyrus amavis[2137]: (02137-02) Passed CLEAN, <root@cyrus.nain-t.net> -> <sysop@nain-t.net>, Message-ID: <20080716082901.F186C4006BF@cyrus.nain-t.net>, mail_id: z4aQN+eLCjhF, Hits: 0.43, queued_as: 609494012E5, 3384 ms
Jul 16 10:29:05 cyrus postfix/smtp[2986]: F186C4006BF: to=<sysop@nain-t.net>, relay=127.0.0.1[127.0.0.1]:10024, delay=3.6, delays=0.21/0.03/0.01/3.4, dsn=2.6.0, status=sent (250 2.6.0 Ok, id=02137-02, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 609494012E5)
Jul 16 10:29:05 cyrus postfix/qmgr[2954]: F186C4006BF: removed
Jul 16 10:29:05 cyrus postfix/qmgr[2954]: 609494012E5: from=<root@cyrus.nain-t.net>, size=763, nrcpt=1 (queue active)
Jul 16 10:29:05 cyrus postfix/virtual[2992]: 609494012E5: to=<sysop@nain-t.net>, relay=virtual, delay=0.31, delays=0.15/0.07/0/0.08, dsn=2.0.0, status=sent (delivered to maildir)
Jul 16 10:29:05 cyrus postfix/qmgr[2954]: 609494012E5: removed

Et nous devons retrouver le message à sa place :

:~# cd /home/virtual/mail/nain-t.net/sysop/Maildir/new/
cyrus:/home/virtual/mail/nain-t.net/sysop/Maildir/new# ls
1216196945.V305I3400083M657329.cyrus
cyrus:/home/virtual/mail/nain-t.net/sysop/new# cat 1216196945.V305I3400083M657329.cyrus
Return-Path: <root@cyrus.nain-t.net>
X-Original-To: sysop@nain-t.net
Delivered-To: sysop@nain-t.net
Received: from localhost (localhost [127.0.0.1])
by cyrus.nain-t.net (Postfix) with ESMTP id 609494012E5
for <sysop@nain-t.net>; Wed, 16 Jul 2008 10:29:05 +0200 (CEST)
X-Virus-Scanned: Debian amavisd-new at cyrus.nain-t.net
Received: from cyrus.nain-t.net ([127.0.0.1])
by localhost (cyrus.nain-t.net [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id z4aQN+eLCjhF for <sysop@nain-t.net>;
Wed, 16 Jul 2008 10:29:02 +0200 (CEST)
Received: by cyrus.nain-t.net (Postfix, from userid 0)
id F186C4006BF; Wed, 16 Jul 2008 10:29:01 +0200 (CEST)
To: sysop@nain-t.net
Subject: test postfix virtuel
Message-Id: <20080716082901.F186C4006BF@cyrus.nain-t.net>
Date: Wed, 16 Jul 2008 10:29:01 +0200 (CEST)
From: root@cyrus.nain-t.net (root)

c'est bon

4-3-2 - Transport dovecot

Le transport virtual fonctionne, mais avec, nous perdons quelques fonctionnalités propres à Dovecot :

- l'utilisation de Sieve ;

- la gestion des quotas, si nous désirons la mettre en œuvre. En effet, Postfix ne gère pas les quotas, son auteur estimant que ce n'est pas aux MTA de le faire.

Dovecot, nous l'avons vu dans le chapitre précédent, propose l'outil /usr/lib/dovecot/deliver. Cet outil peut être aussi bien utilisé pour le transport local que pour le transport virtuel. Il n'est d'ailleurs pas inutile et même conseillé de lire la documentation de Dovecot à ce sujet ainsi que son intégration avec Postfix.

Nous ajoutons donc dans /etc/postfix/master.cf les lignes suivantes :

#
# Dovecot deliver
#
dovecot   unix  -       n       n       -       -       pipe
flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}

Et dans /etc/postfix/main.cf :

# Virtual transport Dovecot
dovecot_destination_recipient_limit = 1
virtual_transport = dovecot

Nous demandons à Postfix de recharger sa configuration avec un postfix reload des familles et nous essayons :

# mail sysop@nain-t.net
Subject: test transport virtuel dovecot
c'est encore bon
.
Cc:

Les logs :

Jul 16 11:07:13 janus postfix/pickup[3029]: C59184006BF: uid=0 from=
Jul 16 11:07:13 janus postfix/cleanup[3076]: C59184006BF: message-id=<20080716090713.C59184006BF@janus.nain-t.net>
Jul 16 11:07:13 janus postfix/qmgr[3030]: C59184006BF: from=, size=337, nrcpt=1 (queue active)
Jul 16 11:07:15 janus postfix/smtpd[3083]: connect from localhost[127.0.0.1]
Jul 16 11:07:15 janus postfix/smtpd[3083]: 74FAA4000B3: client=localhost[127.0.0.1]
Jul 16 11:07:15 janus postfix/cleanup[3076]: 74FAA4000B3: message-id=<20080716090713.C59184006BF@janus.nain-t.net>
Jul 16 11:07:15 janus postfix/qmgr[3030]: 74FAA4000B3: from=, size=780, nrcpt=1 (queue active)
Jul 16 11:07:15 janus amavis[2137]: (02137-03) Passed CLEAN,  -> , Message-ID: <20080716090713.C59184006BF@janus.nain-t.net>, mail_id: TmCa1TrEXu4h, Hits: 0.626, queued_as: 74FAA4000B3, 1732 ms
Jul 16 11:07:15 janus postfix/smtp[3079]: C59184006BF: to=, relay=127.0.0.1[127.0.0.1]:10024, delay=2, delays=0.17/0.03/0.01/1.7, dsn=2.6.0, status=sent (250 2.6.0 Ok, id=02137-03, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 74FAA4000B3)
Jul 16 11:07:15 janus postfix/qmgr[3030]: C59184006BF: removed
Jul 16 11:07:15 janus postfix/smtpd[3083]: disconnect from localhost[127.0.0.1]
Jul 16 11:07:15 janus deliver(sysop@nain-t.net): msgid=<20080716090713.C59184006BF@janus.nain-t.net>: saved mail to INBOX
Jul 16 11:07:15 janus postfix/pipe[3084]: 74FAA4000B3: to=, relay=dovecot, delay=0.26, delays=0.09/0.02/0/0.15, dsn=2.0.0, status=sent (delivered via dovecot service)
Jul 16 11:07:15 janus postfix/qmgr[3030]: 74FAA4000B3: removed

Le message est remis, avec dovecot cette fois-ci, pour la livraison virtuelle.

4-4 - Plus avec Dovecot

Dovecot peut être complété par l'utilisation de « plug-ins ». Voir la page qui y est consacrée.

4-4-1 - Sieve

Si nous désirons utiliser Sieve, il nous faut utiliser le plug-in cmusieve, que nous avons d'ailleurs déjà invoqué dans la configuration de Dovecot :

protocol lda {
postmaster_address = sysop@maison.mrs
hostname = janus.maison.mrs
mail_plugin_dir = /usr/lib/dovecot/modules/lda
sendmail_path = /usr/lib/sendmail
auth_socket_path = /var/run/dovecot/auth-master
mail_plugins = cmusieve
}

Mais ce n'est pas tout, il faut aussi que le compte virtuel dispose d'un « home ». Nous l'avons déjà fait aussi dans la configuration de Dovecot :

userdb static {
args = uid=vmail gid=vmail home=/home/virtual/mail/%d/%n
}

cmusieve va alors chercher un script sieve s'il existe, dans le fichier .dovecot.sieve, situé dans le « home » du compte virtuel (ici, /home/virtual/mail/<domaine>/<utilisateur>). Malheureusement, Dovecot n'implémente pas, du moins dans la version que nous utilisons, de protocole ManageSieve, qui permettrait simplement à l'utilisateur de charger ses scripts Sieve. Lire la documentation de Dovecot ManageSieve Server pour avoir toutes les informations.

A moins de donner un accès ftp aux utilisateurs, ce sera donc à l'administrateur de placer les scripts... En attendant la version 2.0 de Dovecot, à moins de reconstruire un Dovecot patché.

4-4-2 - Les quotas

Le problème des quotas est surtout épineux avec IMAP. Un peu moins avec POP si le client ne choisit pas de garder une copie des messages sur le serveur.

4-4-2-1 - Philosophie

Les quotas se gèrent également au moyen d'un plug-in. Comme il s'agit d'un problème de bord, personne ne sait exactement à qui incombe la gestion de ces quotas. Est-ce le MTA, le serveur POP/IMAP, le système de fichiers du serveur ?

Wietse Zweitze Venema, le concepteur de Postfix, a une position tout à fait claire : ce n'est pas au MTA de le gérer. D'autres MTA comme EXIM le font cependant. Le « File System » doit savoir le faire, mais ici ça se passe au niveau du système d'exploitation et le client de messagerie n'a pas accès aux informations du système. C'est pourtant lui qui a besoin de connaitre cette information, puisque c'est à lui de gérer son espace de stockage.

Que se passe-t-il lorsque l'espace réservé au stockage des mails est entièrement occupé ? Le MDA (LDA) ne peut (le File System le lui interdit) ou ne doit (il a la consigne de gérer l'espace occupé) pas accepter de prendre en charge de nouveaux messages.

- Les nouveaux messages entrants doivent être refusés par le MTA, en notifiant l'expéditeur.

- Le destinataire doit être informé, par un moyen ou un autre, que sa boite déborde.

Nous avons bel et bien au moins deux composants qui sont dans le coup, si ce n'est trois, avec le File System.

Comment prévenir le destinataire que sa boite est pleine... En lui envoyant un message ? Il n'entrera pas dans la boite puisqu'elle est pleine... Il faut donc anticiper un peu et envoyer des alertes avant que ça ne déborde.

Comment prévenir l'émetteur du message de la non remise ?

- soit le MTA gère directement ;

- soit il reçoit l'information du MDA qui gère le quota ;

- soit il reçoit l'information du MDA qui reçoit l'information du File System.

Clairement, c'est dans le cas où le MTA gère qu'il y a le moins d'intermédiaires, au moins du côté des messages de notification.

4-4-2-2 - Où la mécanique en rajoute

La plupart des MUA gèrent de façon assez vilaine l'effacement des messages. Le chapitre sur IMAP vous en dira plus sur la question. Bref résumé :

- un message « effacé » doit être marqué comme tel, mais non détruit. Il reste dans le dossier où il a été effacé ;

- pour détruire physiquement un message, il faut envoyer au serveur IMAP la commande EXPUNGE. Les messages marqués comme effacés sont alors effectivement détruits par le File System.

La grande majorité des MUA utilise la « corbeille » (Trash) comme un dossier de classement :

- le message effacé est marqué comme effacé (protocole oblige) ;

- il est copié dans la corbeille.

L'effacement d'un message se traduit donc par l'augmentation du volume de données ! (Sans compter les MUA qui ne font jamais de expunge automatique. Voir l'astuce avec Thunderbird).

Tout ceci se traduit pour l'utilisateur non spécialiste par un piège dont il ne sait sortir. Sa boite est pleine et comme elle est pleine, il ne peut plus effacer de messages par les moyens habituellement utilisés.

4-4-2-3 - Le plug-in

Le plug-in de Dovecot est relativement souple et non moins relativement éphémère. La lecture de sa documentation montre clairement qu'il n'est pas encore stabilisé (à l'heure des versions 1.x). Nous allons donc l'utiliser dans le cadre de la version 1.0pre15 dont nous disposons.

Puisque nous sommes au format Maildir, nous utiliserons le standard Maildir++ qui permet de fixer non seulement un espace de stockage maximum mais aussi un nombre maximum de messages stockés. Nous n'utiliserons pas cette seconde limitation.

Au paragraphe « plugin » de dovecot.conf il faut ajouter ceci, en modifiant éventuellement les valeurs :

plugin {
# 20 MB + 10000 messages quota limit
quota = maildir:storage=20480
}

Ceci fixera un quota par défaut pour toutes les boites aux lettres soumises au quota. Nous verrons qu'il est possible de surcharger ces valeurs individuellement. Un storage=0 fera qu'il n'y aura pas de quota.

De plus, il faut indiquer pour chaque protocole que l'on utilise le quota :

protocol imap {
mail_plugins = quota imap_quota
}

protocol pop3 {
pop3_uidl_format = %08Xu%08Xv
mail_plugins = quota
}
protocol lda {
postmaster_address = sysop@maison.mrs
hostname = janus.maison.mrs
mail_plugin_dir = /usr/lib/dovecot/modules/lda
sendmail_path = /usr/lib/sendmail
auth_socket_path = /var/run/dovecot/auth-master
mail_plugins = cmusieve quota
}

Pour le protocole IMAP, imap_quota permet au MUA d'être informé du taux d'occupation :

Pour surcharger les valeurs par défaut, nous pouvons exploiter userdb, c'est-à-dire notre base de données. Postfixadmin a d'ailleurs prévu un champ spécifique dans la table mailbox :

mysql> select username, quota from mailbox;
+------------------+-------+
| username         | quota |
+------------------+-------+
| sysop@nain-t.net |     0 |
+------------------+-------+

Nous devons désormais lire toutes les informations de l'utilisateur dans la base. Autrement dit, dans dovecot.conf, le paragraphe :

userdb static {
args = uid=vmail gid=vmail home=/home/virtual/mail/%d/%n
}

Doit être remplacé par :

userdb sql {
args = /etc/dovecot/dovecot-sql.conf
}

Et donc, notre fichier dovecot-sql.conf va devoir tenir compte de cette nouvelle requête qu'il faut ajouter :

user_query = SELECT CONCAT('/home/virtual/mail/',maildir, 'Maildir/') as home, 500 AS uid, 500 AS gid,CONCAT('maildir:storage=', quota) as quota FROM mailbox WHERE username = '%u'

- CONCAT('/home/virtual/mail/',maildir, 'Maildir/') parce que la base construite par postfixadmin ne contient que le chemin relatif du répertoire de l'utilisateur et qu'il faut indiquer le chemin absolu du répertoire Maildir ;

- CONCAT('maildir:storage=', quota) parce que la base ne contient que la valeur numérique, alors qu'il faut transmettre à Dovecot la chaine de paramétrage complète.

4-4-2-4 - Postfixadmin et les quotas

Postfixadmin peut gérer les valeurs de quotas dans la table mailbox. Cependant, dans un souci de simplification probablement, la valeur saisie doit être exprimée en Mio(3) et elle est convertie (de façon approximative) en octets dans la base. Ainsi, lorsque nous mettons 4 dans le formulaire de postfixadmin, celui-ci écrit 4096000 dans la base. Comme le plug-in quota demande des valeurs en Kio, notre requête SQL est donc à revoir comme ceci :

user_query = SELECT CONCAT('/home/virtual/mail/',maildir, 'Maildir/') as home, 500 AS uid, 500 AS gid, CONCAT('maildir:storage=', floor(quota/1000)) as quota FROM mailbox WHERE username = '%u'

Voilà qui commence à faire une belle requête.

4-5 - Bilan d'étape

4-5-1 - Postfixadmin

Postfix Admin permet de créer simplement une base de données avec assez d'informations pour réaliser une gestion de domaines virtuels. Nous n'avons pas exploité la possibilité de définir un domaine en « backup », mais c'est facilement réalisable (voir plus bas). La gestion des alias fonctionne, il est possible d'attribuer plusieurs cibles au même alias, ce qui peut permettre la création de mini listes de diffusion.

Il est possible d'utiliser aussi bien Dovecot que Courier-imap pour le serveur POP/IMAP.

Si la configuration de PHP le permet, il est possible de lancer des scripts shell à la création de comptes, à la suppression de comptes et de domaines, de manière à « faire le ménage » dans le répertoire /home/virtual/mail dans notre cas.

Il est enfin possible, lors de la création de comptes, de créer automatiquement des dossiers imap supplémentaires.

4-5-2 - Dovecot

Dovecot est un serveur POP/IMAP très prometteur, mais encore jeune et sa configuration n'est pas encore complètement stabilisée, ce qui oblige à être très attentif en cas de mise à jour. La version fournie avec Debian Etch n'est qu'une « release candidate », il est cependant assez simple d'effectuer un rétro portage (backport) de la version v1.0.14, fournie dans Debian Lenny. Dans ce cas, il faut bien sûr recompiler le paquet source. Cette technique oblige l'administrateur à beaucoup de vigilance sur les publications de mises à jour de sécurité, puisqu'elles ne seront plus prises en charge par apt. Dovecot est un logiciel qui, pour l'instant, évolue trop vite pour des distributions comme Debian.

Dovecot fournit un service SASL d'authentification pour Postfix, ce qui permet simplement de gérer les clients itinérants sur le port submission.

Enfin, Dovecot sait utiliser aussi bien une base de données SQL qu'un annuaire LDAP.

4-5-3 - Bonus

En complément, la gestion des « MX Backups » pour certains domaines virtuels.

Postfixadmin met un drapeau dans la table domain qui permet de savoir si un domaine est une destination finale ou un « backup ». Rappelez-vous :

# cat mysql_virtual_domains_maps.cf
user = vmail
password = epikoi
hosts = localhost
dbname = vmail
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'

Il nous suffit de créer dans /etc/postfix/db/ un fichier mysql_relay_domains_maps.cf très semblable :

user = vmail
password = epikoi
hosts = localhost
dbname = vmail
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1' and active = '1'

Et d'ajouter la ligne suivante dans notre main.cf :

relay_domains = $mydestination proxy:mysql:/etc/postfix/db/mysql_relay_domains_maps.cf

5 - Postfix, Cyrus, etc.

Pour passer à l'étape supérieure, celle qui consiste à pouvoir « facilement » gérer :

- plusieurs domaines de messagerie sur la même structure ;

- plusieurs centaines de comptes de messagerie ;

- les alias ;

- les redirections ;

- d'autres choses encore...

Il va nous falloir quelque chose d'un peu plus sophistiqué. Nous allons voir pourquoi dans le détail il est intéressant de construire une structure qui dispose de :

- une interface graphique un peu conviviale pour gérer les domaines, les comptes, etc. ;

- une base de données qui contienne toutes les informations concernant les comptes, leur(s) alias, leur(s) redirection(s), les mots de passe associés aux comptes ;

- un serveur POP et/ou IMAP capable de s'appuyer sur cette base pour authentifier les clients, capable aussi de gérer plusieurs domaines de messagerie ;

- un MTA qui sache chercher les informations dont il a besoin dans cette base de données, capable aussi de refiler simplement les messages destinés aux comptes dont nous avons la charge.

5-1 - Ce qui existe

5-1-1 - L'interface graphique

Il n'existe pas une infinité d'interfaces dans le monde libre. L'usage d'une telle interface n'est certes pas une obligation, un jeu de scripts en ligne de commande peut parfaitement faire l'affaire, mais dans le cas d'un « wrapper » en php par exemple, il faudra choisir le reste des composants en fonction.

- Qmailadmin, par exemple, imposera le choix de Qmail + Vpopmail + ezmlm. Ce peut être un bon choix, si l'on est satisfait par Qmail (voir ailleurs sur ce site) ;

- Postfix.admin en PHP implique, comme son nom l'indique, l'emploi de Postfix, mais aussi de MySQL et d'un serveur POP/IMAP comme Dovecot ou Courier. A voir si l'on ne veut pas de Cyrus ;

- Open-Xchange est bien plus qu'une simple interface de gestion de messagerie, il s'agit d'une solution complète de travail collaboratif. Cette solution s'appuie sur Postfix, MySQL et Cyrus pour la partie messagerie ;

- Openmailadmin présente un intérêt certain, mais nécessite une version récente de PHP5 (Debian Lenny). Ce choix induit Postfix, MySQL et Cyrus, très proche donc de la solution adoptée ici ;

- Web-cyradm est également une interface graphique en php. Bien que ce projet ne semble pas jouir d'une vitalité exemplaire, il offre les fonctionnalités nécessaires. Sa licence GPL permettra aussi de l'adapter en toute liberté à chacun des besoins spécifiques. Ce sera notre choix final.

5-1-2 - Les bases de données

MySQL ne se présente plus. Mais il est possible d'envisager l'emploi d'autres solutions, comme PostgreSQL ou encore l'annuaire OpenLDAP.

Un annuaire LDAP n'est pas une chose facile à gérer. À moins de vouloir y centraliser d'autres informations que celles réservées à la messagerie, comme les comptes utilisateurs, les carnets d'adresses, etc., ce n'est sans doute pas la solution idéale.

5-1-3 - Serveurs POP et IMAP

Il en existe de nombreux. Les plus connus et aussi les plus utilisés sont probablement :

- Dovecot, déjà vu sur ce site dans le chapitre « 020postfix2 ». C'est sans doute un excellent choix ;

- Courier-imap fait partie de la suite courier-mta, il en est le constituant probablement le plus employé. Idéal avec Qmail et tout à fait exploitable avec Postfix ;

- Cyrus imap est une solution lourde mais riche. Il gère complètement les domaines et tout l'archivage des messages. Il suffit d'indiquer au MTA comment lui transmettre les messages locaux. De plus, Cyrus permet la mise en place de dossiers partagés IMAP et de serveurs de news. Ces composants sont surtout intéressants dans le cadre du travail collaboratif.

5-1-4 - Les MTA

Là encore il y a du choix :

- Courier-mta. Je n'en connais que le composant Courier-imap et ne saurais comparer cette solution aux autres ;

- Qmail, exposé ailleurs sur ce site. La stratégie de licence et de développement adoptée par son auteur en fait une solution pénible à maintenir. Dommage...

- Exim est le MTA proposé par défaut sur les distributions Debian. Il est hautement configurable, mais pas très simplement. Sa conception monolithique peut déplaire, mais il n'est pas connu pour ses failles de sécurité. Ce peut être un choix judicieux ;

- Postfix est certainement le MTA qui a la meilleure presse. Il est flexible, plutôt facilement configurable, monte bien en charge et son architecture lui permet d'avoir la réputation d'une grande robustesse.

Laissons reposer Sendmail en paix. Il existe encore d'autres solutions, mais celles-ci sont certainement les plus utilisées.

5-2 - Le choix proposé

Soyons clairs. Le choix proposé ici n'est pas forcément le meilleur. Nous l'avons vu, le contexte, les gouts personnels, les éventuelles évolutions du système peuvent amener à d'autres choix.

- Cyrus est un serveur POP/IMAP de qualité, qui présente de nombreuses possibilités, des outils de maintenance efficaces, et, si nous envisageons d'évoluer vers des solutions de travail collaboratif comme Open Xchange, un choix pertinent ;

- Postfix est un MTA de qualité, modulaire, relativement facile à configurer, également choisi dans la solution Open Xchange ;

- MySQL est une base de données réputée et facile à maintenir ;

- web-cyradm est conçu justement pour exploiter ces composants.

Reste à mettre tout ceci en pratique. Il nous faudra aussi quelques accessoires comme SASL, PAM, TLS pour l'authentification et la sécurisation. Également un Apache et les bibliothèques PHP pour l'interface d'administration.

5-3 - Web-Cyradm

Nous sommes sur une Debian Etch (testé aussi sur Lenny), déjà pourvue de :

- apache-mpm-prefork (php oblige) version 2.2.3 ;

- php5 version 5.2.0 ;

- mysql version 5.0.32.

Tout ceci est en état de marche.

Web-cyradm utilise la variable LANGUAGE si elle est définie sur notre système, pour choisir la langue. Cette variable d'environnement n'est pas définie par défaut sur Debian. Si nous voulons un web-cyradm en français, il faut ajouter la ligne :

LANGUAGE="fr_FR:fr:en_GB:en"

Dans le fichier /etc/environment. A noter que dans ce cas, il faudra utiliser la version trunk de web-cyradm que nous aurons placé quelque part sur notre machine (dans /var/www/wc dans l'exemple, pour faire simple).

Attention. J'ai rencontré un problème avec la version svn-5.5 si la variable LANGUAGE est définie. Elle fonctionne cependant mais en anglais seulement, si cette variable n'est pas définie.

5-3-1 - Création de la base

Nous retrouvons dans /var/www/wc/scripts deux scripts SQL qui vont nous permettre de créer la base de données MySQL. Notez qu'il y a aussi ce qu'il faut pour utiliser PostgreSQL).

insertuser_mysql.sql va créer un utilisateur et une base de données pour notre système de messagerie. Il y a bien sûr quelques modifications à apporter de manière à ne pas utiliser les paramètres par défaut :

- le nom de la base ;

- le nom de l'utilisateur qui manipulera cette base ;

- le mot de passe de cet utilisateur.

use mysql;
# Crée l'utilisateur et son mot de passe, sans aucun droit en général
INSERT INTO user (Host, User, Password, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv, Grant_priv, References_priv, Index_priv, Alter_priv) VALUES ('localhost', 'mail', PASSWORD('epikoi'), 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N');

# Accorde à l'utilisateur les droits nécessaires sur la base
INSERT INTO db (Host, Db, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Grant_priv, References_priv, Index_priv, Alter_priv) VALUES ('localhost', 'mail', 'mail', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y ');
flush privileges;

# Crée la base et l'utilisateur associé
create database mail;

Nous sommes restés très imaginatifs, la base et l'utilisateur s'appellent mail, avec un mot de passe désormais classique : epikoi.

create_mysql.sql va construire les tables de la base et y mettre quelques informations vitales (rendez-vous à la fin du script) :

# phpMyAdmin MySQL-Dump
# version 2.2.6
# http://phpwizard.net/phpMyAdmin/
# http://www.phpmyadmin.net/ (download page)
#
# Host: localhost
# Generation Time: Nov 04, 2002 at 01:44 AM
# Server version: 3.23.52
# PHP Version: 4.2.3
# Database : `mail`
# --------------------------------------------------------

#
# Table structure for table `accountuser`
#

CREATE TABLE accountuser (
username varchar(255) binary NOT NULL default '',
password varchar(50) binary NOT NULL default '',
prefix varchar(50) NOT NULL default '',
domain_name varchar(255) NOT NULL default '',
imap int(10) NOT NULL default '1',
pop int(10) NOT NULL default '1',
sieve int(10) NOT NULL default '1',
smtpauth int(10) NOT NULL default '1',
UNIQUE KEY username (username)
) TYPE=MyISAM;
# --------------------------------------------------------

#
# Table structure for table `adminuser`
#

CREATE TABLE adminuser (
username varchar(50) binary NOT NULL default '',
password varchar(50) binary NOT NULL default '',
type int(11) NOT NULL default '0',
SID varchar(255) NOT NULL default '',
home varchar(255) NOT NULL default '',
PRIMARY KEY  (username)
) TYPE=MyISAM;
# --------------------------------------------------------

#
# Table structure for table `settings`
#

CREATE TABLE settings (
`username` varchar(50) binary NOT NULL default '',
`style` varchar(50) NOT NULL default 'default',
`maxdisplay` int(4) NOT NULL default '15',
`warnlevel` int(3) NOT NULL default '90',
PRIMARY KEY  (username)
) TYPE=MyISAM;
# --------------------------------------------------------

#
# Table structure for table `alias`
#

CREATE TABLE alias (
alias varchar(255) NOT NULL default '',
dest longtext,
username varchar(50) NOT NULL default '',
status int(11) NOT NULL default '1',
PRIMARY KEY  (alias)
) TYPE=MyISAM;
# --------------------------------------------------------

#
# Table structure for table `domain`
#

CREATE TABLE domain (
domain_name varchar(255) NOT NULL default '',
prefix varchar(50) NOT NULL default '',
maxaccounts int(11) NOT NULL default '20',
quota int(10) NOT NULL default '20000',
domainquota int(10) NOT NULL default '0',
transport varchar(255) NOT NULL default 'cyrus',
freenames enum('YES','NO') NOT NULL default 'NO',
freeaddress enum('YES','NO') NOT NULL default 'NO',
folders varchar(255) NOT NULL default '',
PRIMARY KEY  (domain_name),
UNIQUE KEY prefix (prefix)
) TYPE=MyISAM;
# --------------------------------------------------------

#
# Table structure for table `domainadmin`
#

CREATE TABLE domainadmin (
domain_name varchar(255) NOT NULL default '',
adminuser varchar(255) NOT NULL default ''
) TYPE=MyISAM;
# --------------------------------------------------------

#
# Table structure for table `search`
#

CREATE TABLE search (
search_id varchar(255) NOT NULL default '',
search_sql text NOT NULL,
perpage int(11) NOT NULL default '0',
timestamp timestamp(14) NOT NULL,
PRIMARY KEY  (search_id),
KEY search_id (search_id)
) TYPE=MyISAM;
# --------------------------------------------------------

#
# Table structure for table `virtual`
#

CREATE TABLE virtual (
alias varchar(255) NOT NULL default '',
dest longtext,
username varchar(50) NOT NULL default '',
status int(11) NOT NULL default '1',
KEY alias (alias)
) TYPE=MyISAM;

CREATE TABLE log (
id int(11) NOT NULL auto_increment,
msg text NOT NULL,
user varchar(255) NOT NULL default '',
host varchar(255) NOT NULL default '',
time datetime NOT NULL default '2000-00-00 00:00:00',
pid varchar(255) NOT NULL default '',
PRIMARY KEY  (id)
) TYPE=MyISAM;

INSERT INTO adminuser (username, password) VALUES ('admin', ENCRYPT('epikoi'));
INSERT INTO domainadmin (domain_name,adminuser) VALUES ('*','admin');
INSERT INTO accountuser (username, password) VALUES ('cyrus', ENCRYPT('epikoi'));
INSERT INTO `settings` ( `username` , `style` , `maxdisplay` , `warnlevel` ) VALUES ( 'admin', 'default', '15', '90');

ALTER TABLE `log` ADD INDEX `idx_log_user` ( `user` );

Dans adminuser, nous plaçons ce qu'il faut pour pouvoir par la suite ouvrir une session sur web-cyradm. Le couple admin/epikoi n'a aucun rapport avec un quelconque utilisateur de la messagerie, c'est juste un « login » qui permet d'utiliser web-cyradm.

Dans accountuser, nous créons cyrus/epikoi. Ce login va permettre l'administration de Cyrus. Il est en principe inconnu de tous, c'est une affaire entre web-cyradm et Cyrus.

Bien entendu, ces logins sont à personnaliser avant de créer la base.

Il suffit maintenant de faire :

mysql -u root -p < insertuser_mysql.sql

pour créer l'utilisateur mail et sa base associée, puis

mysql mail -u mail -p < create_mysql.sql

pour peupler un minimum cette base.

5-3-2 - Accès à la base

web-cyradm pouvant utiliser aussi bien MySQL que PostgreSQL, le concepteur a utilisé une couche d'abstraction (hélas obsolète aujourd'hui), mais qui est pour l'instant encore disponible, il s'agit de Pear::DB. Un :

aptitude install php-pear
pear install DB

Résoudra le problème (avec le « warning » qui va bien), si vous avez bien entendu installé ce qu'il faut pour utiliser Pear.

5-3-3 - Configuration de web-cyradm

Il faut encore configurer l'interface. Dans /var/www/wc/config, il y a un fichier conf.php.dist, qu'il va falloir copier en conf.php et modifier quelque peu :

# The Cyrus login stuff
$CYRUS = array(
'HOST'  => 'localhost',
'PORT'  => 143,
'ADMIN' => 'cyrus',
'PASS'  => 'epikoi'
);

/* DB_TYPE

Possible Values are:
o mysql
o pgsql

To operate a mailsystem with postgreSQL you will need a patch for
Postfix.

Other Databases need to be supported by PAM and postfix
*/

$DB = array(
'TYPE'  => 'mysql',
'USER'  => 'mail',
'PASS'  => 'epikoi',
'PROTO' => 'unix',      // set to "tcp" for TCP/IP
'HOST'  => 'localhost',
'NAME'  => 'mail'
);

$DB['DSN'] = sprintf('%s://%s:%s@%s+%s/%s',     $DB['TYPE'], $DB['USER'],
$DB['PASS'], $DB['PROTO'],
$DB['HOST'], $DB['NAME']);

# Where should web-cyradm write its log to?
$LOG_DIR = "/var/log/web-cyradm/";

/* Log level
Possible values are (from quiet to verbose):
ERR    - only internal errors
WARN   - failed login, security violation
INFO   - all login and logout
DEBUG  - all possible information
*/
$LOG_LEVEL = "INFO";

# The default timeout in seconds for a session, after that you have to login again
$SESS_TIMEOUT = 1000;

# The default quota sets the default quota for new accounts
$DEFAULT_QUOTA = 2000000;

# The default domain quota sets the quota for new domains
# 0 = No quota
$DEFAULT_DOMAIN_QUOTA = 0;

# On what quota level mark accounts on accounts list (in %)
$QUOTA_WARN_LEVEL = 90;

# Defines if passwords are encrypted or not.
# Valid Values:
#  - plain 0 No encription is used
#  - crypt 1 (shadow compatible encription)
#  - mysql 2 (MySQL PASSWORD function)
#  - md5 3 (MD5 digest)
$CRYPT = "crypt";

# web-cyradm is compatible with cyrus-imapd-2.0.16 (and earlier?)
# however, if you are using 2.1.x and wish to use email addresses
# with .'s in them such as 'john.doe@mydomain.com' you can set this
# option DOMAIN_AS_PREFIX to '1'.  NOTE: you also have to add this
# line to your imapd.conf file:
#### imapd.conf: ####
#unixhierarchysep: yes

####
$DOMAIN_AS_PREFIX = 1;

# EXPERIMENTAL
# If you are using cyrus imap 2.2.x and wish to use usernames like
# email addresses you can set option DOMAIN_AS_PREFIX to '1' and
# FQUN to '1'. NOTE: you also have to add this lines to your
# imapd.conf file:
#### imapd.conf: ####
# unixhierarchysep: yes
# virtdomains: yes
####
$FQUN = 1;

# At the moment, web-cyradm supports two methods of password change:
# - through sql
# - poppassd
# sql is the default
$PASSWORD_CHANGE_METHOD = "sql";

# Turn up error reporting level. This overrides settings in your php.ini
#
# E_ALL             - All errors and warnings
# E_ERROR           - fatal run-time errors
# E_WARNING         - run-time warnings (non-fatal errors)
# E_PARSE           - compile-time parse errors
# E_NOTICE          - run-time notices (these are warnings which often result
#                     from a bug in your code, but it's possible that it was
#                     intentional (e.g., using an uninitialized variable and
#                     relying on the fact it's automatically initialized to an
#                     empty string)
# E_CORE_ERROR      - fatal errors that occur during PHP's initial startup
# E_CORE_WARNING    - warnings (non-fatal errors) that occur during PHP's
#                     initial startup
# E_COMPILE_ERROR   - fatal compile-time errors
# E_COMPILE_WARNING - compile-time warnings (non-fatal errors)
# E_USER_ERROR      - user-generated error message
# E_USER_WARNING    - user-generated warning message
# E_USER_NOTICE     - user-generated notice message

error_reporting(E_ERROR);

$VERSION="0.5.5-Beta1";

# Define reserved Emailadresses (Separated by comma):
$RESERVED="postmaster,root";

$TEMPLATE[0]="default";
$TEMPLATE[1]="green";

Nous allons utiliser Cyrus 2.2 et ses possibilités natives de gestion des domaines virtuels. Il existe en effet deux possibilités pour gérer ces domaines virtuels :

- demander à Cyrus (2.2) de le faire lui-même. Dans ce cas, un utilisateur aura comme nom d'utilisateur son adresse e-mail complète, à la manière de Qmail-Vpopmail ;

- faire « à l'ancienne » avec tous les comptes dans un seul domaine, et des alias qui iront pointer dessus. Dans ce cas, l'utilisateur qui aurait par exemple l'adresse machin@chose.tld n'aurait en fait qu'un alias, pointant sur une « vraie » boîte d'adresse, disons, chose.tld-machin@domaineunique.tld et son nom d'utilisateur serait dans ce cas chose.tld-machin.

Nous choisissons la première solution.

Notre web-cyradm n'est pas encore en état de fonctionner, mais nous pouvons déjà vérifier que l'interface fonctionne :

Puis une fois la session ouverte :

À ce niveau, nous ne pouvons pas faire grand-chose de plus, puisque Cyrus n'est pas encore en place.

5-4 - S A S L

Simple Authentication and Security Layer.Méthode d'authentification utilisable avec les protocoles fonctionnant en mode connecté, définie dans les RFC 2222, 2245 et 2444. Voir aussiGSSAPI. (Définition du Jargon Français).

Contrairement à ce que le nom pourrait laisser entendre, SASL est tout sauf simple à mettre en pratique. L'objectif n'étant pas d'en devenir des spécialistes, nous l'utiliserons dans un cas de figure qui répond à la question.

Cyrus va avoir besoin d'authentifier ses clients. Postfix probablement aussi, suivant ce que nous lui demanderons de faire.

SASL va fournir un serveur saslauthd que les applications (Cyrus et probablement Postfix) iront interroger chaque fois qu'il sera nécessaire d'authentifier un utilisateur.

saslauthd est capable d'interroger de façons très diverses différents éléments capables de lui fournir les informations requises. Ici, nous allons utiliser saslauthd de manière à ce qu'il s'appuie sur PAM, qui lui-même s'appuiera sur notre base MySQL. Vous comprenez aisément la souplesse que peut apporter ce type de fonctionnement si nous désirons remplacer MySQL par quelque chose d'autre.

5-4-1 - saslauthd

5-4-1-1 - Installation

Il faut installer le paquet sasl2-bin, qui fera installer les dépendances nécessaires. donc :

aptitude install sasl2-bin libsasl2-modules

Et laissons faire.

5-4-1-2 - Configuration

Il y a un simple fichier à manipuler : /etc/default/saslauthd, car saslauthd n'a pas de fichier de configuration, tout est dans la ligne de commande.

Le fichier doit ressembler à ceci :

#
# Settings for saslauthd daemon
#

# Should saslauthd run automatically on startup? (default: no)
START=yes

# Which authentication mechanisms should saslauthd use? (default: pam)

# Notez la somme de possibilités offertes

# Available options in this Debian package:
# getpwent  -- use the getpwent() library function
# kerberos5 -- use Kerberos 5
# pam       -- use PAM
# rimap     -- use a remote IMAP server
# shadow    -- use the local shadow password file
# sasldb    -- use the local sasldb database file
# ldap      -- use LDAP (configuration is in /etc/saslauthd.conf)
#
# Only one option may be used at a time. See the saslauthd man page
# for more information.
#
# Example: MECHANISMS="pam"
MECHANISMS="pam"

# Additional options for this mechanism. (default: none)
# See the saslauthd man page for information about mech-specific options.
MECH_OPTIONS=""

# How many saslauthd processes should we run? (default: 5)
# A value of 0 will fork a new process for each connection.
THREADS=5

# Other options (default: -c)
# See the saslauthd man page for information about these options.
#
# Example for postfix users: "-c -m /var/spool/postfix/var/run/saslauthd"
# Note: See /usr/share/doc/sasl2-bin/README.Debian
OPTIONS="-c -r -m /var/spool/postfix/var/run/saslauthd"

Dans les options, il y en a deux qui sont fondamentales ici :

- l'option -r combine le domaine (« realm » ou encore « royaume ») avec le login en mettant le signe « @ » entre les deux. Par exemple « login : « foo » realm : « bar » sera transformé en login : « foo@bar ». Avec nos options, nous aurons dans notre base de données l'adresse complète de l'utilisateur en guise de nom d'utilisateur ;

- nous allons utiliser un socket Unix pour communiquer avec saslauthd. Il se trouve que les composants de Postfix impliqués seront en cage (chroot) dans /var/spool/postfix. Nous devons donc modifier le chemin d'accès par défaut à ce socket, pour que les composants de Postfix puissent y accéder, c'est le but de la partie -m /var/spool/postfix/var/run/saslauthd. Il ne faudra donc pas oublier de créer cette arborescence. Autant le faire tout de suite (même si Postfix n'est pas encore installé) :

mkdir -p /var/spool/postfix/var/run/saslauthd

Nous en avons fini avec saslauthd, nous pouvons même le démarrer :

/etc/init.d/saslauthd start

et vérifier qu'il est en service comme nous le lui avons demandé :

# ps aux | grep saslauthd
root      2266  0.0  0.1   7212   980 ?        Ss   15:20   0:00 /usr/sbin/saslauthd -a pam -c -r -m /var/spool/postfix/var/run/saslauthd -n 5
root      2267  0.0  0.3   7256  1564 ?        S    15:20   0:00 /usr/sbin/saslauthd -a pam -c -r -m /var/spool/postfix/var/run/saslauthd -n 5
root      2268  0.0  0.1   7212   540 ?        S    15:20   0:00 /usr/sbin/saslauthd -a pam -c -r -m /var/spool/postfix/var/run/saslauthd -n 5
root      2269  0.0  0.0   7212   360 ?        S    15:20   0:00 /usr/sbin/saslauthd -a pam -c -r -m /var/spool/postfix/var/run/saslauthd -n 5
root      2270  0.0  0.0   7212   360 ?        S    15:20   0:00 /usr/sbin/saslauthd -a pam -c -r -m /var/spool/postfix/var/run/saslauthd -n 5

5-4-2 - Et PAM ?

Lorsque cyrus-imapd va s'adresser à saslauthd, il faudra que pam sache qui interroger et comment le faire. Nous aurons à créer un fichier nommé imap dans /etc/pam.d. Nous le ferons lorsque nous aurons installé cyrus-imapd-2.2, qui va en placer un qu'il nous faudra modifier.

5-5 - Cyrus-imapd

Ici, ça va être un peu plus long et aussi un peu plus délicat.

5-5-1 - Installation

Nous voulons proposer IMAP mais aussi POP3 ? Nous avons à installer deux paquets, les dépendances nécessaires suivront :

aptitude install cyrus-imapd-2.2 cyrus-pop3d-2.2

Pour plus de confort, installons aussi quelques paquets recommandés :

aptitude install cyrus-clients-2.2 cyrus-doc-2.2

Nous devrions disposer de tout ce qui est nécessaire.

5-5-2 - Configuration

Nous avons deux fichiers sur lesquels il nous faut intervenir.

5-5-2-1 - cyrus.conf

Cyrus est un outil très puissant, qui sait répartir les boites aux lettres sur plusieurs serveurs. Notre objectif n'est pas de concurrencer le premier fournisseur d'accès de France, nous resterons plus humbles et n'utiliserons pas ces fonctionnalités.

Dans l'exemple qui suit, nous activons POP3 et IMAP. Nous pourrions aussi activer POP3S et IMAP4 et même aussi un serveur de type usenet (nntp, en installant en plus cyrus-nntpd-2.2) si nous voulons, mais web-cyradm ne gèrera pas ce dernier.

# Debian defaults for Cyrus IMAP server/cluster implementation
# see cyrus.conf(5) for more information
#
# All the tcp services are tcpd-wrapped. see hosts_access(5)
# $Id: cyrus.conf 567 2006-08-14 18:19:32Z sven $

START {
# do not delete this entry!
recover         cmd="/usr/sbin/ctl_cyrusdb -r"

# this is only necessary if idlemethod is set to "idled" in imapd.conf
#idled          cmd="idled"

# this is useful on backend nodes of a Murder cluster
# it causes the backend to syncronize its mailbox list with
# the mupdate master upon startup
#mupdatepush   cmd="/usr/sbin/ctl_mboxlist -m"

# this is recommended if using duplicate delivery suppression
delprune        cmd="/usr/sbin/cyr_expire -E 3"
# this is recommended if caching TLS sessions
tlsprune        cmd="/usr/sbin/tls_prune"
}

# UNIX sockets start with a slash and are absolute paths
# you can use a maxchild=# to limit the maximum number of forks of a service
# you can use babysit=true and maxforkrate=# to keep tight tabs on the service
# most services also accept -U (limit number of reuses) and -T (timeout)
SERVICES {
# --- Normal cyrus spool, or Murder backends ---
# add or remove based on preferences
imap            cmd="imapd -U 30" listen="imap" prefork=0 maxchild=100
#imaps          cmd="imapd -s -U 30" listen="imaps" prefork=0 maxchild=100
pop3            cmd="pop3d -U 30" listen="pop3" prefork=0 maxchild=50
#pop3s          cmd="pop3d -s -U 30" listen="pop3s" prefork=0 maxchild=50
#nntp           cmd="nntpd -U 30" listen="nntp" prefork=0 maxchild=100
#nntps          cmd="nntpd -s -U 30" listen="nntps" prefork=0 maxchild=100

# At least one form of LMTP is required for delivery
# (you must keep the Unix socket name in sync with imap.conf)
#lmtp           cmd="lmtpd" listen="localhost:lmtp" prefork=0 maxchild=20
#lmtpunix       cmd="lmtpd" listen="/var/run/cyrus/socket/lmtp" prefork=0 maxchild=20
lmtpunix       cmd="lmtpd" listen="/var/spool/postfix/cyrussock/lmtp" prefork=0 maxchild=20
# ----------------------------------------------

# useful if you need to give users remote access to sieve
# by default, we limit this to localhost in Debian
sieve           cmd="timsieved" listen="localhost:sieve" prefork=0 maxchild=100

# this one is needed for the notification services
#notify         cmd="notifyd" listen="/var/run/cyrus/socket/notify" proto="udp" prefork=1
notify         cmd="notifyd" listen="/var/spool/postfix/cyrussock/notify" proto="udp" prefork=1

# --- Murder frontends -------------------------
# enable these and disable the matching services above,
# except for sieve (which deals automatically with Murder)

# mupdate database service - must prefork at least 1
# (mupdate slaves)
#mupdate       cmd="mupdate" listen=3905 prefork=1
# (mupdate master, only one in the entire cluster)
#mupdate       cmd="mupdate -m" listen=3905 prefork=1

# proxies that will connect to the backends
#imap           cmd="proxyd" listen="imap" prefork=0 maxchild=100
#imaps          cmd="proxyd -s" listen="imaps" prefork=0 maxchild=100
#pop3           cmd="pop3proxyd" listen="pop3" prefork=0 maxchild=50
#pop3s          cmd="pop3proxyd -s" listen="pop3s" prefork=0 maxchild=50
#lmtp           cmd="lmtpproxyd" listen="lmtp" prefork=1 maxchild=20
# ----------------------------------------------
}

EVENTS {
# this is required
checkpoint      cmd="/usr/sbin/ctl_cyrusdb -c" period=30

# this is only necessary if using duplicate delivery suppression
delprune        cmd="/usr/sbin/cyr_expire -E 3" at=0401

# this is only necessary if caching TLS sessions
tlsprune        cmd="/usr/sbin/tls_prune" at=0401

# indexing of mailboxs for server side fulltext searches

# reindex changed mailboxes (fulltext) approximately every other hour
#squatter_1     cmd="/usr/bin/nice -n 19 /usr/sbin/squatter -s" period=120

# reindex all mailboxes (fulltext) daily
#squatter_a     cmd="/usr/sbin/squatter" at=0517
}

Ici encore, les sockets Unix sont à déplacer dans la cage de Postfix si nous voulons les utiliser (et nous le voudrons).

5-5-2-2 - imapd.conf

Plus spécifique à imap, voici ce fichier débarrassé de ses commentaires « d'usine » :

configdirectory: /var/lib/cyrus
defaultpartition: default
partition-default: /var/spool/cyrus/mail
altnamespace: no

# rappelez-vous, lors de la configuration de web-cyradm...
unixhierarchysep: yes
virtdomains: yes

# Vous avez bien un domaine dans lequel se trouve le serveur ?

lmtp_downcase_rcpt: yes
allowanonymouslogin: no
popminpoll: 1
autocreatequota: 0
umask: 077
sieveusehomedir: false
sievedir: /var/spool/sieve
hashimapspool: true
allowplaintext: yes
sasl_mech_list: PLAIN

# Comment exploiter SASL (et son socket unix)
sasl_pwcheck_method: saslauthd
sasl_saslauthd_path: /var/spool/postfix/var/run/saslauthd/mux
sasl_auto_transition: no

# Nous verrons comment faire du TLS proprement plus tard
tls_ca_path: /etc/ssl/certs
tls_session_timeout: 1440
tls_cipher_list: TLSv1+HIGH:!aNULL:@STRENGTH

# Et n'oublions pas l'emplacement des sockets
lmtpsocket: /var/spool/postfix/cyrussock/lmtp

idlemethod: poll
idlesocket: /var/spool/postfix/cyrussock/idle
notifysocket: /var/spool/postfix/cyrussock/notify

syslog_prefix: cyrus
allowusermoves: yes

# Enfin, il faut déclarer au moins un administrateur
admins: cyrus
imap_admins: cyrus
sieve_admins: cyrus

Rappelez-vous que nous avons dans notre base MySQL un administrateur nommé cyrus. Le paramètre unixhierarchysep: yes indique à Cyrus qu'il doit utiliser le séparateur / plutôt que le . qui est sa configuration par dafaut, et qui a l'inconvénient que le . n'est plus utilisable dans les noms d'utilisateurs. Dans la configuration choisie, il est indispensable de pouvoir mettre des points dans les noms d'utilisateurs.

N'oublions pas :

mkdir -p /var/spool/postfix/cyrussock

Notez que cette configuration n'a que valeur d'exemple. Consultez le imapd.conf « d'usine » pour avoir plus d'informations. Consultez aussi le manuel : man imapd.conf pour tous les paramètres possibles.

5-5-2-3 - Bon. Et PAM ?

Ne l'oublions pas. Dans /etc/pam.d, nous avons le fichier imap à modifier comme suit :

auth sufficient pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password crypt=1
account required pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password crypt=1

Les parties surlignées sont à modifier en fonction de votre personnalisation bien sûr.

Il ne faut pas oublier non plus d'installer ce qu'il faut pour que PAM puisse utiliser MySQL :

aptitude install libpam-mysql

5-5-3 - Vérifications

L'outil testsaslauthd va nous permettre de vérifier que l'utilisateur cyrus est authentifié :

# testsaslauthd -u cyrus -p epikoi -f /var/spool/postfix/var/run/saslauthd/mux
0: OK "Success."

Web-cyradm devrait maintenant nous permettre de créer des domaines et des comptes dans ces domaines.

C'est fait.

Créons maintenant un compte de test :

Voilà qui est fait.

Vérification avec l'outil cyradm en ligne de commande :

aptitude install cyrus-admin-2.2

Puis :

# cyradm --user cyrus --server localhost
Password:
localhost> lm
user/test@nain-t.net (\HasNoChildren)
localhost> lam user/test@nain-t.net
test@nain-t.net lrswipcda
cyrus lrswipcda
localhost> exit

Ça marche. Il faudra quand même approfondir un peu cet outil. Faites m'y penser si j'oubliais...

En gros, la BAL est bien créée, l'utilisateur test@nain-t.net a tous les droits dessus et l'administrateur cyrus aussi (nécessaire pour l'administration par le compte cyrus).

Et l'utilisateur test@nain-t.net est-il bien authentifié par saslauthd ?

# testsaslauthd -u test@nain-t.net -p epikoi -f /var/spool/postfix/var/run/saslauthd/mux
0: OK "Success."

Impeccable, il pourra donc accéder à sa BAL avec son MUA favori.

Vérification avec telnet :

# telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK openmailadmin Cyrus IMAP4 v2.2.13-Debian-2.2.13-14+b1 server ready
10 login test@nain-t.net epikoi
10 OK User logged in
20 logout
* BYE LOGOUT received
20 OK Completedhttp://smartsieve.sourceforge.net/
Connection closed by foreign host.

Il ne reste plus qu'à injecter des messages là dedans avec Postfix et notre solution sera presque opérationnelle. Il restera à s'occuper un peu de la sécurité de l'ensemble.

5-5-4 - Sieve

Il s'agit d'un langage de filtrage d'e-mails, comparable dans sa fonctionnalité au langage de scripts de procmail. Son avantage est d'être normalisé dans le RFC 5228. Son inconvénient est d'être sans doute moins puissant que le langage procmail.

La souplesse de Sieve vient du fait que l'utilisateur peut placer sur le serveur des règles de filtrage, sans pour autant disposer d'un compte Unix. Il existe plusieurs moyens de le faire :

- un plug-in dans squirrelmail : avelsieve ;

- le composant Ingo de la suite horde (non testé) ;

- Smartsieve est un projet autonome en PHP dédié à cette tâche.

Pour des raisons de sécurité, il est préférable de limiter le service timsieved à l'écoute de localhost, ce qui est le cas par défaut dans la distribution Debian. Extrait du /etc/cyrus.conf :

SERVICES {
...
# ----------------------------------------------

# useful if you need to give users remote access to sieve
# by default, we limit this to localhost in Debian
sieve        cmd="timsieved" listen="localhost:sieve" prefork=0 maxchild=100
...
}

Les scripts vont dans /usr/spool/sieve/ où ils sont rangés avec la même logique que les boites aux lettres.

De plus, pour que l'utilisateur puisse manipuler ses scripts sieve, il faudra que PAM dispose dans /etc/pam.d/ d'un fichier nommé sieve et, dans l'immédiat, identique à imap.

5-5-5 - Note importante

5-5-5-1 - Suppression d'un message

Lors de la suppression d'un message dans la boite de réception, le protocole IMAP prévoit que le message est marqué comme effacé, mais n'est pas supprimé. Pour supprimer définitivement un message, c'est-à-dire pour l'effacer physiquement sur le serveur, il faut utiliser la commande expunge. Il se trouve que cette procédure est gérée très diversement suivant le MUA employé.

Le plus souvent, le fait d'effacer un message se traduit pas :

- le marquage dudit message comme « effacé » ;

- la copie du message dans le répertoire « Trash » (la poubelle).

Autrement dit : Effacer un message revient à le recopier dans un autre répertoire. En croyant gagner de la place, on en perd. Plutôt que de longs discours, voyons ceci sur un exemple. La boite aux lettres de sysop@nain-t.net est vide :

cyrus:/var/spool/cyrus/mail/domain/n/nain-t.net/s/user/sysop# ls -l
total 20
-rw------- 1 cyrus mail    4 2008-07-12 20:42 cyrus.cache
-rw------- 1 cyrus mail  199 2008-07-11 15:43 cyrus.header
-rw------- 1 cyrus mail   76 2008-07-12 20:42 cyrus.index
drwx------ 2 cyrus mail 4096 2008-07-12 23:14 Sent
drwx------ 2 cyrus mail 4096 2008-07-12 23:13 Trash

Les répertoires Sent et Trash le sont également.

sysop@nain-t.net reçoit un message :

cyrus:/var/spool/cyrus/mail/domain/n/nain-t.net/s/user/sysop# ls -l
total 24
-rw------- 1 cyrus mail 1270 2008-07-12 23:18 16.
-rw------- 1 cyrus mail  740 2008-07-12 23:18 cyrus.cache
-rw------- 1 cyrus mail  199 2008-07-11 15:43 cyrus.header
-rw------- 1 cyrus mail  136 2008-07-12 23:18 cyrus.index
drwx------ 2 cyrus mail 4096 2008-07-12 23:14 Sent
drwx------ 2 cyrus mail 4096 2008-07-12 23:13 Trash

Nous retrouvons bien le message dans le répertoire de sysop. La poubelle est toujours vide. sysop lit son message, puis le « supprime » avec son Thunderbird favori. Dans son MUA, le message a disparu, mais il se retrouve dans la corbeille. Voyons le résultat dans son répertoire :

cyrus:/var/spool/cyrus/mail/domain/n/nain-t.net/s/user/sysop# ls -l
total 24
-rw------- 2 cyrus mail 1270 2008-07-12 23:18 16.
-rw------- 1 cyrus mail  740 2008-07-12 23:18 cyrus.cache
-rw------- 1 cyrus mail  199 2008-07-11 15:43 cyrus.header
-rw------- 1 cyrus mail  136 2008-07-12 23:21 cyrus.index
drwx------ 2 cyrus mail 4096 2008-07-12 23:14 Sent
drwx------ 2 cyrus mail 4096 2008-07-12 23:21 Trash
cyrus:/var/spool/cyrus/mail/domain/n/nain-t.net/s/user/sysop# ls -l Trash/
total 16
-rw------- 2 cyrus mail 1270 2008-07-12 23:18 19.
-rw------- 1 cyrus mail  740 2008-07-12 23:21 cyrus.cache
-rw------- 1 cyrus mail  199 2008-07-11 16:00 cyrus.header
-rw------- 1 cyrus mail  136 2008-07-12 23:21 cyrus.index

Nous retrouvons bien un message dans Trash, mais le message se trouve toujours dans le répertoire racine (INBOX). En gros, sysop n'a fait que recopier le message dans Trash.

sysop vide la corbeille :

cyrus:/var/spool/cyrus/mail/domain/n/nain-t.net/s/user/sysop# ls -l
total 24
-rw------- 1 cyrus mail 1270 2008-07-12 23:18 16.
-rw------- 1 cyrus mail  740 2008-07-12 23:18 cyrus.cache
-rw------- 1 cyrus mail  199 2008-07-11 15:43 cyrus.header
-rw------- 1 cyrus mail  136 2008-07-12 23:21 cyrus.index
drwx------ 2 cyrus mail 4096 2008-07-12 23:14 Sent
drwx------ 2 cyrus mail 4096 2008-07-12 23:26 Trash
cyrus:/var/spool/cyrus/mail/domain/n/nain-t.net/s/user/sysop# ls -l Trash/
total 12
-rw------- 1 cyrus mail   4 2008-07-12 23:26 cyrus.cache
-rw------- 1 cyrus mail 199 2008-07-11 16:00 cyrus.header
-rw------- 1 cyrus mail  76 2008-07-12 23:26 cyrus.index

Le message a disparu dans Trash, mais il est toujours présent dans la racine du répertoire de sysop (INBOX) ! Pour le faire disparaitre, sysop doit utiliser la commande « compacter », en cliquant du bouton droit sur « courrier entrant » :

cyrus:/var/spool/cyrus/mail/domain/n/nain-t.net/s/user/sysop# ls -l
total 20
-rw------- 1 cyrus mail    4 2008-07-12 23:30 cyrus.cache
-rw------- 1 cyrus mail  199 2008-07-11 15:43 cyrus.header
-rw------- 1 cyrus mail   76 2008-07-12 23:30 cyrus.index
drwx------ 2 cyrus mail 4096 2008-07-12 23:14 Sent
drwx------ 2 cyrus mail 4096 2008-07-12 23:26 Trash

Cette remarque s'applique à tous les dossiers quesysop aura pu créer (à l'exception de la poubelle, qui est systématiquement purgée lorsqu'elle est vidée) y compris le dossierSent (messages envoyés).

Il est donc important que les utilisateurs en prennent conscience, faute de quoi leur quota sera atteint sans qu'ils ne comprennent pourquoi.

Il est possible de demander à Thunderbird de purger automatiquement le répertoire INBOX lorsqu'il est refermé, mais cette opération ne purgera que le répertoire INBOX et pas les autres.

La bonne pratique consiste à ne pas utiliser la corbeille mais à demander à Thunderbird de marquer les messages comme « effacés » ce qui est le comportement normal, prévu par IMAP. De cette manière le message apparait barré, n'est pas recopié dans Trash et ne disparait effectivement dans l'affichage du MUA que lors de l'envoi de la commande « compacter ».

5-6 - Postfix avec cyrus

Nous avons déjà pas mal parlé de ce MTA. Par rapport à la solution « Postfix plus Dovecot » déjà vue, nous avons quelques modifications à apporter :

- expliquer à Postfix qu'il doit désormais remettre les messages locaux à cyrus ;

- lire certaines informations dans les tables de MySQL :

- ses destinations,

- les alias,

- les redirections ;

- vérifier l'authentification des utilisateurs, quand c'est nécessaire, par SASL en utilisant les services de saslauthd.

Comme il y a pas mal de nouveautés, nous allons reprendre progressivement, en partant de la configuration deBase.

Pour master.cf :

#
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       -       -       -       smtpd
#submission inet n       -       -       -       -       smtpd
#  -o smtpd_tls_security_level=encrypt
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#smtps     inet  n       -       -       -       -       smtpd
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#628      inet  n       -       -       -       -       qmqpd
pickup    fifo  n       -       -       60      1       pickup
cleanup   unix  n       -       -       -       0       cleanup
qmgr      fifo  n       -       n       300     1       qmgr
#qmgr     fifo  n       -       -       300     1       oqmgr
tlsmgr    unix  -       -       -       1000?   1       tlsmgr
rewrite   unix  -       -       -       -       -       trivial-rewrite
bounce    unix  -       -       -       -       0       bounce
defer     unix  -       -       -       -       0       bounce
trace     unix  -       -       -       -       0       bounce
verify    unix  -       -       -       -       1       verify
flush     unix  n       -       -       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       -       -       -       smtp
# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
relay     unix  -       -       -       -       -       smtp
-o smtp_fallback_relay=
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq     unix  n       -       -       -       -       showq
error     unix  -       -       -       -       -       error
retry     unix  -       -       -       -       -       error
discard   unix  -       -       -       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       -       -       -       lmtp
anvil     unix  -       -       -       -       1       anvil
scache    unix  -       -       -       -       1       scache
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop  unix  -       n       n       -       -       pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# See the Postfix UUCP_README file for configuration details.
#
uucp      unix  -       n       n       -       -       pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail    unix  -       n       n       -       -       pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix    -    n    n    -    2    pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
${nexthop} ${user}

Pour main.cf :

# See /usr/share/postfix/main.cf.dist for a commented, more complete ersion

# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package or
# information on enabling SSL in the smtp client.

myhostname = cyrus.nain-t.net
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = $myhostname
mydestination = nain-t.net, $myhostname, localhost.nain-t.net, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

5-6-1 - Configuration minimale

Dans un premier temps, nous allons juste expliquer à Postfix qu'il doit transmettre les messages considérés comme locaux (mydestination) à Cyrus, par l'intermédiaire du socket Unix créé par Cyrus. De plus, comme les utilisateurs sont des utilisateurs qui n'ont pas de compte Unix, nous devons reconsidérer la façon dont Postfix évalue l'existence des utilisateurs locaux. En effet, par défaut, Postfix regarde le contenu du fichier passwd.

Nous ajoutons donc ces deux lignes à notre main.cf :

mailbox_transport = lmtp:unix:/cyrussock/lmtp
local_recipient_maps =

- la première ligne indique que le transport local doit se faire par le protocole lmtp via un socket Unix qui se trouve dans le répertoire (mis en cage) /cyrussock/lmtp ;

- la seconde indique à Postfix qu'il n'a pas à se soucier de vérifier l'existence du compte local. Ce n'est pas gravissime pour l'instant, Cyrus le fera de toutes manières. Dans l'avenir, si Postfix peut s'en assurer lui-même ce ne sera pas plus mal en termes de ressources utilisées.

Et nous assurons que le domaine nain-t.net est bien dans nos destinations :

mydestination = nain-t.net, cyrus.nain-t.net, cyrus.nain-t.net, localhost.nain-t.net, localhost

Après avoir forcé la reconfiguration de Postfix (postfix reload), envoyons un message à test@nain-t.net :

# mail test@nain-t.net
Subject: test 0
config mini
.
Cc:

Et voyons dans les logs (/var/log/mail.info) :

Jun 16 10:15:06 cyrus postfix/pickup[8271]: 7CC2E4800D3C: uid=0 from=<root>
Jun 16 10:15:06 cyrus postfix/cleanup[8277]: 7CC2E4800D3C: message-id=<20080616081506.7CC2E4800D3C@cyrus.nain-t.net>
Jun 16 10:15:06 cyrus postfix/qmgr[8272]: 7CC2E4800D3C: from=<root@cyrus.nain-t.net>, size=323, nrcpt=1 (queue active)
Jun 16 10:15:06 cyrus cyrus/lmtpunix[8281]: Delivered: <20080616081506.7CC2E4800D3C@cyrus.nain-t.net> to mailbox: nain-t.net!user.test
Jun 16 10:15:06 cyrus postfix/lmtp[8280]: 7CC2E4800D3C: to=<test@nain-t.net>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.3, delays=0.06/0.01/0.03/0.2, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 10:15:06 cyrus postfix/qmgr[8272]: 7CC2E4800D3C: removed
Jun 16 10:22:32 cyrus cyrus/ctl_cyrusdb[8292]: checkpointing cyrus databases
Jun 16 10:22:32 cyrus cyrus/ctl_cyrusdb[8292]: done checkpointing cyrus databases

C'est bon signe. Mais comment Cyrus a-t-il géré la chose ?

Tout démarre dans /var/spool/cyrus/mail :

:/var/spool/cyrus/mail# ls
a  b  c  d  domain  e  f  g  h  i  j  k  l  m  o  q  r  s  stage.  t  v  w  x  y  z

Le répertoire domain nous attire :

:/var/spool/cyrus/mail# cd domain/
:/var/spool/cyrus/mail/domain# ls
n

Un seul répertoire, qui s'appelle n (comme nain-t ?) :

:/var/spool/cyrus/mail/domain# cd n/
:/var/spool/cyrus/mail/domain/n# ls
nain-t.net

Ah oui, c'est bien rangé n'est-ce pas ?

:/var/spool/cyrus/mail/domain/n# cd nain-t.net/
:/var/spool/cyrus/mail/domain/n/nain-t.net# ls
t

Un seul répertoire t (comme test ?) :

:/var/spool/cyrus/mail/domain/n/nain-t.net# cd t
:/var/spool/cyrus/mail/domain/n/nain-t.net/t# ls
user
:/var/spool/cyrus/mail/domain/n/nain-t.net/t# cd user/
:/var/spool/cyrus/mail/domain/n/nain-t.net/t/user# ls
test

Oui

:/var/spool/cyrus/mail/domain/n/nain-t.net/t/user# cd test/
:/var/spool/cyrus/mail/domain/n/nain-t.net/t/user/test# ls
1.  cyrus.cache  cyrus.header  cyrus.index

Le fichier 1. a l'air intéressant :

:/var/spool/cyrus/mail/domain/n/nain-t.net/t/user/test# cat 1.
Return-Path: <root@cyrus.nain-t.net>
Received: from cyrus.nain-t.net ([unix socket])
by cyrus (Cyrus v2.2.13-Debian-2.2.13-14+b1) with LMTPA;
Mon, 16 Jun 2008 10:15:06 +0200
X-Sieve: CMU Sieve 2.2
Received: by cyrus.nain-t.net (Postfix, from userid 0)
id 7CC2E4800D3C; Mon, 16 Jun 2008 10:15:06 +0200 (CEST)
To: test@nain-t.net
Subject: test 0
Message-Id: <20080616081506.7CC2E4800D3C@cyrus.nain-t.net>
Date: Mon, 16 Jun 2008 10:15:06 +0200 (CEST)
From: root@cyrus.nain-t.net (root)

config mini

C'est lui. Voyons avec telnet si nous pouvons y accéder en imap :

# telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK cyrus Cyrus IMAP4 v2.2.13-Debian-2.2.13-14+b1 server ready
01 login test@nain-t.net epikoi
01 OK User logged in
02 list "*" "*"
* LIST (\HasNoChildren) "/" "INBOX"
02 OK Completed (0.000 secs 2 calls)
03 select INBOX
* FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen \*)]
* 1 EXISTS
* 1 RECENT
* OK [UNSEEN 1]
* OK [UIDVALIDITY 1213600558]
* OK [UIDNEXT 2]
03 OK [READ-WRITE] Completed
04 fetch 1 BODY[HEADER]
* 1 FETCH (FLAGS (\Recent \Seen) BODY[HEADER] {530}
Return-Path:
Received: from cyrus.nain-t.net ([unix socket])
by cyrus (Cyrus v2.2.13-Debian-2.2.13-14+b1) with LMTPA;
Mon, 16 Jun 2008 10:15:06 +0200
X-Sieve: CMU Sieve 2.2
Received: by cyrus.nain-t.net (Postfix, from userid 0)
id 7CC2E4800D3C; Mon, 16 Jun 2008 10:15:06 +0200 (CEST)
To: test@nain-t.net
Subject: test 0
Message-Id: <20080616081506.7CC2E4800D3C@cyrus.nain-t.net>
Date: Mon, 16 Jun 2008 10:15:06 +0200 (CEST)
From: root@cyrus.nain-t.net (root)

)
04 OK Completed (0.000 sec)
05 fetch 1 BODY[TEXT]
* 1 FETCH (BODY[TEXT] {13}
config mini
)
05 OK Completed (0.000 sec)
06 logout
* BYE LOGOUT received
06 OK Completed
Connection closed by foreign host.

Tout va pour le mieux. Mais pour ces premiers essais, nous avons dû indiquer que nain-t.net était dans mydestination « en dur » , dans main.cf. Ce n'est évidemment pas la bonne solution. Il nous faut trouver le moyen de dire à Postfix qu'il doit chercher ces informations dans la base de données MySQL.

5-6-2 - Postfix et MySQL

Postfix sait dialoguer avec MySQL, à la condition d'installer le paquet postfix-mysql (Il existe également postfix-pgsql pour PostgreSQL et postfix-ldap pour les annuaires LDAP).

aptitude install postfix-mysql

5-6-2-1 - Pour « mydestination »

Dans notre base mail, nous avons une table domain. Voyons ce qu'il y a dedans :

# mysql mail -u mail -p
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 73
Server version: 5.0.51a-6 (Debian)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> select * from domain;
+-------------+------------+-------------+---------+-------------+-----------+-----------+-------------+---------+
| domain_name | prefix     | maxaccounts | quota   | domainquota | transport | freenames | freeaddress | folders |
+-------------+------------+-------------+---------+-------------+-----------+-----------+-------------+---------+
| nain-t.net  | nain-t.net |       10000 | 2000000 |           0 | cyrus     | NO        | YES         |         |
+-------------+------------+-------------+---------+-------------+-----------+-----------+-------------+---------+
1 row in set (0.00 sec)

Donc, une requête du genre :

mysql> select domain_name from domain;

devrait faire l'affaire :

+-------------+
| domain_name |
+-------------+
| nain-t.net  |
+-------------+
1 row in set (0.00 sec)

Il suffit de trouver le moyen de dire à Postfix qu'il doit lire ses destinations en faisant cette requête dans la base de données.

Nous allons créer un fichier /etc/postfix/db/mydestination.cf qui aura cette forme (ancienne syntaxe) :

hosts = 127.0.0.1
user = mail
password = epikoi
dbname = mail
table = domain
select_field = domain_name
where_field = domain_name

C'est assez clair pour ne pas trop s'étendre sur le sujet. Le seul point à approfondir un peu est la directive hosts = 127.0.0.1. En effet, si nous mettons à la place hosts = localhost, Postfix va en déduire que puisque la base est locale, il faut y accéder par un socket Unix (que MySQL place par défaut dans /var/run/mysqld/mysqld.sock) et ça ne fonctionnera tout simplement pas. Pourquoi ? Parce que Postfix est en cage dans /var/spool/postfix !

- Soit nous déplaçons ce socket dans la cage, comme nous l'avons fait pour cyrus et saslauthd au risque de perturber d'autres applications qui utiliseraient MySQL ;

- soit il nous faut passer par un socket réseau, c'est ce que comprend Postfix si nous indiquons une adresse IP dans le paramètre hosts ;

- soit, enfin, nous adoptons la même stratégie que dans le chapitre précédent, à savoir utiliser le service proxy de Postfix qui est là pour résoudre ces problèmes.

A vous de voir en fonction de votre contexte. Ici le choix du socket réseau est juste fait pour montrer que ça fonctionne aussi.

Les versions « modernes » (2.2 et plus) de Postfix comprennent une syntaxe plus compacte et plus proche de SQL :

hosts = 127.0.0.1
user = mail
password = epikoi
dbname = mail
query = SELECT domain_name FROM domain WHERE domain_name = '%s'

Puis il faut modifier dans /etc/postfix/main.cf la ligne mydestination comme suit :

mydestination = mysql:/etc/postfix/db/mydestination.cf

Un postfix reload et un essai :

# mail test@nain-t.net
Subject: test 1
mydestination dans MySQL
.
Cc:

Et dans les logs :

Jun 16 11:51:52 cyrus postfix/pickup[8408]: 4418E4800D3C: uid=0 from=<root>
Jun 16 11:51:52 cyrus postfix/cleanup[8414]: 4418E4800D3C: message-id=<20080616095152.4418E4800D3C@cyrus.nain-t.net>
Jun 16 11:51:52 cyrus postfix/qmgr[8409]: 4418E4800D3C: from=<root@cyrus.nain-t.net>, size=336, nrcpt=1 (queue active)
Jun 16 11:51:52 cyrus cyrus/lmtpunix[8418]: Delivered: <20080616095152.4418E4800D3C@cyrus.nain-t.net> to mailbox: nain-t.net!user.test
Jun 16 11:51:52 cyrus postfix/lmtp[8417]: 4418E4800D3C: to=<test@nain-t.net>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.28, delays=0.06/0.01/0.04/0.18, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 11:51:52 cyrus postfix/qmgr[8409]: 4418E4800D3C: removed
Jun 16 11:52:32 cyrus cyrus/ctl_cyrusdb[8419]: checkpointing cyrus databases
Jun 16 11:52:32 cyrus cyrus/ctl_cyrusdb[8419]: done checkpointing cyrus databases

Bon. Mais c'est bien un truc qui marche de façon intelligente ?

# mail test@machin.net
Subject: test 2
domaine inconnu dans notre base
.
Cc:

Et dans les logs ?

Jun 16 11:56:31 cyrus postfix/pickup[8408]: 3A5254800D3C: uid=0 from=<root>
Jun 16 11:56:31 cyrus postfix/cleanup[8431]: 3A5254800D3C: message-id=<20080616095631.3A5254800D3C@cyrus.nain-t.net>
Jun 16 11:56:31 cyrus postfix/qmgr[8409]: 3A5254800D3C: from=<root@cyrus.nain-t.net>, size=327, nrcpt=1 (queue active)
Jun 16 11:56:38 cyrus postfix/smtp[8433]: 3A5254800D3C: host mx00.1and1.co.uk[212.227.15.150] refused to talk to me: 550 RBL rejection: local dynamic IP address 82.243.80.13
Jun 16 11:56:38 cyrus postfix/smtp[8433]: 3A5254800D3C: host mx01.1and1.co.uk[212.227.15.134] refused to talk to me: 550 RBL rejection: local dynamic IP address 82.243.80.13
Jun 16 11:56:38 cyrus postfix/smtp[8433]: 3A5254800D3C: host mx00.1and1.co.uk[212.227.15.134] refused to talk to me: 550 RBL rejection: local dynamic IP address 82.243.80.13
Jun 16 11:56:38 cyrus postfix/smtp[8433]: 3A5254800D3C: host mx00.1and1.co.uk[212.227.15.169] refused to talk to me: 550 RBL rejection: local dynamic IP address 82.243.80.13
Jun 16 11:56:38 cyrus postfix/smtp[8433]: 3A5254800D3C: to=<test@machin.net>, relay=mx01.1and1.co.uk[212.227.15.150]:25, delay=7.5, delays=0.06/0.01/7.5/0, dsn=4.0.0, status=deferred (host mx01.1and1.co.uk[212.227.15.150] refused to talk to me: 550 RBL rejection: local dynamic IP address 82.243.80.13)

Ben oui, le domaine machin.net existe... Postfix a donc essayé de contacter les MX correspondants, preuve que Postfix a bien compris que machin.net n'était pas dans ses destinations.

Au passage, observons que les MX de1and1.co.uk ne prennent pas de gants et blacklistent toutes les adresses IP ditesdynamiques, c'est-à-dire celles qui sont attribuées aux divers fournisseurs d'accès. Ceci veut dire que même avec un Postfix complètement configuré et référencé comme tel sur l'internet, nous ne passerons pas dans certains domaines. Merci aux administrateurs totalitaires.

Mais revenons à nos moutons, car nous n'avons pas encore fini...

5-6-2-2 - Pour les alias

Rappelons-le, un alias est une vraie fausse adresse. Autrement dit, une adresse qui ne correspond pas à une vraie boite, mais qui pointe sur une autre adresse qui, elle, en a une.

Avec notre web-cyradm, créons dans le domaine nain-t.net un alias : aliastest@nain-t.net et faisons le pointer sur l'adresse test@nain-t.net

C'est dans la table virtual que ça se passe :

mysql> select * from virtual;
+----------------------+------------------+------------------+--------+
| alias                | dest             | username         | status |
+----------------------+------------------+------------------+--------+
| test@nain-t.net      | test@nain-t.net  | test@nain-t.net  |      1 |
| aliastest@nain-t.net | test@nain-t.net  | nain-t.net       |      1 |
+----------------------+------------------+------------------+--------+
2 rows in set (0.00 sec)

Il est à peu près clair que si la destination de test@nain-t.net est bien test@nain-t.net, pour aliastest@nain-t.net, la destination n'est pas aliastest@nain-t.net mais toujours test@nain-t.net.

D'ailleurs, cyrus n'est pas du tout au courant de tout ça :

# cyradm --user cyrus --server localhost
Password:
localhost> lm
user/test@nain-t.net (\HasNoChildren)
localhost>

La seule BAL existante est bien test@nain-t.net.

Moralité, nous avons bien les informations dans la base, mais comme nous n'avons pas expliqué à Postfix qu'il fallait en tenir compte, il n'effectuera pas la réécriture d'adresse de destination et le message sera refusé par cyrus. Je vous laisse faire la manip si vous n'êtes pas convaincu, personnellement, j'ai mieux à faire.

Il faut agir sur la paramètre virtual_alias_maps, par le biais d'une requête SQL bien sentie :

mysql> SELECT dest FROM virtual WHERE alias = 'aliastest@nain-t.net' AND status ='1';
+-----------------+
| dest            |
+-----------------+
| test@nain-t.net |
+-----------------+
1 row in set (0.00 sec)

(Si status est différent de 1, c'est que l'alias est désactivé, il ne faut donc pas en tenir compte).

Il ne reste plus qu'à mettre ça dans un fichier /etc/postfix/db/virtual-alias.cf (directement dans la nouvelle syntaxe) :

hosts = 127.0.0.1
user = mail
password = epikoi
dbname = mail
query = SELECT dest FROM virtual WHERE alias = '%s' AND status ='1'

et ajouter à main.cf la ligne :

virtual_alias_maps = mysql:/etc/postfix/db/virtual-alias.cf

(Forcer postfix reload)

Essayons :

# mail aliastest@nain-t.net
Subject: test alias
redirection OK
.
Cc:

Et voir les logs :

Jun 16 14:15:14 cyrus postfix/pickup[8683]: BF7E04800D3C: uid=0 from=<root>
Jun 16 14:15:14 cyrus postfix/cleanup[8689]: BF7E04800D3C: message-id=<20080616121514.BF7E04800D3C@cyrus.nain-t.net>
Jun 16 14:15:14 cyrus postfix/qmgr[8684]: BF7E04800D3C: from=<root@cyrus.nain-t.net>, size=335, nrcpt=1 (queue active)
Jun 16 14:15:15 cyrus cyrus/lmtpunix[8695]: Delivered: <20080616121514.BF7E04800D3C@cyrus.nain-t.net> to mailbox: nain-t.net!user.test
Jun 16 14:15:15 cyrus postfix/lmtp[8694]: BF7E04800D3C: to=<test@nain-t.net>, orig_to=<aliastest@nain-t.net>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.3, delays=0.06/0.01/0.04/0.18, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 14:15:15 cyrus postfix/qmgr[8684]: BF7E04800D3C: removed

C'est explicite. Détail intéressant : nous récupérons l'en-tête du message reçu et stocké par cyrus (nous savons maintenant où le trouver) :

Return-Path: <root@cyrus.nain-t.net>
Received: from cyrus.nain-t.net ([unix socket])
by cyrus (Cyrus v2.2.13-Debian-2.2.13-14+b1) with LMTPA;
Mon, 16 Jun 2008 14:15:14 +0200
X-Sieve: CMU Sieve 2.2
Received: by cyrus.nain-t.net (Postfix, from userid 0)
id BF7E04800D3C; Mon, 16 Jun 2008 14:15:14 +0200 (CEST)
To: aliastest@nain-t.net
Subject: test alias
Message-Id: <20080616121514.BF7E04800D3C@cyrus.nain-t.net>
Date: Mon, 16 Jun 2008 14:15:14 +0200 (CEST)
From: root@cyrus.nain-t.net (root)

redirection OK

Constatez que dans l'en-tête du message reçu, le champ To: contient toujours aliastest@nain-t.net et non test@nain-t.net.

5-6-2-3 - Pour les redirections

D'abord, quelle différence entre une redirection (forward) et un alias ?

Le but du jeu dans le cas d'une redirection, est de renvoyer un message destiné à une vraie adresse (qui dispose d'une BAL) vers une autre adresse, pas nécessairement dans le même domaine d'ailleurs. Il y a donc ici la possibilité de conserver une copie du message redirigé dans la boite initiale.

Autrement, il n'y a aucune différence, comme nous allons le voir.

Avec notre web-cyradm, nous créons un second domaine : autredomaine.net et dedans, nous créons un compte test@autredomaine.fr. Voyons la base :

mysql> select * from domain;
+------------------+------------------+-------------+---------+-------------+-----------+-----------+-------------+---------+
| domain_name      | prefix           | maxaccounts | quota   | domainquota | transport | freenames | freeaddress | folders |
+------------------+------------------+-------------+---------+-------------+-----------+-----------+-------------+---------+
| nain-t.net       | nain-t.net       |       10000 | 2000000 |           0 | cyrus     | NO        | YES         |         |
| autredomaine.net | autredomaine.net |          10 | 2000000 |           0 | cyrus     | NO        | YES         |         |
+------------------+------------------+-------------+---------+-------------+-----------+-----------+-------------+---------+
2 rows in set (0.00 sec)

mysql> select * from accountuser;
+-----------------------+---------------+------------------+------------------+------+-----+-------+----------+
| username              | password      | prefix           | domain_name      | imap | pop | sieve | smtpauth |
+-----------------------+---------------+------------------+------------------+------+-----+-------+----------+
| cyrus                 | ep5LE34pgfO7Q |                  |                  |    1 |   1 |     1 |        1 |
| test@nain-t.net       | ep5LE34pgfO7Q | nain-t.net       | nain-t.net       |    1 |   1 |     1 |        1 |
| test@autredomaine.net | ep5LE34pgfO7Q | autredomaine.net | autredomaine.net |    1 |   1 |     1 |        1 |
+-----------------------+---------------+------------------+------------------+------+-----+-------+----------+
3 rows in set (0.00 sec)

Maintenant, en accédant au compte de test@nain-t.net par web-cyradm, nous créons une redirection vers test@autredomaine.net, en conservant une cpie du message :

La preuve que c'est pareil qu'un alias, nous retrouvons la modification dans la table virtual :

mysql> select * from virtual;
+-----------------------+---------------------------------------+-----------------------+--------+
| alias                 | dest                                  | username              | status |
+-----------------------+---------------------------------------+-----------------------+--------+
| test@nain-t.net       | test@nain-t.net                       | test@nain-t.net       |      1 |
| aliastest@nain-t.net  | test@nain-t.net                       | nain-t.net            |      1 |
| test@nain-t.net       | test@autredomaine.net,test@nain-t.net |                       |      1 |
| test@autredomaine.net | test@autredomaine.net                 | test@autredomaine.net |      1 |
+-----------------------+---------------------------------------+-----------------------+--------+
4 rows in set (0.00 sec)

Donc, a priori, nous n'avons rien à modifier dans la configuration de Postfix, les redirections devraient être opérationnelles. Vérifions :

# mail test@nain-t.net
Subject: premier essai forward
ça roule
.
Cc:

Les logs :

Jun 16 14:54:30 cyrus postfix/pickup[8683]: 961684800D3C: uid=0 from=<root>
Jun 16 14:54:30 cyrus postfix/cleanup[8733]: 961684800D3C: message-id=<20080616125430.961684800D3C@cyrus.nain-t.net>
Jun 16 14:54:30 cyrus postfix/qmgr[8684]: 961684800D3C: from=<root@cyrus.nain-t.net>, size=336, nrcpt=2 (queue active)
Jun 16 14:54:30 cyrus cyrus/lmtpunix[8741]: Delivered: <20080616125430.961684800D3C@cyrus.nain-t.net> to mailbox: autredomaine.net!user.test
Jun 16 14:54:30 cyrus postfix/lmtp[8739]: 961684800D3C: to=<test@autredomaine.net>, orig_to=<test@nain-t.net>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.38, delays=0.07/0.02/0.05/0.24, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 14:54:31 cyrus cyrus/lmtpunix[8742]: Delivered: <20080616125430.961684800D3C@cyrus.nain-t.net> to mailbox: nain-t.net!user.test
Jun 16 14:54:31 cyrus postfix/lmtp[8740]: 961684800D3C: to=<test@nain-t.net>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.46, delays=0.07/0.03/0.11/0.24, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 14:54:31 cyrus postfix/qmgr[8684]: 961684800D3C: removed

C'est bon. Et est-ce que c'est récursif ? Autrement dit, si j'envoie un message à aliastest@nain-t.net, comment ça va se passer ?

Jun 16 15:02:08 cyrus postfix/pickup[8683]: 3807A4800D3C: uid=0 from=<root>
Jun 16 15:02:08 cyrus postfix/cleanup[8746]: 3807A4800D3C: message-id=<20080616130208.3807A4800D3C@cyrus.nain-t.net>
Jun 16 15:02:08 cyrus postfix/qmgr[8684]: 3807A4800D3C: from=<root@cyrus.nain-t.net>, size=343, nrcpt=2 (queue active)
Jun 16 15:02:08 cyrus cyrus/lmtpunix[8752]: Delivered: <20080616130208.3807A4800D3C@cyrus.nain-t.net> to mailbox: autredomaine.net!user.test
Jun 16 15:02:08 cyrus postfix/lmtp[8750]: 3807A4800D3C: to=<test@autredomaine.net>, orig_to=<aliastest@nain-t.net>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.45, delays=0.06/0.01/0.06/0.32, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 15:02:08 cyrus cyrus/lmtpunix[8753]: Delivered: <20080616130208.3807A4800D3C@cyrus.nain-t.net> to mailbox: nain-t.net!user.test
Jun 16 15:02:08 cyrus postfix/lmtp[8751]: 3807A4800D3C: to=<test@nain-t.net>, orig_to=<aliastest@nain-t.net>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.47, delays=0.06/0.03/0.13/0.26, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 15:02:08 cyrus postfix/qmgr[8684]: 3807A4800D3C: removed

Ça fonctionne de manière récursive. Il a oublié d'être bête ce Postfix.

Techniquement, nous sommes en place, à part un petit détail. Quid des messages administratifs, envoyés à root, postmaster, MAILER_DAEMON et autres noms de services ?

Envoyons un message à root pour voir :

# mail root
Subject: vla autre chose
ça va coincer...
.
Cc:

Les logs...

Jun 16 15:09:47 cyrus postfix/pickup[8683]: 6AB974800D3C: uid=0 from=<root>
Jun 16 15:09:47 cyrus postfix/cleanup[8776]: 6AB974800D3C: message-id=<20080616130947.6AB974800D3C@cyrus.nain-t.net>
Jun 16 15:09:47 cyrus postfix/qmgr[8684]: 6AB974800D3C: from=<root@cyrus.nain-t.net>, size=342, nrcpt=1 (queue active)
Jun 16 15:09:47 cyrus postfix/smtp[8778]: 6AB974800D3C: to=<root@cyrus.nain-t.net>, orig_to=<root>, relay=none, delay=0.08, delays=0.06/0.02/0/0, dsn=5.4.4, status=bounced (Host or domain name not found. Name service error for name=cyrus.nain-t.net type=AAAA: Host not found)
Jun 16 15:09:47 cyrus postfix/cleanup[8776]: 7ECA94800D3F: message-id=<20080616130947.7ECA94800D3F@cyrus.nain-t.net>
Jun 16 15:09:47 cyrus postfix/qmgr[8684]: 7ECA94800D3F: from=<>, size=2340, nrcpt=1 (queue active)
Jun 16 15:09:47 cyrus postfix/bounce[8779]: 6AB974800D3C: sender non-delivery notification: 7ECA94800D3F
Jun 16 15:09:47 cyrus postfix/qmgr[8684]: 6AB974800D3C: removed
Jun 16 15:09:47 cyrus postfix/smtp[8778]: 7ECA94800D3F: to=<root@cyrus.nain-t.net>, relay=none, delay=0.03, delays=0.02/0/0/0, dsn=5.4.4, status=bounced (Host or domain name not found. Name service error for name=cyrus.nain-t.net type=AAAA: Host not found)
Jun 16 15:09:47 cyrus postfix/qmgr[8684]: 7ECA94800D3F: removed

Ici, Postfix ne s'en sort pas parce que root n'est pas une adresse. Il en conclut (à juste titre) que c'est le root local et donc reconstruit une adresse présentable en ajoutant @{$myhostname}, ici cyrus.nain-t.net. Une fois cette adresse construite, il ne sait plus trop comment la router, car il ne sait pas que c'est une destination locale (mydestination) et il ne sait pas non plus trouver un MX qui fasse l'affaire.

Notez au passage le ping-pong en perspective : root@cyrus.nain-t.net envoie un message à root@cyrus.nain-t.net, qui n'est pas livrable, et la notification part donc dans la BAL de l'expéditeur, soit root@cyrus.nain-t.net... Mais Postfix s'en tire très bien et n'insiste (heureusement) pas sur les double-bounce.

Une solution possible pour régler cette question est de créer une BAL sysop@nain-t.net par exemple, et d'utiliser le fichier /etc/aliases pour rediriger tous les messages administratifs (locaux) vers cette boite :

# cat /etc/aliases
mailer-daemon: postmaster
postmaster: root
nobody: root
hostmaster: root
usenet: root
news: root
webmaster: root
www: root
www-data: root
ftp: root
abuse: root
noc: root
security: root
clamav: root
amavis: root
cyrus: root

root: sysop@nain-t.net

La technique est simple, tous les noms d'oiseaux susceptibles de recevoir des messages locaux sont redirigés sur root qui, en fin de compte, est redirigé sur sysop@nain-t.net.

Notez que cette table existait déjà mais ne contenait rien, ou rien d'intéressant, mais était déjà référencée dans le main.cf :

...
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
...

Reste à la passer à la moulinette du postalias :

postalias /etc/aliases

Ce qui va créer un nouveau fichier /etc/alias.db

Puis nous vérifions que tous les noms d'hôte local figurent dans mydestination en plus des destinations tirées de MySQL :

mydestination = cyrus.nain-t.net, localhost.nain-t.net, localhost,  mysql:/etc/postfix/db/mydestination.cf

Et de forcer Postfix à revoir sa configuration :

postfix reload

(N'oublions pas de créer la boite sysop@nain-t.net avant d'essayer) :

# mail security
Subject: test redirections locales
ça marche.
.
Cc:
Jun 16 16:32:22 cyrus postfix/pickup[8937]: 657C64800D3C: uid=0 from=<root>
Jun 16 16:32:22 cyrus postfix/cleanup[8953]: 657C64800D3C: message-id=<20080616143222.657C64800D3C@cyrus.nain-t.net>
Jun 16 16:32:22 cyrus postfix/qmgr[8938]: 657C64800D3C: from=<root@cyrus.nain-t.net>, size=350, nrcpt=1 (queue active)
Jun 16 16:32:22 cyrus cyrus/lmtpunix[8957]: Delivered: <20080616143222.657C64800D3C@cyrus.nain-t.net> to mailbox: nain-t.net!user.sysop
Jun 16 16:32:22 cyrus postfix/lmtp[8956]: 657C64800D3C: to=<sysop@nain-t.net>, orig_to=<security>, relay=cyrus.nain-t.net[/cyrussock/lmtp], delay=0.32, delays=0.08/0.01/0.04/0.19, dsn=2.1.5, status=sent (250 2.1.5 Ok)
Jun 16 16:32:22 cyrus postfix/qmgr[8938]: 657C64800D3C: removed

5-6-2-4 - Remarques

- Comme Postfix dispose maintenant du moyen de savoir si une adresse virtuelle existe ou non, par le biais de virtual_alias_maps, nous pouvons retirer la ligne local_recipient_maps = du main.cf.

- La configuration décrite ici ne fonctionnera totalement qu'à la condition que nous ayons choisi de faire gérer les domaines virtuels par Cyrus.

- Nous n'avons pour l'instant pas utilisé les services de SASL dans Postfix. Ils ne sont en effet nécessaires que si Postfix doit authentifier ses clients. Pour l'instant, seul l'hôte local peut être client de Postfix : mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128. Si les notations IPv6 vous gênent ([::ffff:127.0.0.0]/104 [::1]/128), ignorez-les ou mieux, reportez-vous au chapitre idoine.

- Se poser quelques questions sur la sécurité de l'ensemble ne sera pas forcément une mauvaise idée.

5-7 - Postfix avec SASL

5-7-1 - Profitons des acquis

Nous allons faire une synthèse de ce qui a été vu avec Postfix + Dovecot pour aboutir à un main.cf de cette forme :

smtpd_banner = $myhostname ESMTP Experimental

disable_vrfy_command = yes
smtpd_helo_required = yes
smtpd_sender_restrictions =
permit_mynetworks,
reject_non_fqdn_sender
reject_unknown_sender_domain,
permit

smtpd_client_restrictions =
permit_mynetworks,
reject_rbl_client blackholes.easynet.nl,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client proxies.blackholes.wirehub.net,
reject_rbl_client bl.spamcop.net,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client dnsbl.njabl.org,
permit

biff = no

append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

myhostname = cyrus.nain-t.net
myorigin = $myhostname
mydestination = $myhostname, localhost.nain-t.net, localhost,  mysql:/etc/postfix/db/mydestination.cf
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = $myhostname
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

virtual_alias_maps = mysql:/etc/postfix/db/virtual-alias.cf

mailbox_transport = lmtp:unix:/cyrussock/lmtp

Modifions master.cf comme déjà vu pour utiliser le port submission :

#
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       -       -       -       smtpd
submission inet n       -       -       -       -       smtpd
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
#smtps     inet  n       -       -       -       -       smtpd
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#628      inet  n       -       -       -       -       qmqpd
pickup    fifo  n       -       -       60      1       pickup
cleanup   unix  n       -       -       -       0       cleanup
qmgr      fifo  n       -       n       300     1       qmgr
#qmgr     fifo  n       -       -       300     1       oqmgr
tlsmgr    unix  -       -       -       1000?   1       tlsmgr
rewrite   unix  -       -       -       -       -       trivial-rewrite
bounce    unix  -       -       -       -       0       bounce
defer     unix  -       -       -       -       0       bounce
trace     unix  -       -       -       -       0       bounce
verify    unix  -       -       -       -       1       verify
flush     unix  n       -       -       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       -       -       -       smtp
# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
relay     unix  -       -       -       -       -       smtp
-o smtp_fallback_relay=
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq     unix  n       -       -       -       -       showq
error     unix  -       -       -       -       -       error
retry     unix  -       -       -       -       -       error
discard   unix  -       -       -       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       -       -       -       lmtp
anvil     unix  -       -       -       -       1       anvil
scache    unix  -       -       -       -       1       scache
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop  unix  -       n       n       -       -       pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# See the Postfix UUCP_README file for configuration details.
#
uucp      unix  -       n       n       -       -       pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail    unix  -       n       n       -       -       pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix    -    n    n    -    2    pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
${nexthop} ${user}

Mais pour utiliser SASL ici, il va nous falloir créer un fichier /etc/postfix/sasl/smtpd.conf de la forme :

pwcheck_method: saslauthd
mech_list: PLAIN LOGIN
minimum_layer: 0
saslauthd_path: /var/run/saslauthd/mux

Pour être tout à fait explicite, il faudrait aussi ajouter dans le fichier main.cf les deux lignes suivantes :

smtpd_sasl_type = cyrus
smtpd_sasl_path = smtpd

Il se trouve que ce sont les valeurs par défaut, mais mieux vaut le dire de façon explicite.

Ce n'est pas tout... saslauthd, lorsqu'il démarre peut attribuer des droits assez particuliers au répertoire dans lequel se trouve le mux (observé à l'heure où ces lignes sont écrites sur une Debian Lenny) :

# ls -l /var/spool/postfix/var/run
total 0
drwxrwxr-x 2 cyrus postfix 19 jun 12 16:47 cyrus
drwx--x--- 2 root  sasl    88 jun 17 16:47 saslauthd

Si bien que l'utilisateur postfix ne peut accéder au mux de saslauthd et donc, l'authentification échoue systématiquement. Pas question de modifier quoi que ce soit à ces droits, ils sont restaurés à chaque redémarrage de saslauthd.

Dans ce cas, une solution est donc d'intégrer l'utilisateur postfix au groupe sasl :

# usermod -a -G sasl postfix

Vérification :

# groups postfix
postfix sasl

5-7-2 - Et PAM ?

Parce que SASL, c'est bien, mais il fait appel à PAM. Nous avons un fichier imap dans /etc/pam.d/, mais nous n'en avons pas pour smtp ou si nous en avons un, il n'est sans doute pas bon. Nous devons utiliser le même processus que pour imap, donc dans un premier temps, un :

# cp /etc/pam.d/imap /etc/pam.d/smtp

Devrait faire l'affaire pour l'instant.

Redémarrage de Postfix, et la connexion sur le port submission avec authentification doit fonctionner

5-8 - Questions de sécurité

Reste encore à traiter quelques points de détail.

- web-cyradm pose des drapeaux dans la base de données. Nous n'avons pas tenu compte de ces indicateurs qui devraient permettre d'autoriser ou non tel ou tel utilisateur :

- à recevoir des messages,

- à en envoyer,

- à accéder à sa boite aux lettres,

- à utiliser le langage Sieve ;

- l'utilisateur cyrus a tous les droits sur tous les comptes de messagerie. Peut-on limiter cet utilisateur à ne pouvoir se connecter que localement ?

- le fait d'utiliser saslauthd avec PAM implique que les authentifications passent en clair sur le réseau. Le moyen simple de contourner ce problème est d'employer systématiquement TLS, aussi bien pour les connexions IMAP/POP3 que pour les connexions SMTP de la part de nos utilisateurs.

- il faut combattre autant que l'on peut les virus et les spams. Nous avons déjà vu comment le faire, mais n'avons pas encore implémenté la solution ici.

- web-cyradm, c'est bien, mais il faut ajouter plusieurs choses sur notre serveur, qui peuvent apporter des risques :

- apache,

- php,

- le code php de web-cyradm.

5-8-1 - Contrôler finement les accès

Si nous prenons le temps de bien regarder l'interface de web-cyradm, et aussi la structure des tables MySQL associée, nous constatons qu'il existe par compte créé quatre « flags » qui sont :

- imap, qui devrait permettre d'autoriser ou non l'accès du compte au protocole IMAP ;

- pop, idem pour le protocole POP ;

- sieve, idem pour Sieve ;

- smtpauth, idem pour l'authentification SMTP (Port « submission ») ;

- smtp, idem pour la livraison des messages entrants.

Nous n'avons pas vraiment tenu compte de ces « flags ». Pour imap, pop, sieve et smtpauth, il s'agit d'autoriser ou non l'authentification, donc il faut agir sur saslauthd, donc sur PAM, donc sur les fichiers correspondants dans /etc/pam.d/.

Le jour où vous trouverez une documentation sur les syntaxes possibles dans les fichiers de configuration de PAM avec MySQL, vous pourrez vérifier que l'on peut faire ceci :

5-8-1-1 - Pour imap

Nous modifions le fichier /etc/pam.d/imap comme ceci (déroulez bin les lignes jusqu'au bout) :

auth sufficient pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.imap=1 crypt=1
account required pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.imap=1 crypt=1

5-8-1-2 - Pour pop

Même méthode, mais avec le « flag » pop. Le fichier /etc/pam.d/pop doit ressembler à ceci :

auth sufficient pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.pop=1 crypt=1
account required pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.pop=1 crypt=1

5-8-1-3 - Pour sieve

Le fichier /etc/pam.d/sieve :

auth sufficient pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.sieve=1 crypt=1
account required pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.sieve=1 crypt=1

5-8-1-4 - Pour Submission

Et enfin le fichier /etc/pam.d/smtp :

auth sufficient pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.smtpauth=1 crypt=1
account required pam_mysql.so user=mail passwd=epikoi host=localhost db=mail table=accountuser usercolumn=username passwdcolumn=password where=accountuser.smtpauth=1 crypt=1

5-8-1-5 - Pour les destinataires

Ici, ce n'est pas PAM qui va intervenir, mais le fichier /etc/postfix/db/virtual-alias.cf, avec son flag status. Ceci est déjà pris en compte puisque nous avons la requête :

query = SELECT dest FROM virtual WHERE alias = '%s' AND status ='1'

5-8-2 - Restreindre l'utilisateur cyrus

Dans notre configuration actuelle, l'utilisateur cyrus peut se connecter à distance et utiliser par exemple l'outil cyradm sur le serveur distant, ce qui présente un danger potentiel.

Il est cependant possible d'utiliser plusieurs fichiers de configuration différents, suivant certains cas. Pour réaliser ceci, il faut se plonger un peu plus profondément dans le cyrus.confg :

SERVICES {
# --- Normal cyrus spool, or Murder backends ---
# add or remove based on preferences
imap            cmd="imapd -U 30" listen="imap" prefork=0 maxchild=100
#imaps          cmd="imapd -s -U 30" listen="imaps" prefork=0 maxchild=100
pop3            cmd="pop3d -U 30" listen="pop3" prefork=0 maxchild=50
#pop3s          cmd="pop3d -s -U 30" listen="pop3s" prefork=0 maxchild=50
#nntp           cmd="nntpd -U 30" listen="nntp" prefork=0 maxchild=100
#nntps          cmd="nntpd -s -U 30" listen="nntps" prefork=0 maxchild=100

La ligne pointée dit en français que :

- la commande invoquée pour le service imap est imapd, le process pouvant être utilisé par 30 nouvelles connexions avant d'être détruit (et remplacé par un autre) ;

- le process va écouter sur le port imap (143) de toutes les interfaces réseau (puisqu'aucune n'est spécifiée) et il peut, au besoin, y avoir jusqu'à 100 processus fils de créés.

La documentation est assez parcimonieuse, mais le manuel de cyrus.conf indique qu'il est possible :

- d'indiquer explicitement le chemin complet d'accès au fichier de configuration pour un process donné ;

- de restreindre l'écoute (listen) à une seule interface réseau.

Ainsi, si l'on modifie cyrus.conf comme suit :

SERVICES {
# --- Normal cyrus spool, or Murder backends ---
# add or remove based on preferences
imap            cmd="imapd -U 30" listen="192.168.10.7:imap" prefork=0 maxchild=100
imaplocal       cmd="imapd -U 30 -C /etc/imapd-local.conf" listen="127.0.0.1:imap" prefork=0 maxchild=100
#imaps          cmd="imapd -s -U 30" listen="imaps" prefork=0 maxchild=100
pop3            cmd="pop3d -U 30" listen="pop3" prefork=0 maxchild=50
#pop3s          cmd="pop3d -s -U 30" listen="pop3s" prefork=0 maxchild=50
#nntp           cmd="nntpd -U 30" listen="nntp" prefork=0 maxchild=100
#nntps          cmd="nntpd -s -U 30" listen="nntps" prefork=0 maxchild=100

Nous aurons :

- une instance de imapd (nommée imap), qui n'écoutera que sur l'interface connectée au réseau (adresse IP de l'interface) et qui utilisera le fichier de configuration par défaut(/etc/imapd.conf) ;

- une instance de imapd (nommée imaplocal), qui n'écoutera que sur l'interface locale (adresse IP 127.0.0.1) et qui utilisera le fichier de configuration explicite /etc/imapd-local.conf.

Nous allons donc copier notre imapd.conf dans imapd-local.conf, puis nous commenterons la ligne admins: cyrus dans imapd.conf. L'utilisateur cyrus pourra toujours se connecter à distance, mais n'aura plus les droits d'administration.

5-8-3 - Utiliser TLS

Aussi bien Cyrus que Postfix supportent la commande STARTTLS, qui permet au client :

- de recevoir un certificat du serveur ;

- d'établir une connexion chiffrée entre le client et le serveur.

Ainsi le login, bien que transmis en clair, circulera à travers la connexion chiffrée.

Il est donc possible de forcer les utilisateurs à utiliser TLS ou tout au moins le leur permettre. Les forcer, bien que plus totalitaire, est tout de même plus sûr pour tout le monde.

Nous allons faire ça à peu près bien, en créant des certificats signés par une autorité racine « de confiance » : la nôtre. TinyCA fera tout à fait l'affaire. Nous réalisons une CA pour le domaine nain-t, puis créons un certificat serveur pour cyrus.nain-t.net. Ensuite, nous exportons ce certificat sous le nom de cyrus.nain-t.net.cert et la clé privée associée, sans protection par mot de passe, sous le nom de cyrus.nain-t.net.key, ainsi que le certificat de l'autorité sous le nom de Root_nain-t.net-cacert.pem. Enfin, nous les plaçons à l'endroit habituel (/etc/ssl/certs pour le certificat et /etc/ssl/private pour la clé privée), en attribuant les bons droits :

cyrus:/etc/ssl/certs# chmod 644 cyrus.nain-t.net.cert Root_nain-t.net-cacert.pem
cyrus:/etc/ssl/private# chown root:ssl-cert cyrus.nain-t.net.key
cyrus:/etc/ssl/private# chmod 640 cyrus.nain-t.net.key

5-8-3-1 - Pour Postfix

Dans notre main.cf, nous avons déjà la ligne :

smtpd_use_tls=yes

Qui fait que TLS est possible. Des certificats de tests sont même déjà disponibles (snakeoil). Pour utiliser les nôtres, remplaçons les lignes :

smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key

Par celles-ci :

smtpd_tls_cert_file=/etc/ssl/certs/cyrus.nain-t.net.cert
smtpd_tls_key_file=/etc/ssl/private/cyrus.nain-t.net.key
smtpd_tls_CAfile=/etc/ssl/certs/Root_nain-t.net-cacert.pem

Si nous voulons obliger les clients sur le port submission à utiliser TLS, il nous faut modifier master.cf comme suit :

submission inet n       -       -       -       -       smtpd
-o smtpd_enforce_tls=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject

5-8-3-2 - Pour Cyrus-imapd

Nous allons d'abord ajouter ces lignes dans /etc/imapd.conf :

tls_cert_file: /etc/ssl/certs/cyrus.nain-t.net.cert
tls_key_file: /etc/ssl/private/cyrus.nain-t.net.key
tls_ca_file: /etc/ssl/certs/Root_nain-t.net-cacert.pem
tls_ca_path: /etc/ssl/certs
tls_session_timeout: 1440
tls_cipher_list: TLSv1+HIGH:!aNULL:@STRENGTH

En suite, nous allons vérifier que cyrus peut bien lire les certificats et la clé.

Habituellement, tout le monde peut lire les certificats (644), mais en ce qui concerne les clés, il n'y a que root et les membres du groupe ssl-cert qui le peuvent. Nous avons respecté cette règle lorsque nous avons ajouté nos certificats et notre clé. Donc il nous faut mettre cyrus dans le groupe ssl-cert.

A quel(s) groupe(s) cyrus appartient-il ?

# groups cyrus
cyrus : mail sasl

Il faut bien ajouter cyrus à ssl-cert :

usermod -a -G ssl-cert cyrus

Nous relançons cyrus et TLS devrait fonctionner.

Pour empêcher que les utilisateurs puissent ouvrir de session sans utiliser TLS, il faut dans imapd.conf mettre :

allowplaintext: no

A la place de allowplaintext: yes

Ceci aura pour effet de rendre impossible le login sans chiffrement de la connexion.

Il est également possible de n'ouvrir que imaps pour l'extérieur, en conservant imaplocal, nécessaire pour l'administration de cyrus.

5-8-4 - Amavis

il suffit de reprendre ce qui a été vu dans le chapitre Postfix + Dovecot :

- installer clamav ;

- installer spammassassin (et le configurer correctement) ;

- installer amavisd-new ;

- configurer Postfix pour qu'il dialogue avec amavisd-new.

5-8-5 - Interface web

Web-cyradm va nous servir à gérer les comptes. S'il n'y avait que ça, un jeu de scripts bien sentis ferait sans doute tout aussi bien l'affaire, mais nous désirons fournir à nos utilisateurs deux fonctionnalités intéressantes :

- un webmail ;

- une interface pour créer ses scripts Sieve.

Alors, Apache et PHP se justifient, mais il n'y a rien de bien sécurisé là-dedans. Peut-être faire tourner web-cyradm dans un virtualhost dont l'accès serait contrôlé, et utiliser https en plus ?

5-8-6 - limites du système

Si nous avons toutes les informations nécessaires présentes dans la base mail, cyrus utilise sa propre base pour la gestion des boites aux lettres. Suivant les manipulations, il peut se faire que des BALs qui ont été supprimées dans la base MySQL soient restées dans Cyrus. Ce n'est pas très grave, puisque vis-à-vis de Postfix, ces boites n'existant plus, leur destination sera refusée (si l'on a bien supprimé la ligne local_recipient_maps = dans main.cf) et ne recevront plus de messages. De même, elles ne seront plus accessibles ni en IMAP ni en POP, SASL s'appuyant sur MySQL.

Pour rester propre, il faudra tout de même vérifier de temps en temps que la synchronisation des comptes est correcte.

6 - Mailing lists

Il ne manque plus à notre système qu'un gestionnaire de listes de diffusion.

L'objectif étant de pouvoir créer des listes hautement configurables, le tout dans des domaines virtuels, le choix se portera sans doute sur Mailman ou Sympa.

Mailman n'est pas conçu pour la gestion de domaines virtuels. Il y a certes des astuces pour y arriver tout de même, mais Sympa m'est apparu plus... souriant. Aussi allons-nous nous intéresser plutôt à ce dernier.

Sympa permettra l'usage des domaines virtuels, tels que nous les avons vus dans les deux chapitres précédents, bien qu'il soit bien sûr tout à fait possible de l'utiliser pour gérer les listes d'un seul et unique domaine. Cette étude s'appuie sur le chapitre précédent Postfix, Cyrus, etc., à cause de la base MySQL employée, mais pourra être adaptée au cas de la base MySQL employée avec PostfixAdmin.

6-1 - Le principe général

Nous savons désormais que par défaut, lorsque Postfix par un moyen ou un autre identifie une adresse comme étant locale (« vrai domaine » ou domaines virtuels), il transmet le message au MDA, pour qu'il le range dans la boite aux lettres du destinataire.

Dans le cas d'une liste de diffusion qui, à première vue, dispose d'une adresse locale, Postfix ne devra pas transmettre le message au MDA, mais au robot de gestion des listes. Quelle que soit l'adresse de la liste, Postfix devra remettre le message au même robot, qui se chargera de le diffuser sur la liste adéquate, en suivant la politique de gestion de la liste en question.

- Le message entrant doit et peut être relayé vers un autre MTA.

- Le message entrant concerne une livraison dans une boite aux lettres locale, il est remis au MDA.

- Le message entrant concerne une liste de diffusion, il est remis au robot des listes de diffusion.

- Le robot créera le ou les messages nécessaires en fonction de l'entrée reçue, et injectera sa sortie dans l'entrée du MTA.

Il nous faudra donc mettre en place un mécanisme cohérent avec ce que nous avons déjà, et qui permette d'indiquer le bon transport local, suivant qu'il s'agit d'une adresse de boite aux lettres ou de liste de diffusion.

Si la résolution de ce problème est plus ou moins complexe, suivant le nombre de listes créées et aussi suivant le nombre de domaines hébergés.

6-1-1 - Un peu plus de piment ?

Pour compliquer un peu les choses, le travail d'un robot de liste ne se borne pas à dupliquer l'entrée sur tous les inscrits à la liste.

En effet, il existe des règles de gestion pour une liste donnée et le robot doit suivre ces règles :

- l'émetteur du message est-il autorisé à poster sur cette liste ? ;

- la liste est-elle modérée ?

- si oui,

- s'agit-il d'un message entrant ?

- est-ce une autorisation de diffuser un message modéré ?

- si non,

- le destinataire est-il habilité à poster ? ;

- est-ce une demande d'inscription ? ;

- est-ce une demande de résiliation ? ;

- est-ce une demande administrative ?

Suivant la finesse de gestion, le nombre de cas à gérer est plus ou moins important et les réactions du robot de même.

Pour ce faire, le robot crée plusieurs adresses pour une liste donnée. Prenons le cas d'une liste qui s'appellerait liste1@nain-t.net. Nous aurons finalement avec (cas du robot Sympa) les adresses :

- liste1@nain-t.net ;

- liste1-request@nain-t.net ;

- liste1-editor@nain-t.net ;

- liste1-subscribe@nain-t.net ;

- liste1-unsubscribe@nain-t.net ;

- liste1-bounce@nain-t.net.

Nous voyons bien que la création d'une nouvelle liste entraine des modifications dans la configuration de Postfix, qui devra appliquer le bon transport aux adresses associées à cette nouvelle liste. Sympa tout comme Mailman, proposent une aide acceptable à la résolution de cette problématique, du moins tant que nous ne gérons pas de domaines virtuels. C'est à ce niveau que l'on peut être amené à sérieusement se demander si Qmail,Vpopmail et EZmlm, avec Qmailadmin qui centralise toute la gestion de l'usine de façon bien homogène n'est pas finalement une bonne solution, même si la construction de cette usine n'est pas une sinécure.

6-1-2 - État des lieux

Nous avons une interface (web-cyradm) qui ne sait que gérer les comptes de messagerie (en PHP). Nous allons avoir une autre interface, qui ne sait gérer que les listes de diffusion (en Python pour Mailman et en Perl pour Sympa) et ce, en ignorant la configuration du MTA dès lors que l'on a à gérer des domaines virtuels.

Autant dire que nous devons non seulement renoncer à disposer d'une interface de gestion homogène, mais en plus nous résoudre à intervenir plus ou moins en profondeur sur la configuration du MTA en mettant les mains directement dans le cambouis.

6-1-3 - Quelques solutions

Une solution simple, sale et catastrophique en cas de spam, consisterait à dire :

- nous créons un sous-domaine dédié aux listes, par exemple lists.nain-t.net;

- tout ce qui entre à destination de ce sous-domaine est automatiquement dirigé vers le robot des listes.

Pour

Contre

Une seule règle par domaine virtuel nous permet de créer autant de listes qu'on le souhaite dans ce domaine, sans plus toucher à la configuration du MTA.

Le MTA ne gère pas les fausses adresses de listes, c'est au robot de le faire. En cas de spam sur le sous-domaine avec des adresses forgées aléatoirement, le robot sera soumis à rude épreuve.

Comment éviter cet inconvénient ? Créer une règle spécifique pour chaque liste de diffusion.

Pour

Contre

Une adresse de liste (une famille d'adresses, en fait) ne sera acceptée par le MTA que si elle est connue de lui. Le robot ne recevra que des messages légitimes.

Il n'est plus nécessaire de créer un sous-domaine dédié aux listes.

Il faut revenir sur la configuration du MTA à chaque création ou destruction d'une liste. Nous devrons le faire directement dans les fichiers de configuration de Postfix, ce qui obligera à faire intervenir un administrateur système.

La dernière solution consisterait à modifier le code des scripts de gestion des listes de manière à automatiser la configuration de Postfix, ce qui en plus de nécessiter des compétences de programmation, interdirait la mise à jour simple des scripts à partir des paquets de la distribution.

Dans ce qui suit, nous choisirons la méthode de mise en œuvre la plus simple, même si ce n'est pas forcément la meilleure.

6-2 - Mise en place de Sympa

Nous allons utiliser Sympa, qui sait gérer les domaines virtuels. Entendons par là qu'il est assez simple de disposer d'une interface de gestion des listes pour chaque domaine virtuel, permettant ainsi de déléguer la gestion des listes à un « listmaster » différent pour chaque domaine virtuel hébergé.

Sympa est un robot éprouvé, qui est fourni dans la distribution Debian. Il dispose d'une documentation abondante et relativement compréhensible. Il sait gérer un grand nombre de listes, avec un grand nombre d'abonnés, propose une gestion fine des autorisations de diffusion comme des modes d'abonnement (à chaque message, à un résumé périodique, de périodicité paramétrable...).

Note : Sympa n'est pas un gadget, c'est un robot de diffusion très complexe et son installation peut présenter quelques difficultés.

6-2-1 - Installation « de base »

Dans cette installation, il n'y aura pas de domaine virtuel. La machine hôte s'appelle cyrus.nain-t.net, elle gère les messages pour le domaine nain-t.net et nos listes seront @lists.nain-t.net. Il faut bien commencer par le début.

Nous allons utiliser l'interface web de Sympa. Le module fastcgi d'Apache est fortement recommandé (il est dans le dépôt non-free, la licence présentant quelques restrictions) :

aptitude install libapache2-mod-fastcgi

De plus, MySQL est nécessaire, mais nous l'avons déjà.

Puis nous installons Sympa, qui a beaucoup de dépendances :

aptitude install sympa

Nous utiliserons wwsympa, mais pas SOAP. Nous choisissons comme nom de domaine principal lists.nain-t.net. Il est donc nécessaire, si la machine s'appelle autrement (cyrus.nain-t.net dans notre cas), d'avoir un CNAME dans notre (nos) DNS.

# host lists.nain-t.net
lists.nain-t.net is an alias for cyrus.nain-t.net.
cyrus.nain-t.net has address 82.243.85.42

Le script d'installation pose un certain nombre de questions auxquelles il vaut mieux répondre correctement, mais il n'y a rien de définitif puisque la configuration sera par la suite modifiable dans /etc/sympa/sympa.conf. De plus, ce script doit pouvoir créer pour vous la base MySQL nécessaire.

6-2-2 - Vérifications

À l'issue de l'installation, nous devons retrouver quelques éléments remarquables :

- /etc/sympa est le répertoire de configuration. Il y a dedans un certain nombre de choses dont :

- sympa.conf qui est le fichier de configuration principal du robot ;

- wwsympa.conf pour la configuration de l'interface CGI ;

- topics.conf qui contient la liste de classement par thème(4) des listes que nous pourrons créer. Son contenu est à modifier en fonction des besoins ;

- /etc/mail/sympa.aliases est un fichier pour le moment vide, mais qui va se peupler avec la création de listes. Il est nécessaire que l'utilisateur Sympa puisse y pénétrer et y écrire. Vérifiez donc que Sympa est bien propriétaire du répertoire /etc/mail

Ce fichier d'alias, si l'on décide de l'utiliser, va nous imposer un mode de configuration de Postfix qui n'est pas optimal, mais qui nous évitera de devoir intervenir sur main.cf à chaque création ou suppression de liste de diffusion.

Voici un exemple de fichier sympa.conf :

## Configuration file for Sympa
## many parameters are optional (defined in src/Conf.pm)
## refer to the documentation for a detailed list of parameters

###\\\\ Directories and file location ////###

## Directory containing mailing lists subdirectories
home    /var/lib/sympa/expl

## Directory for configuration files ; it also contains scenari/ and templates/ directories
etc     /etc/sympa

## File containing Sympa PID while running.
## Sympa also locks this file to ensure that it is not running more than once. Caution : user sympa need to write access without special privilegee.
pidfile /var/run/sympa/sympa.pid

## Umask used for file creation by Sympa
umask   027

## The main spool containing various specialized spools
## All spool are created at runtime by sympa.pl
spool   /var/spool/sympa

## Incoming spool
queue   /var/spool/sympa/msg

## Bounce incoming spool
queuebounce     /var/spool/sympa/bounce

###\\\\ Syslog ////###

## The syslog facility for sympa
## Do not forget to edit syslog.conf
syslog `/bin/cat /etc/sympa/facility`

## Communication mode with syslogd is either unix (via Unix sockets) or inet (use of UDP)
log_socket_type unix

## Log intensity
## 0 : normal, 2,3,4 for debug
log_level       0

###\\\\ General definition ////###

## Main robot hostname
domain          lists.nain-t.net

## Listmasters email list comma separated
## Sympa will associate listmaster privileges to these email addresses (mail and web interfaces). Some error reports may also be sent to these addresses.
listmaster              sysop@nain-t.net

## Local part of sympa email adresse
## Effective address will be [EMAIL]@[HOST]
email   sympa

## Default lang (cs | de | el | en_US | fr | hu | it | ja_JP | nl | oc | pt_BR | tr)
lang            fr

## Who is able to create lists
## This parameter is a scenario, check sympa documentation about scenarios if you want to define one
create_list     public_listmaster

## Secret used by Sympa to make MD5 fingerprint in web cookies secure
## Should not be changed ! May invalid all user password
cookie `/bin/cat /etc/sympa/cookie`

###\\\\ Errors management ////###

## Bouncing email rate for warn list owner
#bounce_warn_rate       20

## Bouncing email rate for halt the list (not implemented)
## Not yet used in current version, Default is 50
#bounce_halt_rate       50

## Task name for expiration of old bounces
#expire_bounce_task     daily

## Welcome message return-path
## If set to unique, new subcriber is removed if welcome message bounce
#welcome_return_path    unique

###\\\\ MTA related ////###

## Path to the MTA (sendmail, postfix, exim or qmail)
## should point to a sendmail-compatible binary (eg: a binary named 'sendmail' is distributed with Postfix)
sendmail        /usr/sbin/sendmail

## Maximum number of recipients per call to Sendmail. The nrcpt_by_domain.conf file allows a different tuning per destination domain.
nrcpt   25

## Max. number of different domains per call to Sendmail
avg     10

## Max. number of Sendmail processes (launched by Sympa) running simultaneously
## Proposed value is quite low, you can rise it up to 100, 200 or even 300 with powerfull systems.
maxsmtp 40

###\\\\ Pluggin ////###

## Path to the antivirus scanner engine
## supported antivirus : McAfee/uvscan, Fsecure/fsav, Sophos, AVP and Trend Micro/VirusWall
#antivirus_path /usr/local/uvscan/uvscan

## Antivirus pluggin command argument
#antivirus_args --secure --summary --dat /usr/local/uvscan

###\\\\ S/MIME pluggin ////###

## Path to OpenSSL
## Sympa knowns S/MIME if openssl is installed
#openssl        /usr/local/bin/openssl

## The directory path use by OpenSSL for trusted CA certificates
#capath /etc/sympa/ssl.crt

##  This parameter sets the all-in-one file where you can assemble the Certificates of Certification Authorities (CA)
#cafile /usr/local/apache/conf/ssl.crt/ca-bundle.crt

## User CERTs directory
ssl_cert_dir    /var/lib/sympa/x509-user-certs

## Password used to crypt lists private keys
#key_passwd     your_password

###\\\\ Web interface ////###

## Sympa's main page URL
wwsympa_url http://lists.nain-t.net/wws

## Supported languages for the user interface
supported_lang  en_US,fr,

#-- Database configuration begin
# DO NOT REMOVE SURROUNDING COMMENTS

# DO NOT EDIT BY HAND
# USE dpkg-reconfigure -plow sympa TO RECONFIGURE

## Database driver (DBD)
db_type         mysql

## Name of your database
db_name         sympa

## Your database hostname
db_host         localhost

## Username to connect to the DB
db_user         sympa

## Password for the user
db_passwd               epikoi

#-- Database configuration end

Les passages surlignés représentent les paramètres indiqués lors du déroulement du script d'installation.

Vous désirerez sans doute aussi modifier le titre de l'interface cgi de Sympa. Il faut dans ce cas modifier dans le fichier wwsimpa.conf :

## Title of main web page
title   Les listes de nain-t.net

Après toute modification de la configuration de Sympa, il faut relancer Sympa et Apache.

6-2-3 - Apache

Autant prévoir un serveur virtuel, qui répondra dans un premier temps au doux nom de lists.nain-t.net et qui sera configuré pour faire fonctionner proprement wwsympa.fcgi.

Dans /etc/apache2/sites-avalable/, nous créons par exemple un fichier nommé sympa qui contient quelque chose comme ceci :

<VirtualHost *>
ServerAdmin webmaster@nain-t.net
DocumentRoot /var/www/lists.net
ServerName lists.nain-t.net
<Directory /usr/lib/cgi-bin/sympa>
SetHandler fastcgi-script
</Directory>
Alias /static-sympa /var/lib/sympa/static_content
Alias /icons /usr/share/sympa/icons
<Directory /var/lib/sympa/static_content>
Order allow,deny
Allow from all
</directory>
ScriptAlias /wws /usr/lib/cgi-bin/sympa/wwsympa.fcgi
</VirtualHost>

Puis :

# a2ensite sympa

pour créer le lien dans le répertoire /etc/apache2/sites-enabled (nous sommes toujours sous Debian n'est-ce pas), et enfin :

# apache2 graceful

pour actualiser Apache. Une connexion sur http://lists.nain-t.net/wws devrait nous montrer l'interface de notre gestionnaire de liste.

Attention ! Il pourrait se faire que www-data n'ait pas le droit de lecture sur les feuilles de style qui se trouvent dans /var/lib/sympa/static_content/css.

Enfin, pour que ce soit encore plus propre, nous pouvons prévoir une page d'accueil index.html que nous mettrons dans la racine de notre domaine virtuel, qui redirigera automatiquement sur le script cgi :

<html>
<head>
<meta http-equiv="refresh" content="0; url=wws/">
</head>
<body>
</body>
</html>

C'est parti(5) :

6-2-4 - Présentation rapide

Nous n'allons pas entrer dans les détails du fonctionnement de Sympa. Cependant il y a quelques choses à savoir pour pouvoir démarrer :

- l'interface « anonyme » que nous voyons ici ne permet pas de faire grand-chose, ce n'est rien d'autre qu'un portail qui permet aux visiteurs de consulter la liste des listes de diffusions déclarées comme publiques, et éventuellement de demander à s'abonner à certaines d'entre elles ;

- dans notre sympa.conf, nous avons déclaré sysop@nain-t.net comme étant le listmaster, mais nous ne l'avons pas pour autant enregistré dans la base de données. La procédure à suivre est donc celle-ci :

- s'inscrire sur le site avec l'adresse sysop@nain-t.net, ce qui provoquera l'envoi d'un message sur cette adresse, contenant un mot de passe ;

- s'identifier sur le portail avec l'adresse sysop@nain-t.net et le mot de passe reçu.

L'identification fera alors apparaitre plus de fonctionnalités sur le portail, principalement dans ce cas, les outils d'administration des listes :

D'une manière générale, tout abonné à une liste et qui se sera enregistré sur le site disposera d'un « login » lui permettant d'accéder au portail avec des droits adaptés à sa fonction :

- simple abonné ;

- propriétaire d'une liste ;

- modérateur ;

- administrateur des listes.

Sympa est hautement configurable à tous les niveaux. En passant un peu (voire beaucoup) de temps à consulter la documentation, il doit être possible d'arriver à maitriser ce robot.

6-2-5 - Et ça marche ?

Non, bien sûr. Pour l'instant, il est possible de :

- s'inscrire sur le site ;

- créer une liste (ou demander sa création si l'on n'est pas « listmaster ») ;

- recevoir les notifications de Sympa associées à ces actions.

Sympa est fait pour fonctionner avec la plupart des MTA connus Sendmail, Postfix, Exim et même Qmail. À ce titre, son installation ne prend guère d'initiative concernant la configuration du MTA. Même si une liste est créée, elle ne pourra pas fonctionner, Postfix n'étant pas au courant de son existence.

La seule chose qui est faite lors de la création d'une liste (test0 dans notre exemple), c'est l'ajout de quelques alias dans /etc/mail/sympa.aliases :

# cat /etc/mail/sympa.aliases
## List aliases used for the sympa mailing-list manager
#------------------------------ test0: list alias created 04 Jul 2008
test0: "| /usr/lib/sympa/bin/queue test0@lists.nain-t.net"
test0-request: "| /usr/lib/sympa/bin/queue test0-request@lists.nain-t.net"
test0-editor: "| /usr/lib/sympa/bin/queue test0-editor@lists.nain-t.net"
#test0-subscribe: "| /usr/lib/sympa/bin/queue test0-subscribe@lists.nain-t.net"
test0-unsubscribe: "| /usr/lib/sympa/bin/queue test0-unsubscribe@lists.nain-t.net"
test0-owner: "| /usr/lib/sympa/bin/bouncequeue test0@lists.nain-t.net"

Ah tiens, pourquoi l'alias concernant le traditionnel « subscribe » est-il mis en commentaire ? Sans doute pour amener les gens à utiliser plutôt l'interface cgi. Mais comment revenir sur ce paramétrage si nous le souhaitons ? C'est un secret, qui vous sera révélé plus tard...

/usr/lib/sympa/bin/queue, c'est, l'équivalent du MDA, mais pour les messages à destination de la liste de diffusion. Autrement dit, nous devons, avec ce qui est écrit dans ce fichier, arriver à ce que Postfix comprenne que les messages adressés à :

- test0@lists.nain-t.net ;

- test0-request@lists.nain-t.net ;

- test0-editor@lists.nain-t.net ;

- test0-unsubscribe@lists.nain-t.net,

ne soient non pas transmis à Cyrus, mais au programme /usr/lib/sympa/bin/queue de Sympa. De même, les messages à test0-owner@lists.nain-t.net devront être transmis au programme /usr/lib/sympa/bin/bouncequeue.

Ce fichier est donc un fichier d'alias classique, qu'il faut transmettre à Postfix par la directive alias_maps, en plus des alias déjà indiqués :

alias_maps = hash:/etc/aliases, hash:/etc/mail/sympa.aliases

Oui mais voilà, le fichier indexé /etc/mail/sympa.aliases.db n'a sans doute pas été créé et dans les logs de Sympa, après création de la liste, un message d'erreur doit l'indiquer.

Pourquoi tant de haine ?

Lorsque nous créons une nouvelle liste avec l'interface cgi, /etc/mail/sympa.aliases est mis à jour, puis un petit utilitaire, aliaswrapper est invoqué pour lancer la commande newaliases, chargée de synchroniser sympa.aliases.db avec sympa.aliases.db.

Il y a (au moins) deux raisons pour lesquelles ce dispositif peut ne pas fonctionner :

- newaliases prend l'identité du propriétaire du fichier source à traiter qui est ici Sympa. Sympa doit donc pouvoir écrire dans /etc/mail. Ceci a déjà été dit plus haut ;

- newaliases traite le fichier spécifié par le paramètre de configuration alias_database dans main.cf de Postfix. Or, qu'avons-nous dans le main.cf ?

alias_database = hash:/etc/aliases

Qu'il nous faut donc remplacer par :

alias_database = hash:/etc/mail/sympa.aliases

Si ces deux points sont vérifiés, le wwsympa.fcgi devrait à l'avenir gérer correctement les alias qu'il crée. En attendant, un :

postalias /etc/mail/sympa.aliases

devrait permettre de rendre notre liste0 (presque) opérationnelle. Car sommes-nous certains que Postfix va reconnaitre la destination @lists.nain-t.net comme locale ?

Pour anticiper un peu (avenir peuplé de domaines virtuels), plutôt que de l'indiquer « en dur » dans le paramètre mydestination, voyons si ce ne serait pas possible de piquer l'information dans la base de données MySQL nécessaire à Sympa, elle y est certainement. Une investigation rapide dans la base montre que :

mysql> select robot_admin from admin_table;
+------------------+
| robot_admin      |
+------------------+
| lists.nain-t.net |
+------------------+
1 row in set (0.01 sec)

Donc, un fichier que nous appellerons par exemple /etc/postfix/db/lists_destinations.cf qui contiendrait ceci :

hosts = 127.0.0.1
user = sympa
password = epikoi
dbname = sympa
query = SELECT robot_admin FROM admin_table WHERE robot_admin = '%s' limit 1

Le limit 1 est nécessaire, car sans cette limite, si nous créons n listes dans le domaine nain-t.net, la requête sortira n occurrences. Il ne reste plus qu'à ajouter l'appel à ce fichier dans notre main.cf :

mydestination = $myhostname,
localhost, localhost.localdomain,
mysql:/etc/postfix/db/mydestination.cf,
mysql:/etc/postfix/db/lists_destinations.cf

Et de demander à Postfix de relire sa configuration.

(Le fichier /etc/postfix/db/mydestination.cf a été vu dans « Postfix avec Cyrus »).

6-2-5-1 - Résumé d'intervention

Nous nous sommes assurés que Sympa sait lire et écrire dans /etc/mail et nous avons modifié /etc/mostfix/main.cf comme suit :

alias_maps = hash:/etc/aliases, hash:/etc/mail/sympa.aliases
alias_database = hash:/etc/mail/sympa.aliases

Puis nous avons synchronisé le hash des alias générés par Sympa avec la commande :

postalias /etc/mail/sympa.aliases

Ceci ne devrait plus être nécessaire par la suite.

Enfin, nous avons agi sur le mydestination de Postfix en créant un fichier de requête /etc/postfix/db/lists_destinations.cf sur la base MySQL de Sympa :

hosts = 127.0.0.1
user = sympa
password = epikoi
dbname = sympa
query = SELECT robot_admin FROM admin_table WHERE robot_admin = '%s' limit 1

et avons modifié le paramètre mydestination dans notre main.cf comme ceci :

mydestination = $myhostname,
localhost, localhost.localdomain,
mysql:/etc/postfix/db/mydestination.cf,
mysql:/etc/postfix/db/lists_destinations.cf

6-2-6 - C'est tout ?

Si nous n'avons pas de listes à gérer dans d'autres domaines oui, mais ce n'est pas le cas. Il nous reste à voir comment réaliser une configuration fonctionnelle pour plusieurs domaines.

6-3 - Domaines virtuels Sympa

6-3-1 - Le but

L'objectif est double :

- pouvoir créer des listes de diffusion dans les domaines de messagerie que nous gérons. Par exemple, si nous avons aussi à gérer les domaines @machin.net et @chose.net, il faut que nous puissions créer des listes @lists.machin.net et @lists.chose.net, comme nous l'avons fait avec @lists.nain-t.net ;

- offrir une interface de gestion des listes propre à chaque domaine.

Sympa est prévu pour ça et nous aurons assez peu de choses à faire. L'idée est similaire à celle des domaines virtuels d'Apache. Allons-y progressivement.

6-3-2 - La méthode

6-3-2-1 - Étape 1

Nous commençons par créer dans /etc/sympa un sous-répertoire que nous nommerons comme le domaine de listes à créer. Exemple :

mkdir /etc/sympa/lists.machin.net

Dans ce répertoire, il faudra créer un fichier nommé robot.conf assez similaire à /etc/sympa/sympa.conf

Faisons simple :

## This is a sample config file for a Virtual Robot in Sympa

## This hostname will be compared with 'SERVER_NAME' ENV var in wwsympa.fcgi
## To deduce which Virtual Robot is being queried
http_host  lists.machin.net

## Listmasters email addresses
listmaster sysop@machin.net

## Title for the ML service
## It is displayed as a title in the web interface
title Les listes de machin.net

create_list  listmaster

## The default action when entering the web interface
## Can be 'lists', 'home' or 'which'
default_home  home

Rendons Sympa propriétaire de tout ceci :

chown -R sympa:sympa /etc/sympa/lists.machin.net

La première étape est finie. Le fichier est assez compréhensible. Les options indiquées dedans viennent surcharger ou compléter celles qui sont dans /etc/sympa/sympa.conf. Ainsi, sysop@machin.net sera « listmaster » @lists.machin.net mais attention, le ou les listmasters définis dans le domaine principal (ici @lists.nain-t.net) le seront aussi @lists.machin.net. En revanche, sysop@machin.net ne sera pas listmaster dans le domaine principal, ni dans les autres domaines virtuels, sauf mention contraire dans les robots.conf (ou sympa.conf).

Le domaine principal est hiérarchiquement supérieur à tous les domaines virtuels que nous pourrons créer par la suite.

6-3-2-2 - Étape 2

SI vous allez faire un tour dans /var/lib/sympa/expl, vous constaterez que Sympa y range des choses concernant les listes du domaine principal. Suivant la même logique, nous allons y créer un répertoire du nom de notre nouveau domaine :

mkdir /var/lib/sympa/expl/lists.machin.net
chown sympa:sympa /var/lib/sympa/expl/lists.machin.net

Sympa pourra y stocker ses petites affaires concernant les listes @lists.machin.net.

6-3-2-3 - Étape 3

Il faut que le domaine machin.net soit enregistré sur nos DNS de manière à ce qu'ils sachent :

- résoudre lists.machin.net ;

- indiquer un MX pour le domaine machin.net ;

- indiquer un MX pour le sous-domaine lists.machin.net.

Voici un exemple minimal pour la zone machin.net :

$ttl 38400
@        IN    SOA    cyrus. sysop.bts.net. (
2008060702
10800
3600
604800
38400 )
machin.net.        IN    NS    cyrus.machin.net.
MX    10    cyrus
cyrus.machin.net.    IN    A    192.168.10.7

lists.machin.net.    MX    10    cyrus
lists            IN    A    192.168.10.7

6-3-2-4 - Étape 4

Il faut que notre Apache réponde correctement à http://lists.machin.net. Pour ça, il suffit d'ajouter le paramètre ServerAlias lists.machin.net à notre serveur virtuel et demander à l'Apache de relire sa configuration :

apache2ctl graceful

6-3-2-5 - Étape 5

À ce niveau, nous pouvons envisager de créer des listes @lists.machin.net, mais la diffusion des messages ne se fera pas, Postfix n'est pas encore complètement au courant.

Il est déjà informé de deux choses :

- la destination lists.machin.net est acquise, puisqu'elle va venir par la base MySQL de Sympa ;

- les alias dans /etc/mail/sympa.aliases vont être automatiquement créés par le script cgi, mais voyons un peu...

#------------------------------ test0: list alias created 04 Jul 2008
test0: "| /usr/lib/sympa/bin/queue test0@lists.nain-t.net"
test0-request: "| /usr/lib/sympa/bin/queue test0-request@lists.nain-t.net"
test0-editor: "| /usr/lib/sympa/bin/queue test0-editor@lists.nain-t.net"
#test0-subscribe: "| /usr/lib/sympa/bin/queue test0-subscribe@lists.nain-t.net"
test0-unsubscribe: "| /usr/lib/sympa/bin/queue test0-unsubscribe@lists.nain-t.net"
test0-owner: "| /usr/lib/sympa/bin/bouncequeue test0@lists.nain-t.net"
#------------------------------ liste0: list alias created 04 Jul 2008
lists.machin.net-liste0: "| /usr/lib/sympa/bin/queue liste0@lists.machin.net"
lists.machin.net-liste0-request: "| /usr/lib/sympa/bin/queue liste0-request@lists.machin.net"
lists.machin.net-liste0-editor: "| /usr/lib/sympa/bin/queue liste0-editor@lists.machin.net"
#lists.machin.net-liste0-subscribe: "| /usr/lib/sympa/bin/queue liste0-subscribe@lists.machin.net"
lists.machin.net-liste0-unsubscribe: "| /usr/lib/sympa/bin/queue liste0-unsubscribe@lists.machin.net"
lists.machin.net-liste0-owner: "| /usr/lib/sympa/bin/bouncequeue liste0@lists.machin.net"

Dans le domaine principal, test0 correspond bien à la partie utilisateur de l'adresse test0@lists.nain-t.net. Ce n'est en revanche pas le cas dans notre domaine virtuel où il faudra faire correspondre lists.machin.net-liste0 à la partie utilisateur de liste0@lists.machin.net.

L'astuce consiste à utiliser une « expression régulière » que Postfix consultera pour reconnaitre ces alias virtuels. Nous créons donc par exemple un fichier /etc/postfix/sympa_virtual_regexp qui contiendra cette ligne :

/^(.*)@lists\.machin\.net$/ lists.machin.net-$1

Vous ne lisez pas les expressions régulières dans le texte ? Dommage...

Tout ce qui commence (^) par n'importe quel motif ((.*)) suivi de @lists.machin.net sans plus rien après ($) sera remplacé par lists.machin.net- suivi du premier (et unique) motif ($1) trouvé dans la partie gauche. Exemple :

Dans liste0@lists.machin.net, le motif, c'est liste0. Le tout sera donc remplacé par lists.machin.net-liste0, nous retombons bien sur nos pattes.

Il ne nous reste plus qu'à modifier dans le main.cf le paramètre virtual_alias_maps comme ceci :

virtual_alias_maps = mysql:/etc/postfix/db/virtual-alias.cf, regexp:/etc/postfix/sympa_virtual_regexp

Et à demander à Postfix de relire sa configuration. Tout devrait maintenant être opérationnel.

6-3-2-6 - Bilan

Ces cinq étapes ne seront à refaire qu'à chaque création d'un nouveau domaine virtuel. Par la suite la gestion des listes dans ces domaines virtuels ne nécessitera aucune modification sur Postfix ni sur Cyrus, qui n'est pas concerné.

Compte tenu de la souplesse de Postfix, d'autres approches sont possibles bien entendu, mais elles nécessiteront beaucoup plus d'interventions sur la configuration de Postfix, à moins de modifier le script alias_manager.pl fourni avec Sympa, et probablement d'autres scripts aussi.

6-4 - Plus loin avec Sympa

6-4-1 - Versions de Sympa

Debian a pour habitude de faire passer la stabilité avant l'innovation. Ce choix a pour conséquence de disposer de versions logicielles parfois dépassées. Ainsi, au 8 juillet 2008, la distribution Debian « stable » (Etch) propose Sympa 5.2.3 (annoncée en décembre 2006), les versions « Testing » (Lenny) et « Unstable » (Sid) proposent la version 5.3.4 (annoncée en novembre 2007), alors que sur le site de Sympa, la version 5.4.3 a été annoncée le 2 mai 2008). Il est clair que compte tenu de la fréquence des mises à jour de Sympa, il n'est pas possible d'envisager de voir empaquetée une version très récente sur une distribution éprouvée.

La version 5.2.3 est parfaitement exploitable et l'on peut s'en contenter. Le principal avantage de passer à la version 5.3.4 est de disposer du support UTF-8. Il y a plusieurs autres améliorations, mais qui concernent principalement la configuration avancée de Sympa qui n'est pas abordée ici. Voyez le « changelog » pour les détails.

Il est possible d'installer « proprement » une version 5.3.4 sur une Etch en effectuant un « backport » du paquet Debian issu de Lenny. Nous n'entrerons pas dans les détails, une méthode possible est de placer dans /etc/apt/sources.list deb-src http://mir2.ovh.net/debian/ etch main non-free contrib

deb-src http://security.debian.org/ etch/updates main contrib non-free

En changeant éventuellement de miroir, de récupérer le paquet source Sympa et de le recompiler sur Etch. Le paquet binaire de Lenny ne peut s'installer tel quel à cause d'une dépendance à la libc6. Les autres dépendances sont compatibles avec la distribution Etch, à l'exception de deux paquets qui n'existent pas :

- libmime-charset-perl ;

- libmime-encwords-perl.

Ces deux paquets binaires peuvent être récupérés sur Lenny et installés sur Etch.

Il faudra cependant rester attentif aux correctifs de sécurité qui pourraient apparaitre sur ces trois paquets, puisqu'ils échapperont aux mises à jour « normales » de la distribution.

6-4-2 - Personnaliser Sympa

Nous avons déjà parlé du fichier topics.conf qui contient les rubriques de classement des listes, mais beaucoup d'autres choses sont modifiables dans Sympa. Voici quelques pistes de recherche pour ceux qui désireraient approfondir le fonctionnement de ce gestionnaire de listes.

Dans le répertoire /usr/share/sympa se trouvent quelques fichiers intéressants, dont un nommé « README », qui est court, mais qui en dit long :

Because next installation of Sympa will overwrite this directory, if
you need to customize configuration files, then :
1/ copy desired files to /etc/sympa directory
2/ customize these copied files

Parce que la prochaine installation de Sympa va écraser le contenu de ce répertoire, si vous avez besoin de personnaliser les fichiers de configuration, alors :

- copiez les fichiers désirés dans le répertoire /etc/sympa ;

- modifiez ces copies de fichiers.

6-4-2-1 - Un « list-subscribe » ?

Copiez le fichier /usr/share/sympa/list_aliases.tt2 dans /etc/sympa et décommentez les lignes :

#------------------------------ [% list.name %]: list alias created [% date %]
[% IF is_default_domain -%]
[% list.name %]: "| /usr/lib/sympa/bin/queue [% list.name %]@[% list.domain %]"
[% list.name %]-request: "| /usr/lib/sympa/bin/queue [% list.name %]-request@[% list.domain %]"
[% list.name %]-editor: "| /usr/lib/sympa/bin/queue [% list.name %]-editor@[% list.domain %]"
#[% list.name %]-subscribe: "| /usr/lib/sympa/bin/queue [% list.name %]-subscribe@[% list.domain %]"
[% list.name %]-unsubscribe: "| /usr/lib/sympa/bin/queue [% list.name %]-unsubscribe@[% list.domain %]"
[% list.name %][% return_path_suffix %]: "| /usr/lib/sympa/bin/bouncequeue [% list.name %]@[% list.domain %]"
[% ELSE -%]
[% list.domain %]-[% list.name %]: "| /usr/lib/sympa/bin/queue [% list.name %]@[% list.domain %]"
[% list.domain %]-[% list.name %]-request: "| /usr/lib/sympa/bin/queue [% list.name %]-request@[% list.domain %]"
[% list.domain %]-[% list.name %]-editor: "| /usr/lib/sympa/bin/queue [% list.name %]-editor@[% list.domain %]"
#[% list.domain %]-[% list.name %]-subscribe: "| /usr/lib/sympa/bin/queue [% list.name %]-subscribe@[% list.domain %]"
[% list.domain %]-[% list.name %]-unsubscribe: "| /usr/lib/sympa/bin/queue [% list.name %]-unsubscribe@[% list.domain %]"
[% list.domain %]-[% list.name %][% return_path_suffix %]: "| /usr/lib/sympa/bin/bouncequeue [% list.name %]@[% list.domain %]"
[% END -%]

6-4-2-2 - Modèles de listes

Les modèles de listes présentés sur le formulaire de création ne vous conviennent pas ?

Là, c'est un peu plus compliqué, mais le répertoire /usr/share/sympa/create_list_templates/ contient ce qu'il y a à modifier. Commencez par copier ce répertoire dans /etc/sympa, armez-vous de patience, de la documentation et voyez comment rendre cette liste plus personnelle. Attention, modifier ces fichiers n'est pas forcément anodin.

6-4-2-2-1 - TT2

D'une manière générale, les fichiers avec une extension .tt2 sont des « templates » qui utilisent le Template Toolkit. Si vous avez quelques journées à tuer, c'est l'occasion...

6-5 - Cadeau bonus

Pour ceux qui ne seraient pas satisfaits de la façon dont nous avons interfacé Sympa avec Postfix, voici une autre piste qui préserve davantage les ressources système en cas de « spam storm ».

6-5-1 - Les transports

Nous le savons, il est possible de définir des transports particuliers dans le fichier master.cf de postfix.

Nous pouvons en définir un certain nombre qui font référence à /usr/lib/sympa/bin/queue. Voici ce que nous pouvons ajouter dans notre master.cf :

#
# Les « pipes » sympa
# ou
# Les transports du gestionnaire de listes sympa
#
sympalist        unix  -       n       n       -       -       pipe
flags=RF user=sympa argv=/usr/lib/sympa/bin/queue ${user}@${extension}
symparequest     unix  -       n       n       -       -       pipe
flags=RF user=sympa argv=/usr/lib/sympa/bin/queue ${user}-request@${extension}
sympaeditor      unix  -       n       n       -       -       pipe
flags=RF user=sympa argv=/usr/lib/sympa/bin/queue ${user}-editor@${extension}
sympasubscribe   unix  -       n       n       -       -       pipe
flags=RF user=sympa argv=/usr/lib/sympa/bin/queue ${user}-subscribe@${extension}
sympaunsubscribe unix  -       n       n       -       -       pipe
flags=RF user=sympa argv=/usr/lib/sympa/bin/queue ${user}-unsubscribe@${extension}
sympabounce      unix  -       n       n       -       -       pipe
flags=RF user=sympa argv=/usr/lib/sympa/bin/bouncequeue ${user}@${extension}

Nous reconnaissons des syntaxes assez proches de celles que nous avons vues dans /etc/mail/sympa.aliases. Il nous faudra réaliser une « map » des transports à emprunter suivant l'adresse du message à envoyer à Sympa.

6-5-2 - Alias virtuels

Nous allons exploiter les propriétés des extensions d'adresses, avec le recipient_delimiter :

recipient_delimiter = +

Ainsi que les possibilités de réécriture d'adresses avec les alias virtuels de Postfix. La compréhension de ce mécanisme n'est pas d'une grande simplicité, il faut bien le dire.

6-5-2-1 - Extension d'adresse

Si nous écrivons quelque chose comme truc+bidule@undomaine.quelconque, la partie à gauche du @ va être séparée en deux :

- la partie à gauche du + (truc) sera récupérée dans la variable ${user} ;

- la partie à droite du + (bidule) sera récupérée dans la variable ${extension}.

Compte tenu des transports que nous avons créés dans master.cf, nous voyons bien que cette possibilité va nous servir.

6-5-2-2 - Alias virtuels

Une table d'alias, nous l'avons compris à force, permet de remplacer une adresse par une autre. Nous pouvons exploiter les expressions régulières dans ces tables, et n'allons pas nous en priver. Créons par exemple un fichier /etc/postfix/sympa_virtual_aliases qui contiendrait, compte tenu de nos essais précédents, ceci :

/^(sympa|listmaster)\@lists\.nain-t\.net$/    $1+lists.nain-t.net@sympalist.
/^(liste1)-(request|editor|owner|subscribe|unsubscribe)\@lists\.nain-t\.net$/  $1+lists.nain-t.net@sympa$2.
/^(liste1)\@lists\.nain-t\.net$/  $1+lists.nain-t.net@sympalist.

/^(sympa|listmaster)\@lists\.machin\.net$/    $1+lists.machin.net@sympalist.
/^(liste1)-(request|editor|owner|subscribe|unsubscribe)\@lists\.machin\.net$/  $1+lists.machin.net@sympa$2.
/^(liste1)\@lists\.machin\.net$/  $1+lists.machin.net@sympalist.

Vous ne lisez toujours pas les expressions régulières dans le texte ? Tant pis pour vous.

Soit une adresse qui serait par exemple liste1-unsubscribe@lists.machin.net. Elle sera remplacée par liste1+lists.machin.net@sympaunsubscribe. Curieux comme adresse non ?

Mais attendons la suite, nous comprendrons mieux plus tard.

6-5-3 - Transport à la carte

Créons un fichier nommé par exemple /etc/postfix/sympa_transport_maps qui contiendrait ceci :

/^.*\@sympalist$/         sympalist:
/^.*\@symparequest$/      symparequest:
/^.*\@sympaeditor$/       sympaeditor:
/^.*\@sympasubscribe$/    sympasubscribe:
/^.*\@sympaunsubscribe$/  sympaunsubscribe:
/^.*\@sympaowner$/        sympabounce:

(Oui ! Encore des expressions régulières.)

Par exemple, un message destiné à une adresse qui aurait dans sa partie « domaine » (à droite du @ la valeur sympaunsubscribe et seulement cette valeur, sera transmise au transport sympaunsubscribe.

Reprenons notre exemple précédent.

- Postfix a reçu un message pour liste1-unsubscribe@lists.machin.net ;

- cette adresse a donc été transformée en liste1+lists.machin.net@sympaunsubscribe à cause de la table d'alias virtuels ;

- la table des transports dit qu'un message dont l'adresse du destinataire se termine par sympaunsubscribe doit être transmise au transport du même nom ;

- le transport en question (/usr/lib/sympa/bin/queue que nous connaissons déjà) va donc recevoir un message avec une adresse de destination de la forme ${user}-unsubscribe@${extension}.

L'adresse communiquée au transport est donc finalement liste1-unsubscribe@lists.machin.net. Astucieux non ? Je vous rassure, votre serviteur n'a pas inventé un truc aussi compliqué (et aussi efficace). Il s'est contenté de le trouver ici.

6-5-4 - Et finalement...

Dans postfix, à part ajouter les transports dans master.cf, il faut invoquer le récipient-delimiter :

recipient_delimiter = +

Invoquer la carte des transports :

transport_maps=regexp:/etc/postfix/sympa_transport_maps

Invoquer la table des alias virtuels :

virtual_alias_maps = mysql:/etc/postfix/db/virtual-alias.cf, regexp:/etc/postfix/sympa_virtual_aliases

6-5-4-1 - Avantage

Cette méthode élimine les expressions plus génériques que nous avions employées dans la première solution, évitant ainsi d'envoyer du spam à Sympa (ce qui ne l'est pas), Postfix refusant directement ces messages qui ne sont plus pour lui dans ses destinataires connus. Autrement dit, contrairement à la solution d'origine où un message à albert@lists.machin.net aurait été transmis à Sympa et c'est sympa qui l'aurait rejeté, ici, c'est Postfix qui va le rejeter directement.

6-5-4-2 - Inconvénient

À chaque création d'une nouvelle liste, il faudra intervenir manuellement sur le fichier /etc/postfix/sympa_virtual_aliases car les alias construits par alias_manager.pl ne sont ici d'aucune utilité.

Comme ce script utilise des « templates tt2 », il reste peut-être un espoir pour qu'un expert trouve un modèle qui apporte une réponse à la question. Faute de quoi, il faut écrire un autre script pour automatiser cette tâche.

7 - Remerciements Developpez

Vous pouvez retrouver l'article original ici : L'Internet Rapide et Permanent. Christian Caleca a aimablement autorisé l'équipe « Réseaux » de Developpez.com à reprendre son article. Retrouvez tous les articles de Christian Caleca sur cette page.

Nos remerciements à Voïvode, ced et ClaudeLELOUP pour leur relecture orthographique.

N'hésitez pas à commenter cet article ! Commentez

(1)Nous aurions pu aussi utiliser la commande newaliases sans arguments, à la condition que le fichier d'aliases soit indiqué dans la configuration de Postfix avec le paramètre alias_database, ce qui est notre cas présent.

(2)Sieve est un langage normalisé, plus facilement compréhensible que celui de Procmail, mais moins puissant. Les MDA qui l'implémentent complètement proposent un service qui permet à l'utilisateur de placer facilement ses règles de tri sur le serveur, en utilisant par exemple un webmail comme SquirrelMail

(3)Méga octet informatique = 1024 Kio, le Kio étant lui-même un Kilo octet informatique = 1024 octets

(4)Sympa permet de classer les listes de diffusion par thème. Une liste de thèmes est fournie par défaut dans le fichier topics.conf mais ne conviendra sans doute pas à nos attentes. Il convient donc de le modifier selon nos besoins, en respectant sa syntaxe qui est d'une grande simplicité

(5)Le lecteur attentif et qui chercherait à réaliser l'installation constatera que le Sympa illustré ici est en version 5.3.4 alors que Debian Etch fournit la version 5.2.3. Nous verrons plus loin comment réaliser ceci. L'opération permet de disposer d'une version de Sympa qui gère correctement UTF-8, ce qui n'est pas le cas de la 5.2.3.