Postfix, Courier y MySQL para tontos (openSUSE 10.2)

Referencias en orden de uso/importancia que en el momento de escribir esto estaban en linea:

1. Instalación

Quiero un servidor de correos que maneje usuarios virtuales y locales,
pero no me interesa manejar dominios virutales, aun asi, la
confirguracion es casi identica a usar dominios virtuales. Vamos a usar
los siguientes paquetes:

  • mysql
  • mysql-client
  • mysql-debug
  • mysql-shared
  • postfix
  • postfix-mysql
  • cyrus-sasl
  • cyrus-sasl-crammd5
  • cyrus-sasl-digestmd5
  • cyrus-sasl-gssapi
  • cyrus-sasl-otp
  • cyrus-sasl-plain
  • cyrus-sasl-saslauthd
  • cyrus-sasl-sqlauxprop
  • courier-imap
  • courier-authlib
  • courier-authlib-mysql
# yast2 -i mysql mysql-client mysql-debug mysql-shared postfix postfix-mysql cyrus-sasl cyrus-sasl-crammd5 cyrus-sasl-digestmd5 cyrus-sasl-gssapi cyrus-sasl-otp cyrus-sasl-plain cyrus-sasl-saslauthd courier-imap courier-authlib courier-authlib-mysql

2. MySQL

Esta parte es solo para los usuarios virtuales, aunque tambien muesta como instalar y arrancar MySQL en openSUSE 10.2.

2.1. Configuración

Para que el demonio MySQL arranque con la maquita, corres como root

Como voy a trabajar todo en utf8 y en español modifico el archivo /etc/my.cnf según lo que escribí en MySQL en UTF-8

# chkconfig --add mysql

y para iniciarlo

# /etc/init.d/mysql start

Para probarlo

# netstat -tap

y debes ver also asi:

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
[...]
tcp        0      0 *:mysql                 *:*                     LISTEN      7337/mysqld
[...]

Con otros muchos servicios o servidores. No olvides poner una contraseña de root y los demas detalles de seguridad.

Nos creamos un usuario MySQL:

mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON correo.* TO 'cartero'@'localhost' IDENTIFIED BY 'PatoFeliz';
mysql> FLUSH PRIVILEGES;

Ahora a hacer la bases de datos. Yo hice un archibo batch para que me se mas facil:

CREATE DATABASE correo;

use correo;

DROP TABLE IF EXISTS transport;

CREATE TABLE transport (
 id        int(11) unsigned NOT NULL auto_increment,
 dominio   varchar(128) NOT NULL default '',
 transport varchar(128) NOT NULL default 'virtual:',
 activo    enum('S', 'N') NOT NULL default 'N',
 creado    datetime NOT NULL default '0000-00-00 00:00:00',
 modif     datetime NOT NULL default '0000-00-00 00:00:00',
 PRIMARY KEY (id),
 UNIQUE KEY dominio (dominio)
) ENGINE=MyISAM;

DROP TABLE IF EXISTS usuarios;

CREATE TABLE usuarios (
 id      int(11) unsigned NOT NULL auto_increment,
 usuario varchar(128) NOT NULL default '',
 correo  varchar(128) NOT NULL default '',
 clear   varchar(128) NOT NULL default '',
 crypt   varchar(128) NOT NULL default '',
 nombre  tinytext NOT NULL,
 uid     int(11) unsigned NOT NULL default '5000',
 gid     int(11) unsigned NOT NULL default '5000',
 homedir varchar(256) NOT NULL default '/home/vmail',
 maildir varchar(256) NOT NULL,
 quota   varchar(256) NOT NULL default '20971520',
 activo  enum('S','N') NOT NULL default 'S',
 postfix enum('S','N') NOT NULL default 'S',
 creado  datetime NOT NULL default '0000-00-00 00:00:00',
 modif   datetime NOT NULL default '0000-00-00 00:00:00',
 PRIMARY KEY (id),
 UNIQUE KEY usuario (usuario),
 UNIQUE KEY correo (correo)
) ENGINE=MyISAM;

DROP TABLE IF EXISTS virtual;

CREATE TABLE virtual (
 id     int(11) unsigned NOT NULL auto_increment,
 correo varchar(250) NOT NULL,
 goto   TEXT NOT NULL,
 activo enum('S', 'N') NOT NULL default 'N',
 creado datetime NOT NULL default '0000-00-00 00:00:00',
 modif  datetime NOT NULL default '0000-00-00 00:00:00',
 PRIMARY KEY (id),
 UNIQUE KEY correo (correo)
) ENGINE=MyISAM;

