Page suivantePage pr�c�denteTable des mati�res

9. Mail virtuel avec Pop

9.1 Probl�me

Le support du mail virtuel est une demande toujours grandissante. Sendmail affirme qu'il supporte le mail virtuel. En fait, il se contente d'�tre � l'�coute de mail pour diff�rents domaines. Vous pouvez alors demander � faire suivre le mail quelque part. Cependant, si vous le faites suivre sur la machine locale et que vous avez du mail pour bob@domaine1.com et bob@domaine2.com, ils vont atteindre la m�me bo�te. C'est un probl�me puisque les bob sont deux personnes diff�rentes, avec du courrier �lectronique diff�rent.

9.2 Solution

Vous pouvez vous assurer que chaque nom d'utilisateur est unique en utilisant une num�rotation des noms d'utilisateurs : bob1, bob2, etc... Vous pourriez �galement hacker le mail et le pop pour que ces conversions soient invisibles, mais cela peut devenir d�sordonn�. Le mail sortant � pour domaine domaineprincipal.com et vous d�sirez que chaque mail envoy� dans chaque sous-domaine ait une adresse From: diff�rente.

J'ai deux solutions. L'une fonctionne avec sendmail et l'autre avec Qmail. La solution avec sendmail devrait fonctionner avec une installation standard de sendmail. Cependant elle partage toutes les limitations �tablies dans sendmail. Il est n�cessaire aussi qu'un sendmail ait �t� lanc� en mode de file d'attente (queue mode) pour chaque domaine. Avoir 50 ou plus processus sendmail en mode de file d'attente qui se r�veillent toutes les heures peut ajouter des contraintes sur une machine.

La solution pour Qmail ne requiert pas plusieurs exemplaires de Qmail et peut n'utiliser qu'un seul r�pertoire de file d'attente. Il a besoin d'un autre programme puisque que Qmail ne se fonde pas sur virtuald. Je crois qu'une proc�dure similaire peut �tre faite avec Sendmail. Cependant, Qmail se pr�te plus ais�ment � cette solution.

Je ne cautionne aucun des deux programmes en particulier. L'installation de Sendmail est un peu moins complexe mais Qmail est pobablement le plus puissant des deux paquetages de serveur Mail.

9.3 Solution pour Sendmail

Introduction

Chaque syst�me de fichiers virtuel fournit � chaque domaine un fichier /etc/passwd. Cela signifie que bob@domaine1.com et bob@domaine2.com sont des utilisateurs diff�rents dans des fichiers /etc/passwd diff�rents, donc le mail ne constituera aucun probl�me. Ils poss�dent �galement chacun un spool de mail, donc les bo�tes aux lettres seront des fichiers diff�rents sur des syst�me de fichiers virtuels diff�rents.

Cr�er un fichier de configuration Sendmail

Cr�ez /etc/sendmail.cf comme vous le feriez d'habitude avec m4 :

