Está en la página 1de 10

MAR

Instalar un servidor de correo IMAP en Linux

Hoy vamos a dejar por aquí un paso a paso para montar un servidor de correo de la forma más
sencilla posible y con acceso a través de IMAP y de webmail. Partimos, para ello, de un servidor
Debian recien instalado y disponemos de un dominio y de un servicio desde el que gestionar los
registros de nuestro DNS. Para la instalación usaremos Postfix como SMTP, Dovecot como
servidor IMAP y Squirrel como servicio de Webmail.
Lo primero que debemos de hacer es planificar los nombres que necesitamos dar de alta en el
DNS para hacerlo cuanto antes y dar tiempo a que se propaguen. Realmente un único registro A
y otro MX nos valdrían ya que todo va a funcionar en la misma máquina, pero por aquello de que
quede bonito y pensando en futuros cambios en los que el servicio crezca y necesitemos usar
máquinas diferentes para cada cosa, deberíamos de crear un registro A diferente para cada uno
de los servicios. Algo así:
smtp IN A 99.99.99.99
mail IN A 99.99.99.99
webmail IN A 99.99.99.99
@ IN MX 10 mail.midominio.com

Donde, lógicamente, hemos de cambiar midominio.com por el nombre de dominio que vamos a
usar y 99.99.99.99 por la IP de nuestra máquina.
En segundo lugar debemos de instalar los paquetes que necesitamos. Dejaremos el webmail
para el final y nos centraremos en el resto. Para ponerlo en funcionamiento necesitamos
instalar, además de postfix y dovecot, los paquetes necesarios para realizar la autenticación
mediante el protocolo SASL:
# apt-get install postfix-tls libsasl2-2 sasl2-bin libsasl2-modules
dovecot-imapd

El archivo de configuración principal de postfix es /etc/postfix/main.cf. Lo siguiente que


tenemos que hacer es editarlo y añadir las siguientes líneas a su contenido:
smtpd_sasl_local_domain = midominio.com
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_recipient_restrictions = permit_mynetworks,
permit_sasl_authenticated, reject_unauth_destination
smtpd_sasl_security_options = noanonymous
home_mailbox = Maildir/

En la primera línea debemos de sustituir la cadena en negritas por el dominio cuyo correo
queremos recibir. El resto de los parámetros determinan el tipo de autenticación que vamos a
realizar, el servicio que se encargará de la autenticación (dovecot en este caso) y las
restricciones de acceso más comunes al servidor. Tienes información detallada de todas ellas en
este enlace.
Con el parámetro home_mailbox, muy importante, indicamos a Postfix que queremos usar el
formato de correo Maildir y que la ubicación de las carpetas donde se almacenará este será un
directorio denominado Maildir en el raiz del directorio home de cada usuario. Si no lo
especificamos así, el correo se almacenará en un único fichero con el nombre de la cuenta de
cada usuario y bajo el directorio /var/mail.
Una de las operaciones que se realiza durante la instalación de Dovecot es crear la estructura
necesaria para albergar los buzones de correo en el directorio /etc/skel que es el que sirve de
plantilla para generar el home de los nuevos usuarios. Eso quiere decir que los usuarios que
tengamos previamente creados antes de hacer esta instalación no dispondrán de dichos
directorios y, por tanto, no funcionaran correctamente. Para remedir esto tenemos que copiar
manualmente dicha estructura. Supongamos que queremos copiar la estructura de buzones al
usuario josemaria, ya creado antes de esta instalación. La operación sería la siguiente:
# cp -r /etc/skel/Maildir /home/josemaria
# chown -R josemaria:josemaria /home/josemaria/Maildir
# chmod -R 700 /home/josemaria/Maildir

La configuración de dovecot la realizamos en el fichero /etc/dovecot/dovecot.conf. Así como el


archivo de configuración de postfix es sencillito y asequible (apenas tiene 20 líneas), el de
dovecot es un engendro de más de 1000 líneas. Casi todas son comentarios, si, pero aun así
asusta bastante…
Los dos primeros cambios son para determinar el protocolo que vamos a usar y habilitar la
autenticación mediante texto plano. Busca las siguientes líneas y asegúrate de que no están
comentadas y de que sus valores son estos:
protocols = imap
disable_plaintext_auth = no

El siguiente cambio va encaminado a configurar el identificador único que usaremos para cada
email. Para que exista compatibilidad con algunos de los clientes de Microsoft es necesario que
se defina de esta forma:
pop3_uidl_format = %08Xu%08Xv

Y ya sólo nos resta por definir los parámetros relativos al mecanismo de autenticación que
hemos elegido. Lo hacemos con el siguiente bloque:
auth default {
mechanisms = plain login
passdb pam {
}
userdb passwd {
}
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = postfix
}
}
}

