User Tools

Site Tools


haas:system:mail.offbyone.lan

Overview

mail.offbyone.lan is the LAIR mail server primarily serving the offbyone.lan network.

hostname RAM disk swap OS Kernel
mail.offbyone.lan 192MB 2GB (/) 128MB Debian 5.0 “Lenny” (AMD64) 2.6.26-2-xen-amd64

mail.lair.lan is the LAIR mail server primarily serving the lair.lan network.

hostname RAM disk swap OS Kernel
mail.lair.lan 192MB 2GB (/) 128MB Debian 5.0 “Lenny” (AMD64) 2.6.26-2-xen-amd64

mail.offbyone.lan created on sokraits on 01/04/2010:

sokraits:~$ sudo xen-create-image --hostname=mail --mac 00:16:3E:5D:88:CC --role=udev

mail.lair.lan created on ahhcobras on 01/06/2010:

ahhcobras:~$ sudo xen-create-image --hostname=mail --mac 00:16:3E:42:EE:3E --role=udev

News

  • 01/04/2010 - mail.offbyone.lan created, DNS updates made on caprisun and jb2
  • 01/06/2010 - created separate disk image for /var/mail
  • 01/06/2010 - mail.lair.lan created, DNS/DHCP entries updated on jb2
  • 01/12/2010 - installed lighttpd and mailman onto mail.offbyone.lan
  • 01/16/2010 - integrated mail.offbyone.lan into the new user creation process
  • 09/14/2010 - /var/mail moved from Xen disk image to nfs share (/export/lib/mail)

TODO

  • integrate into backup system
  • consider more frequent backups of the user mail directories

Other potentially desirable features:

  • web mail?
  • secondary mail server, DSLAB mail server
  • look up pam logic to eliminate pam_unix errors popping up in the log (it falls through to ldap and succeeds)
  • mail quotas?
  • authenticated SMTP?

Network Configuration

Machine Interface IP Address MAC Address Other Names
mail.lair.lan eth0 10.80.1.17 00:16:3e:42:ee:3e smtp.lair.lan, imap.lair.lan
mail.offbyone.lan eth0 10.80.2.17 00:16:3e:5d:88:cc

Packages

The following packages have been installed on mail:

lair-std
lair-vm
lair-nfs
lair-autofs
lair-ldap
alpine
postfix
mb2md
dovecot-imapd         from lenny-backports
lighttpd              from lenny-backports
mailman

Utilizing Backports

I always thought that once backports were included in the package database, we were good to go- that is apparently not correct.

