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

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


#  create passwords
function genpasswd {
head -c 32 /dev/urandom | md5sum | awk '{ print $1 }'
}
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"`

#  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 }' /etc/dovecot-pgsql.conf`
fi

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

#  figure out dovecot version
DOVECOTVER=`rpm -q --queryformat '%{version}' dovecot`
DOVECOTVER="${DOVECOTVER%%.*}"

VPOSTMASTER_UID=`grep '^vpostmaster:' /etc/passwd | awk -F: '{ print $3 }'`
VPOSTMASTER_GID=`grep '^vpostmaster:' /etc/passwd | awk -F: '{ print $4 }'`
(  # run following commands in umasked subshell for added password security
	umask 077
	if [ ! -f /etc/dovecot-pgsql.conf ]
	then
		if [ "$DOVECOTVER" -ge 1 ]
		then
			echo "driver = pgsql" >/etc/dovecot-pgsql.conf
		else
			:>/etc/dovecot-pgsql.conf
		fi
		echo "connect = host=localhost dbname=vpostmaster user=imapserver" \
	  			" password=$PASSWORD_IMAPSERVER" >>/etc/dovecot-pgsql.conf
		echo "default_pass_scheme = CRYPT" >>/etc/dovecot-pgsql.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'" >>/etc/dovecot-pgsql.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'" >>/etc/dovecot-pgsql.conf
		chown root /etc/dovecot-pgsql.conf
		chmod 400 /etc/dovecot-pgsql.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
PGVER=`rpm -q --queryformat '%{version}' postgresql`
PGVER="${PGVER%%.*}"
HOSTLINE='host all all 127.0.0.1 255.255.255.255 password'
if [ "$PGVER" -le 7 -o -z "$PGVER" ]
then
	if ! grep -q '^tcpip_socket = true' /var/lib/pgsql/data/postgresql.conf
	then
		bkup /var/lib/pgsql/data/postgresql.conf
		echo "tcpip_socket = true" >> /var/lib/pgsql/data/postgresql.conf
	fi
else
	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
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
RARG=""
createuser -? 2>&1 | grep -q no-createrole && RARG=-R
su postgres -c "cd /tmp; createuser $RARG -A -D -q postfix"
su postgres -c "cd /tmp; createuser $RARG -A -D -q vpostmaster"
su postgres -c "cd /tmp; createuser $RARG -A -D -q vpostmasterwww"
su postgres -c "cd /tmp; createuser $RARG -A -D -q imapserver"

#  initialize postgres 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=/usr/share/doc/vpostmaster-*/schema.sql
	if [ ! -f "$SCHEMAFILE" -a -f schema.sql ]
	then
		SCHEMAFILE=`mktemp -tp /var/tmp schema.XXXXXXXXXX`
		if [ -z "$SCHEMAFILE" ]
		then
			echo "Cannot create tempfile"
			exit 1
		fi
		cp schema.sql "${SCHEMAFILE}"
	fi
	chown postgres "${SCHEMAFILE}"
	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

#  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
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
	bkup "/etc/dovecot.conf"
	if [ "$DOVECOTVER" -ge 1 ]
	then
		cat >/etc/dovecot.conf <<@EOF
#  vPostMaster Configuration
protocol imap {
}

protocol pop3 {
}

auth default {
  mechanisms = plain
  passdb sql {
     args = /etc/dovecot-pgsql.conf
  }
  userdb sql {
     args = /etc/dovecot-pgsql.conf
  }
  user = root
}

default_mail_env = maildir:~/Maildir/
first_valid_uid = 100
protocols = imap imaps pop3 pop3s
@EOF
	else
		cat >>/etc/dovecot.conf <<@EOF

#  vPostMaster Configuration
default_mail_env = maildir:~/Maildir/
auth_userdb = pgsql /etc/dovecot-pgsql.conf
auth_passdb = pgsql /etc/dovecot-pgsql.conf
first_valid_uid = 100
protocols = imap imaps pop3 pop3s
@EOF
	fi
fi
service dovecot restart
chkconfig dovecot on

service spamassassin restart
chkconfig spamassassin on

#  set up saslauthd
if ! grep -q '#vpostmaster' /etc/sysconfig/saslauthd
then
	bkup "/etc/sysconfig/saslauthd"
	echo >>/etc/sysconfig/saslauthd
	echo '#vpostmaster' >>/etc/sysconfig/saslauthd
	echo MECH=rimap >>/etc/sysconfig/saslauthd
	echo 'FLAGS="-r -O 127.0.0.1"' >>/etc/sysconfig/saslauthd
fi
if ! grep -q '#vpostmaster' /usr/lib/sasl2/smtpd.conf
then
	bkup "/usr/lib/sasl2/smtpd.conf"
	echo >>/usr/lib/sasl2/smtpd.conf
	echo '#vpostmaster' >>/usr/lib/sasl2/smtpd.conf
	echo 'mech_list: plain login' >>/usr/lib/sasl2/smtpd.conf
fi
service saslauthd restart
chkconfig saslauthd 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
