#!/bin/bash
#
# (c) 2005-2012 tummy.com, ltd.
#
#  Set up vPostMaster on the system, including the database and config
#  files.  For CentOS 6 systems.

PATH=$PATH:/usr/sbin:/sbin

DOVECOT_SQL_CONF=/etc/dovecot/dovecot-sql.conf.ext


#  create passwords
function genpasswd {
PW=`( head -c 32 /dev/urandom | base64 | sed 's/[^A-Za-z0-9]//g' ) 2>/dev/null`
if [ -z "$PW" ]; then
	head -c 32 /dev/urandom | md5sum | awk '{ print $1 }'
else
	echo "$PW"
fi
}
function cryptpasswd {
python -c "import crypt; print crypt.crypt('$1', '$2')"
}
function bkup {
[ -f "$1" -a ! -f "$1".vpostmaster ] && cp "$1" "$1".vpostmaster
}
PASSWORD_POSTFIX=`genpasswd`
PASSWORD_VPOSTMASTER=`genpasswd`
PASSWORD_VPOSTMASTERWWW=`genpasswd`
PASSWORD_IMAPSERVER=`genpasswd`
PASSWORD_SUPERUSER=`genpasswd | cut -c 1-8`
SALT=`genpasswd | cut -c 1-2`
CRYPTED_SUPERUSER=`cryptpasswd "$PASSWORD_SUPERUSER" "$SALT"`

#  create database
if [ ! -d /var/lib/pgsql/data/base ]; then
	/etc/init.d/postgresql initdb
	/etc/init.d/postgresql restart
fi
if [ ! -d /var/lib/pgsql/data/base ]; then
	echo 'Initial database directory "/var/lib/pgsql/data/base" does not exist.'
	echo 'Aborting.'
	exit 1
fi

#  move wwwdb.conf out of the way if it's the distribution copy
head -1 /usr/lib/vpostmaster/etc/wwwdb.conf 2>/dev/null \
		| grep -q "password=secret" \
		&& mv /usr/lib/vpostmaster/etc/wwwdb.conf \
			/usr/lib/vpostmaster/etc/wwwdb.conf.orig

# read old passwords if set
if [ -f /usr/lib/vpostmaster/etc/wwwdb.conf ]
then
	PASSWORD_VPOSTMASTERWWW=`awk -F '=' '/^dbname/ { print $5 }' \
			/usr/lib/vpostmaster/etc/wwwdb.conf`
fi
if [ -f /usr/lib/vpostmaster/etc/vpostmaster-db.conf ]
then
	PASSWORD_VPOSTMASTER=`awk -F '=' '/^dbname/ { print $5 }' \
			/usr/lib/vpostmaster/etc/vpostmaster-db.conf`
fi

#  write passwords
(  # run following commands in a umasked subshell for added password security
	umask 077
	if [ ! -f /usr/lib/vpostmaster/etc/wwwdb.conf ]
	then
		echo "dbname=vpostmaster host=127.0.0.1 user=vpostmasterwww " \
				"password=${PASSWORD_VPOSTMASTERWWW}" \
				>/usr/lib/vpostmaster/etc/wwwdb.conf
	fi
	chown vpostmaster:apache /usr/lib/vpostmaster/etc/wwwdb.conf
	chmod 440 /usr/lib/vpostmaster/etc/wwwdb.conf
	if [ ! -f /usr/lib/vpostmaster/etc/vpostmaster-db.conf ]
	then
		echo "dbname=vpostmaster host=127.0.0.1 user=vpostmaster " \
				"password=${PASSWORD_VPOSTMASTER}" \
				>/usr/lib/vpostmaster/etc/vpostmaster-db.conf
	fi
	chown vpostmaster:root /usr/lib/vpostmaster/etc/vpostmaster-db.conf
	chmod 400 /usr/lib/vpostmaster/etc/vpostmaster-db.conf
)

#  dovecot SQL file
#  NOTE: variable cannot happen inside of a subshell or it won't be
#    readable later
if [ -f /etc/dovecot-pgsql.conf ]
then
	PASSWORD_IMAPSERVER=`awk -F '=' \
			'/^connect/ { print $6 }' "$DOVECOT_SQL_CONF"`
fi

if [ -f /etc/postfix/vpm-domains ]
then
	PASSWORD_POSTFIX=`awk -F '=' '/^password/ { print $2 }' \
			/etc/postfix/vpm-domains`