El resultado debe ser el siguiente:

mysql> show tables;
+------------------+
| Tables_in_correo |
+------------------+
| transport        |
| usuarios         |
| virtual          |
+------------------+
3 rows in set (0.00 sec)

mysql> describe transport;
+-----------+------------------+------+-----+---------------------+----------------+
| Field     | Type             | Null | Key | Default             | Extra          |
+-----------+------------------+------+-----+---------------------+----------------+
| id        | int(11) unsigned | NO   | PRI | NULL                | auto_increment |
| dominio   | varchar(128)     | NO   | UNI |                     |                |
| transport | varchar(128)     | NO   |     | virtual:            |                |
| activo    | enum('S','N')    | NO   |     | N                   |                |
| creado    | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
| modif     | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
+-----------+------------------+------+-----+---------------------+----------------+
6 rows in set (0.03 sec)

mysql> describe usuarios;
+---------+------------------+------+-----+---------------------+----------------+
| Field   | Type             | Null | Key | Default             | Extra          |
+---------+------------------+------+-----+---------------------+----------------+
| id      | int(11) unsigned | NO   | PRI | NULL                | auto_increment |
| usuario | varchar(128)     | NO   | UNI |                     |                |
| correo  | varchar(128)     | NO   | UNI |                     |                |
| clear   | varchar(128)     | NO   |     |                     |                |
| crypt   | varchar(128)     | NO   |     |                     |                |
| nombre  | tinytext         | NO   |     |                     |                |
| uid     | int(11) unsigned | NO   |     | 5000                |                |
| gid     | int(11) unsigned | NO   |     | 5000                |                |
| homedir | varchar(256)     | NO   |     | /home/vmail         |                |
| maildir | varchar(256)     | NO   |     |                     |                |
| quota   | varchar(256)     | NO   |     | 20971520            |                |
| activo  | enum('S','N')    | NO   |     | S                   |                |
| postfix | enum('S','N')    | NO   |     | S                   |                |
| creado  | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
| modif   | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
+---------+------------------+------+-----+---------------------+----------------+


15 rows in set (0.00 sec)

mysql> describe virtual;
+--------+------------------+------+-----+---------------------+----------------+
| Field  | Type             | Null | Key | Default             | Extra          |
+--------+------------------+------+-----+---------------------+----------------+
| id     | int(11) unsigned | NO   | PRI | NULL                | auto_increment |
| correo | varchar(250)     | NO   | UNI |                     |                |
| goto   | text             | NO   |     |                     |                |
| activo | enum('S','N')    | NO   |     | N                   |                |
| creado | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
| modif  | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
+--------+------------------+------+-----+---------------------+----------------+
6 rows in set (0.00 sec)

De todas mis tablas los campos id, activo, crado y modificado no son necesarios, yo los puese por que los uso en otros partes. De una vez, pongan datos en la tablas.

mysql> INSERT INTO correo.transport (dominio, transport, activo, creado) VALUES ('rmf.fciencias.unam.mx', 'local:', 'S', NOW() );

mysql> INSERT INTO correo.usuarios (usuario, correo, clear, crypt, nombre, maildir, quota, creado) VALUES ('sara', 'sara@rmf.fciencias.unam.mx', 'sara', 'sara', 'Sara Cortés', 'sara/', DEFAULT, NOW() );

mysql> INSERT INTO correo.virtual (correo, goto, activo, creado) VALUES ('root', 'paris', 'S', NOW() );

mysql> INSERT INTO correo.virtual (correo, goto, activo, creado) VALUES ('webmaster@rmf.fciencias.unam.mx', 'paris', 'S', NOW() );

mysql> INSERT INTO correo.virtual (correo, goto, activo, creado) VALUES ('postmaster@rmf.fciencias.unam.mx', 'paris', 'S', NOW() );

2. Postfix con SMTP-AUTH, TLS y Quota

2.1. Configuracion
2.1.1 Firma tus propios certificados

Hacemos los certificados para TLS, si no has instalado openssl haslo ahora.


