1#!/bin/sh
2#         $NetBSD: postfix-script,v 1.5 2025/02/25 19:15:41 christos Exp $
3#
4
5#++
6# NAME
7#         postfix-script 1
8# SUMMARY
9#         execute Postfix administrative commands
10# SYNOPSIS
11#         \fBpostfix-script\fR \fIcommand\fR
12# DESCRIPTION
13#         The \fBpostfix-script\fR script executes Postfix administrative
14#         commands in an environment that is set up by the \fBpostfix\fR(1)
15#         command.
16# SEE ALSO
17#         master(8) Postfix master program
18#         postfix(1) Postfix administrative interface
19# LICENSE
20# .ad
21# .fi
22#         The Secure Mailer license must be distributed with this software.
23# AUTHOR(S)
24#         Wietse Venema
25#         IBM T.J. Watson Research
26#         P.O. Box 704
27#         Yorktown Heights, NY 10598, USA
28#
29#         Wietse Venema
30#         Google, Inc.
31#         111 8th Avenue
32#         New York, NY 10011, USA
33#
34#         Wietse Venema
35#         porcupine.org
36#         Amawalk, NY 10501, USA
37#--
38
39# Avoid POSIX death due to SIGHUP when some parent process exits.
40
41trap '' 1
42
43case $daemon_directory in
44"") echo This script must be run by the postfix command. 1>&2
45    echo Do not run directly. 1>&2
46    exit 1
47esac
48
49LOGGER="$command_directory/postlog -t $MAIL_LOGTAG/postfix-script"
50INFO="$LOGGER -p info"
51WARN="$LOGGER -p warn"
52ERROR="$LOGGER -p error"
53FATAL="$LOGGER -p fatal"
54PANIC="$LOGGER -p panic"
55
56umask 022
57SHELL=/bin/sh
58
59#
60# Can't do much without these in place.
61#
62cd $command_directory || {
63          $FATAL no Postfix command directory $command_directory!
64          exit 1
65}
66cd $daemon_directory || {
67          $FATAL no Postfix daemon directory $daemon_directory!
68          exit 1
69}
70test -f master || {
71          $FATAL no Postfix master program $daemon_directory/master!
72          exit 1
73}
74cd $config_directory || {
75          $FATAL no Postfix configuration directory $config_directory!
76          exit 1
77}
78case $shlib_directory in
79no) ;;
80 *) cd $shlib_directory || {
81          $FATAL no Postfix shared-library directory $shlib_directory!
82        exit 1
83    }
84esac
85cd $meta_directory || {
86          $FATAL no Postfix meta directory $meta_directory!
87          exit 1
88}
89cd $queue_directory || {
90          $FATAL no Postfix queue directory $queue_directory!
91          exit 1
92}
93def_config_directory=`$command_directory/postconf -dh config_directory` || {
94          $FATAL cannot execute $command_directory/postconf!
95          exit 1
96}
97
98# If this is a secondary instance, don't touch shared files.
99
100instances=`test ! -f $def_config_directory/main.cf ||
101    $command_directory/postconf -qc $def_config_directory \
102    -h multi_instance_directories | sed 'y/,/ /'` || {
103          $FATAL cannot execute $command_directory/postconf!
104          exit 1
105}
106
107check_shared_files=1
108for name in $instances
109do
110    case "$name" in
111    "$def_config_directory") ;;
112    "$config_directory") check_shared_files=; break;;
113    esac
114done
115
116#
117# Parse JCL
118#
119case $1 in
120
121start_msg)
122
123          echo "Start postfix"
124          ;;
125
126stop_msg)
127
128          echo "Stop postfix"
129          ;;
130
131start|start-fg)
132
133          $daemon_directory/master -t 2>/dev/null || {
134                    $FATAL the Postfix mail system is already running
135                    exit 1
136          }
137          if [ -f $queue_directory/quick-start ]
138          then
139                    rm -f $queue_directory/quick-start
140          else
141                    $daemon_directory/postfix-script check-fatal || {
142                              $FATAL Postfix integrity check failed!
143                              exit 1
144                    }
145                    # Foreground this so it can be stopped. All inodes are cached.
146                    $daemon_directory/postfix-script check-warn
147          fi
148          $INFO starting the Postfix mail system || exit 1
149          case $1 in
150          start)
151              # NOTE: wait in foreground process to get the initialization status.
152              $daemon_directory/master -w || {
153                    $FATAL "mail system startup failed"
154                    exit 1
155              }
156              ;;
157          start-fg)
158              # Foreground start-up is incompatible with multi-instance mode.
159              # Use "exec $daemon_directory/master" only if PID == 1.
160              # Otherwise, doing so would break process group management,
161              # and "postfix stop" would kill too many processes.
162              case $instances in
163              "") case $$ in
164                     1) exec $daemon_directory/master -i
165                        $FATAL "cannot start-fg the master daemon"
166                        exit 1;;
167                     *) $daemon_directory/master -s;;
168                    esac
169                    ;;
170               *) $FATAL "start-fg does not support multi_instance_directories"
171                    exit 1
172                    ;;
173              esac
174              ;;
175          esac
176          ;;
177
178drain)
179
180          $daemon_directory/master -t 2>/dev/null && {
181                    $FATAL the Postfix mail system is not running
182                    exit 1
183          }
184          $INFO stopping the Postfix mail system
185          kill -9 `sed 1q pid/master.pid`
186          ;;
187
188quick-stop)
189
190          $daemon_directory/postfix-script stop
191          touch $queue_directory/quick-start
192          ;;
193
194stop)
195
196          $daemon_directory/master -t 2>/dev/null && {
197                    $FATAL the Postfix mail system is not running
198                    exit 1
199          }
200          $INFO stopping the Postfix mail system
201          kill `sed 1q pid/master.pid`
202          for i in 5 4 3 2 1
203          do
204              $daemon_directory/master -t && exit 0
205              $INFO waiting for the Postfix mail system to terminate
206              sleep 1
207          done
208          $WARN stopping the Postfix mail system with force
209          pid=`awk '{ print $1; exit 0 } END { exit 1 }' pid/master.pid` &&
210                    kill -9 -$pid
211          ;;
212
213abort)
214
215          $daemon_directory/master -t 2>/dev/null && {
216                    $FATAL the Postfix mail system is not running
217                    exit 1
218          }
219          $INFO aborting the Postfix mail system
220          kill `sed 1q pid/master.pid`
221          ;;
222
223reload)
224
225          # Warn once for deprecated parameters.
226          $command_directory/postconf >/dev/null
227
228          $daemon_directory/master -t 2>/dev/null && {
229                    $FATAL the Postfix mail system is not running
230                    exit 1
231          }
232          $INFO refreshing the Postfix mail system
233          $command_directory/postsuper active || exit 1
234          kill -HUP `sed 1q pid/master.pid`
235          $command_directory/postsuper &
236          ;;
237
238flush)
239
240          cd $queue_directory || {
241                    $FATAL no Postfix queue directory $queue_directory!
242                    exit 1
243          }
244          $command_directory/postqueue -f
245          ;;
246
247check)
248
249          $daemon_directory/postfix-script check-fatal || exit 1
250          $daemon_directory/postfix-script check-warn
251          exit 0
252          ;;
253
254status)
255
256          # Warn once for deprecated parameters.
257          $command_directory/postconf >/dev/null
258
259          $daemon_directory/master -t 2>/dev/null && {
260                    $INFO the Postfix mail system is not running
261                    exit 1
262          }
263          $INFO the Postfix mail system is running: PID: `sed 1q pid/master.pid`
264          exit 0
265          ;;
266
267
268check-fatal)
269          # This command is NOT part of the public interface.
270
271          $SHELL $daemon_directory/post-install create-missing || {
272                    $FATAL unable to create missing queue directories
273                    exit 1
274          }
275
276          # Look for incomplete installations.
277
278          test -f $config_directory/master.cf || {
279                    $FATAL no $config_directory/master.cf file found
280                    exit 1
281          }
282
283          maillog_file=`$command_directory/postconf -qh maillog_file` || {
284                    $FATAL cannot execute $command_directory/postconf!
285                    exit 1
286          }
287          test -n "$maillog_file" && {
288                    $command_directory/postconf -qM postlog/unix-dgram 2>/dev/null \
289                        | grep . >/dev/null || {
290                              $FATAL "missing 'postlog' service in master.cf - run 'postfix upgrade-configuration'"
291                              exit 1
292                    }
293          }
294
295          # See if all queue files are in the right place. This is slow.
296          # We must scan all queues for mis-named queue files before the
297          # mail system can run.
298
299          $command_directory/postsuper || exit 1
300          exit 0
301          ;;
302
303check-warn)
304          # This command is NOT part of the public interface.
305
306          # Warn once for deprecated parameters.
307          $command_directory/postconf >/dev/null
308
309          # Check Postfix root-owned directory owner/permissions.
310
311          find $queue_directory/. $queue_directory/pid \
312              -prune ! -user root \
313              -exec $WARN not owned by root: {} \;
314
315          find $queue_directory/. $queue_directory/pid \
316              -prune \( -perm -020 -o -perm -002 \) \
317              -exec $WARN group or other writable: {} \;
318
319          # Check Postfix root-owned directory tree owner/permissions.
320
321          todo="$config_directory/."
322          test -n "$check_shared_files" && {
323                    todo="$daemon_directory/. $meta_directory/. $todo"
324                    test "$shlib_directory" = "no" ||
325                        todo="$shlib_directory/. $todo"
326          }
327          todo=`echo "$todo" | tr ' ' '\12' | sort -u`
328
329          find $todo ! -user root \
330              -exec $WARN not owned by root: {} \;
331
332          find $todo \( -perm -020 -o -perm -002 \) \
333              -exec $WARN group or other writable: {} \;
334
335          # Check Postfix mail_owner-owned directory tree owner/permissions.
336
337          find $data_directory/. ! -user $mail_owner \
338              -exec $WARN not owned by $mail_owner: {} \;
339
340          find $data_directory/. \( -perm -020 -o -perm -002 \) \
341              -exec $WARN group or other writable: {} \;
342
343          # Check Postfix mail_owner-owned directory tree owner.
344
345          find `ls -d $queue_directory/* | \
346              grep -E '/(saved|incoming|active|defer|deferred|bounce|hold|trace|corrupt|public|private|flush)$'` \
347              ! \( -type p -o -type s \) ! -user $mail_owner \
348                    -exec $WARN not owned by $mail_owner: {} \;
349
350          # WARNING: this should not descend into the maildrop directory.
351          # maildrop is the least trusted Postfix directory.
352
353          find $queue_directory/maildrop -prune ! -user $mail_owner \
354              -exec $WARN not owned by $mail_owner: $queue_directory/maildrop \;
355
356          # Check Postfix setgid_group-owned directory and file group/permissions.
357
358          todo="$queue_directory/public $queue_directory/maildrop"
359          test -n "$check_shared_files" &&
360             todo="$command_directory/postqueue $command_directory/postdrop $todo"
361
362          find $todo \
363              -prune ! -group $setgid_group \
364              -exec $WARN not owned by group $setgid_group: {} \;
365
366          test -n "$check_shared_files" &&
367          find $command_directory/postqueue $command_directory/postdrop \
368              -prune ! -perm -02111 \
369              -exec $WARN not set-gid or not owner+group+world executable: {} \;
370
371          # Check non-Postfix root-owned directory tree owner/content.
372
373          for dir in bin etc lib sbin usr
374          do
375              test -d $dir && {
376                    find $dir ! -user root \
377                        -exec $WARN not owned by root: $queue_directory/{} \;
378
379                    find $dir -type f -print | while read path
380                    do
381                        test -f /$path && {
382                              cmp -s $path /$path ||
383                                  $WARN $queue_directory/$path and /$path differ
384                        }
385                    done
386              }
387          done
388
389          find corrupt -type f -exec $WARN damaged message: {} \;
390
391          # Check for non-Postfix MTA remnants.
392
393          test -n "$check_shared_files" -a -f /usr/sbin/sendmail -a \
394                    -f /usr/lib/sendmail && {
395              cmp -s /usr/sbin/sendmail /usr/lib/sendmail || {
396                    $WARN /usr/lib/sendmail and /usr/sbin/sendmail differ
397                    $WARN Replace one by a symbolic link to the other
398              }
399          }
400          exit 0
401          ;;
402
403set-permissions|upgrade-configuration)
404          $daemon_directory/post-install create-missing "$@"
405          ;;
406
407post-install)
408          # Currently not part of the public interface.
409          shift
410          $daemon_directory/post-install "$@"
411          ;;
412
413tls)
414          shift
415          $daemon_directory/postfix-tls-script "$@"
416          ;;
417
418/*)
419          # Currently not part of the public interface.
420          "$@"
421          ;;
422
423logrotate)
424          case $# in
425          1) ;;
426          *) $FATAL "usage postfix $1 (no arguments)"; exit 1;;
427          esac
428          for name in maillog_file maillog_file_compressor \
429             maillog_file_rotate_suffix
430          do
431              value="`$command_directory/postconf -qh $name`"
432              case "$value" in
433              "") $FATAL "empty '$name' parameter value - logfile rotation failed"
434                    exit 1;;
435              esac
436              eval $name='"$value"';
437          done
438
439          case "$maillog_file" in
440          /dev/*) $FATAL "not rotating '$maillog_file'"; exit 1;;
441          esac
442
443          errors=`(
444              suffix="\`date +$maillog_file_rotate_suffix\`" || exit 1
445              mv "$maillog_file" "$maillog_file.$suffix" || exit 1
446              $daemon_directory/master -t 2>/dev/null ||
447                    kill -HUP \`sed 1q pid/master.pid\` || exit 1
448              sleep 1
449              "$maillog_file_compressor" "$maillog_file.$suffix" || exit 1
450          ) 2>&1` || {
451              $FATAL "logfile '$maillog_file' rotation failed: $errors"
452              exit 1
453          }
454          ;;
455
456*)
457          $FATAL "unknown command: '$1'. Usage: postfix start (or stop, reload, abort, flush, check, status, set-permissions, upgrade-configuration, logrotate)"
458          exit 1
459          ;;
460
461esac
462