Archives pour la catégorie ‘Messagerie’

Postfix : configuration d’une redirection catch-all en sortie

# vim /etc/postfix/main.cf
# catch all
recipient_canonical_classes = envelope_recipient
recipient_canonical_maps = regexp:/etc/postfix/recipient_canonical_map
# vim /etc/postfix/recipient_canonical_map
/./ user@localhost

Dovecot : désactiver l’écoute sur les ports non sécurisés POP3/IMAP

# vim /etc/dovecot/conf.d/10-master.conf
service imap-login {
   inet_listener imap {
   port = 0
   }
   inet_listener imaps {
      port = 993
      ssl = yes
   }
}

service pop3-login {
   inet_listener pop3 {
      port = 0
   }
   inet_listener pop3s {
      port = 995
      ssl = yes
   }
}

Postfix : configuration backup MX

root@mxbackup ~ # cat /etc/postfix/main.cf
relay_domains = $mydestination my.domain1 my.domain2

smtpd_client_restrictions =
        permit_mynetworks,
        reject_unknown_reverse_client_hostname,
        reject_rbl_client zen.spamhaus.org,
        reject_rbl_client bl.spamcop.net,
        reject_rbl_client cbl.abuseat.org,
        permit

smtpd_helo_restrictions =
        permit_mynetworks,
        reject_invalid_hostname,
        reject_unknown_hostname,
        permit

smtpd_sender_restrictions =
        reject_non_fqdn_sender,
        permit_mynetworks,
        reject_unknown_sender_domain,
        permit

smtpd_recipient_restrictions =
        reject_non_fqdn_recipient,
        permit_mynetworks,
        reject_unknown_recipient_domain,
        reject_unauth_destination,
        permit

smtpd_data_restrictions =
        reject_unauth_pipelining

iRedMail : configurer un second node en backup MX

Configuration du serveur LDAP sur le node MX1

root@mx1 ~ # nano /etc/ldap/slapd.conf
moduleload syncprov
overlay syncprov
syncprov-checkpoint 100 10
syncprov-sessionlog 200
root@mx1 ~ # /etc/init.d/slapd restart

Configuration du serveur LDAP sur le node MX2

root@mx2 ~ # nano /etc/ldap/slapd.conf
syncrepl rid=1
   provider=ldap://mx1.my.domain
   type=refreshAndPersist
   searchbase="dc=mailing,dc=com"
   bindmethod=simple
   binddn="cn=Manager,dc=mailing,dc=com"
   credentials=mypassword
   scope=sub
   schemachecking=on
   type=refreshOnly
   retry="60 +"
   scope=sub
   interval=00:00:01:00
   attrs="*,+"

updateref ldap://mx1.my.domain/
root@mx2 ~ # /etc/init.d/slapd restart

Activation du backup MX sur le node MX2

Au niveau LDAP, il ne faut aucun attribut supplémentaire sur les objets MailDomain pour permettre le backup MX. Plus précisément, il n’y a plus de vérification sur l’attribut domainBackupMX, mais il peut être utilisé avec la valeur no pour ne pas relayer un domaine sur le MX2.

root@mx2 ~ # cat /etc/postfix/ldap/relay_domains.cf
query_filter = (&(objectClass=mailDomain)(|(domainName=%s)(&(enabledService=domainalias)(domainAliasName=%s)))(accountStatus=active)(enabledService=mail))
root@mx2 ~ # cat /etc/postfix/ldap/virtual_mailbox_domains.cf
query_filter = (&(objectClass=mailDomain)(|(domainName=%s)(&(enabledService=domainalias)(domainAliasName=%s)))(domainBackupMX=no)(accountStatus=active)(enabledService=mail))
root@mx2 ~ # cat /etc/postfix/ldap/transport_maps_domain.cf
query_filter = (&(objectClass=mailDomain)(|(domainName=%s)(domainAliasName=%s))(domainBackupMX=no)(accountStatus=active)(enabledService=mail))
root@mx2 ~ # nano /etc/postfix/main.cf
maximal_queue_lifetime=9d
root@mx2 ~ # /etc/init.d/postfix restart

Swaks : vérifier l’envoi de mail au format HTML

boris.huisgen@muse:~$ swaks --body content.html --add-header "MIME:Version 1.0" --add-header "Content-Type: text/html" --to dst@outlook.com --from src@my.domain --auth-user toto --auth-pass tata --server smtp.my.domain -p 587