Ahora necesitamos hacer unas pequeñas modificaciones para permitir la comunicación entre
postfix y sasl. Puesto que el daemon de postix se ejecuta mediante chroot en el directorio
/var/spool/postfix, crearemos un enlace allí al que podrá acceder el daemon de sasl:
# mkdir -p /var/spool/postfix/var/run/saslauthd
# rm -r /var/run/saslauthd/
# ln -s /var/spool/postfix/var/run/saslauthd /var/run
# chgrp sasl /var/spool/postfix/var/run/saslauthd
# adduser postfix sasl

Y, finalmente, debemos de reiniciar los tres servicios involucrados para que lean los cambios
hechos en sus respectivas configuraciones:
#/etc/init.d/saslauthd restart
#/etc/init.d/postfix restart
#/etc/init.d/dovecot restart

Para quién la autenticación mediante usuario y contraseña con texto plano se le quede corta,
puede echarle un vistazo a este tutorial donde explican como realizarla mediante TLS.
Vamos ahora con la instalación de Squirrel Mail que es mucho más sencilla. Para ello
necesitamos instalar apache, php y el propio squirrel:
# apt-get install apache2 libapache2-mod-php5 php5-cli php5-common php5-
cgi squirrelmail

En el directorio /etc/squirrelmail tenemos un archivo llamado apache.conf con la configuración


necesaria para crear la instancia de apache que nos permitirá acceder a Squirrel. Debemos de
editarlo para modificar los datos correspondientes al Virtual Host que queremos crear:
<VirtualHost *:80 >
DocumentRoot /usr/share/squirrelmail
ServerName webmail.midominio.com
</VirtualHost>

Luego creamos un enlace a este archivo en el directorio sites-availables de apache:


# ln -s /etc/squirrelmail/apache.conf /etc/apache2/sites-
available/squirrelmail

Y, por último, habilitamos el sitio y pedimos a Apache que vuelva a recargar su configuración:
# a2ensite squirrelmail
# /etc/init.d/apache2 reload

La configuración de squirrel se realiza a través de un sencillo programa en modo consola que


permite seleccionar, desde el idioma por defecto o el icono de la página de login, hasta la
ubicación de carpetas por defecto o los plugins disponibles. Dicho programa se lanza con el
siguiente comando:
# /usr/sbin/squirrelmail-configure
Con esto tenemos nuestro servidor de correo perfectamente operativo. Para crear una nueva
cuenta de correo basta con que creemos un nuevo usuario en la máquina. Si creamos una
cuenta llamada paquito, automaticamente se creará un buzón de correo para
paquito@midominio.com cuyos mensajes se almacenaran en un directorio llamado Maildir que
colgará del home de nuestro nuevo usuario.
Un par de ajustes finales. Si nuestra máquina permite el acceso por ssh y sólo queremos dar
acceso de correo pero no permitir que estos usuarios accedan a la consola de la misma, lo mejor
es que creemos un grupo con los usuarios que tendrán acceso de ssh y lo indiquemos así.
Además, recordad que la autenticación de las cuentas de correo la estamos haciendo en texto
plano, con lo cual cualquiera podría “escucharlas” y disponer de una cuenta de acceso a nuestra
máquina. Podríamos, por ejemplo, tener un grupo llamado ssh_permitido al que pertenecerían
los usuarios con permiso de acceso e indicarlo en el fichero /etc/ssh/sshd_config con la siguiente
directiva:
AllowGroups ssh_permitido

Otro posible “extra” sería permitir que los usuarios con cuenta de correo pudieran modificar sus
contraseñas a través de la web. En Unixcraft nos cuentan como hacer un script PHP para
permitirlo.

Change Linux or UNIX system password


using PHP script
by nixcraft · 66 comments

If you just wanted to change your own password or other user passwords use passwd
command.

I was asked to setup a PHP based interface to change the password. Since my knowledge of
php is limited. Here is what I did:

Required tools/setup:

You must have following tools/software installed

=> Shell script to change password

=> Sudo access

=> Apache or Lighttpd web server

=> PHP server side

Step # 1: Setup a shell script to change password


This shell script use expect tool to change the password (see more about expect tool here).

Sample shell script code

#!/bin/sh
# \
exec expect -f "$0" ${1+"$@"}
set password [lindex $argv 1]
spawn passwd [lindex $argv 0]
sleep 1
expect "assword:"
send "$password\r"
expect "assword:"
send "$password\r"
expect eof

You can execute this script as follows (dowload link):


$ chpasswd username password

Download script and copy to your webroot or location where webserver can read this script
file:
$ cp chpasswd /var/www/

ALTERNATIVELY, if you are using Ligtttpd web server:


$ cp chpasswd /home/lighttpd

Step # 2: Setup sudo to execute a command as root user

Apache or Lighttpd web server drops root privileges as soon as they go into background.
This makes changing password scenario difficult as passwd command needs root privileges
to change other user account password.

Typically, Apache 2 use www-data user and Lighttpd use lighttppd username to drop
privileges. Login as root user and type the following command:
# visudo

