From: Wietse Venema Date: Sat, 19 May 2018 05:00:00 +0000 (-0500) Subject: postfix-3.3.1 X-Git-Tag: v3.3.1^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1d4b403e285f09103644695560cca406c5400163;p=thirdparty%2Fpostfix.git postfix-3.3.1 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index f73f89960..2aeef0986 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -23334,3 +23334,33 @@ Apologies for any names omitted. 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 --git a/postfix/conf/postfix-script b/postfix/conf/postfix-script index cd77dd973..104e7dd1e 100755 --- a/postfix/conf/postfix-script +++ b/postfix/conf/postfix-script @@ -150,11 +150,16 @@ start|start-fg) ;; 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 --git a/postfix/html/master.8.html b/postfix/html/master.8.html index 4a064c784..7d52be65c 100644 --- a/postfix/html/master.8.html +++ b/postfix/html/master.8.html @@ -10,7 +10,7 @@ MASTER(8) MASTER(8) master - Postfix master process SYNOPSIS - master [-Ddtvw] [-c config_dir] [-e exit_time] + master [-Dditvw] [-c config_dir] [-e exit_time] DESCRIPTION The master(8) daemon is the resident process that runs Postfix daemons @@ -47,6 +47,11 @@ MASTER(8) MASTER(8) Terminate the master process after exit_time seconds. Child pro- cesses terminate at their convenience. + -i Enable init 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. + -t Test mode. Return a zero exit status when the master.pid lock file does not exist or when that file is not locked. This is evidence that the master(8) daemon is not running. diff --git a/postfix/html/postfix.1.html b/postfix/html/postfix.1.html index cff351cc3..a83385bc5 100644 --- a/postfix/html/postfix.1.html +++ b/postfix/html/postfix.1.html @@ -37,13 +37,14 @@ POSTFIX(1) POSTFIX(1) check described above. start-fg - Like start, but keep the master daemon running in the fore- - ground. This 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 con- - tainer host's /dev/log socket inside the container (example: - "docker run -v /dev/log:/dev/log ...") and specify a distinct - Postfix "syslog_name" prefix that identifies logging from the + Like start, but keep the master(8) daemon running in the fore- + ground, and enable master(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 con- + tainer host's /dev/log socket inside the container (example: + "docker run -v /dev/log:/dev/log ...") and specify a distinct + Postfix "syslog_name" prefix that identifies logging from the Postfix instance. stop Stop the Postfix mail system in an orderly fashion. If possible, diff --git a/postfix/man/man1/postfix.1 b/postfix/man/man1/postfix.1 index fa0216050..01c972e88 100644 --- a/postfix/man/man1/postfix.1 +++ b/postfix/man/man1/postfix.1 @@ -38,8 +38,10 @@ and create missing directories. 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 --git a/postfix/man/man8/master.8 b/postfix/man/man8/master.8 index 1eda9afe7..6594edc08 100644 --- a/postfix/man/man8/master.8 +++ b/postfix/man/man8/master.8 @@ -8,7 +8,7 @@ Postfix master process .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 @@ for debugging only. .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 --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index bf7e94de6..d3d039c40 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 --git a/postfix/src/local/unknown.c b/postfix/src/local/unknown.c index 733aa1350..c97cef39b 100644 --- a/postfix/src/local/unknown.c +++ b/postfix/src/local/unknown.c @@ -73,11 +73,14 @@ #include #include #include +#include /* 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 @@ int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr) 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 @@ int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr) 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 @@ int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr) * 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 --git a/postfix/src/master/master.c b/postfix/src/master/master.c index 846b2a415..4d77f1041 100644 --- a/postfix/src/master/master.c +++ b/postfix/src/master/master.c @@ -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 @@ int main(int argc, char **argv) /* * 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 @@ int main(int argc, char **argv) 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 @@ int main(int argc, char **argv) */ 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 @@ int main(int argc, char **argv) * 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 --git a/postfix/src/master/master.h b/postfix/src/master/master.h index baf5b143a..60f5f81ec 100644 --- a/postfix/src/master/master.h +++ b/postfix/src/master/master.h @@ -109,6 +109,7 @@ typedef struct MASTER_PROC { * master.c */ extern int master_detach; +extern int init_mode; /* * master_ent.c diff --git a/postfix/src/master/master_sig.c b/postfix/src/master/master_sig.c index 81ae7f460..0560b1ab3 100644 --- a/postfix/src/master/master_sig.c +++ b/postfix/src/master/master_sig.c @@ -199,6 +199,15 @@ static void master_sigdeath(int sig) */ 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 --git a/postfix/src/postconf/postconf_dbms.c b/postfix/src/postconf/postconf_dbms.c index 707bafa54..eddeab0a1 100644 --- a/postfix/src/postconf/postconf_dbms.c +++ b/postfix/src/postconf/postconf_dbms.c @@ -174,10 +174,10 @@ static void pcf_check_dbms_client(const PCF_DBMS_INFO *dp, const char *cf_file) */ 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 --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c index c9b3174e8..1b7e64fea 100644 --- a/postfix/src/postfix/postfix.c +++ b/postfix/src/postfix/postfix.c @@ -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 --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c index 808689c24..2c855ffcc 100644 --- a/postfix/src/tlsproxy/tlsproxy.c +++ b/postfix/src/tlsproxy/tlsproxy.c @@ -663,7 +663,7 @@ static void tlsp_ciphertext_event(int event, void *context) /* 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 @@ static void tlsp_start_tls(TLSP_STATE *state) if (state->tls_context == 0) { tlsp_state_free(state); - return; + return (-1); } /* @@ -729,6 +729,7 @@ static void tlsp_start_tls(TLSP_STATE *state) * 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 @@ static void tlsp_get_fd_event(int event, void *context) * 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 --git a/postfix/src/util/killme_after.c b/postfix/src/util/killme_after.c index 1ce06d675..5d461706f 100644 --- a/postfix/src/util/killme_after.c +++ b/postfix/src/util/killme_after.c @@ -46,11 +46,17 @@ void killme_after(unsigned int seconds) * 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);