and broke reject_unauthenticated_sender_login_mismatch and
reject_sender_login_mismatch. Based on fix by Victor
Duchovni. File: smtpd/smtpd_check.c.
+
+20090603
+
+ Cleanup: Postfix 2.3 adopted a file descriptor passing
+ workaround for OpenBSD. This workaround was hard-coded for
+ all platforms because there were no have adverse effects.
+ This is no longer the case: OpenBSD is fixed, and NetBSD
+ does not like the workaround. We now default back to the
+ non-workaround code and turn on the workaround dynamically.
+ Files: util/unix_send_fd.c, unix_recv_fd.c, unix_pass_fd_fix.c.
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20090528"
+#define MAIL_RELEASE_DATE "20090603"
#define MAIL_VERSION_NUMBER "2.7"
#ifdef SNAPSHOT
vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \
allascii.c load_file.c killme_after.c vstream_tweak.c upass_connect.c \
- upass_listen.c upass_trigger.c edit_file.c inet_windowsize.c
+ upass_listen.c upass_trigger.c edit_file.c inet_windowsize.c \
+ unix_pass_fd_fix.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \
allascii.o load_file.o killme_after.o vstream_tweak.o upass_connect.o \
- upass_listen.o upass_trigger.o edit_file.o inet_windowsize.o
+ upass_listen.o upass_trigger.o edit_file.o inet_windowsize.o \
+ unix_pass_fd_fix.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \
edit_file.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
- stream_test.c dup2_pass_on_exec.c
+ stream_test.c dup2_pass_on_exec.c test_send_fd test_recv_fd
DEFS = -I. -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
FILES = Makefile $(SRCS) $(HDRS)
inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \
attr_scan0 host_port attr_scan_plain attr_print_plain htable \
unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
- myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv
+ myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \
+ test_send_fd test_recv_fd
LIB_DIR = ../../lib
INC_DIR = ../../include
argv.o: sys_defs.h
argv_split.o: argv.h
argv_split.o: argv_split.c
-argv_split.o: mymalloc.h
argv_split.o: msg.h
+argv_split.o: mymalloc.h
argv_split.o: stringops.h
argv_split.o: sys_defs.h
argv_split.o: vbuf.h
unix_listen.o: sane_accept.h
unix_listen.o: sys_defs.h
unix_listen.o: unix_listen.c
+unix_pass_fd_fix.o: iostuff.h
+unix_pass_fd_fix.o: name_mask.h
+unix_pass_fd_fix.o: sys_defs.h
+unix_pass_fd_fix.o: unix_pass_fd_fix.c
+unix_pass_fd_fix.o: vbuf.h
+unix_pass_fd_fix.o: vstring.h
unix_recv_fd.o: iostuff.h
unix_recv_fd.o: msg.h
unix_recv_fd.o: sys_defs.h
#define CLOSE_ON_EXEC 1
#define PASS_ON_EXEC 0
+extern int unix_pass_fd_fix;
+extern void set_unix_pass_fd_fix(const char *);
+
+#define UNIX_PASS_FD_FIX_NONE (0)
+#define UNIX_PASS_FD_FIX_CMSG_LEN (1<<0)
+
/* LICENSE
/* .ad
/* .fi
--- /dev/null
+/*++
+/* NAME
+/* unix_pass_fd_fix 3
+/* SUMMARY
+/* file descriptor passing bug workarounds
+/* SYNOPSIS
+/* #include <iostuff.h>
+/*
+/* void set_unix_pass_fd_fix(workarounds)
+/* const char *workarounds;
+/* DESCRIPTION
+/* This module supports programmatic control over workarounds
+/* for sending or receiving file descriptors over UNIX-domain
+/* sockets.
+/*
+/* set_unix_pass_fd_fix() takes a list of workarouds in external
+/* form, and stores their internal representation. The result
+/* is used by unix_send_fd() and unix_recv_fd().
+/*
+/* Arguments:
+/* .IP workarounds
+/* List of zero or more of the following, separated by comma
+/* or whitespace.
+/* .RS
+/* .IP cmsg_len
+/* Send the CMSG_LEN of the file descriptor, instead of
+/* the total message buffer length.
+/* .RE
+/* SEE ALSO
+/* unix_send_fd(3) send file descriptor
+/* unix_recv_fd(3) receive file descriptor
+/* DIAGNOSTICS
+/* Fatal errors: non-existent workaround.
+/* 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
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <iostuff.h>
+#include <name_mask.h>
+
+int unix_pass_fd_fix = 0;
+
+/* set_unix_pass_fd_fix - set workaround programmatically */
+
+void set_unix_pass_fd_fix(const char *workarounds)
+{
+ const static NAME_MASK table[] = {
+ "cmsg_len", UNIX_PASS_FD_FIX_CMSG_LEN,
+ 0,
+ };
+
+ unix_pass_fd_fix = name_mask("descriptor passing workarounds",
+ table, workarounds);
+}
/*
* Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
* Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE, for
- * portability to LP64 environments.
+ * portability to some LP64 environments. See also unix_send_fd.c.
*/
#if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
union {
memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
msg.msg_control = control_un.control;
- msg.msg_controllen = CMSG_LEN(sizeof(newfd)); /* Fix 200506 */
+ if (unix_pass_fd_fix & UNIX_PASS_FD_FIX_CMSG_LEN) {
+ msg.msg_controllen = CMSG_LEN(sizeof(newfd)); /* Fix 200506 */
+ } else {
+ msg.msg_controllen = sizeof(control_un.control); /* normal */
+ }
#else
msg.msg_accrights = (char *) &newfd;
msg.msg_accrightslen = sizeof(newfd);
ssize_t read_count;
char buf[1024];
- if (argc != 2
+ if (argc < 2 || argc > 3
|| (endpoint = split_at(transport = argv[1], ':')) == 0
|| *endpoint == 0 || *transport == 0)
- msg_fatal("usage: %s transport:endpoint", argv[0]);
+ msg_fatal("usage: %s transport:endpoint [workaround]", argv[0]);
if (strcmp(transport, "unix") == 0) {
listen_sock = unix_listen(endpoint, 10, BLOCKING);
if (client_sock < 0)
msg_fatal("accept: %m");
+ set_unix_pass_fd_fix(argv[2] ? argv[2] : "");
+
while ((client_fd = unix_recv_fd(client_sock)) >= 0) {
- msg_info("client_fd = %d", client_fd);
+ msg_info("client_fd = %d, fix=%d", client_fd, unix_pass_fd_fix);
while ((read_count = read(client_fd, buf, sizeof(buf))) > 0)
write(1, buf, read_count);
if (read_count < 0)
/*
* Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
- * Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE; the
- * latter breaks on LP64 systems.
+ * Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE, for
+ * portability to some LP64 environments. See also unix_recv_fd.c.
*/
#if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
union {
} control_un;
struct cmsghdr *cmptr;
- memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
+ memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
msg.msg_control = control_un.control;
- msg.msg_controllen = CMSG_LEN(sizeof(sendfd)); /* Fix 200506 */
-
+ if (unix_pass_fd_fix & UNIX_PASS_FD_FIX_CMSG_LEN) {
+ msg.msg_controllen = CMSG_LEN(sizeof(sendfd)); /* Fix 200506 */
+ } else {
+ msg.msg_controllen = sizeof(control_un.control); /* normal */
+ }
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(sendfd));
cmptr->cmsg_level = SOL_SOCKET;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
- return (sendmsg(fd, &msg, 0));
+ /*
+ * The CMSG_LEN workaround was originally developed for OpenBSD 3.6 on
+ * 64-bit SPARC (later also confirmed on AMD64). It was hard-coded with
+ * Postfix 2.3 for all platforms because of increasing pressure to work
+ * on other things.
+ *
+ * The investigation was reopened with Postfix 2.7 because the workaround
+ * broke on NetBSD 5.0. This time it was found that OpenBSD on AMD64
+ * needs the workaround for sending only. We assume that OpenBSD on AMD64
+ * and SPARC64 are similar, and turn on the workaround on-the-fly. The
+ * OpenBSD problem was fixed for AMD64 and SPARC64 with OpenBSD 4.4 or
+ * 4.5.
+ *
+ * The workaround was made run-time configurable to make the investigation
+ * possible on many different platforms. Though the code is over-kill for
+ * this particular problem, it is left in place so that it can serve as
+ * an example of how to add run-time configurable workarounds to Postfix.
+ */
+ if (sendmsg(fd, &msg, 0) >= 0)
+ return (0);
+ if (unix_pass_fd_fix == 0) {
+ if (msg_verbose)
+ msg_info("sendmsg error (%m). Trying CMSG_LEN workaround.");
+ unix_pass_fd_fix = UNIX_PASS_FD_FIX_CMSG_LEN;
+ return (unix_send_fd(fd, sendfd));
+ } else {
+ return (-1);
+ }
#endif
}
int server_sock;
int client_fd;
+ msg_verbose = 1;
+
if (argc < 3
|| (endpoint = split_at(transport = argv[1], ':')) == 0
|| *endpoint == 0 || *transport == 0)