fi

VPOSTMASTER_UID=`grep '^vpostmaster:' /etc/passwd | awk -F: '{ print $3 }'`
VPOSTMASTER_GID=`grep '^vpostmaster:' /etc/passwd | awk -F: '{ print $4 }'`

#  CentOS 6 needs dovecot-pgsql
yum -y install dovecot-pgsql
(  # run following commands in umasked subshell for added password security
	umask 077
	if [ ! -f "$DOVECOT_SQL_CONF" ]
	then
		echo "driver = pgsql" >"$DOVECOT_SQL_CONF"
		echo "connect = host=localhost dbname=vpostmaster user=imapserver" \
	  			" password=$PASSWORD_IMAPSERVER" >>"$DOVECOT_SQL_CONF"
		echo "default_pass_scheme = CRYPT" >>"$DOVECOT_SQL_CONF"
		echo "password_query = SELECT users.cryptedpasswd AS password " \
				"FROM users WHERE users.name = '%n' AND users.domainsname = '%d'" \
				"AND users.active = 't' AND (SELECT active FROM domains" \
				"WHERE name = '%d') = 't'" >>"$DOVECOT_SQL_CONF"
		echo "user_query = SELECT userdir AS home, $VPOSTMASTER_UID" \
	  			"AS uid, $VPOSTMASTER_GID AS gid FROM users" \
				"WHERE users.name = '%n' AND users.domainsname = '%d'" \
				"AND users.active = 't' AND (SELECT active FROM domains" \
				"WHERE name = '%d') = 't'" >>"$DOVECOT_SQL_CONF"
		chown root "$DOVECOT_SQL_CONF"
		chmod 400 "$DOVECOT_SQL_CONF"
	fi

	#  postfix SQL integration
	if [ ! -f /etc/postfix/vpm-domains ]
	then
		echo "user=postfix" >/etc/postfix/vpm-domains
		echo "password=${PASSWORD_POSTFIX}" >>/etc/postfix/vpm-domains
		echo "hosts=localhost" >>/etc/postfix/vpm-domains
		echo "dbname=vpostmaster" >>/etc/postfix/vpm-domains
		echo "table=domains" >>/etc/postfix/vpm-domains
		echo "select_field='X'" >>/etc/postfix/vpm-domains
		echo "where_field=name" >>/etc/postfix/vpm-domains
		echo "additional_conditions = and active = 't'" \
				>>/etc/postfix/vpm-domains
		chown root /etc/postfix/vpm-domains
		chmod 400 /etc/postfix/vpm-domains
	fi
)

#  set up the PostgreSQL data directory if it isn't already
if [ ! -f /var/lib/pgsql/data/postgresql.conf ]
then
	service postgresql restart
fi

#  reconfigure postgres to allow local TCP access
HOSTLINE='host all all 127.0.0.1/32 md5'
if ! grep -q "^listen_addresses = '127.0.0.1'" \
		/var/lib/pgsql/data/postgresql.conf
then
	bkup /var/lib/pgsql/data/postgresql.conf
	echo "listen_addresses = '127.0.0.1'" \
			>> /var/lib/pgsql/data/postgresql.conf
fi
if ! grep -q '^'"$HOSTLINE" /var/lib/pgsql/data/pg_hba.conf
then
	bkup /var/lib/pgsql/data/pg_hba.conf
	sed --in-place -r 's/^(host *all *all *127.0.0.1.*ident.*)$/#\1/' \
			/var/lib/pgsql/data/pg_hba.conf
	echo "$HOSTLINE" >>/var/lib/pgsql/data/pg_hba.conf
fi

#  start up postgresql
chkconfig postgresql on
service postgresql restart

#  wait until postgres has actually started up
for (( x=0; x<30; x++ ))
do
	if su postgres -c \
		"cd /tmp; psql -d template1 -At -c 'SELECT count(*) FROM pg_proc'" \
		2>/dev/null
	then
		break
	fi
	sleep 1
done

# create users
for PG_USERNAME in postfix vpostmaster vpostmasterwww imapserver; do
	su postgres -c "cd /tmp; createuser -R -D -A -S $PG_USERNAME"
done

#  load schema if needed
DBEXIST=`su postgres -c \
		"cd /tmp; psql -d vpostmaster -At -c 'SELECT count(*) FROM meta'" \
				2>/dev/null`