Postfix : ajout du support DMARC

Pour prendre en charge DMARC sur un MTA Postfix, il convient d’installer OpenDMARC. Çà tombe bien c’est rapide.

Installation

root@mailsrv:~# cat /etc/apt/apt.conf
APT::Default-Release "stable";
root@mailsrv:~# nano /etc/apt/apt.conf
# stable
deb http://ftp.debian.org/debian wheezy main contrib non-free
deb http://security.debian.org wheezy/updates main contrib non-free

# testing
deb http://ftp.debian.org/debian testing main contrib non-free
deb http://security.debian.org testing/updates main contrib non-free
root@mailsrv:~# apt-get update
root@mailsrv:~# apt-get dist-upgrade
root@mailsrv:~# apt-get -t testing install opendmarc

Configuration de Postfix

root@mailsrv:~# nano /etc/postfix/main.conf
smtpd_milters = inet:127.0.0.1:8893
non_smtpd_milters = inet:127.0.0.1:8893

Dovecot : restriction de l’authentification utilisateur

Je vous présente ici la solution que j’ai retenu pour restreindre les possibilités d’authentification de Dovecot selon le protocole utilisé (POP/IMAP/SMTP/Sieve). La gestion des comptes de messagerie étant effectué en SQL avec PostfixAdmin, le schéma a été repris tel quel ; seule une table a été ajoutée. L’authentification SMTP est déportée de Postfix vers Dovecot (configuration LMTP).

Configuration SQL

La table dédiée à l’authentification est la suivante :