Maybe it works for the packages that are entirely missing from Lenny (such as alpine), but duplicately named packages— like dovecot-imapd, which exists in both lenny proper AND lenny-backports, it defers to lenny (and doesn't even show you the backports available choice).

So, to check things out:

Search backports

lab46:~$ sudo aptitude -t lenny-backports search dovecot

Show something in more detail

lab46:~$ sudo aptitude -t lenny-backports show dovecot-imapd

Of particular interest here is the version— Lenny proper only includes version 1.0.15 of dovetail. Lenny-backports includes 1.2.9. Much more preferable.

And, Install something from backports

lab46:~$ sudo aptitude -t lenny-backports install dovecot-imapd

Postfix Configuration

In /etc/postfix/main.cf, we ended up with the following:

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

append_dot_mydomain = no
readme_directory = no

# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

smtp_generic_maps = hash:/etc/postfix/generic

mydomain = lab46.corning-cc.edu
myorigin = /etc/mailname
myhostname = mail.offbyone.lan
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = mail, mail.offbyone.lan, offbyone.lan, mail.lair.lan, lair.lan, mail.student.lab, student.lab, lab46.corning-cc.edu, lab46.offbyone.lan, lab46.lair.lan, lab46, caprisun.offbyone.lan, juicebox.lair.lan, koolaid.student.lab, localhost, web.offbyone.lan, www.offbyone.lan, *.offbyone.lan
relayhost = mail.corning-cc.edu
mynetworks = 127.0.0.0/8 10.80.1.0/24 10.80.2.0/24 10.80.3.0/24 10.81.1.0/24
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

# Maildir configuration
mail_spool_directory = /var/mail/
# trailing '/' signifies maildir format

# Additions
virtual_maps = hash:/etc/postfix/virtusertable

# SMTPd error handling limits
smtpd_error_sleep_time = 1s
smtpd_soft_error_limit = 32
smtpd_hard_error_limit = 64
broken_sasl_auth_clients = yes

disable_dns_lookups = yes
smtp_host_lookup = dns

# Masquerading
#masquerade_domains = www.offbyone.lan lab46.corning-cc.edu
#masquerade_exceptions = root

# Relay/Transport
#relay_domains = hash:/etc/postfix/relay_domains
#transport_maps = hash:/etc/postfix/transport
#virtual_alias_maps = hash:/etc/postfix/virtual
#parent_domain_matches_subdomains = 

#virtual_alias_domains = lab46.corning-cc.edu
#virtual_alias_maps = hash:/var/lib/mailman/data/virtual-mailman

##
## SMTP data timeouts
##
smtp_data_xfer_timeout = 600
smtp_data_init_timeout = 180

In /etc/postfix/virtusertable, we have:

hass				wedge@lair.lan
hass@corning-cc.edu		wedge@lair.lan
hass@lab46.corning-cc.edu	wedge@lair.lan
haas@corning-cc.edu		wedge@lair.lan haas@corning-cc.edu
wedge@corning-cc.edu		wedge@lair.lan

Postfix hash generation

virtusertable

If any changes are made to /etc/postfix/virtusertable, we need to regenerate the postfix hash:

mail:~# postmap hash:/etc/postfix/virtusertable

generic

Similarly, changes made to /etc/postfix/generic need their postfix hash regenerated:

mail:~# postmap hash:/etc/postfix/generic

dovecot Configuration

To complement postfix serving SMTP, dovecot will provide IMAP4 services to the LAIR.

dovecot keeps its configuration in /etc/dovecot, with /etc/dovecot/dovecot.conf being its primary configuration file:

## Dovecot configuration file
#
# If you're in a hurry, see http://wiki.dovecot.org/QuickConfiguration
#
# "dovecot -n" command gives a clean output of the changed settings. Use it
# instead of copy&pasting this file when posting to the Dovecot mailing list.
#
 
protocols = imap imaps
disable_plaintext_auth = yes
log_timestamp = "%Y-%m-%d %H:%M:%S "
 
##
## SSL settings
##
ssl = required
ssl_cert_file = /etc/ssl/certs/dovecot.pem
ssl_key_file = /etc/ssl/private/dovecot.pem
 
##
## Mailbox locations and settings
##
mail_location = maildir:/var/mail/%u
mail_privileged_group = mail
 
##
## IMAP specific settings
##
protocol imap {
}
 
##
## Authentication Process
##
auth default {
  # Space separated list of wanted authentication mechanisms:
  #   plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey
  #   gss-spnego
  mechanisms = plain
 
  passdb pam {
  }
 
  userdb passwd {
  }
 
  user = root
 
}
 
dict {
}
 
plugin {
}

mailing list configuration

Mailing lists are accomplished via GNU mailman and a local install of lighttpd on mail.offbyone.lan (to avoid the schism caused with trying to run mailman on separate web server and mail server boxes).

So, first up, I give thee lighttpd:

lighttpd configuration

Just to get the latest in goodness, I snorked lighttpd from backports:

mail:~$ sudo aptitude install -t lenny-backports lighttpd

main config

Residing in /etc/lighttpd/lighttpd.conf, this is the central config for the lighttpd web server.

The default likely works upon installation, but I went and further tweaked it, and removed comments.

lighttpd.conf
server.modules       = ( "mod_access", "mod_alias", "mod_accesslog", "mod_compress" )
server.document-root = "/var/www/"
server.upload-dirs   = ( "/var/cache/lighttpd/uploads" )
server.errorlog      = "/var/log/lighttpd/error.log"
index-file.names     = ( "index.php", "index.html" )
accesslog.filename   = "/var/log/lighttpd/access.log"
url.access-deny      = ( "~", ".inc" )
server.pid-file      = "/var/run/lighttpd.pid"
dir-listing.encoding = "utf-8"
server.dir-listing   = "disable"
server.username      = "www-data"
server.groupname     = "www-data"
compress.cache-dir   = "/var/cache/lighttpd/compress/"
compress.filetype    = ("text/plain", "text/html", "application/x-javascript", "text/css")
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
$HTTP["remoteip"] =~ "127.0.0.1" {
    alias.url += (
        "/doc/" => "/usr/share/doc/",
        "/images/" => "/usr/share/images/"
    )
    $HTTP["url"] =~ "^/doc/|^/images/" {
        dir-listing.activate = "enable"
    }
}

lighttpd mailman config

Next up, we wander into /etc/lighttpd/conf-available/, which has the various modules or subconfigurations that can be loaded.

We'll make a new file, and call it 12-mailman.conf:

12-mailman.conf
server.modules += ("mod_redirect", "mod_alias", "mod_cgi", "mod_accesslog")
 
alias.url += (
    "/mailman/images/" => "/var/lib/mailman/icons/",
    "/mailman/pipermail" => "/var/lib/mailman/archives/public/",
    "/mailman" => "/var/lib/mailman/cgi-bin/"
)
 
$HTTP["url"] =~ "^/mailman" {
    server.name = "lab46.corning-cc.edu"
 
    cgi.assign = (
        "/admin" => "",
        "/admindb" => "",
        "/confirm" => "",
        "/create" => "",
        "/edithtml" => "",
        "/listinfo" => "",
        "/options" => "",
        "/private" => "",
        "/rmlist" => "",
        "/roster" => "",
        "/subscribe" => "")
    server.indexfiles = ("listinfo", "index.html")
}
 
$HTTP["url"] =~ "^/mailman/pipermail/" {
    dir-listing.activate = "enable"
    dir-listing.hide-dotfiles = "enable"
    server.follow-symlink = "enable"
}

Following this, we need to enable the mailman “module”, which we can do by issuing the following:

mail:/etc/lighttpd/conf-available$ sudo lighty-enable-mod mailman

These values were tweaked until proven working.

Be sure to restart lighttpd to ensure the settings take effect.

mailman config

After much pain and effort, I ended up with a (somehow and mostly) operational mailman setup.

The somehow I'm just going to chalk up to the right config options in the config file and options specified when interacting with mailman– not indicating ideal conditions for administration, but at least functional for the end-user.

The mostly is that we'll be avoiding some of the mailman web interface, because it uses the wrong hostname… the list summary pages mainly… the actual list pages end up being correct– I'll just rig up a page off the Lab46 site to point directly at lists.

Anyway, on with the actual task:

mail:~$ sudo aptitude install mailman

Then onto its configuration:

mm_cfg.py

Open up /etc/mailman/mm_cfg.py to make some changes.

I ended up adding 2 or 3 new variable declarations, so here is the comment-free condensed version of the file:

"""This is the module which takes your site-specific settings.

From a raw distribution it should be copied to mm_cfg.py.  If you
already have an mm_cfg.py, be careful to add in only the new settings
you want.  The complete set of distributed defaults, with annotation,
are in ./Defaults.  In mm_cfg, override only those you want to
change, after the

  from Defaults import *

line (see below).

Note that these are just default settings - many can be overridden via the
admin and user interfaces on a per-list or per-user basis.

Note also that some of the settings are resolved against the active list
setting by using the value as a format string against the
list-instance-object's dictionary - see the distributed value of
DEFAULT_MSG_FOOTER for an example."""

from Defaults import *

DEFAULT_EMAIL_HOST      = 'lab46.corning-cc.edu'
DEFAULT_SEND_REMINDERS  = 0
DEFAULT_SERVER_LANGUAGE = 'en'
DEFAULT_URL             = 'http://lab46.corning-cc.edu/mailman/'
DEFAULT_URL_PATTERN     = 'http://%s/mailman/'
DEFAULT_URL_HOST        = 'lab46.corning-cc.edu'
HOST_NAME               = 'lab46.corning-cc.edu'
IMAGE_LOGOS             = '/mailman/images/'
MAILMAN_SITE_LIST       = 'mailman'
PRIVATE_ARCHIVE_URL     = '/mailman/private'
PUBLIC_ARCHIVE_URL      = 'http://lab46.corning-cc.edu/mailman/pipermail/%(listname)s'
USE_ENVELOPE_SENDER     = 0
VIRTUAL_HOSTS.clear()
add_virtualhost('lists.lab46.corning-cc.edu')

The options reflect the configuration settings established in lighttpd, along with mailman's own directory structure.

The goal here was to really convince mailman its machine name is 'lab46.corning-cc.edu', without really changing the name of the machine.

initializing mailman

Before mailman will start, we need to create the so-called 'site-wide mailing list', a list, as we see from the setting of MAILMAN_SITE_LIST in /etc/mailman/mm_cfg.py, wants to be called 'mailman'.

So let's create it (here's where one has to be mindful, otherwise settings end up awry):

