diff --git a/postfix/HISTORY b/postfix/HISTORY
index 6948b8a2b..4766e1711 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -27157,3 +27157,18 @@ Apologies for any names omitted.
versus virtual aliasing, and inet_interfaces. Files:
proto/postconf.proto, proto/aliases, proto/virtual,
proto/ADDRESS_REWRITING_README.html.
+
+20230516
+
+ Bugfix (defect introduced: Postfix 3.4): the postlog(1)
+ command created a logfile with permissions 0644, but the
+ postlogd(8) daemon created it with permissions 0600, for
+ example after "postfix logrotate". The discrepancy is now
+ eliminated, and the permissions when creating a file are
+ now configurable with the "maillog_file_permissions"
+ parameter, default 0600 for backwards compatibility. Files:
+ mantools/postlink, proto/MAILLOG_README.html, proto/postconf.proto,
+ global/mail_params.c, global/mail_params.h, global/Makefile.in,
+ master/master.c, postlog/postlog.c, postlogd/postlogd.c,
+ util/logwriter.c, util/logwriter.h, util/Makefile.in,
+ util/vstream.c.
diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink
index 15e965f41..9966ea45d 100755
--- a/postfix/mantools/postlink
+++ b/postfix/mantools/postlink
@@ -1153,6 +1153,7 @@ while (<>) {
s;\bmail[-]*\n*[ ]*log_file_compressor\b;$&;g;
s;\bmail[-]*\n*[ ]*log_file_prefixes\b;$&;g;
s;\bmail[-]*\n*[ ]*log_file_rotate_suffix\b;$&;g;
+ s;\bmail[-]*\n*[ ]*log_file_permissions\b;$&;g;
s;\bpostlog_service_name\b;$&;g;
s;\bpostlogd_watchdog_timeout\b;$&;g;
diff --git a/postfix/proto/MAILLOG_README.html b/postfix/proto/MAILLOG_README.html
index da1c1a8b5..13c1091e8 100644
--- a/postfix/proto/MAILLOG_README.html
+++ b/postfix/proto/MAILLOG_README.html
@@ -63,10 +63,16 @@ Postfix version.
/var/log/postfix.log. See also the " In the example below, specifying maillog_file_permissions is
+optional (Postfix 3.9 and later). The default value is 0600, i.e.,
+only the super-user can access the file; the value 0644 also
+adds 'group' and 'other' read access.
+
The next time it logs an event, postlogd(8) will create a
+new logfile, with permissions specified with the maillog_file_permissions
+parameter (default: 0600).
+
Notes:
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 0604d2413..0ec06fe49 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -18263,6 +18263,17 @@ default suffix, YYYYMMDD-HHMMSS, allows logs to be rotated frequently.
This feature is available in Postfix 3.4 and later.
+%PARAM maillog_file_permissions 0600
+
+ The file access permissions that will be set when the file
+$maillog_file is created for the first time, or when the file is
+created after an existing file is rotated. Specify one of: 0600
+(only super-user read/write access), 0640 (adds 'group' read
+access), or 0644 (also adds 'other' read access). The leading
+'0' is optional.
+
+ This feature is available in Postfix 3.9 and later.
+
%PARAM info_log_address_format external
The email address form that will be used in non-debug logging
diff --git a/postfix/proto/stop b/postfix/proto/stop
index 1026d9c4b..238698457 100644
--- a/postfix/proto/stop
+++ b/postfix/proto/stop
@@ -1580,3 +1580,4 @@ stderr
charset
latin
utf
+mb
diff --git a/postfix/proto/stop.double-history b/postfix/proto/stop.double-history
index 0327ec379..60b8572a1 100644
--- a/postfix/proto/stop.double-history
+++ b/postfix/proto/stop.double-history
@@ -48,3 +48,5 @@ proto proto ADDRESS_REWRITING_README html
postfix postfix c
aliasing Files proto aliases proto virtual postfix postfix c
proto proto aliases proto virtual proto ADDRESS_REWRITING_README html
+ master master c postlog postlog c postlogd postlogd c
+ proto postconf proto proto aliases proto virtual
diff --git a/postfix/proto/stop.spell-cc b/postfix/proto/stop.spell-cc
index 84fcd8758..aa28bee99 100644
--- a/postfix/proto/stop.spell-cc
+++ b/postfix/proto/stop.spell-cc
@@ -1801,3 +1801,4 @@ bitcount
bytecount
ipproto
cw
+uncreate
diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in
index 86390ede2..562290232 100644
--- a/postfix/src/global/Makefile.in
+++ b/postfix/src/global/Makefile.in
@@ -1911,6 +1911,7 @@ mail_params.o: ../../include/htable.h
mail_params.o: ../../include/inet_addr_list.h
mail_params.o: ../../include/inet_proto.h
mail_params.o: ../../include/iostuff.h
+mail_params.o: ../../include/logwriter.h
mail_params.o: ../../include/midna_domain.h
mail_params.o: ../../include/mkmap.h
mail_params.o: ../../include/msg.h
diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c
index 81aee73cf..1763fd383 100644
--- a/postfix/src/global/mail_params.c
+++ b/postfix/src/global/mail_params.c
@@ -159,6 +159,7 @@
/* char *var_maillog_file_pfxs;
/* char *var_maillog_file_comp;
/* char *var_maillog_file_stamp;
+/* char *var_maillog_file_perms;
/* char *var_postlog_service;
/*
/* char *var_dnssec_probe;
@@ -226,6 +227,7 @@
#include
#include
#include
+#include
/* Global library. */
@@ -375,6 +377,7 @@ char *var_maillog_file;
char *var_maillog_file_pfxs;
char *var_maillog_file_comp;
char *var_maillog_file_stamp;
+char *var_maillog_file_perms;
char *var_postlog_service;
char *var_dnssec_probe;
@@ -729,6 +732,7 @@ void mail_params_init()
VAR_MAILLOG_FILE_PFXS, DEF_MAILLOG_FILE_PFXS, &var_maillog_file_pfxs, 1, 0,
VAR_MAILLOG_FILE_COMP, DEF_MAILLOG_FILE_COMP, &var_maillog_file_comp, 1, 0,
VAR_MAILLOG_FILE_STAMP, DEF_MAILLOG_FILE_STAMP, &var_maillog_file_stamp, 1, 0,
+ VAR_MAILLOG_FILE_PERMS, DEF_MAILLOG_FILE_PERMS, &var_maillog_file_perms, 1, 0,
VAR_POSTLOG_SERVICE, DEF_POSTLOG_SERVICE, &var_postlog_service, 1, 0,
VAR_DNSSEC_PROBE, DEF_DNSSEC_PROBE, &var_dnssec_probe, 0, 0,
VAR_KNOWN_TCP_PORTS, DEF_KNOWN_TCP_PORTS, &var_known_tcp_ports, 0, 0,
@@ -979,6 +983,9 @@ void mail_params_init()
dict_db_cache_size = var_db_read_buf;
dict_lmdb_map_size = var_lmdb_map_size;
inet_windowsize = var_inet_windowsize;
+ if (set_logwriter_create_perms(var_maillog_file_perms) < 0)
+ msg_warn("ignoring bad permissions: %s = %s",
+ VAR_MAILLOG_FILE_PERMS, var_maillog_file_perms);
/*
* Variables whose defaults are determined at runtime, after other
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 7c80add97..c008f46f7 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -4349,6 +4349,10 @@ extern char *var_maillog_file_comp;
#define DEF_MAILLOG_FILE_STAMP "%Y%m%d-%H%M%S"
extern char *var_maillog_file_stamp;
+#define VAR_MAILLOG_FILE_PERMS "maillog_file_permissions"
+#define DEF_MAILLOG_FILE_PERMS "0600"
+extern char *var_maillog_file_perms;
+
#define VAR_POSTLOG_SERVICE "postlog_service_name"
#define DEF_POSTLOG_SERVICE MAIL_SERVICE_POSTLOG
extern char *var_postlog_service;
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index aadda2771..4704e0ba6 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20230508"
+#define MAIL_RELEASE_DATE "20230516"
#define MAIL_VERSION_NUMBER "3.9"
#ifdef SNAPSHOT
diff --git a/postfix/src/master/master.c b/postfix/src/master/master.c
index 1fc3fe9e4..f34df22e9 100644
--- a/postfix/src/master/master.c
+++ b/postfix/src/master/master.c
@@ -135,13 +135,13 @@
/* The external command to execute when a Postfix daemon program is
/* invoked with the -D option.
/* .IP "\fBinet_interfaces (all)\fR"
-/* The network interface addresses that this mail system receives
+/* The local network interface addresses that this mail system receives
/* mail on.
/* .IP "\fBinet_protocols (see 'postconf -d output')\fR"
/* The Internet protocols Postfix will attempt to use when making
/* or accepting connections.
/* .IP "\fBimport_environment (see 'postconf -d' output)\fR"
-/* The list of environment parameters that a privileged Postfix
+/* The list of environment variables that a privileged Postfix
/* process will import from a non-Postfix parent process, or name=value
/* environment overrides.
/* .IP "\fBmail_owner (postfix)\fR"
@@ -495,7 +495,7 @@ int main(int argc, char **argv)
vstring_sprintf(lock_path, "%s/%s.pid", DEF_PID_DIR, var_procname);
if (test_lock && access(vstring_str(lock_path), F_OK) < 0)
exit(0);
- lock_fp = open_lock(vstring_str(lock_path), O_RDWR | O_CREAT, 0644, why);
+ lock_fp = open_lock(vstring_str(lock_path), O_RDWR | O_CREAT, 0600, why);
if (test_lock)
exit(lock_fp ? 0 : 1);
if (lock_fp == 0)
@@ -513,7 +513,7 @@ int main(int argc, char **argv)
vstring_sprintf(data_lock_path, "%s/%s.lock", var_data_dir, var_procname);
set_eugid(var_owner_uid, var_owner_gid);
data_lock_fp =
- open_lock(vstring_str(data_lock_path), O_RDWR | O_CREAT, 0644, why);
+ open_lock(vstring_str(data_lock_path), O_RDWR | O_CREAT, 0600, why);
set_ugid(getuid(), getgid());
if (data_lock_fp == 0)
msg_fatal("open lock file %s: %s",
diff --git a/postfix/src/postlog/postlog.c b/postfix/src/postlog/postlog.c
index 7175f4234..195ebd918 100644
--- a/postfix/src/postlog/postlog.c
+++ b/postfix/src/postlog/postlog.c
@@ -82,6 +82,12 @@
/* \fBpostlogd\fR(8) service.
/* .IP "\fBpostlog_service_name (postlog)\fR"
/* The name of the \fBpostlogd\fR(8) service entry in master.cf.
+/* .PP
+/* Available in Postfix 3.9 and later:
+/* .IP "\fBmaillog_file_permissions (0600)\fR"
+/* The file access permissions that will be set when the file
+/* $maillog_file is created for the first time, or when the file is
+/* created after an existing file is rotated.
/* SEE ALSO
/* postconf(5), configuration parameters
/* postlogd(8), Postfix logging
diff --git a/postfix/src/postlogd/postlogd.c b/postfix/src/postlogd/postlogd.c
index 902cbe5d3..33d7c8b41 100644
--- a/postfix/src/postlogd/postlogd.c
+++ b/postfix/src/postlogd/postlogd.c
@@ -56,6 +56,12 @@
/* .IP "\fBpostlogd_watchdog_timeout (10s)\fR"
/* How much time a \fBpostlogd\fR(8) process may take to process a request
/* before it is terminated by a built-in watchdog timer.
+/* .PP
+/* Available in Postfix 3.9 and later:
+/* .IP "\fBmaillog_file_permissions (0600)\fR"
+/* The file access permissions that will be set when the file
+/* $maillog_file is created for the first time, or when the file is
+/* created after an existing file is rotated.
/* SEE ALSO
/* postconf(5), configuration parameters
/* syslogd(8), system logging
diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in
index f69dec58e..d795f69d6 100644
--- a/postfix/src/util/Makefile.in
+++ b/postfix/src/util/Makefile.in
@@ -2157,6 +2157,7 @@ logwriter.o: logwriter.c
logwriter.o: logwriter.h
logwriter.o: msg.h
logwriter.o: mymalloc.h
+logwriter.o: name_code.h
logwriter.o: safe_open.h
logwriter.o: sys_defs.h
logwriter.o: vbuf.h
diff --git a/postfix/src/util/logwriter.c b/postfix/src/util/logwriter.c
index aea2767f8..4a18be314 100644
--- a/postfix/src/util/logwriter.c
+++ b/postfix/src/util/logwriter.c
@@ -21,6 +21,9 @@
/* const char *path,
/* const char *buffer,
/* ssize_t buflen)
+/*
+/* int set_logwriter_create_perms(
+/* const char *mode)
/* DESCRIPTION
/* This module manages a logfile writer.
/*
@@ -38,6 +41,15 @@
/* logwriter_one_shot() combines all the above operations. The
/* result is zero if successful, VSTREAM_EOF if any operation
/* failed.
+/*
+/* set_logwriter_create_perms() sets the file permissions that
+/* will be used when creating a logfile. Valid inputs are
+/* "644", "640", and "600". Leading zeros are allowed and
+/* ignored.
+/* DIAGNOSTICS
+/* Fatal error: logfile create error; warning: logfile permission
+/* change error. set_logwriter_create_perms() returns the file
+/* create permission if the request is valid, -1 otherwise.
/* LICENSE
/* .ad
/* .fi
@@ -66,10 +78,12 @@
#include
#include
#include
+#include
/*
* Application-specific.
*/
+static int logwriter_perms = 0600;
/* logwriter_open_or_die - open logfile */
@@ -82,7 +96,7 @@ VSTREAM *logwriter_open_or_die(const char *path)
#define NO_CHOWN (-1)
#define NO_CHGRP (-1)
- fp = safe_open(path, O_CREAT | O_WRONLY | O_APPEND, 0644,
+ fp = safe_open(path, O_CREAT | O_WRONLY | O_APPEND, logwriter_perms,
NO_STATP, NO_CHOWN, NO_CHGRP, why);
if (fp == 0)
msg_fatal("open logfile '%s': %s", path, vstring_str(why));
@@ -122,3 +136,21 @@ int logwriter_one_shot(const char *path, const char *buf, ssize_t len)
err |= logwriter_close(fp);
return (err ? VSTREAM_EOF : 0);
}
+
+/* set_logwriter_create_perms - logfile permission control */
+
+int set_logwriter_create_perms(const char *mode_str)
+{
+ static const NAME_CODE sane_perms[] = {
+ "644", 0644,
+ "640", 0640,
+ "600", 0600,
+ 0, -1,
+ };
+ int perms;
+
+ if ((perms = name_code(sane_perms, NAME_CODE_FLAG_NONE,
+ mode_str + strspn(mode_str, "0"))) != -1)
+ logwriter_perms = perms;
+ return (perms);
+}
diff --git a/postfix/src/util/logwriter.h b/postfix/src/util/logwriter.h
index f5266e4b7..c827d25f5 100644
--- a/postfix/src/util/logwriter.h
+++ b/postfix/src/util/logwriter.h
@@ -23,6 +23,7 @@ extern VSTREAM *logwriter_open_or_die(const char *);
extern int logwriter_write(VSTREAM *, const char *, ssize_t);
extern int logwriter_close(VSTREAM *);
extern int logwriter_one_shot(const char *, const char *, ssize_t);
+extern int set_logwriter_create_perms(const char *);
/* LICENSE
/* .ad
diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c
index b4f9fbb67..affbcc0df 100644
--- a/postfix/src/util/vstream.c
+++ b/postfix/src/util/vstream.c
@@ -522,6 +522,7 @@
/* System library. */
#include
+#include
#include /* 44BSD stdarg.h uses abort() */
#include
#include
@@ -1386,7 +1387,38 @@ VSTREAM *vstream_fopen(const char *path, int flags, mode_t mode)
VSTREAM *stream;
int fd;
- if ((fd = open(path, flags, mode)) < 0) {
+ /*
+ * To set permissions on new files only, we need to distinguish between
+ * creating a new file and opening an existing one.
+ */
+#define open_create(path, flags, mode) \
+ open((path), (flags) | (O_CREAT | O_EXCL), (mode))
+#define open_exist(path, flags, mode) \
+ open((path), (flags) & ~(O_CREAT | O_EXCL), (mode))
+
+ switch (flags & (O_CREAT | O_EXCL)) {
+ case O_CREAT:
+ fd = open_exist(path, flags, mode);
+ if (fd < 0 && errno == ENOENT) {
+ fd = open_create(path, flags, mode);
+ if (fd >= 0) {
+ if (fchmod(fd, mode) < 0) /* can't uncreate */
+ msg_warn("fchmod %s 0%o: %m", path, (unsigned) mode);
+ } else if ( /* fd < 0 && */ errno == EEXIST)
+ fd = open_exist(path, flags, mode);
+ }
+ break;
+ case O_CREAT | O_EXCL:
+ fd = open(path, flags, mode);
+ if (fd >= 0)
+ if (fchmod(fd, mode) < 0) /* can't uncreate */
+ msg_warn("fchmod %s 0%o: %m", path, (unsigned) mode);
+ break;
+ default:
+ fd = open(path, flags, mode);
+ break;
+ }
+ if (fd < 0) {
return (0);
} else {
stream = vstream_fdopen(fd, flags);