Now allow your web server to execute a script (chpasswd) w/o password. If you are using
Apache web server, type the following command:
www-data ALL=NOPASSWD: /var/www/chpasswd

ALTERNATIVELY, if you are using Ligtttpd web server, type the following command:
lighttpd ALL=NOPASSWD: /home/lighttpd/chpasswd

Save and close the file.

Step # 3: Create a PHP based interface

Now you need to write a php script. Here is sample php script. This is a demo script. You
should modify it according to your requirement or setup. At minimum, you need to setup
correct shell script location so that it will work for you out of box. Open php script and
locate line:
$shellscript = "sudo /home/lighttpd/chpasswd";

Change it to point to correct location. PHP Source code:

<?php
// change .. me! - shell script name
$shellscript = "sudo /home/lighttpd/chpasswd";

// Make sure form is submitted by user


if(!(isset($_POST['pwdchange']))) {
// if not display them form
writeHead("Change password");
writeForm();
writeFoot();
}
else {
// try to change the password
$callshell=true;
// get username and password
$_POST['username'] = stripslashes(trim($_POST['username']));
$_POST['passwd'] = stripslashes(trim($_POST['passwd']));

// if user skip our javascript ...


// make sure we can only change password if we have both username and
password
if(empty($_POST['username'])) {
$callshell=false;
}
if(empty($_POST['passwd'])) {
$callshell=false;
}
if ( $callshell == true ) {
// command to change password
$cmd="$shellscript " . $_POST['username'] . " " . $_POST['passwd'];
// call command
// $cmd - command, $output - output of $cmd, $status - useful to find
if command failed or not
exec($cmd,$output,$status);
if ( $status == 0 ) { // Success - password changed
writeHead("Password changed");
echo '
<h3>Password changed</h3>

Setup a new password';


writeFoot();
}
else { // Password failed
writeHead("Password change failed");
echo '
<h3>Password change failed</h3>

';
echo '
System returned following information:

';
print_r($output);
echo '

<em>Please contact tech-support for more info! Or try <a


href='.$_SERVER['PHP_SELF'].'again</a></em>

';
writeFoot();
}
}
else {
writeHead("Something was wrong -- Please try again");
echo 'Error - Please enter username and password';
writeForm();
writeFoot();
}
}

// display html head


function writeHead($title) {
echo '
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> ' .$title. '</title>
<style type="text/css" media="screen">
.passwdform {
position: static;
overflow: hidden;
}

.passwdleft {
width: 25%;
text-align: right;
clear: both;
float: left;
display: inline;
padding: 4px;
margin: 5px 0;
}

.passwdright {
width: 70%;
text-align: left;
float: right;
display: inline;
padding: 4px;
margin: 5px 0;
}

.passwderror {
border: 1px solid #ff0000;
}
.passwdsubmit {
}
</style>

</head>

<body>';

}
// display html form
function writeForm() {
echo '
<h3>Use following form to change password:</h3>

<script>
function checkForm() {
if (document.forms.changepassword.elements[\'username\'].value.length ==
0) {
alert(\'Please enter a value for the "User name" field\');
return false;
}
if (document.forms.changepassword.elements[\'passwd\'].value.length == 0)
{
alert(\'Please enter a value for the "Password" field\');
return false;
}
return true;
}
</script>
<div class="contactform">
<form action="' . $_SERVER[PHP_SELF]. '" method="post" onSubmit="return
checkForm()" name="changepassword">
<div class="passwdleft"><label for="lblusername">User Name:
</label></div>
<div class="passwdright">
<input type="text" name="username" id="lblusername" size="30"
maxlength="50" value="" /> (required)</div>
<div class="passwdleft"><label for="lblpasswd">Password: </label></div>
<div class="passwdright">
<input type="password" name="passwd" id="lblpasswd" size="30"
maxlength="50" value="" /> (required)</div>
<div class="passwdright">
<input type="submit" name="Submit" value="Change password"
id="passwdsubmit" />
<input type="hidden" name="pwdchange" value="process" /></div>
</form>
</div>

';

}
// display footer
function writeFoot(){
echo '</body>
</html>
';
}
?>

Step # 4: Run the script

Point a web browser to your server url - https://mydomain.com/changepassword.php. You


should see a username and password form as follows:

If a password is changed successfully, you should get confirmation as follows:

For some reason if a password failed to change, you should get detailed error message as
follows:

Step # 5: Security

Note this is an example and not final solution as it is little insecure.

• Never ever run this script over http session. Always run over https session.
• Put script in a password protected directory (see how to setup Apache or Lighttpd
web server password protected directory).
• Never ever, trust user input. Above php script is just a sample, for real life
production you should consider more powerful user input validation. Discussion
regarding PHP programming security is beyond the scope of this article. You can
consult a good PHP book or search a web using your favorite search engine :)

También podría gustarte