#!/bin/bash

LOGIN=""
GID=""
HOMEDIR=""
COMFILE=`cygpath $COMSPEC`
COMPATH=`dirname $COMFILE`
USERS=`getent group 545 | awk -F: '{printf $1}'`
ADMINS=`getent group 544 | awk -F: '{printf $1}'`
VERSION=`uname | awk -F_ '{print $2}'`
HOST=`hostname`
DOMAIN=""
WINDOMAIN="$HOST"
FQDN=""
PREVIEW=""

function welcome {
	echo
	echo "You have almost finished installing the Sendmail Mail Transfer Agent. If you "
	echo "are running Cygwin XP, 2002, or older, the server will run 'out of the box'. "
	echo "You can start it by entering:"
	echo
	printf -- "\tnet start sendmail\n"
	echo
	echo "If you are running Cygwin 2003, 7 or newer, you will have to take some "
	echo "extra steps to get it running. You will need the following:"
	echo
	echo "1. A super-user which is a member of the '$ADMINS' group"
	echo "2. Grant the 'SeServiceLogonRight' to this user"
	echo "3. Grant the 'SeAssignPrimaryTokenPrivilege' to this user"
	echo "4. Configure the 'sendmail' Service to start with this user"
	echo
	echo "If you want this done automatically, re-start this script with the 'install'"
	echo "command:"
	echo
	printf -- "\tsendmail-config install\n"
	echo
	echo "Use the --help option for available configuration options. For extensive "
	echo "Sendmail configuration options view the /usr/share/sendmail/README file."
}
function need_FQDN {
	echo
	echo "Your system does not seem to have a fully qualified domain name (FQDN). Sendmail"
	echo "needs this to work properly. The proposed domain name is: $DOMAIN "
	echo
	echo "To attach this domain to your host name ($HOST), open the 'System Properties' "
	echo "window, using the following command:"
	echo
	printf -- "\tcmd /c sysdm.cpl\n"
	echo
	echo "Select the 'Computer Name' tab, click 'Change' and then 'More options...'. Here "
	echo "you should be able to change the 'Primary DNS suffix' of your computer. Change "
	echo "it to: $DOMAIN"
	echo
	echo "You will need to restart your computer. After that, run this script again:"
	echo
	printf -- "\tsendmail-config\n"
}
function install_FQDN {
	if ! [[ `grep -i "\b$FQDN\b" /etc/hosts` ]]; then
		echo "Adding hostname: $FQDN [127.0.1.1]"
		printf "127.0.1.1\t%s\r\n" $FQDN >>/etc/hosts
	fi
}
function install_aliases {
	if ! [ -f /etc/mail/aliases.db ]; then
		newaliases
	fi
}
function find_FQDN {
	DOMAIN=`ipconfig | grep "\bDNS\b" | awk -F": " '$NF {printf $NF; exit}'`
	FQDN=`printf "%s.%s" $HOST $DOMAIN`
}
function check_hostname {
	FULLHOST=`$COMPATH/net config workstation | grep " $HOST\b" | awk '{printf $NF; exit}'`
	FQDN=`nslookup -type=A "$HOST" 2>/dev/null | awk '$NF ~ /\y'"$FULLHOST"'\y/ {printf $NF}'`
	if [ "$FQDN" ]; then		#lookup succeeded
		return
	elif [[ $FULLHOST == *.* ]]; then		#full host name contains dots
		FQDN="$FULLHOST"
		install_FQDN
	else
		find_FQDN
		return 1
	fi
}

#-------------------------------------------------

# MTA binary ownership
MBINOWN="SYSTEM"
MBINGRP="$USERS"

# owner of MSP queue
MSPQOWN="smmsp"

# Setgid binary ownership/permissions
GBINOWN="SYSTEM"
GBINGRP="mail"
GBINMODE="2555"

# User, system, MTA binaries
UBINDIR="/usr/bin"
SBINDIR="/usr/sbin"
MBINDIR="/usr/libexec"

