Base de conocimiento

Creado por eth0
2011-04-25
22:29:59

Categorías
Etiquetas

Montar un servidor de correo con Postfix, Dovecot y DSPAM

Notas preliminares

Sistema Operativo: Debian estable.

Servicios:

Proceso de instalación

MySQL

Vamos a utilizar la siguiente estructura de base de datos:

  1. CREATE TABLE `aliases` (
  2.     `pkid` smallint(3) NOT NULL auto_increment,
  3.     `mail` varchar(120) NOT NULL default '',
  4.     `destination` text NOT NULL default '',
  5.     `enabled` tinyint(1) NOT NULL default '1',
  6.     PRIMARY KEY  (`pkid`),
  7.     UNIQUE KEY `mail` (`mail`)
  8. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  9.  
  10. CREATE TABLE `domains` (
  11.     `pkid` smallint(6) NOT NULL auto_increment,
  12.     `domain` varchar(120) NOT NULL default '',
  13.     `transport` varchar(120) NOT NULL default 'virtual:',
  14.     `enabled` tinyint(1) NOT NULL default '1',
  15.     PRIMARY KEY  (`pkid`)
  16. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  17.  
  18. CREATE TABLE `users` (
  19.     `id` varchar(128) NOT NULL default '',
  20.     `id2` varchar(128) default NULL,
  21.     `name` varchar(128) NOT NULL default '',
  22.     `uid` smallint(5) unsigned NOT NULL default '5000',
  23.     `gid` smallint(5) unsigned NOT NULL default '5000',
  24.     `home` varchar(255) NOT NULL default '/home/mail',
  25.     `maildir` varchar(255) NOT NULL default '',
  26.     `enabled` tinyint(1) unsigned NOT NULL default '1',
  27.     `change_password` tinyint(1) unsigned NOT NULL default '1',
  28.     `clear` varchar(128) NOT NULL default 'ChangeMe',
  29.     `crypt` varchar(64) NOT NULL default 'MD5(\'ChangeMe\')',
  30.     `quota` int(10) NOT NULL default 10485760,
  31.     `procmailrc` varchar(128) NOT NULL default '',
  32.     `spamassassinrc` varchar(128) NOT NULL default '',
  33.     `domain` char(200) default NULL,
  34.     PRIMARY KEY  (`id`),
  35.     KEY `id` (`id2`)
  36. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Para crear una cuenta de correo nueva es necesario realizar los siguientes pasos:

Dovecot

Instalamos el servidor:

$ apt-get install dovecot-imapd dovecot-pop3d

Editamos el fichero /etc/dovecot/dovecot.conf:

protocols = imap pop3
listen = *
disable_plaintext_auth = no
login_greeting_capability = yes
log_path = /var/log/mail.log
info_log_path = /var/log/mail.info
log_timestamp = "%Y-%m-%d %H:%M:%S "

# Esta opción especifica el lugar donde se encuentra
# el directorio de correo del usuario. Está establecido
# de forma que la ruta del maildir del usuario se obtiene
# en la consulta SQL, en el campo userdb_home.
mail_location = maildir:%h

mail_extra_groups = mail
protocol imap {
    # Activamos esta opción para solucionar problemas con
    # Outlook Express.
    imap_client_workarounds = outlook-idle
    mail_plugins = quota imap_quota
}
protocol pop3 {
    pop3_uidl_format = %08Xu%08Xv
    # Activamos esta opción para solucionar problemas con
    # Outlook Express.
    pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
    mail_plugins = quota
}
auth default {
    mechanisms = plain login digest-md5 cram-md5
    passdb sql {
        args = /etc/dovecot/dovecot-sql.conf
    }
    # Activando esta opción sólo es necesaria una consulta
    # SQL para autentificar al usuario y obtener los datos
    # del mismo.
    userdb prefetch {
    }
    user = root
    # Esta opción abre un socket que Postfix utilizará para
    # la autentificación SMTP.
    socket listen {
        master {
            path = /var/spool/postfix/private/auth-master
            mode = 0600
            user = postfix
            group = postfix
        }
        client {
            path = /var/spool/postfix/private/auth-client
            mode = 0660
            user = postfix
            group = postfix
        }
    }
}
dict {
}
plugin {
}

Editamos el fichero /etc/dovecot/dovecot-sql.conf:

driver = mysql
connect = dbname=maildb host=localhost user=usermail password=passwordmail
# Esta opción especifica qué tipo de huella contiene el campo crypt.
# En nuestro caso es el valor del campo clear pasado a la función MD5().
default_pass_scheme = PLAIN-MD5
password_query = SELECT id AS user, crypt AS password,
    CONCAT(home, '/', maildir) AS userdb_home, uid AS userdb_uid,
    gid AS userdb_gid, CONCAT('maildir:storage=', FLOOR(quota / 1024)) AS userdb_quota
    FROM users WHERE id = '%u' OR id2 = '%u'

Nos aseguramos de que los campos uid y gid de la tabla de usuarios coinciden con el usuario y grupo propietarios de los directorios del correo. Dovecot se cambiará a ese usuario y grupo cuando tenga que acceder al maildir de ese usuario.

Por último, reiniciamos Dovecot:

$ invoke-rc.d dovecot restart

Postfix

Instalamos el servidor, aplicándole de paso el parche para cuotas:

$ apt-get install build-essential dpkg-dev fakeroot debhelper
$ apt-get build-dep postfix
$ cd /usr/src
$ apt-get source postfix
$ wget http://vda.sourceforge.net/VDA/postfix-2.3.8-vda.patch.gz
$ gunzip postfix-2.3.8-vda.patch.gz
$ patch -p0 < postfix-2.3.8-vda.patch
$ cd postfix-2.3.8
$ dpkg-buildpackage
$ cd ..
$ dpkg -i postfix_2.3.8-2_i386.deb
$ dpkg -i postfix-mysql_2.3.8-2_i386.deb
$ dpkg -i postfix-pcre_2.3.8-2_i386.deb

Editamos el fichero /etc/postfix/main.cf:

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
myhostname = example.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = localhost
mynetworks = 127.0.0.0/8, 192.168.0.0/16, 172.16.138.0/24
mailbox_command =
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = no
smtpd_recipient_restrictions =
    reject_unauth_pipelining,
    reject_non_fqdn_recipient,
    reject_unknown_recipient_domain,
    permit_mynetworks,
    permit_sasl_authenticated,
    reject_unauth_destination,
    warn_if_reject,
    reject_non_fqdn_sender,
    reject_invalid_hostname,
    reject_rbl_client list.dsbl.org,
    reject_rbl_client sbl-xbl.spamhaus.org,
    permit

# Estas dos opciones configuran Postfix de forma que la
# autentificación se realiza a través del Dovecot, mediante
# el socket que éste crea.
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth-client

home_mailbox = Maildir/
disable_dns_lookups = no
delay_warning_time = 4h
unknown_local_recipient_reject_code = 450

# Opciones para la conexión con MySQL
virtual_mailbox_base = /mail
virtual_mailbox_maps = mysql:/etc/postfix/mysql_mailbox.cf
virtual_mailbox_limit_maps = mysql:/etc/postfix/mysql_quotas.cf
virtual_mailbox_limit_override = yes
virtual_mailbox_limit_inbox = yes
virtual_maildir_extended = yes
virtual_create_maildirsize = yes
virtual_maildir_limit_message = "La cuenta del destinatario está llena."
virtual_overquota_bounce = yes
virtual_uid_maps = mysql:/etc/postfix/mysql_uid.cf
virtual_gid_maps = mysql:/etc/postfix/mysql_gid.cf
virtual_alias_maps = mysql:/etc/postfix/mysql_alias.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql_domains.cf

Editamos los ficheros de configuración para conectar Postfix con MySQL:

# /etc/postfix/mysql_alias.cf
hosts=127.0.0.1
user=usermail
password=passwordmail
dbname=maildb
query=SELECT destination FROM aliases WHERE mail='%s' AND enabled='1'

# /etc/postfix/mysql_domains.cf
hosts=127.0.0.1
user=usermail
password=passwordmail
dbname=maildb
query=SELECT domain FROM domains WHERE domain='%s' AND enabled='1'

# /etc/postfix/mysql_gid.cf
hosts=127.0.0.1
user=usermail
password=passwordmail
dbname=maildb
query=SELECT gid FROM users WHERE id='%s' OR id2='%s'

# /etc/postfix/mysql_mailbox.cf
hosts=127.0.0.1
user=usermail
password=passwordmail
dbname=maildb
query=SELECT maildir FROM users WHERE id='%s' OR id2='%s'

# /etc/postfix/mysql_uid.cf
hosts=127.0.0.1
user=usermail
password=passwordmail
dbname=maildb
query=SELECT uid FROM users WHERE id='%s' OR id2='%s'

# /etc/postfix/mysql_quotas.cf
hosts=127.0.0.1
user=usermail
password=passwordmail
dbname=maildb
query=SELECT quotas FROM users WHERE id='%s' OR id2='%s'

Por último, reiniciamos Postfix:

$ invoke-rc.d postfix restart

DSPAM

La distribución estable de Debian no tiene los paquetes de DSPAM, sino que deben instalarse desde los backports. En el siguiente enlace se dan instrucciones para agregar los backports al gestor de paquetes:

http://backports-master.debian.org/Instructions/

Instalamos los paquetes necesarios:

$ apt-get install dspam libdspam7-drv-mysql postfix-pcre

Editar el fichero /etc/dspam/dspam.conf:

Home /var/spool/dspam
StorageDriver /usr/lib/dspam/libmysql_drv.so
DeliveryHost 127.0.0.1
DeliveryPort 10026
DeliveryIdent localhost
DeliveryProto SMTP
OnFail error
Trust root
Trust dspam
Trust mail
Trust postfix
Trust www
#Debug *
TrainingMode teft
TestConditionalTraining on
Feature chained
Feature whitelist
Algorithm graham burton
PValue graham
Preference "spamAction=tag"
Preference "signatureLocation=headers"  # 'message' or 'headers'
Preference "showFactors=on"
Preference "spamSubject=[SPAM]"
AllowOverride trainingMode
AllowOverride spamAction spamSubject
AllowOverride statisticalSedation
AllowOverride enableBNR
AllowOverride enableWhitelist
AllowOverride signatureLocation
AllowOverride showFactors
AllowOverride optIn optOut
AllowOverride whitelistThreshold
Notifications   off
PurgeSignatures 14          # Stale signatures
PurgeNeutral    90          # Tokens with neutralish probabilities
PurgeUnused     90          # Unused tokens
PurgeHapaxes    30          # Tokens with less than 5 hits (hapaxes)
PurgeHits1S     15          # Tokens with only 1 spam hit
PurgeHits1I     15          # Tokens with only 1 innocent hit
LocalMX 127.0.0.1
SystemLog on
UserLog   on
#Opt in
ProcessorBias on
ParseToHeaders on
ChangeModeOnParse on
ChangeUserOnParse full
ServerPID /var/run/dspam.pid
ServerParameters "--deliver=innocent,spam"
ServerIdent "localhost"
Include /etc/dspam/dspam.d/

Editar el fichero /etc/dspam/dspam.d/mysql.conf:

MySQLServer       127.0.0.1
MySQLUser         libdspam7-drv-my
MySQLPass         password-de-mysql
MySQLDb           libdspam7drvmysql

Editar el fichero /etc/dspam/default.prefs:

trainingMode=TEFT
spamAction=tag
spamSubject=[SPAM]
enableBNR=on
enableWhitelist=on
statisticalSedation=5
signatureLocation=message
whitelistThreshold=10
showFactors=on

Agregar las siguientes líneas al fichero /etc/postfix/master.cf:

  1. dspam    unix  -   n   n   -   10  pipe  
  2.    flags=Ru user=dspam argv=/usr/bin/dspam --deliver=innocent,spam --user ${recipient} -i -f $sender -- $recipient  
  3.  
  4. localhost:10026 inet n -   n   -   -   smtpd  
  5.    -o content_filter=  
  6.    -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks  
  7.    -o smtpd_helo_restrictions=  
  8.    -o smtpd_client_restrictions=  
  9.    -o smtpd_sender_restrictions=  
  10.    -o smtpd_recipient_restrictions=permit_mynetworks,reject  
  11.    -o mynetworks=127.0.0.0/8  
  12.    -o smtpd_authorized_xforward_hosts=127.0.0.0/8

Crear el fichero /etc/postfix/dspam_client_access:

/./ FILTER dspam:dspam

Ejecutar la siguiente orden para generar el filtro:

$ postmap /etc/postfix/dspam_client_access

Aplicar el siguiente parche al fichero /etc/postfix/main.cf:

  1. --- main.cf.pre-dspam   2007-12-12 13:10:18.000000000 +0100
  2. +++ main.cf     2007-12-12 13:10:00.000000000 +0100
  3. @@ -26,7 +26,7 @@
  4.     reject_invalid_hostname,
  5.     reject_rbl_client list.dsbl.org,
  6.     reject_rbl_client sbl-xbl.spamhaus.org,
  7. -   permit
  8. +   check_client_access pcre:/etc/postfix/dspam_client_access
  9.  
  10. # Estas dos opciones configuran Postfix de forma que la
  11. # autentificación se realiza a través del Dovecot, mediante
  12. @@ -46,3 +46,4 @@
  13. virtual_gid_maps = mysql:/etc/postfix/mysql_gid.cf
  14. virtual_alias_maps = mysql:/etc/postfix/mysql_alias.cf
  15. virtual_mailbox_domains = mysql:/etc/postfix/mysql_domains.cf
  16. +dspam_destination_recipient_limit = 1

Lo siguiente es entrenar a DSPAM. Para ello vamos a utilizar ficheros de corpus que pasaremos por el DSPAM para que los aprenda.

Lo primero que debemos hacer es crear un grupo global en el DSPAM, de forma que enviemos a ese grupo todos los mensajes del corpus y así tener una base para todos los usuarios.

Para crear un grupo de clasificación global en el DSPAM editamos el fichero /var/spool/dspam/group:

global:merged:*

Una vez creado el fichero, reiniciamos DSPAM:

$ invoke-rc.d dspam restart

Y ya podemos empezar a entrenarlo con los corpus.

Los corpus son conjuntos de miles de mensajes recopilados para entrenar filtros antispam. Vamos a utilizar los que hay en la página de SpamAssassin:

http://spamassassin.apache.org/publiccorpus/

En esa página hay varios ficheros de spam y de ham. Vamos a coger dos de spam y dos de ham, lo más actuales posible.

Ahora extraemos un fichero de spam y otro de ham, y nos aseguramos de que se extraen en los directorios spam y ham respectivamente. Si el tar crea un directorio que se llame distinto lo renombramos y listo. Vamos a usar los ficheros de spam y ham uno por uno: sacamos uno de spam y uno de ham, los entrenamos y luego sacamos los otros dos.

Además de los ficheros de corpus, sería conveniente entrenar como ham todos los mensajes de una cuenta de correo existente que sepamos que está totalmente limpia de spam, para así alimentar el filtro con mensajes en español además de en inglés.

Para el proceso de entrenamiento y posterior afinación del DSPAM, vamos a crear un script que recogerá un fichero de mensaje como parámetro y lo entrenará como spam o como ham según le digamos:

  1. #!/bin/sh
  2.  
  3. if [ "$2" == "" ]; then
  4.     exit 1
  5. fi
  6.  
  7. CMD="$1"
  8. MSG="$2"
  9.  
  10. if [ "$CMD" != "spam" ] && [ "$CMD" != "innocent" ]; then
  11.     echo "$0: Error: el mensaje debe aprenderse como spam o como innocent." >&2
  12.     exit 1
  13. fi
  14.  
  15. echo -n "Entrenando mensaje $MSG..."
  16. dspam --mode=teft --source=corpus --class=$CMD --feature=chained,noise --user global < "$MSG"
  17. echo " hecho."

Ahora vamos a pasarle todos los mensajes al script para que los aprenda:

$ find /ruta/al/ham/ -name "*" ! -type d -exec \
> /ruta/al/dspam_corpus innocent '{}' \;

$ find /ruta/al/spam/ -name "*" ! -type d -exec \
> /ruta/al/dspam_corpus spam '{}' \;

Y ya sólo queda montar alguna forma de que los usuarios puedan realimentar mensajes que hayan sido marcados incorrectamente hacia el DSPAM. Para ello vamos a crear dos carpetas IMAP en todas las cuentas de correo y suscribiremos automáticamente a todas ellas a esas dos carpetas. Para crear automáticamente las carpetas de spam en todas las cuentas podemos usar el siguiente script:

  1. #!/bin/sh
  2.  
  3. PATH=/bin:/sbin:/usr/bin:/usr/sbin
  4.  
  5. MAIL_PATH=/mail/
  6.  
  7. SPAM_FOLDER=".Marcar Como SPAM"
  8. HAM_FOLDER=".Marcar Como NO SPAM"
  9.  
  10. MAIL_USER=correo
  11. MAIL_GROUP=mail
  12.  
  13. find ${MAIL_PATH} -mindepth 2 -maxdepth 2 -type d -exec sh -c " \
  14.    test -d \"{}/${SPAM_FOLDER}\" || ( echo -n 'Creando carpeta de SPAM en {}...' && \
  15.    maildirmake.dovecot \"{}/${SPAM_FOLDER}\" && \
  16.    chown -R ${MAIL_USER}.${MAIL_GROUP} \"{}/${SPAM_FOLDER}\" && echo ' hecho.' ); \
  17.    test -d \"{}/${HAM_FOLDER}\" || ( echo -n 'Creando carpeta de NO SPAM en {}...' && \
  18.    maildirmake.dovecot \"{}/${HAM_FOLDER}\" && \
  19.    chown -R ${MAIL_USER}.${MAIL_GROUP} \"{}/${HAM_FOLDER}\" && echo ' hecho.' ); \
  20. " \;

Luego estableceremos una tarea programada en el crontab para entrenar todos los mensajes que hayan sido copiados a esas carpetas, usando dos scripts para realizar el proceso de clasificación y advertencia a cada usuario en caso de que se intente reentrenar un mensaje que ha sido correctamente marcado. Este es el primero:

  1. #!/bin/sh
  2.  
  3. if [ "$2" == "" ]; then
  4.     exit 1
  5. fi
  6.  
  7. CMD="$1"
  8. MSG="$2"
  9. DSPAM_USER="$(dirname "$MSG" | cut -d'/' -f4)@$(dirname "$MSG" | cut -d'/' -f3)"
  10.  
  11. if [ "$CMD" != "spam" ] && [ "$CMD" != "innocent" ]; then
  12.     echo "$0: Error: el mensaje debe aprenderse como spam o como innocent." >&2
  13.     exit 1
  14. fi
  15.  
  16. if [ "$CMD" = "spam" ] && grep "X-DSPAM-Result: Spam" "$MSG"; then
  17.     echo "El usuario $DSPAM_USER ha intentado reentrenar como spam un mensaje que ya ha sido marcado como spam." >&2
  18.     if [ -f "$SPAM_WARNING" ]; then
  19.         (grep "$DSPAM_USER" "$SPAM_WARNING" > /dev/null 2>&1) || (echo "$DSPAM_USER" >> "$SPAM_WARNING")
  20.     fi
  21.     exit 0
  22. fi
  23.  
  24. if [ "$CMD" = "innocent" ] && grep "X-DSPAM-Result: Innocent" "$MSG"; then
  25.     echo "El usuario $DSPAM_USER ha intentado reentrenar como inocente un mensaje que ya ha sido marcado como inocente." >&2
  26.     if [ -f "$HAM_WARNING" ]; then
  27.         (grep "$DSPAM_USER" "$HAM_WARNING" > /dev/null 2>&1) || (echo "$DSPAM_USER" >> "$HAM_WARNING")
  28.     fi
  29.     exit 0
  30. fi
  31.  
  32. echo -n "Entrenando mensaje $MSG..."
  33. dspam --mode=toe --source=error --class=$CMD --user "$DSPAM_USER" < "$MSG"
  34. echo " hecho."
  35. exit 0

Y este el segundo:

  1. #!/bin/sh
  2.  
  3. PATH=/bin:/sbin:/usr/bin:/usr/sbin
  4.  
  5. MAIL_PATH=/mail/
  6.  
  7. SPAM_FOLDER=".Marcar Como SPAM"
  8. HAM_FOLDER=".Marcar Como NO SPAM"
  9.  
  10. SPAM_RETRAIN_PATH="/home/usuario/spam-errors/marcar-como-spam/"
  11. HAM_RETRAIN_PATH="/home/usuario/spam-errors/marcar-como-ham/"
  12.  
  13. LEARN_COMMAND="/home/usuario/script/dspam_learn"
  14.  
  15. SPAM_TYPE=spam
  16. HAM_TYPE=innocent
  17.  
  18. # Esta medida es necesaria para avisar a aquellos usuarios que echen a reentrenar
  19. # mensajes que ya hayan sido correctamente marcados.
  20. WARNING_FROM="DSPAM.no-responder@example.com"
  21.  
  22. export SPAM_WARNING=$(mktemp -t dspam_warning.spam.XXXXXXXX)
  23. export HAM_WARNING=$(mktemp -t dspam_warning.ham.XXXXXXXX)
  24.  
  25. find ${MAIL_PATH} ! -type d -wholename "*/${SPAM_FOLDER}/*/*" -exec sh -c " \
  26.    ${LEARN_COMMAND} ${SPAM_TYPE} '{}' && \
  27.    echo -n \"Borrando mensaje {}...\" && \
  28.    mv '{}' "${SPAM_RETRAIN_PATH}" && \
  29.    echo \" hecho.\" \
  30. " \;
  31. find ${MAIL_PATH} ! -type d -wholename "*/${HAM_FOLDER}/*/*" -exec sh -c " \
  32.    ${LEARN_COMMAND} ${HAM_TYPE} '{}' && \
  33.    echo -n \"Borrando mensaje {}...\" && \
  34.    mv '{}' "${HAM_RETRAIN_PATH}" && \
  35.    echo \" hecho.\" \
  36. " \;
  37.  
  38. # Ahora advertimos a los usuarios que hayan enviado a reentrenar mensajes
  39. # bien marcados.
  40. for i in $(cat "$SPAM_WARNING"); do
  41.     cat <<EOF | sendmail -f "sysadmin@example.com" "$i"
  42. From: "Sistema antispam" <$WARNING_FROM>
  43. Subject: Advertencia sobre la realimentación de SPAM al sistema
  44.  
  45. ESTE ES UN MENSAJE AUTOMÁTICO Y NO DEBE RESPONDER A ÉL.
  46.  
  47. El sistema antispam ha detectado que usted está intentando marcar como
  48. SPAM mensajes que ya han sido marcados como tal por el sistema.
  49.  
  50. Los mensajes marcados como SPAM son fácilmente identificables porque
  51. el sistema les añade el texto [SPAM] delante del asunto. Esos
  52. mensajes ya han sido identificados por el sistema y no es necesario
  53. que los realimente para que éste aprenda que son SPAM.
  54.  
  55. Es posible que su error se deba a que usted está confuso respecto a
  56. la función del sistema antispam. Dicho sistema no elimina los mensajes
  57. marcados como SPAM: eso supondría violar la reglamentación sobre
  58. protección de datos si por cualquier motivo el sistema identificara
  59. como SPAM un mensaje que no lo es.
  60.  
  61. El cometido del sistema antispam es el de ayudarle a marcar los
  62. mensajes identificados como SPAM de forma que usted, en su cliente de
  63. correo, pueda establecer las reglas pertinentes para mover todos esos
  64. mensajes a una carpeta determinada o borrarlos directamente si así lo
  65. desea. El propósito de la carpeta "Marcar Como SPAM" es el de ayudar
  66. al filtro antispam a aprender mensajes que no conozca previamente,
  67. afinando así su precisión al identificarlos.
  68.  
  69. EOF
  70. done
  71. rm "$SPAM_WARNING"
  72. unset SPAM_WARNING
  73.  
  74. for i in $(cat "$HAM_WARNING"); do
  75.     cat <<EOF | sendmail -f "sysadmin@example.com" "$i"
  76. From: "Sistema antispam" <$WARNING_FROM>
  77. Subject: Advertencia sobre la realimentación de mensajes inocentes
  78.  
  79. ESTE ES UN MENSAJE AUTOMÁTICO Y NO DEBE RESPONDER A ÉL.
  80.  
  81. El sistema antispam ha detectado que usted está intentando marcar como
  82. inocentes mensajes que ya han sido marcados como tal por el sistema.
  83.  
  84. Al contrario que en los mensajes marcados como SPAM, en los que el
  85. sistema agrega el texto [SPAM] delante del asunto, los mensajes que el
  86. sistema considera inocentes no sufren ese cambio. Así pues, aquellos
  87. mensajes que no tengan el texto [SPAM] en el asunto ya han sido
  88. identificados por el sistema como mensajes inofensivos y no es
  89. necesario que los realimente para que éste aprenda que lo son.
  90.  
  91. El propósito de la carpeta "Marcar Como NO SPAM" es el de corregir
  92. al filtro antispam cuando identifique como SPAM un mensaje que no lo
  93. es, evitando así que vuelva a incurrir en el mismo error.
  94.  
  95. EOF
  96. done
  97. rm "$HAM_WARNING"
  98. unset HAM_WARNING

Y, por último, esto es lo que introducimos en el crontab para realizar el reentrenamiento, basándonos en las gráficas de entradas al correo para tomar las horas en las que hay poca actividad y por tanto es más seguro el realizar el proceso:

  1. # Hacemos que se reentrene el DSPAM cuatro veces al día, a horas que
  2. # sabemos que hay poca actividad: las seis y las once de la mañana,
  3. # las tres de la tarde y las nueve de la noche.
  4. 0 6,11,15,21 * * * /home/usuario/script/dspam_learn_all

Scripts de ayuda

Para crear cuentas de correo nuevas

El proceso de creación de cuentas de correo se puede automatizar con el siguiente script:

  1. #!/bin/bash
  2.  
  3. DBUSER=usermail
  4. DBPASS=passwordmail
  5. DBDATABASE=maildb
  6.  
  7. MAILROOT=/mail
  8.  
  9. MAILUSER=correo
  10. MAILGROUP=mail
  11.  
  12. if [ $# == 1 ]; then
  13.     CUENTA="$1"
  14.     if echo "$CUENTA" | grep "@" > /dev/null 2>&1; then
  15.         USER="$(echo "$CUENTA" | cut -d"@" -f1)"
  16.         DOMAIN="$(echo "$CUENTA" | cut -d"@" -f2)"
  17.     else
  18.         USER="$CUENTA"
  19.         read -p "Dominio: " DOMAIN
  20.     fi
  21. else
  22.     read -p "Usuario o cuenta de correo: " USER
  23.     if echo "$USER" | grep "@" > /dev/null 2>&1; then
  24.         CUENTA="$USER"
  25.         USER="$(echo "$CUENTA" | cut -d"@" -f1)"
  26.         DOMAIN="$(echo "$CUENTA" | cut -d"@" -f2)"
  27.     else
  28.         read -p "Dominio: " DOMAIN
  29.     fi
  30. fi
  31.  
  32. CHECK_ADDRESS="$(mysql -u $DBUSER -e "SELECT id FROM users WHERE id = '$USER@$DOMAIN'" $DBDATABASE -p$DBPASS)"
  33.  
  34. if [[ "$CHECK_ADDRESS" != "" ]]; then
  35.     echo ''
  36.     echo "La dirección $USER@$DOMAIN ya existe."
  37.     exit 1
  38. fi  
  39.  
  40. read -p "Password para la cuenta $USER@$DOMAIN: " PASSWORD
  41.  
  42. DOMAINROOT=$MAILROOT/$DOMAIN
  43. USERDIR=$DOMAINROOT/$USER
  44.  
  45. CHECK_DOMAIN="$(mysql -u $DBUSER -e "SELECT domain FROM domains WHERE domain = '$DOMAIN'" $DBDATABASE -p$DBPASS)"
  46.  
  47. if [[ "$CHECK_DOMAIN" == "" ]]; then
  48.     echo ''
  49.     echo "El dominio $DOMAIN aún no está dado de alta en la base de datos."
  50.     echo -n "Agregando el dominio $DOMAIN a la tabla de dominios... "
  51.     mysql -u $DBUSER -e "INSERT INTO domains (domain) VALUES ('$DOMAIN')" $DBDATABASE -p$DBPASS && echo "hecho."
  52. fi
  53.  
  54. if [ ! -d $DOMAINROOT ]; then
  55.     echo ''
  56.     echo "El directorio correspondiente al dominio $DOMAIN aún no existe."
  57.     echo -n "Creando directorio $DOMAINROOT... "
  58.     mkdir -p $DOMAINROOT && \
  59.     chown $MAILUSER.$MAILGROUP "$DOMAINROOT" && \
  60.     echo "hecho."
  61. fi
  62.  
  63. echo ''
  64. echo -n "Creando buzón de correo para la cuenta $USER@$DOMAIN... "
  65. maildirmake.dovecot "$USERDIR"
  66. maildirmake.dovecot "$USERDIR/.Sent"
  67. maildirmake.dovecot "$USERDIR/.Trash"
  68. maildirmake.dovecot "$USERDIR/.Drafts"
  69. maildirmake.dovecot "$USERDIR/.Marcar Como SPAM"
  70. maildirmake.dovecot "$USERDIR/.Marcar Como NO SPAM"
  71. cat <<EOF > "$USERDIR/subscriptions"
  72. Sent
  73. Trash
  74. Drafts
  75. Marcar Como SPAM
  76. Marcar Como NO SPAM
  77. EOF
  78. chown -R $MAILUSER.$MAILGROUP "$USERDIR"
  79. cat <<EOF | mysql -u $DBUSER -p$DBPASS $DBDATABASE
  80. INSERT INTO users
  81. (
  82.     id,
  83.     id2,
  84.     name,
  85.     maildir,
  86.     clear,
  87.     crypt,
  88.     domain,
  89.     quota
  90. )
  91. VALUES
  92. (
  93.     '$USER@$DOMAIN',
  94.     '$USER.$DOMAIN',
  95.     '$USER',
  96.     '$DOMAIN/$USER/',
  97.     '$PASSWORD',
  98.     MD5('$PASSWORD'),
  99.     '$DOMAIN',
  100.     '0'
  101. );
  102. EOF
  103. echo "hecho."
  104.  
  105. echo ''
  106. echo "Se ha terminado de crear la cuenta de correo $USER@$DOMAIN con la contraseña '$PASSWORD'."

Para consultar las contraseñas de las cuentas de correo

En el puesto del administrador se puede utilizar el siguiente script que genera una interfaz gráfica simple —usando Zenity— para consultar las contraseñas de las cuentas de correo:

  1. #!/bin/bash
  2.  
  3. CRITERIO="$(zenity --entry --title='Contraseña de correo' --text='Introduzca la dirección de correo:')"
  4.  
  5. if [[ "$CRITERIO" == "" ]]; then
  6.     exit 1
  7. fi
  8. CRITERIO="$(echo ${CRITERIO} | tr -d \')"
  9. CONSULTA="SELECT IF(enabled = 1, 'TRUE', 'FALSE') AS enabled, id, clear FROM users WHERE id LIKE '${CRITERIO}' ORDER BY id"
  10. RESULTADO="$(echo ${CONSULTA} | mysql -h cignus -u usermail -b maildb -ppasswordmail | tail -n +2)"
  11. if [[ "$RESULTADO" == "" ]]; then
  12.     zenity --error --title="Contraseña de correo" --text="No se ha encontrado el correo o ha habido un error al intentar obtener la contraseña."
  13.     exit 1
  14. fi
  15. cat <<EOF | tr \\t ':'
  16. ${RESULTADO}
  17. EOF
  18. cat <<EOF | tr \\t \\n | zenity --list --title="Contraseña de correo" --text="Direcciones encontradas:" \
  19.     --column="Activa" --column="E-mail" --column="Contraseña" --checklist --separator=":" --width=640 --height=480 > /dev/null
  20. ${RESULTADO}
  21. EOF