Prereq: "3.3.0"
diff -ur --new-file /var/tmp/postfix-3.3.0/src/global/mail_version.h ./src/global/mail_version.h
--- /var/tmp/postfix-3.3.0/src/global/mail_version.h	2018-02-21 19:17:21.000000000 -0500
+++ ./src/global/mail_version.h	2018-05-19 16:14:35.000000000 -0400
@@ -20,8 +20,8 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE	"20180221"
-#define MAIL_VERSION_NUMBER	"3.3.0"
+#define MAIL_RELEASE_DATE	"20180519"
+#define MAIL_VERSION_NUMBER	"3.3.1"
 
 #ifdef SNAPSHOT
 #define MAIL_VERSION_DATE	"-" MAIL_RELEASE_DATE
diff -ur --new-file /var/tmp/postfix-3.3.0/HISTORY ./HISTORY
--- /var/tmp/postfix-3.3.0/HISTORY	2018-02-19 11:29:00.000000000 -0500
+++ ./HISTORY	2018-05-19 16:13:44.000000000 -0400
@@ -23334,3 +23334,33 @@
 	built-in or service-defined parameters for ldap, *sql, etc.
 	database names. Problem reported by Christian Rößner. Files:
 	postconf/postconf_user.c.
+
+20180306
+
+	Bugfix (introduced: 19990302): when luser_relay specifies
+	a non-existent local address, the luser_relay feature becomes
+	a black hole. Reported by Jørgen Thomsen. File: local/unknown.c.
+
+20180422
+
+	Bugfix (introduced: Postfix 2.8): missing tls_server_start()
+	error propagation in tlsproxy(8) resulting in segfault after
+	TLS handshake error. Found during code maintenance. File:
+	tlsproxy/tlsproxy.c.
+
+20180509
+
+	Bugfix (introduced: 20170617): postconf(1) command segfault
+	if unable to open a Postfix database configuration file due
+	to a file permission error. Report by Andreas Hasenack, fix
+	by Viktor Dukhovni.  File: postconf/postconf_dbms.c.
+
+20180519
+
+	Cleanup: Postfix did not support running as a PID=1 process,
+	which complicated Postfix management in containers. The
+	"postfix start-fg" command will now run the Postfix master
+	daemon as a PID=1 process if possible. Thanks to inputs
+	from Andreas Schulze, Eray Aslan, and Viktor Dukhovni.
+	Files: postfix/postfix.c, master/master.c, master/master.h,
+	master/master_sig.c, conf/postfix-script.
diff -ur --new-file /var/tmp/postfix-3.3.0/conf/postfix-script ./conf/postfix-script
--- /var/tmp/postfix-3.3.0/conf/postfix-script	2017-12-27 17:30:27.000000000 -0500
+++ ./conf/postfix-script	2018-05-19 10:17:23.000000000 -0400
@@ -150,11 +150,16 @@
 	    ;;
 	start-fg)
 	    # Foreground start-up is incompatible with multi-instance mode.
-	    # We can't use "exec $daemon_directory/master" here: that would
-	    # break process group management, and "postfix stop" would kill
-	    # too many processes.
+	    # 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
-	    "") $daemon_directory/master
+	    "") case $$ in
+		 1) exec $daemon_directory/master -i
+		    $FATAL "cannot start-fg the master daemon"
+		    exit 1;;
+		 *) $daemon_directory/master;;
+		esac
 		;;
 	     *) $FATAL "start-fg does not support multi_instance_directories"
 		exit 1
diff -ur --new-file /var/tmp/postfix-3.3.0/html/master.8.html ./html/master.8.html
--- /var/tmp/postfix-3.3.0/html/master.8.html	2018-01-14 11:48:37.000000000 -0500
+++ ./html/master.8.html	2018-05-19 15:48:33.000000000 -0400
@@ -10,7 +10,7 @@
        master - Postfix master process
 
 <b>SYNOPSIS</b>
-       <b>master</b> [<b>-Ddtvw</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<b>-e</b> <i>exit</i><b>_</b><i>time</i>]
+       <b>master</b> [<b>-Dditvw</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<b>-e</b> <i>exit</i><b>_</b><i>time</i>]
 
 <b>DESCRIPTION</b>
        The  <a href="master.8.html"><b>master</b>(8)</a> daemon is the resident process that runs Postfix daemons