# mkdir /etc/postfix/ssl
# cd /etc/postfix/ssl/ 
# openssl genrsa -des3 -rand /etc/hosts -passout pass:secreto -out /etc/postfix/ssl/smtpd.key 1024
# chmod 600 /etc/postfix/ssl/smtpd.key
# openssl req -new -passin pass:secreto -passout pass:secreto -key /etc/postfix/ssl/smtpd.key -out /etc/postfix/ssl/smtpd.csr
# openssl req -x509 -passin pass:secreto -passout pass:secreto -in /etc/postfix/ssl/smtpd.csr -key /etc/postfix/ssl/smtpd.key -out /etc/postfix/ssl/smtpd.crt -days 3650
# openssl rsa -passin pass:secreto -in /etc/postfix/ssl/smtpd.key -out /etc/postfix/ssl/smtpd.key.unencrypted
# mv -f /etc/postfix/ssl/smtpd.key.unencrypted /etc/postfix/ssl/smtpd.key
# openssl req -new -x509 -extensions v3_ca -keyout /etc/postfix/ssl/cakey.pem -out /etc/postfix/ssl/cacert.pem -days 3650

2.1.2. Configuración general

Editamos # vi /etc/postfix/master.cf y asegurate que tenga las siguiente lineas:

[...]
smtp	inet	n	-	n	-	-	smtpd
[...]
virtual	unix	-	n	n	-	-	virtual
[...]
tlsmgr	unix	-	-	n	1000?	1	tlsmgr
[...]

y corre postconf para editar main.cf de postfix sin meterla pata, las siguientes lineas son configuración basica de postfix.

# postconf -e 'mydomain = fciencias.unam.mx'
# postconf -e 'myhostname = rmf.$mydomain'
# postconf -e 'mynetworks = 127.0.0.0/8'
# postconf -e 'home_mailbox = Maildir/'
# postconf -e 'recipient_delimiter = +'
# postconf -e 'mydestination = $myhostname, $transport_maps'
# postconf -e 'inet_interfaces = all'
# postconf -e 'alias_maps = hash:/etc/aliases'

2.1.3. Configuración SMTP-AUTH y TLS

# postconf -e 'smtp_tls_note_starttls_offer = yes'
# postconf -e 'smtp_use_tls = yes'
# postconf -e 'smtpd_use_tls = yes'
# postconf -e 'smtpd_tls_auth_only = no'
# postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, check_relay_domains'
# postconf -e 'smtpd_sasl_auth_enable = yes'
# postconf -e 'smtpd_sasl_local_domain = $myhostname'
# postconf -e 'smtpd_sasl_security_options = noanonymous'
# postconf -e 'smtpd_tls_key_file = /etc/postfix/ssl/smtpd.key'
# postconf -e 'smtpd_tls_cert_file = /etc/postfix/ssl/smtpd.crt'
# postconf -e 'smtpd_tls_CAfile = /etc/postfix/ssl/cacert.pem'
# postconf -e 'smtpd_tls_loglevel = 1'
# postconf -e 'smtpd_tls_received_header = yes'
# postconf -e 'smtpd_tls_session_cache_timeout = 3600s'
# postconf -e 'broken_sasl_auth_clients = yes'
# postconf -e 'tls_random_source = dev:/dev/urandom'

Arrancamos saslauthd

# chkconfig --add saslauthd 
# /etc/init.d/saslauthd start

2.1.4. Configurando usuarios virtuales ¡AUN NO TERMINO ESTO!

Primero creamos un usuario Linux que sera el que manejara la cuenta de los usuarios virtuales, le hacemos carpeta y grupo, con uid (user id) y gid (grupo id) especificos (sera 5000), para que podamos manejarlo a nuesto antojo.

# mkdir /home/vmail
# useradd -u 5000 -d /home/vmail vmail
# groupadd -g 5000 vmail

Con lo siguiente le decimos a postfix donde encontra la informacion de los usuarios virtuales.

# postconf -e 'fallback_transport = virtual'
# postconf -e 'virtual_mailbox_domains ='
# postconf -e 'virtual_minimum_uid  = 100'
# postconf -e 'virtual_mailbox_base = /home/vmail'
# postconf -e 'virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual_mailbox_maps.cf'
# postconf -e 'virtual_uid_maps     = mysql:/etc/postfix/mysql-virtual_uid_maps.cf'
# postconf -e 'virtual_gid_maps     = mysql:/etc/postfix/mysql-virtual_gid_maps.cf'
# postconf -e 'virtual_alias_maps   = mysql:/etc/postfix/mysql-virtual_alias_maps.cf'

Creamos los archivos

# vi /etc/postfix/mysql-transport_maps.cf

user = cartero
password = PatoFeliz
hosts = localhost
dbname = correo
query = SELECT transport FROM transport WHERE dominio='%s' AND activo = 'S'
# vi /etc/postfix/mysql-virtual_mailbox_maps.cf

user = cartero
password = PatoFeliz
hosts = localhost
dbname = correo
query = SELECT maildir FROM usuarios WHERE correo='%s' AND postfix = 'S' AND activo = 'S'
# vi /etc/postfix/mysql-virtual_uid_maps.cf