divert(0)
VERSIONID(`tcpproto.mc')
OSTYPE(linux)
FEATURE(redirect)
FEATURE(always_add_domain)
FEATURE(use_cw_file)
FEATURE(local_procmail)
MAILER(local)
MAILER(smtp)

�dition du fichier de configuration

�ditez /virtual/domain1.com/etc/sendmail.cf pour l'adapter � votre domaine virtuel :

vi /virtual/domain1.com/etc/sendmail.cf
Approximativement � la ligne 86 il doit y avoir :
#Dj$w.Foo.COM
Remplacez-le avec :
Djdomain1.com

Distribution locale par Sendmail

�ditez /virtual/domain1.com/etc/sendmail.cw

vi /virtual/domain1.com/etc/sendmail.cw
mail.domain1.com
domain1.com
domain1
localhost

Sendmail et les domaines virtuels : la bidouille (pre8.8.6)

Cependant, sendmail n�cessite un changement mineur de son code source. Sendmail utilise un fichier nomm� /etc/sendmail.cw qui contient tous les noms de machine pour lequel il distribuera le mail localement au lieu de le faire suivre � une autre machine. Sendmail fait une v�rification interne de toutes les interfaces r�seau de la machine pour initialiser cette liste avec les adresses IP locales. Cela pr�sente un probl�me si vous envoyez des mails entre deux domaines virtuels de la m�me machine. Sendmail pensera que l'autre domaine virtuel est une adresse locale et il distribuera le mail localement. Par exemple, bob@domaine1.com envoie un mail � fred@domaine2.com. Puisque le sendmail de domaine1.com pense que domaine2.com est une adresse locale, il va envoyer ce mail � domaine1.com et ne l'enverra jamais � domaine2.com. Vous avez � modifier sendmail (ce que j'ai fait sans probl�me sur la version 8.8.6) :

vi v8.8.5/src/main.c
Vers la ligne 494 vous devriez remplacer la ligne :
load_if_names();
Par :
/* load_if_names(); Comment� puisque cela casse les domaines virtuels */

Notez que cette modification n'est n�cessaire que si vous d�sirez envoyer du mail entre des domaines virtuels, ce qui est probable, je pense.

Cela corrigera le probl�me. Cependant, l'adaptateur r�seau principal eth0 n'est pas supprim�. Ainsi, si vous envoyez un mail depuis une adresse IP virtuelle vers une adresse sur eth0 de la m�me machine, il sera d�livr� localement. Pour cela, j'utilise une adresse IP bidon virtuel1.domaine.com (10.10.10.157). Je n'envoie jamais de mail � cet h�te, les domaines virtuels non plus. C'est aussi l'adresse IP que j'utiliserai pour me connecter sur la machine via ssh, pour v�rifier si le syst�me fonctionne.

Sendmail et les domaines virtuels : Nouvelle fonction (POST8.8.6)

Depuis la version 8.8.6 de Sendmail, il existe une option qui d�sactive le chargement des interfaces r�seaux suppl�mentaires. Ce qui implique la NON n�c�ssit� de toucher au code source. Elle s'appelle DontProbeInterfaces .

Editer /virtual/domain1.com/etc/sendmail.cf

vi /virtual/domain1.com/etc/sendmail.cf
Ajouter la ligne :
O DontProbeInterfaces=True

Sendmail.init

Sendmail ne peut pas �tre lanc� tel quel, vous allez devoir le lancer � travers inetd. C'est un moyen inefficace qui implique un temps de r�ponse plus long, mais si vous avez un site tellement occup� pour que la diff�rence soit importante, alors vous devriez utiliser une machine d�di�e � ce site. Notez que vous ne de devez PAS utiliser l'option -bd. Notez �galement que vous devez lancer sendmail -q pour chaque domaine que vous g�rez. Le nouveau fichier sendmail.init est le suivant :

#!/bin/sh
# Source function library.
. /etc/rc.d/init.d/functions
case "$1" in
 start)
 echo -n "Starting sendmail: "
 daemon sendmail -q1h
 echo
 echo -n "Starting virtual sendmail: "
 for i in /virtual/*
 do
 if [ ! -d "$i" ]
 then
 continue
 fi
 if [ "$i" = "/virtual/lost+found" ]
 then
 continue
 fi
 chroot $i sendmail -q1h
 echo -n "."
 done
 echo " done"
 touch /var/lock/subsys/sendmail
 ;;
 stop)
 echo -n "Stopping sendmail: "
 killproc sendmail
 echo
 rm -f /var/lock/subsys/sendmail
 ;;
 *)
 echo "Usage: sendmail {start|stop}"
 exit 1
esac
exit 0

Configuration d'inetd

Pop devrait s'installer normalement, sans effort suppl�mentaire. Vous n'avez qu'� modifier l'entr�e pour pop dans le fichier inetd.conf pour utiliser le d�mon virtuald. Pour sendmail et pop, cela donne :

pop-3 stream tcp nowait root /usr/bin/virtuald \
 virtuald /virtual/conf.pop in.qpop -s
smtp stream tcp nowait root /usr/bin/virtuald \
 virtuald /virtual/conf.mail sendmail -bs

9.4 Solution pour Qmail

Introduction

Cette solution prend la responsabilit� de distribution du qmail-local, donc l'utilisation des fichiers .qmail dans les r�pertoire home des domaines virtuels ne marcheront pas. Cependant, chaque domaine aura toujours un utilisateur ma�tre par domaine qui contr�lera les aliasing du domaine. Deux programmes externes seront utilis�s pour le fichier .qmail-default des ma�tres de domaine. Le mail passera par ces deux programmes afin de distribuer le courrier � chaque domaine.

Deux programmes sont nec�ssaires, car l'un deux est lanc� avec le setuid root. C'est un petit programme qui se change en un utilisateur non administrateur et lance le second programme. Consultez le site le plus proche relatif � la s�curit� pour une discussion sur le pourquoi est-ce n�cessaire.

Cette solution se passe de virtuald. Qmail est assez flexible pour ne pas avoir besoin d'une configuration virtuald g�nerale. La conception de Qmail utilise l'encha�nement de programmes pour distribuer les mails. Cette conception facilite l'insertion d'une section virtuelle dans le processus de distribution de Qmail sans alt�rer une installation standard de Qmail.

Depuis que vous utilisez Qmail, tout nom de domaine non qualifi� sera d�velopp� en utilisant le serveur principal. C'est d� au fait que vous n'avez pas un Qmail pour chaque domaine. Donc, soyez s�r que vos clients (Eudora, elm, mutt, etc.) puissent developper tous vos noms de domaines non qualifi�s.

Installation des domaines virtuels

Qmail doit �tre configur� de mani�re � accepter les mails pour chaque domaine que vous d�sservez. Tapez la commande suivante :

echo "domain1.com:domain1" >> /var/qmail/control/virtualdomains

Installation de l'utilisateur ma�tre du domaine

Ajouter � votre fichier /etc/passwd principal l'utilisateur domain1. Je choisirais le shell /bin/false pour que le ma�tre du domaine ne puisse se connecter. Cet utilisateur sera capable d'ajouter des fichier .qmail et tous les mails passeront par ce compte. Notez que les noms d'utilisateurs ne peuvent faire que 8 caract�res et les noms de domaines peuvent �tre plus long. Les caract�res restants seront ignor�s. Ce qui implique, que les utilisateurs domain12 et domain123 seraient le m�me utilisateur et Qmail pourra �tre perturb�. Donc, attention � votre convention pour nommer les utilisateurs ma�tres des domaines.

Cr�er les fichiers .qmail du ma�tre de domaine avec les commandes suivantes. Ajoutez les autres alias syst�me au m�me endroit. Par exemple, webmaster ou hostmaster.

echo "user@domain1.com" > /home/d/domain1/.qmail-mail-daemon
echo "user@domain1.com" > /home/d/domain1/.qmail-postmaster
echo "user@domain1.com" > /home/d/domain1/.qmail-root

Cr�ez le fichier .qmail-default du ma�tre de domaine. Il filtre tous les mails du domaine virtuel.

echo "| /usr/local/bin/virtmailfilter" > /home/d/domain1/.qmail-default

Tcpserver

Qmail a besoin d'un pop sp�cial qui supporte le format maildir. Le programme pop doit �tre rendu virtuel. L'auteur de Qmail recommande d'utiliser tcpserver (un remplacement � inetd) avec Qmail, donc mes exemples utilisent tcpserver et NON inetd.

Tcpserver n'a pas besoin de fichier de configuration. Toutes les informations peuvent etre pass�es par une ligne de commande. Ci-dessous, se trouve le fichier tcpserver.ini que vous devez utiliser pour le d�mon mail et le serveur pop :

#!/bin/sh
. /etc/rc.d/init.d/functions
QMAILDUSER=`grep qmaild /etc/passwd | cut -d: -f3`
QMAILDGROUP=`grep qmaild /etc/passwd | cut -d: -f4`
# Regarder comment nous �tions appell�s.
case "$1" in
 start)
 echo -n "Starting tcpserver: "
 tcpserver -u 0 -g 0 0 pop-3 /usr/local/bin/virtuald \
 /virtual/conf.pop qmail-popup virt.domain1.com \
 /bin/checkpassword /bin/qmail-pop3d Maildir &
 echo -n "pop "
 tcpserver -u $QMAILDUSER -g $QMAILDGROUP 0 smtp \
 /var/qmail/bin/qmail-smtpd &
 echo -n "qmail "
 echo
 touch /var/lock/subsys/tcpserver
 ;;
 stop)
 echo -n "Stopping tcpserver: "
 killall -TERM tcpserver
 echo -n "killing "
 echo
 rm -f /var/lock/subsys/tcpserver
 ;;
 *)
 echo "Usage: tcpserver {start|stop}"
 exit 1
esac
exit 0

Qmail.init

Vous pouvez utiliser le script standard de Qmail.init fourni. Qmail est livr� avec une tr�s bonne documentation d�crivant comment le mettre en place.

Source

Vous avez besoin de deux autres programmes pour que votre serveur mail virtuel fonctionne avec Qmail. Ce sont virtmailfilter et virtmaildelivery. Ceci est le code source en C de virtmailfilter. Il doit �tre install� dans /usr/local/bin avec les permissions 4750, l'utilisateur root et le groupe nofiles.

#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <pwd.h>
#define VIRTPRE                 "/virtual"
#define VIRTPWFILE              "etc/passwd"
#define VIRTDELIVERY            "/usr/local/bin/virtmaildelivery"
#define VIRTDELIVERY0           "virtmaildelivery"
#define PERM                    100
#define TEMP                    111
#define BUFSIZE                 8192
int main(int argc,char **argv)
{
 char *username,*usernameptr,*domain,*domainptr,*homedir;
 char virtpath[BUFSIZE];
 struct passwd *p;
 FILE *fppw;
 int status;
 gid_t gid;
 pid_t pid;
 if (!(username=getenv("EXT")))
 {
 fprintf(stdout,"environment variable EXT not set\n");
 exit(TEMP);
 }
 for(usernameptr=username;*usernameptr;usernameptr++)
 {
 *usernameptr=tolower(*usernameptr);
 }
 if (!(domain=getenv("HOST")))
 {
 fprintf(stdout,"environment variable HOST not set\n");
 exit(TEMP);
 }
 for(domainptr=domain;*domainptr;domainptr++)
 {
 if (*domainptr=='.' && *(domainptr+1)=='.')
 {
 fprintf(stdout,"environment variable HOST has ..\n");
 exit(TEMP);
 }
 if (*domainptr=='/')
 {
 fprintf(stdout,"environment variable HOST has /\n");
 exit(TEMP);
 }
 *domainptr=tolower(*domainptr);
 }
 for(domainptr=domain;;)
 {
 snprintf(virtpath,BUFSIZE,"%s/%s",VIRTPRE,domainptr);
 if (chdir(virtpath)>=0)
 break;
 if (!(domainptr=strchr(domainptr,'.')))
 {
 fprintf(stdout,"domain failed: %s\n",domain);
 exit(TEMP);
 }
 domainptr++;
 }
 if (!(fppw=fopen(VIRTPWFILE,"r+")))
 {
 fprintf(stdout,"fopen failed: %s\n",VIRTPWFILE);
 exit(TEMP);
 }
 while((p=fgetpwent(fppw))!=NULL)
 {
 if (!strcmp(p->pw_name,username))
 break;
 }
 if (!p)
 {
 fprintf(stdout,"user %s: not exist\n",username);
 exit(PERM);
 }
 if (fclose(fppw)==EOF)
 {
 fprintf(stdout,"fclose failed\n");
 exit(TEMP);
 }
 gid=p->pw_gid;
 homedir=p->pw_dir;
 if (setgid(gid)<0 || setuid(p->pw_uid)<0)
 {
 fprintf(stdout,"setuid/setgid failed\n");
 exit(TEMP);
 }
 switch(pid=fork())
 {
 case -1:
 fprintf(stdout,"fork failed\n");
 exit(TEMP);
 case 0:
 if (execl(VIRTDELIVERY,VIRTDELIVERY0,username,homedir,NU                        {
 fprintf(stdout,"execl failed\n");
 exit(TEMP);
 }
 default:
 if (wait(&status)<0)
 {
 fprintf(stdout,"wait failed\n");
 exit(TEMP);
 }
 if (!WIFEXITED(status))
 {
 fprintf(stdout,"child did not exit normally\n");                        }
 break;
 }
 exit(WEXITSTATUS(status));
}

Source

Ceci est le code source de virtmaildelivery. Il doit etre install� dans /usr/local/bin avec les permissions 0755, l'utilisateur root et le groupe root.

#include <sys/stat.h>
#include <sys/file.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#define TEMP                    111
#define BUFSIZE                 8192
#define ATTEMPTS                10
int main(int argc,char **argv)
{
 char *user,*homedir,*dtline,*rpline,buffer[BUFSIZE],*p,mail[BUFSIZE];
 char maildir[BUFSIZE],newmaildir[BUFSIZE],host[BUFSIZE];
 int fd,n,nl,i,retval;
 struct stat statp;
 time_t thetime;
 pid_t pid;
 FILE *fp;
 retval=0;
 if (!argv[1])
 {
 fprintf(stdout,"invalid arguments: need username\n");
 exit(TEMP);
 }
 user=argv[1];
 if (!argv[2])
 {
 fprintf(stdout,"invalid arguments: need home directory\n");
 exit(TEMP);
 }
 homedir=argv[2];
 if (!(dtline=getenv("DTLINE")))
 {
 fprintf(stdout,"environment variable DTLINE not set\n");
 exit(TEMP);
 }
 if (!(rpline=getenv("RPLINE")))
 {
 fprintf(stdout,"environment variable RPLINE not set\n");
 exit(TEMP);
 }
 while (*homedir=='/')
 homedir++;
 snprintf(maildir,BUFSIZE,"%s/Maildir",homedir);
 if (chdir(maildir)<0)
 {
 fprintf(stdout,"chdir failed: %s\n",maildir);
 exit(TEMP);
 }
 time(&thetime);
 pid=getpid();
 if (gethostname(host,BUFSIZE)<0)
 {
 fprintf(stdout,"gethostname failed\n");
 exit(TEMP);
 }
 for(i=0;i<ATTEMPTS;i++)
 {
 snprintf(mail,BUFSIZE,"tmp/%u.%d.%s",thetime,pid,host);
 errno=0;
 stat(mail,&statp);
 if (errno==ENOENT)
 break;
 sleep(2);
 time(&thetime);
 }
 if (i>=ATTEMPTS)
 {
 fprintf(stdout,"could not create %s\n",mail);
 exit(TEMP);
 }
 if (!(fp=fopen(mail,"w+")))
 {
 fprintf(stdout,"fopen failed: %s\n",mail);
 retval=TEMP; goto unlinkit;
 }
 fd=fileno(fp);
 if (fprintf(fp,"%s",rpline)<0)
 {
 fprintf(stdout,"fprintf failed\n");
 retval=TEMP; goto unlinkit;
 }
 if (fprintf(fp,"%s",dtline)<0)
 {
 fprintf(stdout,"fprintf failed\n");
 retval=TEMP; goto unlinkit;
 }
 while(fgets(buffer,BUFSIZE,stdin))
 {
 for(p=buffer;*p=='>';p++)
 ;
 if (!strncmp(p,"From ",5))
 {
 if (fputc('>',fp)<0)
 {
 fprintf(stdout,"fputc failed\n");
 retval=TEMP; goto unlinkit;
 }
 }
 if (fprintf(fp,"%s",buffer)<0)
 {
 fprintf(stdout,"fprintf failed\n");
 retval=TEMP; goto unlinkit;
 }
 }
 p=buffer+strlen(buffer);
 nl=2;
 if (*p=='\n')
 nl=1;
 for(n=0;n<nl;n++)
 {
 if (fputc('\n',fp)<0)
 {
 fprintf(stdout,"fputc failed\n");
 retval=TEMP; goto unlinkit;
 }
 }
 if (fsync(fd)<0)
 {
 fprintf(stdout,"fsync failed\n");
 retval=TEMP; goto unlinkit;
 }
 if (fclose(fp)==EOF)
 {
 fprintf(stdout,"fclose failed\n");
 retval=TEMP; goto unlinkit;
 }
 snprintf(newmaildir,BUFSIZE,"new/%u.%d.%s",thetime,pid,host);
 if (link(mail,newmaildir)<0)
 {
 fprintf(stdout,"link failed: %s %s\n",mail,newmaildir);
 retval=TEMP; goto unlinkit;
 }
unlinkit:
 if (unlink(mail)<0)
 {
 fprintf(stdout,"unlink failed: %s\n",mail);
 retval=TEMP;
 }
 exit(retval);
}

9.5 Remerciements

Merci � Vicente Gonzalez (vince@nycrc.net) pour son aide qui a rendu possible la solution pour Qmail. Vous pouvez certainement �crire a Vince, pour le remercier, ainsi que lui poser vos questions et commentaires a propos de Qmail, le reste concernant ce HOWTO devant m'�tre adress�.


Page suivantePage pr�c�denteTable des mati�res

Hosting by: Hurra Communications GmbH
Generated: 2007-01-26 18:01:22