#!/bin/sh -e

# Start or stop Postfix
#
# LaMont Jones <lamont@debian.org>
# based on sendmail's init.d script

### BEGIN INIT INFO
# Provides:          postfix-chroot mail-transport-agent-chroot
# Required-Start:    $local_fs $remote_fs $syslog $named $network $time
# Required-Stop:     $local_fs $remote_fs $syslog $named $network
# Should-Start:      postgresql mysql clamav-daemon postgrey spamassassin saslauthd dovecot
# Should-Stop:       postgresql mysql clamav-daemon postgrey spamassassin saslauthd dovecot
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: start and stop the Postfix Mail Transport Agent chrooted
# Description:       postfix is a Mail Transport agent (chrooted)
### END INIT INFO

CHRBIN=/usr/sbin/chroot
CHRDIR=/chroot/maild

PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/usr/sbin/postfix
NAME=Postfix
TZ=
unset TZ

# Defaults - don't touch, edit /etc/default/postfix
SYNC_CHROOT="y"

test -f $CHRDIR/etc/default/postfix && . $CHRDIR/etc/default/postfix

test -x $CHRDIR$DAEMON && test -f $CHRDIR/etc/postfix/main.cf || exit 0

. /lib/lsb/init-functions
#DISTRO=$(lsb_release -is 2>/dev/null || echo Debian)

enabled_instances() {
	$CHRBIN $CHRDIR postmulti -l -a | awk '($3=="y") { print $1}'
}

running() {
    INSTANCE="$1"
    if [ "X$INSTANCE" = X ]; then
	    POSTCONF="$CHRBIN $CHRDIR postconf"
    else
	    POSTCONF="$CHRBIN $CHRDIR postmulti -i $INSTANCE -x postconf"
    fi

    queue=$($POSTCONF -h queue_directory 2>/dev/null || echo /var/spool/postfix)
    if [ -f $CHRDIR${queue}/pid/master.pid ]; then
	pid=$(sed 's/ //g' $CHRDIR${queue}/pid/master.pid)
	# what directory does the executable live in.  stupid prelink systems.
	dir=$(ls -l /proc/$pid/exe 2>/dev/null | sed 's/.* -> //; s/\/[^\/]*$//')
	if [ "X$dir" = "X$CHRDIR/usr/lib/postfix" ]; then
	    echo y
	fi
    fi
}

pidof_children() {
    queue=$1
    for pid in $(ps -o pid -A); do
	if [ -h /proc/$pid/root ]; then
    	    rootdir=`readlink /proc/$pid/root`
    	    if [ "$rootdir" = "$CHRDIR$queue" ]; then
    		echo -n " $pid"
    	    fi
	fi
    done
}

wait_stop_children() {
    INSTANCE="$1"
    if [ "X$INSTANCE" = X ]; then
            POSTCONF="$CHRBIN $CHRDIR postconf"
    else
            POSTCONF="$CHRBIN $CHRDIR postmulti -i $INSTANCE -x postconf"
    fi
    queue=$($POSTCONF -h queue_directory 2>/dev/null || echo /var/spool/postfix)

    for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
	cpids=$(pidof_children $queue)
	if [ "X$cpids" = "X" ]; then
	    break
	fi
	echo -n "."
	if [ $i -gt "5" ]; then
	    kill $cpids
	fi
        sleep 1
    done 
}

fix_setgids() {
	chmod g+s $CHRDIR/usr/sbin/postdrop
	chmod g+s $CHRDIR/usr/sbin/postqueue
	chmod g+s $CHRDIR/var/spool/postfix/public
}