if [ "$DBEXIST" != 1 ]
then
	#  load schema
	SCHEMAFILE=`rpm -ql vpostmaster | grep schema.sql`
	su postgres -c "cd /tmp; sh ${SCHEMAFILE}"
fi

#  upgrade the database, apache, postfix, and dovecot should be 
#  restarted shortly
/usr/lib/vpostmaster/bin/vpm-dbupgrade --force

#  get or set superuser password
if [ -f /usr/lib/vpostmaster/etc/superuser ]
then
	PASSWORD_SUPERUSER=`awk '{ print $4 }' /usr/lib/vpostmaster/etc/superuser`
	CRYPTED_SUPERUSER=`cryptpasswd "$PASSWORD_SUPERUSER" "$SALT"`
else
	(  # run in subshell for added password security
		umask 077
		echo "superuser password is: $PASSWORD_SUPERUSER" \
				>/usr/lib/vpostmaster/etc/superuser
	)
fi

#  find mailman user name
MAILMANUSER=
grep -q '^list:' /etc/passwd && MAILMANUSER=list
grep -q '^mailman:' /etc/passwd && MAILMANUSER=mailman
[ -z "$MAILMANUSER" ] && MAILMANUSER=mailman

#  update user passwords and create superuser account
(
	echo "ALTER USER postfix WITH PASSWORD '${PASSWORD_POSTFIX}';"
	echo "ALTER USER vpostmaster WITH PASSWORD '${PASSWORD_VPOSTMASTER}';"
	echo "ALTER USER vpostmasterwww WITH PASSWORD
			'${PASSWORD_VPOSTMASTERWWW}';"
	echo "ALTER USER imapserver WITH PASSWORD '${PASSWORD_IMAPSERVER}';"
	echo "DELETE FROM adminusers WHERE name='superuser';"
	echo "INSERT INTO adminusers ( name, issuperuser, cryptedpasswd )
			VALUES ( 'superuser', 't', '$CRYPTED_SUPERUSER' );"
	echo "UPDATE meta SET mailmanusername = '$MAILMANUSER';"
) | su postgres -c "cd /tmp; psql -d vpostmaster"

#  configure to handle config_local.php broken by default
SQUIRRELMAILCONF=/etc/squirrelmail/config_local.php
if [ -f "$SQUIRRELMAILCONF" ] && grep -q '^?>' "$SQUIRRELMAILCONF"
then
	bkup "$SQUIRRELMAILCONF"
	sed -i 's/^\?>//' "$SQUIRRELMAILCONF"
	echo "?>" >> "$SQUIRRELMAILCONF"
fi

#  restart apache
chkconfig httpd on
service httpd restart

#  set up sudoers file
if ! grep -q "vpostmaster helper" /etc/sudoers
then
	bkup "/etc/sudoers"
	cat >>/etc/sudoers <<@EOF

#  vpostmaster helper, allow Apache to run it as vpostmaster
apache       ALL=(vpostmaster) NOPASSWD: /usr/lib/vpostmaster/bin/vpm-wwwhelper
apache       ALL=(root) NOPASSWD: /usr/lib/vpostmaster/bin/vpm-wwwhelper
@EOF
	echo "vpostmaster  ALL=($MAILMANUSER) NOPASSWD: " \
			"/usr/lib/mailman/mail/mailman" >>/etc/sudoers
fi

#  disable SELINUX
if ! grep -q '^SELINUX=disabled' /etc/sysconfig/selinux; then
	echo '' >>/etc/sysconfig/selinux
	echo '#  for vPostMaster' >>/etc/sysconfig/selinux
	echo 'SELINUX=disabled' >>/etc/sysconfig/selinux
fi

#  NOTE: Disabled, this blows up pretty spectacularly
##  set up SELinux if necessary
#if [ -f /etc/sysconfig/selinux ] && ! grep -q 'SELINUX=disabled' &&
#		! grep -q httpd_sys_script_t \
#			/etc/selinux/strict/src/policy/domains/misc/local.te
#then
#	cat >>/etc/selinux/strict/src/policy/domains/misc/local.te <<@EOF
#allow httpd_sys_script_t self:capability { setgid setuid };
#allow httpd_sys_script_t self:process setrlimit;
#allow httpd_sys_script_t shadow_t:file read;
#allow postgresql_t tmp_t:file read;
#@EOF
#	( cd /etc/selinux/strict/src/policy; make load )
#fi