function install_homedir {
	if [ $PREVIEW ]; then
		printf -- ' mkdir "%s"\n' "$1"
	elif ! [ -d "$1" ]; then
		mkdir "$1"
		chown "$2" "$1"
	fi
}
function import_login {
	pwd=`mkpasswd -l -u "$1"`
	if [ $GID ]; then
		pwd=`echo "$pwd" | awk -F: -v GID=$GID '{OFS=FS; $4=GID; print}'`
	fi
	if [ "$HOMEDIR" ]; then
		pwd=`echo "$pwd" | awk -F: -v DIR="$HOMEDIR" '{OFS=FS; $6=DIR; print}'`
	fi
	if [ $PREVIEW ]; then
		echo "$pwd"
	else
		echo "$pwd" >>/etc/passwd
	fi
}
function useradd {
	if [ $PREVIEW ]; then
		printf -- ' Windows: net user /expires:never "%s" /add\n' "$2"
		printf -- ' Windows: net localgroup "%s" "%s" /add\n' "$1" "$2"
		echo " Windows: wmic USERACCOUNT WHERE Name='$2' SET PasswordExpires=FALSE"
	else
		$COMPATH/net user /expires:never "$2" /add >/dev/null
		echo "wmic USERACCOUNT WHERE Name='$2' SET PasswordExpires=FALSE" | cmd /K >/dev/null
		$COMPATH/net localgroup "$1" "$2" /add >/dev/null
	fi
	[ $? -ne 0 ] || import_login "$2"
}
function usermod_lock {
	if [ $PREVIEW ]; then
		printf -- ' Windows: net localgroup "%s" "%s" /delete\n' "$USERS" "$1"
	else
		$COMPATH/net localgroup "$USERS" "$1" /delete >/dev/null
		editrights -u "$1" -a SeDenyInteractiveLogonRight
	fi
}
function usermod_cookie {
	if [ $PREVIEW ]; then
		printf -- ' Windows: net user "%s" "%s"\n' "$2" "$1"
	else
		$COMPATH/net user "$2" "$1" >/dev/null
	fi
}
function install_multiroot {
	if ! editrights -u "$ADMINS" -t SeCreateTokenPrivilege; then
		editrights -u "$ADMINS" -a SeCreateTokenPrivilege
		gpupdate /Force /Logoff >/dev/null
	fi
}
function install_service {
	if ! [[ `cygrunsrv -Q sendmail 2>/dev/null` ]]; then
		cygrunsrv -I sendmail -d "CYGWIN sendmail" -p $MBINDIR/sendmail.exe -a "-L sm-mta -bD -q30m" -t manual -o
	fi
}
function install_root_user {
	LOGIN="root"
	GID=544
	HOMEDIR="/root"
	if ! [ "$cookie" ]; then
		printf "Enter password for '%s': " "$LOGIN"
		read cookie
	fi
	if ! [[ `getent passwd "$LOGIN"` ]]; then
		echo "Creating super-user '$LOGIN'"
		install_homedir "$HOMEDIR" SYSTEM
		useradd "$ADMINS" "$LOGIN"
		usermod_lock "$LOGIN"
		if ! [ $PREVIEW ]; then
			editrights -u "$LOGIN" -a SeServiceLogonRight
			editrights -u "$LOGIN" -a SeDenyInteractiveLogonRight
			editrights -u "$LOGIN" -a SeAssignPrimaryTokenPrivilege
		fi
	fi
	usermod_cookie "$cookie" "$LOGIN"
}
function install_msp_user {
	LOGIN="$MSPQOWN"
	GID=`getent group "$GBINGRP" | awk -F: '{printf $3}'`
	HOMEDIR="/var/empty"
	if ! [[ `getent passwd "$LOGIN"` ]]; then
		echo "Creating Sendmail unprivileged user '$LOGIN'"
		install_homedir "$HOMEDIR" SYSTEM
		useradd "$GBINGRP" "$LOGIN"
		usermod_lock "$LOGIN"
		if ! [ $PREVIEW ]; then
			editrights -u "$LOGIN" -a SeCreateTokenPrivilege
			editrights -u "$LOGIN" -a SeImpersonatePrivilege
		fi
	fi
}
function install_conf {
	echo "Modifying Sendmail's configuration (/usr/share/sendmail/cf/sendmail.mc)"
	if [ $PREVIEW ]; then
		echo " cd /usr/share/sendmail/cf"
		printf -- " echo \" define(\`confRUN_AS_USER', \`$LOGIN')dnl\" >>sendmail.mc\n"
		echo " make install-cf"
		echo " pkill -HUP sendmail"
	else
		cd /usr/share/sendmail/cf/
		echo "define(\`confRUN_AS_USER', \`$LOGIN')dnl" >>sendmail.mc
		make install-cf >/dev/null
		pkill -HUP sendmail
	fi
}

#-------------------------------------------------