mail:~$ sudo newlist -u lab46.corning-cc.edu -e lab46.corning-cc.edu mailman
Enter the email of the person running the list: wedge@lab46.corning-cc.edu
Initial mailman password: 
To finish creating your mailing list, you must edit your /etc/aliases (or
equivalent) file by adding the following lines, and possibly running the
`newaliases' program:

## mailman mailing list
mailman:              "|/var/lib/mailman/mail/mailman post mailman"
mailman-admin:        "|/var/lib/mailman/mail/mailman admin mailman"
mailman-bounces:      "|/var/lib/mailman/mail/mailman bounces mailman"
mailman-confirm:      "|/var/lib/mailman/mail/mailman confirm mailman"
mailman-join:         "|/var/lib/mailman/mail/mailman join mailman"
mailman-leave:        "|/var/lib/mailman/mail/mailman leave mailman"
mailman-owner:        "|/var/lib/mailman/mail/mailman owner mailman"
mailman-request:      "|/var/lib/mailman/mail/mailman request mailman"
mailman-subscribe:    "|/var/lib/mailman/mail/mailman subscribe mailman"
mailman-unsubscribe:  "|/var/lib/mailman/mail/mailman unsubscribe mailman"

Hit enter to notify mailman owner...

mail:~$ 

Be sure to copy and paste that into /etc/aliases, and then run “newaliases” to regenerate the aliases database for postfix.

Now, if all is good and well in the universe, we can restart mailman and things should kick into gear:

mail:~$ sudo /etc/init.d/mailman restart

Once I did this, I noticed in the logs that a message went through the mail queue and was delivered to my mailbox– indeed! It was the notification that I had created the 'mailman' list.

Looking good so far.

accessing the web interface

We're actually going to avoid the front-end mailman web interface as much as possible, but just for reference (with our current configuration), it WOULD be at:

http://mail.offbyone.lan/mailman/listinfo

but we'll all predominantly be accessing it via:

http://lab46.corning-cc.edu/mailman/listinfo

because that's how the world can access it.

useful resources

Establishing proxying on www to mail

Because the world will be accessing the mailman web frontend, it needs to be accessible via 'lab46.corning-cc.edu', ie www's web server.

To accomplish this, we set up proxying via apache to point any mailman-bound requests to mail at the appropriate location, so unless one knew better, one would think the mailman content was hosted locally on www.

First up, we need to enable the apache proxy module. There are several… we are after http proxying, so just to be on the safe side:

www:~$ sudo a2enmod proxy
www:~$ sudo a2enmod proxy_http

Messages confirming the module's enablement will be output (and likely yell saying it is already loaded with at least one of the steps– but hey, we're going for completeness).

Next, we need to allow proxying attempts to get through, which need to be directed at the /etc/apache2/mods-available/proxy.conf file (on www):

proxy.conf
<IfModule mod_proxy.c>
    ProxyRequests Off
 
    <Proxy *>
        AddDefaultCharset off
        Order deny,allow
        Allow from all
        ProxyFtpDirCharset UTF-8
    </Proxy>
    ProxyVia On
</IfModule>

Really the only change made here was the disabling of “Deny from all” and the explicit enabling of “Allow from all”.

Save, and exit.

Next file we're after is where actions on the existing web space are taking place… in time this is likely to evolve, but at the time of writing the following snippet was added at the end of /etc/apache2/httpd.conf on www.

httpd.conf
<IfModule mod_proxy.c>
    ProxyRequests Off
    <Location /mailman/>
        ProxyPass           http://mail.offbyone.lan/mailman/
        ProxyPassReverse    http://mail.offbyone.lan/mailman/
    </Location>
</IfModule>

This is where the real magic takes place– it tells us that any requests to the mailman directory off the documentroot should be directed to mail's web server, at the specified location (for convenience, I just made them match up, but this is only for aesthetics… it could literally be where-ever I'd like it to be).

And there you have it— save, exit, and restart apache.

I didn't confirm this, but everyone seems to say after enabling a module, to make it take effect, you need to do:

www:~$ sudo /etc/init.d/apache2 force-reload

versus just a 'restart' action. I'm pointing it out here because even if there's nothing extra to it than what would have happened during a restart, it still accomplishes the task we want, with some verbage giving us additional certainty that things are in fact being reloaded.

Creating a new list in mailman

I think it is important to highlight the various steps needed to create and utilize a mailing list in the current setup. Really everything is functional from the end-user perspective, but from the backend administrative point of view, we need to be mindful so that settings don't get autodetected incorrectly.

I think the bulk of the problem goes to mailman trying to be either secure or overly intelligent. Which certainly works out nicely when it is running in an ideal environment (ie the mailserver and webserver are on the same box AND there's no funky domain business going on).

So, without further ado, let's create the 'unix' list…

mail:~$ sudo newlist -u lab46.corning-cc.edu -e lab46.corning-cc.edu unix
Enter the email of the person running the list: wedge@lab46.corning-cc.edu
Initial unix password: 
To finish creating your mailing list, you must edit your /etc/aliases (or
equivalent) file by adding the following lines, and possibly running the
`newaliases' program:

## unix mailing list
unix:              "|/var/lib/mailman/mail/mailman post unix"
unix-admin:        "|/var/lib/mailman/mail/mailman admin unix"
unix-bounces:      "|/var/lib/mailman/mail/mailman bounces unix"
unix-confirm:      "|/var/lib/mailman/mail/mailman confirm unix"
unix-join:         "|/var/lib/mailman/mail/mailman join unix"
unix-leave:        "|/var/lib/mailman/mail/mailman leave unix"
unix-owner:        "|/var/lib/mailman/mail/mailman owner unix"
unix-request:      "|/var/lib/mailman/mail/mailman request unix"
unix-subscribe:    "|/var/lib/mailman/mail/mailman subscribe unix"
unix-unsubscribe:  "|/var/lib/mailman/mail/mailman unsubscribe unix"

Hit enter to notify unix owner...

mail:~$ 

Make sure to copy the requested text into /etc/aliases, then run “newaliases”.

Bam! Done.

Setting up the Certificates

To transact mail utilizing TLS, we need to sign ourselves some certificates and distribute them appropriately.

Creating the Certificates

The dovecot pages have information available, specifically: http://wiki.dovecot.org/SSL/CertificateCreation

The mkcert.sh file used is as follows:

#!/bin/sh
 
# Generates a self-signed certificate.
# Edit dovecot-openssl.cnf before running this.
 