@@ -47,6 +47,11 @@
               Terminate the master process after <i>exit</i><b>_</b><i>time</i> seconds. Child pro-
               cesses terminate at their convenience.
 
+       <b>-i</b>     Enable  <b>init</b> mode: do not attempt to become a session or process
+              group leader; and to force termination, set an  explicit  signal
+              handler  instead  of  relying on the default signal action. This
+              mode is allowed only if the process ID equals 1.
+
        <b>-t</b>     Test  mode.  Return  a zero exit status when the <b>master.pid</b> lock
               file does not exist or when that file is not  locked.   This  is
               evidence that the <a href="master.8.html"><b>master</b>(8)</a> daemon is not running.
diff -ur --new-file /var/tmp/postfix-3.3.0/html/postfix.1.html ./html/postfix.1.html
--- /var/tmp/postfix-3.3.0/html/postfix.1.html	2018-02-11 10:17:59.000000000 -0500
+++ ./html/postfix.1.html	2018-05-19 15:47:30.000000000 -0400
@@ -37,13 +37,14 @@
               check described above.
 
        <b>start-fg</b>
-              Like <b>start</b>, but keep the master  daemon  running  in  the  fore-
-              ground.  This  requires  that multi-instance support is disabled
-              (i.e. the <a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a>  parameter  value  must  be
-              empty).  When running Postfix inside a container, mount the con-
-              tainer host's /dev/log socket  inside  the  container  (example:
-              "docker  run  -v /dev/log:/dev/log ...")  and specify a distinct
-              Postfix "<a href="postconf.5.html#syslog_name">syslog_name</a>" prefix that identifies  logging  from  the
+              Like <b>start</b>, but keep the <a href="master.8.html"><b>master</b>(8)</a> daemon running in  the  fore-
+              ground,  and enable <a href="master.8.html"><b>master</b>(8)</a> "init" mode when running as PID 1.
+              This command requires that multi-instance  support  is  disabled
+              (i.e.  the  <a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a>  parameter  value must be
+              empty). When running Postfix inside a container, mount the  con-
+              tainer  host's  /dev/log  socket  inside the container (example:
+              "docker run -v /dev/log:/dev/log ...")  and specify  a  distinct
+              Postfix  "<a href="postconf.5.html#syslog_name">syslog_name</a>"  prefix  that identifies logging from the
               Postfix instance.
 
        <b>stop</b>   Stop the Postfix mail system in an orderly fashion. If possible,
diff -ur --new-file /var/tmp/postfix-3.3.0/man/man1/postfix.1 ./man/man1/postfix.1
--- /var/tmp/postfix-3.3.0/man/man1/postfix.1	2018-02-11 10:17:59.000000000 -0500
+++ ./man/man1/postfix.1	2018-05-19 15:45:33.000000000 -0400
@@ -38,8 +38,10 @@
 Start the Postfix mail system. This also runs the configuration
 check described above.
 .IP \fBstart\-fg\fR
-Like \fBstart\fR, but keep the master daemon running in the
-foreground. This requires that multi\-instance support is
+Like \fBstart\fR, but keep the \fBmaster\fR(8) daemon running
+in the foreground, and enable \fBmaster\fR(8) "init" mode
+when running as PID 1.
+This command requires that multi\-instance support is
 disabled (i.e. the multi_instance_directories parameter
 value must be empty). When running Postfix inside a container,
 mount the container host's /dev/log socket inside the
diff -ur --new-file /var/tmp/postfix-3.3.0/man/man8/master.8 ./man/man8/master.8
--- /var/tmp/postfix-3.3.0/man/man8/master.8	2018-01-14 11:48:35.000000000 -0500
+++ ./man/man8/master.8	2018-05-19 15:45:33.000000000 -0400
@@ -8,7 +8,7 @@
 .SH "SYNOPSIS"
 .na
 .nf
-\fBmaster\fR [\fB\-Ddtvw\fR] [\fB\-c \fIconfig_dir\fR] [\fB\-e \fIexit_time\fR]
+\fBmaster\fR [\fB\-Dditvw\fR] [\fB\-c \fIconfig_dir\fR] [\fB\-e \fIexit_time\fR]
 .SH DESCRIPTION
 .ad
 .fi