function syntax {
	printf 'Usage: %s [COMMAND] [options]\n' `basename $0`
	echo
	echo "Commands:"
	printf -- " install\t\t\tConfigure the 'sendmail' Service to start with the \n"
	printf -- "\t\t\t\t'root' LOGIN. This user will be created if it does not \n"
	printf -- "\t\t\t\texist. Use the --login option to specify an existing LOGIN.\n"
	printf -- " setuid\t\t\t\tMake the queue runner setuid '$MSPQOWN' (privilege separation)\n"
	printf -- " setgid\t\t\t\tMake the queue runner setgid '$GBINGRP'\n"
	printf -- " setalt\t\t\t\tMake Sendmail the default MSP in the Alternatives system\n"
	echo
	echo "Options:"
	printf -- " -l, --login LOGIN\t\tSelect LOGIN with COMMAND\n"
	printf -- " -g, --group GROUP\t\tSelect GROUP with COMMAND\n"
	printf -- " -d, --domain DOMAIN\t\tSelect Windows DOMAIN with COMMAND\n"
	printf -- " -p, --password PASSWORD\tUse PASSWORD with LOGIN\n"
	printf -- " -h, --help\t\t\tThis help text\n"
	printf -- " -W, --windows\t\t\tPreview actual Windows commands without executing\n"
}

command=""
cookie=""

function set_login {
	if ! [[ `getent passwd "$1"` ]]; then
		echo "$1: No such user."
		exit 1
	fi
	LOGIN="$1"
}
function set_group {
	id=`getent group "$1" | awk -F: '{printf $3}'`
	if ! [ $id ]; then
		echo "$1: No such group."
		exit 1
	fi
	GBINGRP="$1"
	GID=$id
}
function set_cookie {
	if ! [ "$1" ]; then
		echo "Password must be non-empty."
		exit 1
	fi
	cookie="$1"
}

while [ "$1" ]; do
	case "$1" in
		-l|--login)
			set_login "$2"
			shift
			;;
		-p|--password)
			set_cookie "$2"
			shift
			;;
		-h|--help)
			syntax
			exit
			;;
		-W|--windows)
			echo
			PREVIEW="yes"
			;;
		-g|--group)
			set_group "$2"
			shift
			;;
		-d|--domain)
			WINDOMAIN="$2"
			shift
			;;
		-*)
			echo "$1: No such option."
			exit 1
			;;
		install|setalt|setuid|setgid)
			command="$1"
			;;
		*)
			echo "$1: No such command."
			exit 1
			;;
	esac
	shift
done

function do_setuid {
	if ! [ "$LOGIN" ]; then
		install_msp_user
	fi
	list="/etc/aliases /etc/mail /etc/mail/aliases.db /etc/mail/certs /var/spool/mqueue"
	if [ $PREVIEW ]; then
		printf -- ' chown "%s" %s\n' "$LOGIN" "$list"
	else
		chown "$LOGIN" $list
		if [ "$LOGIN" == "SYSTEM" ]; then
			chmod u-s $UBINDIR/procmail.exe
		else
			chmod u+s $UBINDIR/procmail.exe
		fi
	fi
	install_conf
}
function do_setgid {
	procmail-config -e
	list="/etc/mail /etc/mail/certs /var/spool/clientmqueue /var/spool/mqueue $MBINDIR/sendmail.exe"
	if [ $PREVIEW ]; then
		printf -- ' chgrp "%s" %s\n' "$GBINGRP" "$list"
	else
		chgrp "$GBINGRP" $list
	fi
}
function do_setalt {
	/usr/sbin/alternatives --set mta $MBINDIR/sendmail.exe
}
function do_install {
	if ! [ "$LOGIN" ]; then
		install_root_user
	elif ! [ "$cookie" ]; then
		printf "Enter password for '%s': " "$LOGIN"
		read cookie
	fi
	cmd=`printf '%s/sc config sendmail obj= "%s\%s" password= "%s"' "$COMPATH" "$WINDOMAIN" "$LOGIN" "$cookie"`
	if [ $PREVIEW ]; then
		echo "Windows: $cmd"
	else
		eval "$cmd" >/dev/null
		rm -f /var/log/sendmail.log
	fi
}

install_multiroot
install_service

if [ $command ]; then
	do_$command
else
	check_hostname
	if [ $? -eq 0 ]; then
		install_aliases
		welcome
	elif [[ "$VERSION" > "NT-5.1" ]]; then
		need_FQDN
	else
		install_FQDN
		install_aliases
		welcome
	fi
fi