OPENSSL=${OPENSSL-openssl}
SSLDIR=${SSLDIR-/etc/ssl}
OPENSSLCONFIG=${OPENSSLCONFIG-dovecot-openssl.cnf}
 
CERTDIR=$SSLDIR/certs
KEYDIR=$SSLDIR/private
 
CERTFILE=$CERTDIR/dovecot.pem
KEYFILE=$KEYDIR/dovecot.pem
 
if [ ! -d $CERTDIR ]; then
  echo "$SSLDIR/certs directory doesn't exist"
  exit 1
fi
 
if [ ! -d $KEYDIR ]; then
  echo "$SSLDIR/private directory doesn't exist"
  exit 1
fi
 
if [ -f $CERTFILE ]; then
  echo "$CERTFILE already exists, won't overwrite"
  exit 1
fi
 
if [ -f $KEYFILE ]; then
  echo "$KEYFILE already exists, won't overwrite"
  exit 1
fi
 
$OPENSSL req -new -x509 -nodes -config $OPENSSLCONFIG -out $CERTFILE -keyout $KEYFILE -days 3650 || exit 2
chmod 0600 $KEYFILE
echo 
$OPENSSL x509 -subject -fingerprint -noout -in $CERTFILE || exit 2

This changes from the default one specified in that I've updated it to sign the certificate for a period of 10 years, as opposed to the 365 days it would have done by default (some bit of knowledge we still need– how to update a certificate after it has expired? Probably just– create a new one, propagate it).

What's particularly neat are things like:

OPENSSL=${OPENSSL-openssl}

Which appear to mean— if the first item, the definition of $OPENSSL, is defined, use it, otherwise fall back to the thing on the other side of the - sign… in this case, 'openssl'.

dovecot-openssl.cnf is as follows:

[ req ]
default_bits = 1024
encrypt_key = yes
distinguished_name = req_dn
x509_extensions = cert_type
prompt = no
 