configure_instance() {
    INSTANCE="$1"
    if [ "X$INSTANCE" = X ]; then
	    POSTCONF="$CHRBIN $CHRDIR postconf"
    else
	    POSTCONF="$CHRBIN $CHRDIR postmulti -i $INSTANCE -x postconf"
    fi


    # if you set myorigin to 'ubuntu.com' or 'debian.org', it's wrong, and annoys the admins of
    # those domains.  See also sender_canonical_maps.

    MYORIGIN=$($POSTCONF -h myorigin | tr 'A-Z' 'a-z')
    if [ "X${MYORIGIN#/}" != "X${MYORIGIN}" ]; then
	MYORIGIN=$(tr 'A-Z' 'a-z' < $MYORIGIN)
    fi
    if [ "X$MYORIGIN" = Xubuntu.com ] || [ "X$MYORIGIN" = Xdebian.org ]; then
	log_failure_msg "Invalid \$myorigin ($MYORIGIN), refusing to start"
	log_end_msg 1
	exit 1
    fi

    config_dir=$($POSTCONF -h config_directory)
    # see if anything is running chrooted.
    NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' $CHRDIR${config_dir}/master.cf)
    # just for coloring: '

    if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then
	# Make sure that the chroot environment is set up correctly.
	oldumask=$(umask)
	umask 022
	queue_dir=$($POSTCONF -h queue_directory)
	cd "$CHRDIR$queue_dir"

	# copy the CA path if specified
	ca_path=$($POSTCONF -h smtp_tls_CApath)
	case "$ca_path" in
	    '') :;; # no ca_path
	    $queue_dir/*) :;;  # skip stuff already in chroot
	    *)
		if test -d "$CHRDIR$ca_path"; then
		    dest_dir="$CHRDIR$queue_dir/${ca_path#/}"
		    new=0
		    if test -d "$dest_dir"; then
			# write to a new directory ...
			dest_dir="${dest_dir%/}.NEW"
			new=1
		    else
			mkdir --parent ${dest_dir%/*}
		    fi
		    # handle files in subdirectories
		    (cd "$CHRDIR$ca_path" && find . -name '*.pem' -print0 | cpio -0pdL --quiet "$dest_dir") 2>/dev/null || 
		        (log_failure_msg failure copying certificates; exit 1)
		    c_rehash "$dest_dir" >/dev/null 2>&1
		    if [ "$new" = 1 ]; then
			# and replace the old directory
			rm -r "${dest_dir%.NEW}"
			mv "$dest_dir" "${dest_dir%.NEW}"
		    fi
		fi
		;;
	esac

	# if there is a CA file, copy it
	ca_file=$($POSTCONF -h smtp_tls_CAfile)
	case "$ca_file" in
	    $queue_dir/*) :;;  # skip stuff already in chroot
	    '') # no ca_file
		# or copy the bundle to preserve functionality
		ca_bundle=/etc/ssl/certs/ca-certificates.crt
		if [ -f $CHRDIR$ca_bundle ]; then
		    mkdir --parent "$CHRDIR$queue_dir/${ca_bundle%/*}"
		    cp -L "$CHRDIR$ca_bundle" "$CHRDIR$queue_dir/${ca_bundle%/*}"
		fi
		;;
	    *)
		if test -f "$CHRDIR$ca_file"; then
		    dest_dir="$CHRDIR$queue_dir/${ca_path#/}"
		    mkdir --parent "$dest_dir"
		    cp -L "$CHRDIR$ca_file" "$dest_dir"
		fi
		;;
	esac

	# if we're using unix:passwd.byname, then we need to add etc/passwd.
	local_maps=$($POSTCONF -h local_recipient_maps)
	if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then
	    if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then
		sed 's/^\([^:]*\):[^:]*/\1:x/' $CHRDIR/etc/passwd > etc/passwd
		chmod a+r etc/passwd
	    fi
	fi

	FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \
	    etc/nsswitch.conf etc/nss_mdns.config"
	for file in $FILES; do
	    [ -d ${file%/*} ] || mkdir -p ${file%/*}
	    if [ -f $CHRDIR/${file} ]; then rm -f ${file} && cp $CHRDIR/${file} ${file}; fi
	    if [ -f  ${file} ]; then chmod a+rX ${file}; fi
	done
	# ldaps needs this. debian bug 572841
	(echo /dev/random; echo /dev/urandom) | cpio -pdL --quiet . 2>/dev/null || true
	rm -f usr/lib/zoneinfo/localtime
	mkdir -p usr/lib/zoneinfo
	ln -sf /etc/localtime usr/lib/zoneinfo/localtime

	LIBLIST=$(for name in gcc_s nss resolv; do
	    for f in $CHRDIR/lib/*/lib${name}*.so* $CHRDIR/lib/lib${name}*.so*; do
	       if [ -f "$f" ]; then  echo ${f#$CHRDIR/}; fi;
	    done;
	done)

	if [ -n "$LIBLIST" ]; then
	    for f in $LIBLIST; do
		rm -f "$f"
	    done
	    tar cf - -C $CHRDIR/ $LIBLIST 2>/dev/null |tar xf -
	fi
	umask $oldumask
    fi
}

case "$1" in
    start)
	log_daemon_msg "Starting Postfix Mail Transport Agent" postfix-chroot
	fix_setgids
	RET=0
	# for all instances that are not already running, handle chroot setup if needed, and start
	for INSTANCE in $(enabled_instances); do
	    RUNNING=$(running $INSTANCE)
	    running $INSTANCE
	    if [ "X$RUNNING" = X ]; then
		configure_instance $INSTANCE
		CMD="$CHRBIN -- $CHRDIR /usr/sbin/postmulti -i $INSTANCE -x ${DAEMON}"
		if ! start-stop-daemon --start --exec $CMD quiet-quick-start; then
		    RET=1
		fi
	    fi
	done
	log_end_msg $RET
    ;;

    stop)
	log_daemon_msg "Stopping Postfix Mail Transport Agent" postfix-chroot
	RET=0
	# for all instances that are not already running, handle chroot setup if needed, and start
	for INSTANCE in $(enabled_instances); do
	    RUNNING=$(running $INSTANCE)
	    if [ "X$RUNNING" != X ]; then
		CMD="$CHRBIN $CHRDIR /usr/sbin/postmulti -i $INSTANCE -x ${DAEMON}"
		if ! ${CMD} quiet-stop; then
		    RET=1
		fi
	    fi
	    wait_stop_children $INSTANCE
	done
	log_end_msg $RET
    ;;

    restart)
        $0 stop
        $0 start
    ;;

    force-reload|reload)
	log_action_begin_msg "Reloading Postfix configuration (chroot)"
	if ${DAEMON} quiet-reload; then
	    log_action_end_msg 0
	else
	    log_action_end_msg 1
	fi
    ;;

    status)
	ALL=1
	ANY=0
	# for all instances that are not already running, handle chroot setup if needed, and start
	for INSTANCE in $(enabled_instances); do
	    RUNNING=$(running $INSTANCE)
	    if [ "X$RUNNING" != X ]; then
	    	ANY=1
	    else
	    	ALL=0
	    fi
	done
	# handle the case when postmulti returns *no* configured instances
	if [ $ANY = 0 ]; then
	   ALL=0
	fi
	if [ $ALL = 1 ]; then
	   log_success_msg "postfix is running (in chroot)"
	   exit 0
	elif [ $ANY = 1 ]; then
	   log_success_msg "some postfix instances are running (in chroot)"
	   exit 0
	else
	   log_success_msg "postfix is not running (in chroot)"
	   exit 3
	fi
    ;;

    flush|check|abort)
	${DAEMON} $1
    ;;

    *)
	log_action_msg "Usage: /etc/init.d/postfix-chroot {start|stop|restart|reload|flush|check|abort|force-reload|status}"
	exit 1
    ;;
esac

exit 0