CREATE TABLE IF NOT EXISTS `auth` (
  `username` varchar(255) NOT NULL,
  `allow_smtp` tinyint(1) NOT NULL DEFAULT '1',
  `smtp_nets` varchar(255) NOT NULL DEFAULT '::1,127.0.0.1,0::0/0,0.0.0.0/0',
  `allow_imap` tinyint(1) NOT NULL DEFAULT '1',
  `imap_nets` varchar(255) NOT NULL DEFAULT '::1,127.0.0.1',
  `allow_pop3` tinyint(1) NOT NULL DEFAULT '1',
  `pop3_nets` varchar(255) NOT NULL DEFAULT '::1,127.0.0.1,0::0/0,0.0.0.0/0',
  `allow_sieve` tinyint(1) NOT NULL DEFAULT '1',
  `sieve_nets` varchar(255) NOT NULL DEFAULT '::1,127.0.0.1',
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Elle contiendra donc l’ensemble des comptes utilisateurs (username) avec les possibilités de chacun. Les valeurs par défaut autorisent ici :

  • la connexion SMTP quelque soit l’IP source (IPv4 et IPv6)
  • la connexion IMAP uniquement par IP locale (par webmail)
  • la connexion POP3 quelque soit l’IP source
  • la gestion des filtres Sieve uniquement en local (par webmail)

Configuration de Dovecot

Les requêtes SQL sont à modifier de cette façon :

user_query = \
   SELECT \
      CONCAT('/var/spool/vmail/', maildir) AS home, \
      CONCAT('maildir:/var/spool/vmail/', maildir) AS mail, \
      999 AS uid, \
      999 AS gid, \
      'dict:User quota::proxy::quota' AS quota, \
      CONCAT('*:storage=',FLOOR(quota/1000)) AS quota_rule, \
      'Trash:storage=+100M' AS quota_rule2 \
   FROM \
      mailbox \
   WHERE \
      username='%u' AND domain='%d' AND active='1'

password_query = \
   SELECT \
      mailbox.username AS user, \
      mailbox.domain AS domain, \
      password, \
      CONCAT('/var/spool/vmail/', maildir) AS userdb_home, \
      CONCAT('maildir:/var/spool/vmail/', maildir) AS userdb_mail, \
      999 AS userdb_uid, \
      999 AS userdb_gid, \
      'dict:User quota::proxy::quota' AS userdb_quota, \
      CONCAT('*:storage=',FLOOR(quota/1000)) AS userdb_quota_rule, \
      'Trash:storage=+100M' AS userdb_quota_rule2, \
      CASE '%s' \
         WHEN 'smtp' THEN smtp_nets \
         WHEN 'imap' THEN imap_nets \
         WHEN 'pop3' THEN pop3_nets \
         WHEN 'sieve' THEN sieve_nets \
      END AS allow_nets \
   FROM \
      mailbox, auth \
   WHERE \
      mailbox.username=auth.username AND \
      mailbox.username='%u' AND domain='%d' AND active='1' AND \
      ( \
         ('%s'='smtp' AND allow_smtp='1') \
         OR \
         ('%s'='imap' AND allow_imap='1') \
         OR \
         ('%s'='pop3' AND allow_pop3='1') \
         OR \
         ('%s'='sieve' AND allow_sieve='1') \
         OR \
         '%s'='doveadm' \
      )

iterate_query = \
   SELECT \
      username AS user \
   FROM \
      mailbox \
   WHERE \
      active='1'

Scripts complémentaires pour une gestion avec Postfixadmin

Du côté de PostfixAdmin, l’ajout et la suppresion de comptes déclenchent les scripts de modification des enregistrements dans la table auth :

root@mail:~# more mailbox-postcreation.d/10-auth
#!/usr/bin/perl

my $sql_host = 'localhost';                         # SQL server hostname
my $sql_port = '3306';                              # SQL server port
my $sql_database = 'postfix';                       # SQL database name
my $sql_user = 'postfixadmin';                      # SQL user
my $sql_password = 'blablablaaa';                   # SQL password

use strict;
use warnings;
use DBI;
use DBD::mysql;

my ($dsn, $dbh, $qh, $mailbox);

$mailbox = $ARGV[0];
if (!defined($mailbox) || ($mailbox eq '')) {
   exit 1
}

$dsn = "dbi:mysql:$sql_database:$sql_host:$sql_port";
$dbh = DBI->connect($dsn, $sql_user, $sql_password)
	or die "failed to connect to database: $DBI::errstr\n";
$qh = $dbh->prepare("INSERT INTO auth (username) VALUES ('$mailbox')");
$qh->execute();
root@mail:~# more /root/scripts/postfixadmin/mailbox-postdeletion.d/10-auth
#!/usr/bin/perl

my $sql_host = 'localhost';                         # SQL server hostname
my $sql_port = '3306';                              # SQL server port
my $sql_database = 'postfix';                       # SQL database name
my $sql_user = 'postfixadmin';                      # SQL user
my $sql_password = 'blablablaaa';                   # SQL password

use strict;
use warnings;
use DBI;
use DBD::mysql;

my ($dsn, $dbh, $qh, $mailbox);

$mailbox = $ARGV[0];
if (!defined($mailbox) || ($mailbox eq '')) {
   exit 1
}

$dsn = "dbi:mysql:$sql_database:$sql_host:$sql_port";
$dbh = DBI->connect($dsn, $sql_user, $sql_password)
	or die "failed to connect to database: $DBI::errstr\n";
$qh = $dbh->prepare("DELETE FROM auth WHERE username='$mailbox'");
$qh->execute();

Script pour autoconfiguration avec Thunderbird

Je vous renvoie sur mon article présentant l’autoconfiguration d’un compte sous Thunderbird. L’intérêt du script PHP est de récupérer les paramètres adaptés/autorisés pour l’utilisateur concerné.

<?php
/*
 * autoconf.php
 *
 * Boris HUISGEN <bhuisgen@hbis.fr>
 */

   define("SYSLOG_IDENT", "autoconfig");
   define("SYSLOG_OPTIONS", LOG_PID|LOG_NDELAY);
   define("SYSLOG_LOCAL", LOG_USER);
   define("DB_DSN", "mysql:host=localhost;dbname=postfix");
   define("DB_USER", "autoconfig");
   define("DB_PASSWORD", "blablablaaa");
   define("REGEX_ALLOWNETS", "/^(.*,)?(0::0\/0|0\.0\.0\.0\/0)(,.*)$/");

   // script

   openlog(SYSLOG_IDENT, SYSLOG_OPTIONS, SYSLOG_LOCAL);

   if (getenv("HTTP_CLIENT_IP"))
      $ip = getenv("HTTP_CLIENT_IP");
   else if(getenv("HTTP_X_FORWARDED_FOR"))
      $ip = getenv("HTTP_X_FORWARDED_FOR");
   else if(getenv("REMOTE_ADDR"))
      $ip = getenv("REMOTE_ADDR");
   else $ip = "unknown IP";

   if (!isset($_GET["emailaddress"]))
   {
      syslog(LOG_ERR, "[client=$ip] failed to get email address, aborting execution");
      exit(1);
   }

   $username = $_GET["emailaddress"];
   {
      $c = new PDO(DB_DSN, DB_USER, DB_PASSWORD);
      $c->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

      $s = $c->prepare("SELECT allow_smtp, smtp_nets, allow_pop3, pop3_nets, " .
                          "allow_imap, imap_nets FROM auth WHERE username = ?");
      $s->bindColumn(1, $allow_smtp, PDO::PARAM_INT);
      $s->bindColumn(2, $smtp_nets, PDO::PARAM_STR, 255);
      $s->bindColumn(3, $allow_pop3, PDO::PARAM_INT);
      $s->bindColumn(4, $pop3_nets, PDO::PARAM_STR, 255);
      $s->bindColumn(5, $allow_imap, PDO::PARAM_INT);
      $s->bindColumn(6, $imap_nets, PDO::PARAM_STR, 255);
      $s->bindParam(1, $username);
      $s->execute();
      if ($s->rowCount() != 1)
      {
         syslog(LOG_ERR, "[client=$ip] $username not found");
         exit(3);
      }

      $s->fetch(PDO::FETCH_BOUND);
   }
   catch (PDOException $e)
   {
      syslog(LOG_ERR, "PDO exception, aborting execution");
      exit(2);
   }

   syslog(LOG_NOTICE, "[client=$ip] $username configured");

   header("Content-type: text/xml; charset=utf-8");
?>
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
  <emailProvider id="domaine.fr">
    <domain>domaine.fr</domain>
    <displayName>Test</displayName>
    <displayShortName>Test</displayShortName>
<?php
   if (($allow_imap == 1) &&
       (preg_match(REGEX_ALLOWNETS, $imap_nets) == 1))
   {
?>
    <incomingServer type="imap">
      <hostname>mail.domaine.fr</hostname>
      <port>143</port>
      <socketType>STARTTLS</socketType>
      <username>%EMAILADDRESS%</username>
      <authentication>password-cleartext</authentication>
    </incomingServer>
<?php
   }

   if (($allow_pop3 == 1) &&
       (preg_match(REGEX_ALLOWNETS, $pop3_nets) == 1))
   {
?>
    <incomingServer type="pop3">
      <hostname>mail.domaine.fr</hostname>
      <port>995</port>
      <socketType>SSL</socketType>
      <authentication>password-cleartext</authentication>
      <username>%EMAILADDRESS%</username>
    </incomingServer>
<?php
   }

   if (($allow_smtp == 1) &&
       (preg_match(REGEX_ALLOWNETS, $smtp_nets) == 1))
   {
?>
    <outgoingServer type="smtp">
      <hostname>noreply.domaine.fr</hostname>
      <port>587</port>
      <socketType>STARTTLS</socketType>
      <username>%EMAILADDRESS%</username>
    </outgoingServer>
<?php
   }
?>
  </emailProvider>
</clientConfig>

Postfix : réécriture des entêtes mail

Je présente ici deux méthodes permettant de réécrire les entêtes d’un message électronique.

root@srv# apt-get install postfix-pcre

Avant filtrage externe

root@srv# nano /etc/postfix/main.cf
header_checks = pcre:/etc/postfix/header_checks.cf
root@srv# cat /etc/postfix/header_checks.cf
/^Subject:/ WARN
/^Subject: .*(@domain1|@domain2)\.(com|fr)/ DISCARD

Après filtrage externe

root@srv# nano /etc/postfix/master.cf
127.0.0.1:10025 inet n  -       n       -       -       smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_restriction_classes=
    -o smtpd_client_restrictions=
    -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
    -o strict_rfc821_envelopes=yes
    -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_address_mappings,no_unknown_recipient_checks,no_milters
    -o cleanup_service_name=smtp-cleanup
    -o local_header_rewrite_clients=

smtp-cleanup   unix  n  -       n       -       0       cleanup
    -o header_checks=pcre:/etc/postfix/header_cleanup.cf
root@srv:# cat /etc/postfix/header_cleanup.cf
/^Received: from localhost \(localhost \[127\.0\.0\.1\]\)/ IGNORE
/^Received: (.*) \(Postfix\) (.*)/ REPLACE Received: ${1} ${2}
/^X-Originating-IP:/ IGNORE

Swaks : le couteau suisse SMTP

Site web : http://www.jetmore.org/john/code/swaks/

Exemple de test en TLS :

boris.huisgen@vm-test:~$ swaks --server mail.hbis.fr --tls --from postmaster@hbis.fr --to postmaster@hbis.fr
=== Trying mail.hbis.fr:25...
=== Connected to mail.hbis.fr.
<-  220 mail.hbis.fr ESMTP
 -> EHLO vks10205.ip-37-59-126.eu
<-  250-mail.hbis.fr
<-  250-PIPELINING
<-  250-SIZE 20480000
<-  250-VRFY
<-  250-ETRN
<-  250-STARTTLS
<-  250-AUTH PLAIN
<-  250-ENHANCEDSTATUSCODES
<-  250-8BITMIME
<-  250 DSN
 -> STARTTLS
<-  220 2.0.0 Ready to start TLS
=== TLS started w/ cipher ECDHE-RSA-AES256-GCM-SHA384
=== TLS peer subject DN="/CN=www.hbis.fr"
 ~> EHLO vks10205.ip-37-59-126.eu
<~  250-mail.hbis.fr
<~  250-PIPELINING
<~  250-SIZE 20480000
<~  250-VRFY
<~  250-ETRN
<~  250-AUTH PLAIN
<~  250-ENHANCEDSTATUSCODES
<~  250-8BITMIME
<~  250 DSN
 ~> MAIL FROM:<postmaster@hbis.fr>
<~  250 2.1.0 Ok
 ~> RCPT TO:<postmaster@hbis.fr>
<~  250 2.1.5 Ok
 ~> DATA
<~  354 End data with <CR><LF>.<CR><LF>
 ~> Date: Fri, 24 May 2013 23:47:06 +0200
 ~> To: postmaster@hbis.fr
 ~> From: postmaster@hbis.fr
 ~> Subject: test Fri, 24 May 2013 23:47:06 +0200
 ~> X-Mailer: swaks v20120320.0 jetmore.org/john/code/swaks/
 ~>
 ~> This is a test mailing
 ~>
 ~> .
<~  250 2.0.0 Ok: queued as D9EE73B6004B
 ~> QUIT
<~  221 2.0.0 Bye
=== Connection closed with remote host.

Amavis : mise en place du support DKIM

Amavis intègre depuis la version 2.6 le support DKIM ce qui évite de faire appel à un filtre/logiciel externe. Je présente ici l’activation du support pour le domaine domaine.fr.

Génération des clés DKIM

root@mail# mkdir -p /etc/amavis/dkim/domaine.fr
root@mail# cd /etc/amavis/dkim/domaine.fr
root@mail# amavisd-new genrsa domaine.fr.key

Configuration d’Amavis

root@mail# nano /etc/amavis/conf.d/52-dkim
use strict;

$enable_dkim_verification = 0;
$enable_dkim_signing = 0;

dkim_key('domaine.fr', 'default', '/etc/amavis/dkim/domaine.fr/key.pem');

@dkim_signature_options_bysender_maps = (
  { '.' => { ttl => 21*24*3600, c => 'relaxed/simple' } }
);

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

La clé publique DKIM peut enfin être affichée et déclarée dans la zone DNS :

root@mail:/etc/amavis/conf.d# amavisd-new showkeys
; key#1, domain domaine.fr, /etc/amavis/dkim/domaine.fr/key.pem
default._domainkey.domaine.fr.	3600 TXT (
  "v=DKIM1; p="
  "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCr9GYVLvcBqDhE1+GidlfLf8u1"
  "DURlfC8r8on1nr6cWM3r2H3yEPGQwsctVEQWtKRIEonBR+cUZNJWizeE1UslqL32"
  "YnppNcZJq7BMzFJO+uAYU7nLC1ZWueGKDUr7IgYmmW2TDJWpt7DgBMkD2Y/d6qOc"
  "7oOVkQMdIduxPsI6kQIDAQAB")
root@mail:/etc/amavis/conf.d# amavisd-new testkeys
TESTING#1: default._domainkey.domaine.fr      => pass

Le test étant validé, la vérification et la signature DKIM peuvent être activés :

root@mail# nano /etc/amavis/conf.d/52-dkim
$enable_dkim_verification = 1;
$enable_dkim_signing = 1;
Haut de page