user = cartero
password = PatoFeliz
hosts = localhost
dbname = correo
query = SELECT uid FROM usuarios WHERE correo='%s' AND postfix = 'S' AND activo = 'S'

# vi /etc/postfix/mysql-virtual_gid_maps.cf

user = cartero
password = PatoFeliz
hosts = localhost
dbname = correo
query = SELECT gid FROM usuarios WHERE correo='%s' AND postfix = 'S' AND activo = 'S'
# vi /etc/postfix/mysql-virtual_alias_maps.cf

user = cartero
password = PatoFeliz
hosts = localhost
dbname = correo
query = SELECT goto FROM virtual WHERE correo='%s' AND activo = 'S'

Creamos un harlink para que Postfix que se ejecuta en modo chroot pueda tener acceso a mysql.

# mkdir -p /var/spool/postfix/var/lib/mysql
# chown mysql /var/spool/postfix/var/lib/mysql
# ln /var/lib/mysql/mysql.sock /var/spool/postfix/var/lib/mysql/mysql.sock

Esta solución es solo si MySQL y Postfix funcionana en la misma maquina y la misma particion.

Por ultimo, editamos:

vi /etc/sasl2/smtpd.conf

pwcheck_method: saslauthd
mech_list: plain login
auxprop_plugin: sql
sql_engine: mysql
sql_hostnames: localhost
sql_user: cartero
sql_database: correo
sql_passwd: PatoFeliz
sql_select: select clear from usuarios where correo = '%u@%r'

2.1.5. Aplicar el parche Quota a Postfix (opcional)

Antes de parchar nada, una pequeña advertencia. Si son como yo y no saben nada de linux ponganse a leer un poco sobre rpm’s, librerias de desarroyo y progrmacion. Que conste, ¡estan advertidos! Otra pequeña adevertencia, este parche solo funcioa para usuarios virtuales, mas adelante indicare de nuevo esto.

Necesitamos obtener los fuentes rpm de Postfix, parcharlo con el "soft-quota patch" y hacer un nuevo paquete rpm de Postfix e instalarlo.

# cd /usr/src
# wget http://download.opensuse.org/distribution/10.2/repo/src-oss/suse/src/postfix-2.3.2-28.src.rpm
# rpm -ivh postfix-2.2.3.2-28.src.rpm # cd /usr/src/packages/SOURCES/ # wget http://vda.sourceforge.net/VDA/postfix-2.3.2-vda.patch.gz # gunzip postfix-2.3.2-vda.patch.gz # cd /usr/src/packages/SPECS/

Debemos editar el archivo postfix.spec añadiendo Patch2: postfix-2.2.8-vda.patch, y agregar %patch2 -p1 -b .vda en los lugares aduecuados,

# vi postfix.spec

[...]
Patch: dynamic_maps.patch
Patch1: dynamic_maps_pie.patch
Patch2: postfix-2.3.2-vda.patch
[...]
#---------------------------------------------------------------------------
%prep
%setup -n postfix-%{version} -a 1
%patch -p1
%patch1 -p1
%patch2 -p1 -b .vda
#---------------------------------------------------------------------------
[...]

Luego, construimos nuestro nuevo paquete rpm de Postfix con quota:

# rpmbuild -ba postfix.spec

Cuando tengas la salida:

Wrote: /usr/src/packages/RPMS/i586/postfix-2.3.2-28.i586.rpm
Wrote: /usr/src/packages/RPMS/i586/postfix-debuginfo-2.3.2-28.i586.rpm
Wrote: /usr/src/packages/RPMS/i586/postfix-mysql-2.3.2-28.i586.rpm
Wrote: /usr/src/packages/RPMS/i586/postfix-postgresql-2.3.2-28.i586.rpm
Wrote: /usr/src/packages/RPMS/i586/postfix-devel-2.3.2-28.i586.rpm

ya lo lograste! Ahora si te da mucha dificultad bajate los mios postfix-2.3.2-28.i586.rpm postfix-mysql-2.3.2-28.i586.rpm.

2.1.6. Soft-Qutoa y Postfix (opcional) ¡AUN NO TERMINO ESTO!

Si ya llegaste a este punto, seguro me queras matar, puede debes instalar de nuevo postfix y casi seguro que te borra la mayoria de la configuración, pero… bueno ahora sabes que antes de seguir un Howto debes leerlo complero (=P es broma) yo recomiendo que los pruebes primero sin el parche, unavez que todo funcione bien si quieres instalalo. Total, si ya pudiste una vez seguro puedes de nuevo.