[ req_dn ]
# country (2 letter code)
C=US
 
# State or Province Name (full name)
ST=New York
 
# Locality Name (eg. city)
L=Corning
 
# Organization (eg. company)
O=Corning Community College
 
# Organizational Unit Name (eg. section)
OU=LAIR mail services
 
# Common Name (*.example.com is also possible)
CN=mail.offbyone.lan
 
# E-mail contact
emailAddress=haas@lab46.corning-cc.edu
 
[ cert_type ]
nsCertType = server

After running the script, /etc/ssl/certs/dovecot.pem, and /etc/ssl/private/dovecot.pem, will be created.

Configuring dovecot to use the Certificates

Referencing from http://wiki.dovecot.org/SSL/DovecotConfiguration

Seems straightforward enough– updated /etc/dovecot/dovecot.conf to reflect the SSL settings.

Configuring clients to utilize certificates

The following page has detailed information for configuring various clients:

http://wiki.dovecot.org/SSL/CertificateClientImporting

Basically, to get it happy on Lab46 I did the following:

mail:/etc/ssl/certs$ sudo openssl x509 -in dovecot.pem -hash -noout
052fb78e
mail:/etc/ssl/certs$ 

Then, on Lab46:

lab46:~$ sudo openssl version -d
OPENSSLDIR: "/usr/lib/ssl"
lab46:~$ cd /usr/lib/ssl/certs
lab46:/usr/lib/ssl/certs$ scp mail:/etc/ssl/certs/dovecot.pem 052fb78e.0

To make pine/alpine not prompt for the password each time:

lab46:~$ touch .pine-passfile
lab46:~$ chmod 600 .pine-passfile

On the next invocation of pine/alpine, it will prompt you to save it to disk. Affirmative!

Enabling users to actually use IMAP

When a user connects to their IMAP folders, a lock is created. This exists as a real process (named imap) on mail.offbyone.lan, owned by the particular user.

As a result, the user must be able to establish processes on mail.offbyone.lan

Default PAM settings need to make sure this is allowable.

Specifically, in /etc/pam_ldap.conf, the following lines need to be COMMENTED:

#pam_check_host_attr    yes
#pam_filter |(host=mail)(host=\*)

Otherwise, things will fail and seem to not work, making it seem like something is wrong with LDAP. No, nothing is wrong with LDAP, the user's just aren't able to get on the system to start a process.

Do this, and things light up beautifully.

Setting up new users

As part of the new user creation process, the /var/mail/$USER maildir directory will need to be created, and contents blessed appropriately.

Creating a maildir

A maildir folder appears to consist of the following data:

  • cur/
  • new/
  • tmp/

2 folders; “Sent” and “Trash”. At the base level, these folders exist as:

  • .Sent/
  • .Trash/

And each of them as their own cur/, new/, and tmp/ directories.

There are also index files, and these are handled and generated by the imap server process.

To establish a maildir for a new user, the process appears to be as simple as creating the necessary directories and setting permissions/ownership. Upon their first visit to the actual folder, the imap server process takes care of index generation.

mkmail
#!/bin/bash
#
# mkmail - create Maildir for specified user
#
 
# Set user to the first command-line argument
user="$1"
 
# Do a root check
rchk="`whoami | grep root | wc -l`"
if [ $rchk -eq 0 ]; then
    echo "Error! This script NEEDS to be run as root."
    exit 1
fi
 
# Ensure a user argument was provided
nchk="`echo $1 | wc -l`"
if [ $nchk -eq 0 ]; then
    echo "Error! Username MUST be given as first (and only) argument."
    exit 1
fi
 
# Ensure the user exists
uchk="`id $user 2>/dev/null | wc -l`"
if [ $uchk -eq 0 ]; then
    echo "Error! User MUST exist for script to run."
    exit 1
fi
 
cd /var/mail
for type in cur new tmp; do
    mkdir -p $user/$type $user/.Sent/$type $user/.Trash/$type
done
chmod -R 750 $user
chown -R $user:mail $user
chmod 700 $user

Converting users with mbox to maildir

Since the LAIR universe has their mail in mbox format, we'll need to extract that into the appropriate maildir format to drop it on the mail server.

The home directories are on NFS, so that's where our journey begins:

nfs1:/export/home$ sudo for user in `ls -l | grep lab46 | cut -c56-64`; do
> mkdir /tmp/maildir/$user
> chown -R $user:lab46 /tmp/maildir/$user
> chmod 700 /tmp/maildir/$user
> done

Next, we start the conversion process. Utilizing the nifty 'mb2md' script, we need to:

  • attack each user's /var/mail/$USER file
  • /export/home/$USER/mbox
  • AND be on the lookout for any extra mail folders (/export/home/$USER/mail/).

A good site on mb2md: http://batleth.sapienti-sat.org/projects/mb2md/

The first two are relatively straightforward. The last will most likely require manual intervention… I expect the number of occurrences of the last one to be minimal (and we shall soon find out if this is true).

Converting the /var/mail/$USER files

This script appears to work (run as root):

nfs1:/tmp/maildir$ for user in `ls -1 --color=no`; do
> sudo -u $user mb2md -s /export/lib/mail/$user -d /tmp/maildir/$user
> done

It spits out a lot of stuff… as some user's /var/mail/ files are empty, and others don't exist at all… but for those that DO exist. It extracts messages adequately.

Converting the /export/home/$USER/mbox files

Likely very similar (again, run as root):

nfs1:/tmp/maildir$ for user in `ls -1 --color=no`; do
> sudo -u $user mb2md -s /export/home/$user/mbox -d /tmp/maildir/$user
> done

Also looks like a winner.

Semi-hand pick through ~/mail

This one is going to be ugly, there's no way around that… but we can save ourselves some work (as *root*):

nfs1:/tmp/maildir$ for user in `ls -1 --color=no`; do
> ls -1 /export/home/$user/mail >/dev/null 2>/dev/null && echo $user >> userlist
> done

/tmp/maildir/userlist will now only contain the users that possess a ~/mail directory

Taking that, we filter it down a bit:

nfs1:/tmp/maildir$ for user in `cat userlist`; do
> /bin/ls -1 /export/home/$user/mail | grep -v saved | grep -v 'sent-mail' && echo "$user" >> got_something
> done

The new file 'got_something' will only contain users that have mail files other than saved-messages or sent-mail. This cuts down the list considerably, probably to 30-40… after analyzing each one by hand, it turns out that there are only 12 users that have actually stored messages.

12. Nice and simple :) I went through and manually changed any folders with spaces in them to be without spaces in their name (just in case)… only 2 users needed attention in this regard.

So, to take care of these remaining ones, I'm going to represent it as a bash script, because it is a nested for loop:

# run as root
for user in `cat got_something`; do
    for mfile in `/bin/ls /export/home/$user/mail | grep -v 'saved' | grep -v 'sent-mail'`; do
        sudo -u $user mb2md -s /home/$user/mail/$mfile -d /tmp/maildir/$user
    done
done

Ha! All users in group 'lab46' have now been converted over to maildir format!

We slap this on mail under /var/mail (tar cpf it up, untar it), and that part of the equation is done.

Bonus script: migrating the rest of group 'lair'

This combines all 3 actions into one easy script:

for user in alius dparson3 ian joe kinney synack; do
    mkdir /tmp/$user
    chown $user:lair /tmp/$user
    chmod 700 /tmp/$user
    chmod g+s /tmp/$user
    sudo -u $user mb2md -s /export/lib/mail/$user -d /tmp/$user
    sudo -u $user mb2md -s /export/home/$user/mbox -d /tmp/$user
    for mfile in `/bin/ls /export/home/$user/mail | grep -v 'saved' | grep -v 'sent-mail'`; do
        sudo -u $user mb2md -s /export/home/$user/mail/$mfile -d /tmp/$user
    done
done

Bonus script 2: backing up and removing old user mbox data

So we don't have any conflicts, I've backed up all the old mbox data and removed it from the user home directories. The following script accomplished this task:

cd /home
for user in `/bin/ls -1`; do
    tar cpf /tmp/$user-mbox-mail.tar $user/mbox $user/mail
    gzip -9 /tmp/$user-mbox-mail.tar
    rm -rf $user/mbox $user/mail/*
done

The pine issue

Some web-based info on configuring pine:

With the proper settings, pine becomes quite usable as an IMAP client.

I ended up creating a LAIR-custom .pinerc file that resides in nfs's /etc/skel (so when new users are created, they will inherit these settings).

The issue at hand is, what about all the existing users? Well, we'll just have to give them this file.

I took the hard line and just overwrote settings with this- I figured it would be easier in the long run that way.

So, here's the script (run as root on nfs):

cd /home
for user in `/bin/ls -1`; do
    rm -f $user/.pinerc 2>/dev/null
    cat /etc/skel/.pinerc | sed -e "s/=USER/=$user/g" > $user/.pinerc
    chmod 600 $user/.pinerc
    chown $user:lab46 $user/.pinerc
done

I then went in and re-chgrp'ed the .pinerc files of users in group 'lair'. Basically: DONE.

Creating /var/mail partition disk image

Although we were safe for the moment, I realized that since maildir relies heavily upon the existence of many small files, we could at some unsuspecting point in the future, experience a situation where there is still disk space available, but no free inodes to create new files.

So, opting to spend some time in the present to prevent a potential future headache, I made a 4GB disk image that mail mounts as /var/mail, hosting all the user maildirs.

The process to do that was as follows:

Create disk image on Xen host

Straightforward, just as we've always done:

sokraits:/xen/images$ sudo dd if=/dev/zero of=mailvar.disk bs=1M count=4096
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB) copied, 77.8013 s, 55.2 MB/s
sokraits:/xen/images$ 

Format disk image with ext3, optimizing for more inodes

Instead of the default ext3 settings (which usually default to 8192 bytes per inode), we're going to aim for 4096 bytes per inode– basically, a little less free space to get about twice as many inodes:

sokraits:/xen/images$ sudo mkfs.ext3 -b 4096 -i 4096 -m 1 -O dir_index,filetype,has_journal,sparse_super mailvar.disk 
mke2fs 1.41.3 (12-Oct-2008)
mailvar.disk is not a block special device.
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
1048576 inodes, 1048576 blocks
10485 blocks (1.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=1073741824
32 block groups
32768 blocks per group, 32768 fragments per group
32768 inodes per group
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736

Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 22 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
sokraits:/xen/images$ 

Configure mail VM to see disk image

Editing /xen/conf/mail.cfg, we add an entry so mail can see the new disk image. Well make it visible as /dev/xvda2:

disk        = [ 'file:/xen/images/mail.disk,xvda1,w',
                'file:/xen/images/mailvar.disk,xvda2,w',
                'file:/xen/images/mail.swap,xvda3,w'  ]

Changing existing configs on mail

We'll need to make a change to /etc/fstab so it doesn't get confused:

# /etc/fstab: static file system information.
#
# <file system> <mount point>   <type>  <options>              <dump>  <pass>
proc            /proc           proc    defaults               0       0
/dev/xvda1      /               ext3    noatime,nodiratime,errors=remount-ro 0 1
/dev/xvda2      /var/mail       ext3    noatime,nodiratime,errors=remount-ro 0 2
/dev/xvda3      none            swap    sw                     0       0

Note that the topmost ###LAIRCONF### was removed, so any future updates to lair-std won't overwrite our fstab file (since we just effectively changed it from LAIR defaults).

Data Transfer

I opted for the least hoop-hopping method as possible– shutting down mail, local loop mounting the two images, and copying the data:

Shutdown mail VM

sokraits:~$ sudo xm shutdown mail

… wait, run “xm list” to verify it is no longer running …

Mount Images

Mount the two disk images:

sokraits:~$ sudo mount -o loop /xen/images/mail.disk /media
sokraits:~$ sudo mount -o loop /xen/images/mailvar.disk /mnt

Copy Data

And then, copy preserving all permissions:

sokraits:~$ sudo cp -a /media/var/mail/* /mnt/

Just to be on the safe side, we'll temporarily back up the maildir data before emptying the mount point:

sokraits:~$ sudo cp -a /media/var/mail /media/var/mailbak
sokraits:~$ sudo rm -rf /media/var/mail/*

/var/mail on mail will now be empty, so it can mount /dev/xvda2 to /var/mail on boot.

Unmount Disk Images

Never forget to unmount before booting:

sokraits:~$ sudo umount /media
sokraits:~$ sudo umount /mnt

Boot up mail once again

Operation complete! Boot up mail, verify /var/mail mounts, and if data appears intact, we can delete /var/mailbak.

sokraits:~$ sudo xm create -c /xen/conf/mail.cfg
haas/system/mail.offbyone.lan.txt · Last modified: 2011/02/19 16:38 by 127.0.0.1