#  set up Postfix
if ! grep -q 'vPostMaster setup' /etc/postfix/main.cf
then
	bkup "/etc/postfix/main.cf"
	if postconf -m | grep -q '^pgsql$'; then
		VMB_DOMAINS_MAP=pgsql:/etc/postfix/vpm-domains
	else
		VMB_DOMAINS_MAP=hash:/etc/postfix/vpm-domains-dump
	fi
	cat >>/etc/postfix/main.cf <<@EOF

#  vPostMaster setup
inet_interfaces = all
virtual_transport = vpm-pftransport
vpm-pftransport_destination_recipient_limit = 1
virtual_mailbox_domains = $VMB_DOMAINS_MAP
smtpd_sasl_auth_enable = yes
smtpd_sasl_application_name = smtpd
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
broken_sasl_auth_clients = yes
#always_bcc = archive_address@example.com

smtpd_recipient_restrictions =
	permit_mynetworks
	permit_sasl_authenticated
	check_policy_service unix:private/vpm-pfpolicy
	reject_unauth_destination
@EOF
fi

#  don't do local delivery for the hostname in case it matches the
#  one of the vPostMaster domains, use vPostMaster instead
if egrep '^mydestination.*\$myhostname' /etc/postfix/main.cf
then
	sed --in-place -r 's/^(mydestination.*)\$myhostname,? ?/\1/' \
			/etc/postfix/main.cf
fi

if ! grep -q 'vPostMaster setup' /etc/postfix/master.cf
then
	bkup "/etc/postfix/master.cf"
	cat >>/etc/postfix/master.cf <<@EOF

#  vPostMaster setup
vpm-pfpolicy  unix  -       n       n       -       5       spawn
  user=vpostmaster argv=/usr/lib/vpostmaster/postfix/vpm-pfpolicy
vpm-pftransport unix  -       n       n       -       5       pipe
    flags=qhu user=vpostmaster argv=/usr/lib/vpostmaster/postfix/vpm-pftransport \$sender \$recipient
submission inet n       -       n       -       -       smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
@EOF
fi
chkconfig postfix on
service postfix restart

#  set up dovecot
if ! grep -q 'vPostMaster Configuration' /etc/dovecot.conf
then
	cat >/etc/dovecot/conf.d/auth-vpostmaster.conf <<@EOF
#  vPostMaster Configuration
auth_mechanisms = plain

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
}

passdb {
   driver = sql
   args = /etc/dovecot/vpostmaster-pgsql.conf
}
userdb {
   driver = sql
   args = /etc/dovecot/vpostmaster-pgsql.conf
}

mail_location = maildir:~/Maildir/
first_valid_uid = 100
@EOF
	cat >/etc/dovecot/vpostmaster-pgsql.conf <<@EOF
driver = pgsql
connect = host=localhost dbname=vpostmaster user=imapserver password=$PASSWORD_IMAPSERVER
default_pass_scheme = CRYPT
password_query = SELECT users.cryptedpasswd AS password FROM users WHERE users.name = '%n' AND users.domainsname = '%d' AND users.active = 't' AND (SELECT active FROM domains WHERE name = '%d') = 't'
user_query = SELECT userdir AS home, $VPOSTMASTER_UID AS uid, $VPOSTMASTER_GID AS gid FROM users WHERE users.name = '%n' AND users.domainsname = '%d' AND users.active = 't' AND (SELECT active FROM domains WHERE name = '%d') = 't'
@EOF
fi
service dovecot restart
chkconfig dovecot on

service spamassassin restart
chkconfig spamassassin on

#  set up home directory
if [ ! -d ~vpostmaster/.spamassassin ]
then
	mkdir ~vpostmaster/.spamassassin
	chown vpostmaster:vpostmaster ~vpostmaster/.spamassassin
	chmod 700 ~vpostmaster/.spamassassin
fi

#  set up mailman paths
[ -x /usr/lib/vpostmaster/bin/setup-mailman ] && \
		su postgres -c /usr/lib/vpostmaster/bin/setup-mailman

#  fix sudoers to not require a tty
if grep -q '^Defaults.*requiretty' /etc/sudoers
then
	sed -i 's/^\(Defaults.*requiretty.*\)$/#\1/' /etc/sudoers
fi