@@ -43,6 +43,12 @@
 .IP "\fB\-e \fIexit_time\fR"
 Terminate the master process after \fIexit_time\fR seconds. Child
 processes terminate at their convenience.
+.IP \fB\-i\fR
+Enable \fBinit\fR mode: do not attempt to become a session
+or process group leader; and to force termination, set an
+explicit signal handler instead of relying on the default
+signal action. This mode is allowed only if the process ID
+equals 1.
 .IP \fB\-t\fR
 Test mode. Return a zero exit status when the \fBmaster.pid\fR lock
 file does not exist or when that file is not locked.  This is evidence
diff -ur --new-file /var/tmp/postfix-3.3.0/src/local/unknown.c ./src/local/unknown.c
--- /var/tmp/postfix-3.3.0/src/local/unknown.c	2015-01-11 15:30:20.000000000 -0500
+++ ./src/local/unknown.c	2018-03-06 19:29:36.000000000 -0500
@@ -73,11 +73,14 @@
 #include <sent.h>
 #include <deliver_pass.h>
 #include <defer.h>
+#include <canon_addr.h>
 
 /* Application-specific. */
 
 #include "local.h"
 
+#define STREQ(x,y) (strcasecmp((x),(y)) == 0)
+
 /* deliver_unknown - delivery for unknown recipients */
 
 int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
@@ -85,6 +88,7 @@
     const char *myname = "deliver_unknown";
     int     status;
     VSTRING *expand_luser;
+    VSTRING *canon_luser;
     static MAPS *transp_maps;
     const char *map_transport;
 
@@ -139,8 +143,20 @@
     if (*var_luser_relay) {
 	state.msg_attr.unmatched = 0;
 	expand_luser = vstring_alloc(100);
+	canon_luser = vstring_alloc(100);
 	local_expand(expand_luser, var_luser_relay, &state, &usr_attr, (void *) 0);
-	status = deliver_resolve_addr(state, usr_attr, STR(expand_luser));
+	/* In case luser_relay specifies a domain-less address. */
+	canon_addr_external(canon_luser, vstring_str(expand_luser));
+	/* Assumes that the address resolver won't change the address. */
+	if (STREQ(vstring_str(canon_luser), state.msg_attr.rcpt.address)) {
+	    dsb_simple(state.msg_attr.why, "5.1.1",
+		       "unknown user: \"%s\"", state.msg_attr.user);
+	    status = bounce_append(BOUNCE_FLAGS(state.request),
+				   BOUNCE_ATTR(state.msg_attr));
+	} else {
+	    status = deliver_resolve_addr(state, usr_attr, STR(expand_luser));
+	}
+	vstring_free(canon_luser);
 	vstring_free(expand_luser);
 	return (status);
     }
@@ -149,8 +165,6 @@
      * If no alias was found for a required reserved name, toss the message
      * into the bit bucket, and issue a warning instead.
      */
