#!/bin/sh # $NetBSD: postfix-script,v 1.2.14.1 2023/12/25 12:54:33 martin Exp $ # #++ # NAME # postfix-script 1 # SUMMARY # execute Postfix administrative commands # SYNOPSIS # \fBpostfix-script\fR \fIcommand\fR # DESCRIPTION # The \fBpostfix-script\fR script executes Postfix administrative # commands in an environment that is set up by the \fBpostfix\fR(1) # command. # SEE ALSO # master(8) Postfix master program # postfix(1) Postfix administrative interface # LICENSE # .ad # .fi # The Secure Mailer license must be distributed with this software. # AUTHOR(S) # Wietse Venema # IBM T.J. Watson Research # P.O. Box 704 # Yorktown Heights, NY 10598, USA # # Wietse Venema # Google, Inc. # 111 8th Avenue # New York, NY 10011, USA #-- # Avoid POSIX death due to SIGHUP when some parent process exits. trap '' 1 case $daemon_directory in "") echo This script must be run by the postfix command. 1>&2 echo Do not run directly. 1>&2 exit 1 esac LOGGER="$command_directory/postlog -t $MAIL_LOGTAG/postfix-script" INFO="$LOGGER -p info" WARN="$LOGGER -p warn" ERROR="$LOGGER -p error" FATAL="$LOGGER -p fatal" PANIC="$LOGGER -p panic" umask 022 SHELL=/bin/sh # # Can't do much without these in place. # cd $command_directory || { $FATAL no Postfix command directory $command_directory! exit 1 } cd $daemon_directory || { $FATAL no Postfix daemon directory $daemon_directory! exit 1 } test -f master || { $FATAL no Postfix master program $daemon_directory/master! exit 1 } cd $config_directory || { $FATAL no Postfix configuration directory $config_directory! exit 1 } case $shlib_directory in no) ;; *) cd $shlib_directory || { $FATAL no Postfix shared-library directory $shlib_directory! exit 1 } esac cd $meta_directory || { $FATAL no Postfix meta directory $meta_directory! exit 1 } cd $queue_directory || { $FATAL no Postfix queue directory $queue_directory! exit 1 } def_config_directory=`$command_directory/postconf -dh config_directory` || { $FATAL cannot execute $command_directory/postconf! exit 1 } # If this is a secondary instance, don't touch shared files. instances=`test ! -f $def_config_directory/main.cf || $command_directory/postconf -c $def_config_directory \ -h multi_instance_directories | sed 's/,/ /'` || { $FATAL cannot execute $command_directory/postconf! exit 1 } check_shared_files=1 for name in $instances do case "$name" in "$def_config_directory") ;; "$config_directory") check_shared_files=; break;; esac done # # Parse JCL # case $1 in start_msg) echo "Start postfix" ;; stop_msg) echo "Stop postfix" ;; start|start-fg) $daemon_directory/master -t 2>/dev/null || { $FATAL the Postfix mail system is already running exit 1 } if [ -f $queue_directory/quick-start ] then rm -f $queue_directory/quick-start else $daemon_directory/postfix-script check-fatal || { $FATAL Postfix integrity check failed! exit 1 } # Foreground this so it can be stopped. All inodes are cached. $daemon_directory/postfix-script check-warn fi $INFO starting the Postfix mail system || exit 1 case $1 in start) # NOTE: wait in foreground process to get the initialization status. $daemon_directory/master -w || { $FATAL "mail system startup failed" exit 1 } ;; start-fg) # Foreground start-up is incompatible with multi-instance mode. # Use "exec $daemon_directory/master" only if PID == 1. # Otherwise, doing so would break process group management, # and "postfix stop" would kill too many processes. case $instances in "") case $$ in 1) exec $daemon_directory/master -i $FATAL "cannot start-fg the master daemon" exit 1;; *) $daemon_directory/master -s;; esac ;; *) $FATAL "start-fg does not support multi_instance_directories" exit 1 ;; esac ;; esac ;; drain) $daemon_directory/master -t 2>/dev/null && { $FATAL the Postfix mail system is not running exit 1 } $INFO stopping the Postfix mail system kill -9 `sed 1q pid/master.pid` ;; quick-stop) $daemon_directory/postfix-script stop touch $queue_directory/quick-start ;; stop) $daemon_directory/master -t 2>/dev/null && { $FATAL the Postfix mail system is not running exit 1 } $INFO stopping the Postfix mail system kill `sed 1q pid/master.pid` for i in 5 4 3 2 1 do $daemon_directory/master -t && exit 0 $INFO waiting for the Postfix mail system to terminate sleep 1 done $WARN stopping the Postfix mail system with force pid=`awk '{ print $1; exit 0 } END { exit 1 }' pid/master.pid` && kill -9 -$pid ;; abort) $daemon_directory/master -t 2>/dev/null && { $FATAL the Postfix mail system is not running exit 1 } $INFO aborting the Postfix mail system kill `sed 1q pid/master.pid` ;; reload) $daemon_directory/master -t 2>/dev/null && { $FATAL the Postfix mail system is not running exit 1 } $INFO refreshing the Postfix mail system $command_directory/postsuper active || exit 1 kill -HUP `sed 1q pid/master.pid` $command_directory/postsuper & ;; flush) cd $queue_directory || { $FATAL no Postfix queue directory $queue_directory! exit 1 } $command_directory/postqueue -f ;; check) $daemon_directory/postfix-script check-fatal || exit 1 $daemon_directory/postfix-script check-warn exit 0 ;; status) $daemon_directory/master -t 2>/dev/null && { $INFO the Postfix mail system is not running exit 1 } $INFO the Postfix mail system is running: PID: `sed 1q pid/master.pid` exit 0 ;; check-fatal) # This command is NOT part of the public interface. $SHELL $daemon_directory/post-install create-missing || { $FATAL unable to create missing queue directories exit 1 } # Look for incomplete installations. test -f $config_directory/master.cf || { $FATAL no $config_directory/master.cf file found exit 1 } maillog_file=`$command_directory/postconf -h maillog_file` || { $FATAL cannot execute $command_directory/postconf! exit 1 } test -n "$maillog_file" && { $command_directory/postconf -M postlog/unix-dgram 2>/dev/null \ | grep . >/dev/null || { $FATAL "missing 'postlog' service in master.cf - run 'postfix upgrade-configuration'" exit 1 } } # See if all queue files are in the right place. This is slow. # We must scan all queues for mis-named queue files before the # mail system can run. $command_directory/postsuper || exit 1 exit 0 ;; check-warn) # This command is NOT part of the public interface. # Check Postfix root-owned directory owner/permissions. find $queue_directory/. $queue_directory/pid \ -prune ! -user root \ -exec $WARN not owned by root: {} \; find $queue_directory/. $queue_directory/pid \ -prune \( -perm -020 -o -perm -002 \) \ -exec $WARN group or other writable: {} \; # Check Postfix root-owned directory tree owner/permissions. todo="$config_directory/." test -n "$check_shared_files" && { todo="$daemon_directory/. $meta_directory/. $todo" test "$shlib_directory" = "no" || todo="$shlib_directory/. $todo" } todo=`echo "$todo" | tr ' ' '\12' | sort -u` find $todo ! -user root \ -exec $WARN not owned by root: {} \; find $todo \( -perm -020 -o -perm -002 \) \ -exec $WARN group or other writable: {} \; # Check Postfix mail_owner-owned directory tree owner/permissions. find $data_directory/. ! -user $mail_owner \ -exec $WARN not owned by $mail_owner: {} \; find $data_directory/. \( -perm -020 -o -perm -002 \) \ -exec $WARN group or other writable: {} \; # Check Postfix mail_owner-owned directory tree owner. find `ls -d $queue_directory/* | \ grep -E '/(saved|incoming|active|defer|deferred|bounce|hold|trace|corrupt|public|private|flush)$'` \ ! \( -type p -o -type s \) ! -user $mail_owner \ -exec $WARN not owned by $mail_owner: {} \; # WARNING: this should not descend into the maildrop directory. # maildrop is the least trusted Postfix directory. find $queue_directory/maildrop -prune ! -user $mail_owner \ -exec $WARN not owned by $mail_owner: $queue_directory/maildrop \; # Check Postfix setgid_group-owned directory and file group/permissions. todo="$queue_directory/public $queue_directory/maildrop" test -n "$check_shared_files" && todo="$command_directory/postqueue $command_directory/postdrop $todo" find $todo \ -prune ! -group $setgid_group \ -exec $WARN not owned by group $setgid_group: {} \; test -n "$check_shared_files" && find $command_directory/postqueue $command_directory/postdrop \ -prune ! -perm -02111 \ -exec $WARN not set-gid or not owner+group+world executable: {} \; # Check non-Postfix root-owned directory tree owner/content. for dir in bin etc lib sbin usr do test -d $dir && { find $dir ! -user root \ -exec $WARN not owned by root: $queue_directory/{} \; find $dir -type f -print | while read path do test -f /$path && { cmp -s $path /$path || $WARN $queue_directory/$path and /$path differ } done } done find corrupt -type f -exec $WARN damaged message: {} \; # Check for non-Postfix MTA remnants. test -n "$check_shared_files" -a -f /usr/sbin/sendmail -a \ -f /usr/lib/sendmail && { cmp -s /usr/sbin/sendmail /usr/lib/sendmail || { $WARN /usr/lib/sendmail and /usr/sbin/sendmail differ $WARN Replace one by a symbolic link to the other } } exit 0 ;; set-permissions|upgrade-configuration) $daemon_directory/post-install create-missing "$@" ;; post-install) # Currently not part of the public interface. shift $daemon_directory/post-install "$@" ;; tls) shift $daemon_directory/postfix-tls-script "$@" ;; /*) # Currently not part of the public interface. "$@" ;; logrotate) case $# in 1) ;; *) $FATAL "usage postfix $1 (no arguments)"; exit 1;; esac for name in maillog_file maillog_file_compressor \ maillog_file_rotate_suffix do value="`$command_directory/postconf -h $name`" case "$value" in "") $FATAL "empty '$name' parameter value - logfile rotation failed" exit 1;; esac eval $name='"$value"'; done case "$maillog_file" in /dev/*) $FATAL "not rotating '$maillog_file'"; exit 1;; esac errors=`( suffix="\`date +$maillog_file_rotate_suffix\`" || exit 1 mv "$maillog_file" "$maillog_file.$suffix" || exit 1 $daemon_directory/master -t 2>/dev/null || kill -HUP \`sed 1q pid/master.pid\` || exit 1 sleep 1 "$maillog_file_compressor" "$maillog_file.$suffix" || exit 1 ) 2>&1` || { $FATAL "logfile '$maillog_file' rotation failed: $errors" exit 1 } ;; *) $FATAL "unknown command: '$1'. Usage: postfix start (or stop, reload, abort, flush, check, status, set-permissions, upgrade-configuration, logrotate)" exit 1 ;; esac