# cd /usr/src/packages/RPMS/i586/
# rpm -ivh postfix-2.3.2-28.i586.rpm postfix-mysql-2.3.2-28.i586.rpm
# cd /etc/postfix/

# vi /etc/postfix/mysql-virtual_limit_maps.cf

user = cartero
password = PatoFeliz
dbname = mail
table = users
select_field = quota
where_field = user
hosts = 127.0.0.1

2.2. Probando Postfix

Reiniciamos Postfix y lo probamos

# /etc/init.d/postfix restart

Para ver si SMTP-AUTH y TLS funcionen de modo apropiado usamos el comando:

# telnet localhost 25

Despues de haber establicido la conexion con el servidor de coreso Postfix, escribe:

# ehlo localhost

Si ves las linas

250-STARTTLS

y

250-AUTH

Entonces todo va bien, en mi sistema la salida se ve asi:

rmf:/etc/postfix # telnet localhost 25 

Trying 127.0.0.1...

Connected to localhost.
Escape character is '^]'.
220 rmf.fciencias.unam.mx ESMTP Postfix
ehlo localhost
250-rmf.fciencias.unam.mx
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.
rmf:/etc/postfix/ssl #

Con quit regresas a tu shell.

Ahora envia un correo desde tu servidor con una de tus cuentas locales, puedes hacerlo con el comando mail de la siguiente manera.


# mail correo@quepuedasrevisar.com

Subject: hola quetal
como te va?
EOT
#

Despues de escribir el mensaje da un espacio con la tecla Enter y con Crtl+d envias el mensaje. Luego revisa que la bandeja de entrada de correo@quepuedasrevisar.com y si en verdad las cosas ban bien deberias tener el correo que enviaste.

3. Courier-IMAP/Courier-POP3

Configuramos los demonios para que arranquen:

# chkconfig --add fam
# chkconfig --add courier-authdaemon
# chkconfig --add courier-pop
# chkconfig --add courier-imap
# chkconfig --add courier-pop-ssl
# chkconfig --add courier-imap-ssl

3.1. Courier-IMAP/Courier-POP3 con usuarios virtuales

hay que editar algunos archivos,

vi /etc/authlib/authdaemonrc

authmodulelist="authmysql"

vi /etc/authlib/authmysqlrc

MYSQL_SERVER	localhost
MYSQL_USERNAME	cartero
MYSQL_PASSWORD	PatoFeliz
MYSQL_SOCKET	/var/lib/mysql/mysql.sock
MYSQL_PORT	0
MYSQL_OPT	0
MYSQL_DATABASE	correo
MYSQL_USER_TABLE	usuarios
#MYSQL_CRYPT_PWFIELD    crypt ## descomenta para contraseña encriptada
MYSQL_CLEAR_PWFIELD     clear
MYSQL_UID_FIELD uid
MYSQL_GID_FIELD gid
MYSQL_LOGIN_FIELD       usuario
MYSQL_HOME_FIELD        homedir
MYSQL_NAME_FIELD        nombre
MYSQL_MAILDIR_FIELD     maildir
MYSQL_UID_FIELD	uid
MYSQL_GID_FIELD	gid
MYSQL_WHERE_CLAUSE	activo='S'
MYSQL_NAME_FIELD	nombre

Y reinicia los demonios

# /etc/init.d/courier-authdaemon restart
# /etc/init.d/courier-imap restart
# /etc/init.d/courier-imap-ssl restart
# /etc/init.d/courier-pop restart
# /etc/init.d/courier-pop-ssl restart

Para probar el courier abre un shell y escribe:

# telnet "nombre del servidor" pop3
+OK Hello there.
# user "nombre_de_usuario"
# pass "contraseña"
# list <-- Deberias obtener una lista con los correos.
# retr "numero" <-- Deberias ver el correo con el numero que escribiste.
# quit

Si esto funciona ya puedes dar brincos de gusto!

5. Fire wall

Por ultimo tienes que abrir la comunicación en el fire wall de openSUSE 10.2. Para eso abre Yast2 entra a Seguridad y usuarios, da clic en Cortafuegos, selecciona Servicios autorizados y en el menu deplegable debajo de Servicios que se van a utorizar busca Servidor IMAP, IMAPS, POP3, POP3S y de correos, y añadelos. Has clic en Siguiente luego en Aceptar.

Buscate otra computadora, incluso puede ser una con windows abre un “shell” y has la ultima prueba, debe funcionar igual que en linux.