-#define STREQ(x,y) (strcasecmp(x,y) == 0)
-
     if (STREQ(state.msg_attr.user, MAIL_ADDR_MAIL_DAEMON)
 	|| STREQ(state.msg_attr.user, MAIL_ADDR_POSTMASTER)) {
 	msg_warn("required alias not found: %s", state.msg_attr.user);
diff -ur --new-file /var/tmp/postfix-3.3.0/src/master/master.c ./src/master/master.c
--- /var/tmp/postfix-3.3.0/src/master/master.c	2018-01-14 11:48:25.000000000 -0500
+++ ./src/master/master.c	2018-05-19 15:16:11.000000000 -0400
@@ -4,7 +4,7 @@
 /* SUMMARY
 /*	Postfix master process
 /* SYNOPSIS
-/*	\fBmaster\fR [\fB-Ddtvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-e \fIexit_time\fR]
+/*	\fBmaster\fR [\fB-Dditvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-e \fIexit_time\fR]
 /* DESCRIPTION
 /*	The \fBmaster\fR(8) daemon is the resident process that runs Postfix
 /*	daemons on demand: daemons to send or receive messages via the
@@ -37,6 +37,12 @@
 /* .IP "\fB-e \fIexit_time\fR"
 /*	Terminate the master process after \fIexit_time\fR seconds. Child
 /*	processes terminate at their convenience.
+/* .IP \fB-i\fR
+/*	Enable \fBinit\fR mode: do not attempt to become a session
+/*	or process group leader; and to force termination, set an
+/*	explicit signal handler instead of relying on the default
+/*	signal action. This mode is allowed only if the process ID
+/*	equals 1.
 /* .IP \fB-t\fR
 /*	Test mode. Return a zero exit status when the \fBmaster.pid\fR lock
 /*	file does not exist or when that file is not locked.  This is evidence
@@ -229,6 +235,7 @@
 #include "master.h"
 
 int     master_detach = 1;
+int     init_mode = 0;
 
 /* master_exit_event - exit for memory leak testing purposes */
 
@@ -334,7 +341,7 @@
     /*
      * Process JCL.
      */
-    while ((ch = GETOPT(argc, argv, "c:Dde:tvw")) > 0) {
+    while ((ch = GETOPT(argc, argv, "c:Dde:itvw")) > 0) {
 	switch (ch) {
 	case 'c':
 	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
@@ -346,6 +353,11 @@
 	case 'e':
 	    event_request_timer(master_exit_event, (void *) 0, atoi(optarg));
 	    break;
+	case 'i':
+	    if (getpid() != 1)
+		msg_fatal("-i is allowed only for PID 1 process");
+	    init_mode = 1;
+	    break;
 	case 'D':
 	    debug_me = 1;
 	    break;
@@ -375,6 +387,8 @@
      */
     if (test_lock && wait_flag)
 	msg_fatal("the -t and -w options cannot be used together");
+    if (init_mode && (debug_me || !master_detach || wait_flag))
+	msg_fatal("the -i option cannot be used with -D, -d, or -w");
 
     /*
      * Run a foreground monitor process that returns an exit status of 0 when
@@ -403,7 +417,8 @@
      * all MTA processes cleanly. Give up if we can't separate from our
      * parent process. We're not supposed to blow away the parent.
      */
-    if (debug_me == 0 && master_detach != 0 && setsid() == -1 && getsid(0) != getpid())
+    if (init_mode == 0 && debug_me == 0 && master_detach != 0
+	&& setsid() == -1 && getsid(0) != getpid())
 	msg_fatal("unable to set session and process group ID: %m");
 
     /*
diff -ur --new-file /var/tmp/postfix-3.3.0/src/master/master.h ./src/master/master.h
--- /var/tmp/postfix-3.3.0/src/master/master.h	2012-03-06 17:06:35.000000000 -0500
+++ ./src/master/master.h	2018-04-04 18:59:07.000000000 -0400
@@ -109,6 +109,7 @@
   * master.c
   */
 extern int master_detach;
+extern int init_mode;
 
  /*
   * master_ent.c
diff -ur --new-file /var/tmp/postfix-3.3.0/src/master/master_sig.c ./src/master/master_sig.c
--- /var/tmp/postfix-3.3.0/src/master/master_sig.c	2014-12-06 20:35:33.000000000 -0500
+++ ./src/master/master_sig.c	2018-05-19 10:47:08.000000000 -0400
@@ -200,6 +200,15 @@
     msg_info("terminating on signal %d", sig);
 
     /*
+     * Undocumented: when a process runs with PID 1, Linux won't deliver a
+     * signal unless the process specifies a handler (i.e. SIG_DFL is treated
+     * as SIG_IGN).
+     */
+    if (init_mode)
+	/* Don't call exit() from a signal handler. */
+	_exit(0);
+
+    /*
      * Deliver the signal to ourselves and clean up. XXX We're running as a
      * signal handler and really should not be doing complicated things...
      */
diff -ur --new-file /var/tmp/postfix-3.3.0/src/postconf/postconf_dbms.c ./src/postconf/postconf_dbms.c
--- /var/tmp/postfix-3.3.0/src/postconf/postconf_dbms.c	2018-02-18 20:48:47.000000000 -0500
+++ ./src/postconf/postconf_dbms.c	2018-05-09 01:17:49.000000000 -0400
@@ -174,10 +174,10 @@
 	 */
 	dict = dict_ht_open(dict_spec, O_CREAT | O_RDWR, 0);
 	dict_register(dict_spec, dict);
-	if ((fp = vstream_fopen(cf_file, O_RDONLY, 0)) == 0
-	    && errno != EACCES) {
-	    msg_warn("open \"%s\" configuration \"%s\": %m",
-		     dp->db_type, cf_file);
+	if ((fp = vstream_fopen(cf_file, O_RDONLY, 0)) == 0) {
+	    if (errno != EACCES)
+		msg_warn("open \"%s\" configuration \"%s\": %m",
+			 dp->db_type, cf_file);
 	    myfree(dict_spec);
 	    return;
 	}
diff -ur --new-file /var/tmp/postfix-3.3.0/src/postfix/postfix.c ./src/postfix/postfix.c
--- /var/tmp/postfix-3.3.0/src/postfix/postfix.c	2018-02-11 10:17:58.000000000 -0500
+++ ./src/postfix/postfix.c	2018-05-19 11:13:16.000000000 -0400
@@ -32,8 +32,10 @@
 /*	Start the Postfix mail system. This also runs the configuration
 /*	check described above.
 /* .IP \fBstart-fg\fR
-/*	Like \fBstart\fR, but keep the master daemon running in the
-/*	foreground. This requires that multi-instance support is
+/*	Like \fBstart\fR, but keep the \fBmaster\fR(8) daemon running
+/*	in the foreground, and enable \fBmaster\fR(8) "init" mode
+/*	when running as PID 1.
+/*	This command requires that multi-instance support is
 /*	disabled (i.e. the multi_instance_directories parameter
 /*	value must be empty). When running Postfix inside a container,
 /*	mount the container host's /dev/log socket inside the
diff -ur --new-file /var/tmp/postfix-3.3.0/src/tlsproxy/tlsproxy.c ./src/tlsproxy/tlsproxy.c
--- /var/tmp/postfix-3.3.0/src/tlsproxy/tlsproxy.c	2018-01-14 11:48:25.000000000 -0500
+++ ./src/tlsproxy/tlsproxy.c	2018-05-19 08:02:00.000000000 -0400
@@ -663,7 +663,7 @@
 
 /* tlsp_start_tls - turn on TLS or force disconnect */
 
-static void tlsp_start_tls(TLSP_STATE *state)
+static int tlsp_start_tls(TLSP_STATE *state)
 {
     TLS_SERVER_START_PROPS props;
     static char *cipher_grade;
@@ -716,7 +716,7 @@
 
     if (state->tls_context == 0) {
 	tlsp_state_free(state);
-	return;
+	return (-1);
     }
 
     /*
@@ -729,6 +729,7 @@
      * XXX Do we care about certificate verification results? Not as long as
      * postscreen(8) doesn't actually receive email.
      */
+    return (0);
 }
 
 /* tlsp_get_fd_event - receive final postscreen(8) hand-off information */
@@ -776,7 +777,8 @@
      * Perform the TLS layer before-handshake initialization. We perform the
      * remainder after the TLS handshake completes.
      */
-    tlsp_start_tls(state);
+    if (tlsp_start_tls(state) < 0)
+	return;
 
     /*
      * Trigger the initial proxy server I/Os.
diff -ur --new-file /var/tmp/postfix-3.3.0/src/util/killme_after.c ./src/util/killme_after.c
--- /var/tmp/postfix-3.3.0/src/util/killme_after.c	2006-12-05 09:35:35.000000000 -0500
+++ ./src/util/killme_after.c	2018-05-19 14:59:59.000000000 -0400
@@ -46,11 +46,17 @@
      * Schedule an ALARM signal, and make sure the signal will be delivered
      * even if we are being called from a signal handler and SIGALRM delivery
      * is blocked.
+     * 
+     * Undocumented: when a process runs with PID 1, Linux won't deliver a
+     * signal unless the process specifies a handler (i.e. SIG_DFL is treated
+     * as SIG_IGN). Conveniently, _exit() can be used directly as a signal
+     * handler. This changes the wait status that a parent would see, but in
+     * the case of "init" mode on Linux, no-one would care.
      */
     alarm(0);
     sigemptyset(&sig_action.sa_mask);
     sig_action.sa_flags = 0;
-    sig_action.sa_handler = SIG_DFL;
+    sig_action.sa_handler = (getpid() == 1 ? _exit : SIG_DFL);
     sigaction(SIGALRM, &sig_action, (struct sigaction *) 0);
     alarm(seconds);
     sigaddset(&sig_action.sa_mask, SIGALRM);
