]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.7-20090603
authorWietse Venema <wietse@porcupine.org>
Wed, 3 Jun 2009 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:35:30 +0000 (06:35 +0000)
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/util/Makefile.in
postfix/src/util/iostuff.h
postfix/src/util/unix_pass_fd_fix.c [new file with mode: 0644]
postfix/src/util/unix_recv_fd.c
postfix/src/util/unix_send_fd.c

index 11e8501ef106e6a5cb2dbee4ad79cc53cb75d4dc..693173fe0e3f0bffe613fc0d96f88a7ef6505f53 100644 (file)
@@ -15268,3 +15268,13 @@ Apologies for any names omitted.
        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.
index 8a6f55a6d312ed7f0267321de31e3bea67c12ad1..f17139bfc008ed502629da84518ebdee6aaa5235 100644 (file)
@@ -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      "20090528"
+#define MAIL_RELEASE_DATE      "20090603"
 #define MAIL_VERSION_NUMBER    "2.7"
 
 #ifdef SNAPSHOT
index de0172e2faa55b25ca75521fcb7db0676a5cb0ef..96ca508b886b0246f8c41b5174ef43e108e80005 100644 (file)
@@ -31,7 +31,8 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        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 \
@@ -64,7 +65,8 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.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 \
@@ -86,7 +88,7 @@ HDRS  = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.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)
@@ -101,7 +103,8 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
        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
@@ -568,8 +571,8 @@ argv.o: mymalloc.h
 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
@@ -1552,6 +1555,12 @@ unix_listen.o: msg.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
index da0955c66f199f0b6c6660daf6ac9d6a568b632c..8a2704a96d87f7a7a6ed09a142b733ca87966a58 100644 (file)
@@ -45,6 +45,12 @@ extern void set_inet_windowsize(int, int);
 #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
diff --git a/postfix/src/util/unix_pass_fd_fix.c b/postfix/src/util/unix_pass_fd_fix.c
new file mode 100644 (file)
index 0000000..d59f089
--- /dev/null
@@ -0,0 +1,67 @@
+/*++
+/* 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);
+}
index 7958489c4fe8db04afbacf26a2b0a7f0d2fb5788..cb6c8aaffe3f00c5b547dd50e78d4a089559544e 100644 (file)
@@ -63,7 +63,7 @@ int     unix_recv_fd(int fd)
     /*
      * 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 {
@@ -74,7 +74,11 @@ int     unix_recv_fd(int fd)
 
     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);
@@ -141,10 +145,10 @@ int     main(int argc, char **argv)
     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);
@@ -158,8 +162,10 @@ int     main(int argc, char **argv)
     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)
index a598b4496211d36a5d525a0c69c35a48d361c2e3..d9266244a6f8649531b618ab76d76823ef32ee9f 100644 (file)
@@ -64,8 +64,8 @@ int     unix_send_fd(int fd, int sendfd)
 
     /*
      * 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 {
@@ -74,10 +74,13 @@ int     unix_send_fd(int fd, int sendfd)
     }       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;
@@ -101,7 +104,34 @@ int     unix_send_fd(int fd, int sendfd)
     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
 }
 
@@ -126,6 +156,8 @@ int     main(int argc, char **argv)
     int     server_sock;
     int     client_fd;
 
+    msg_verbose = 1;
+
     if (argc < 3
        || (endpoint = split_at(transport = argv[1], ':')) == 0
        || *endpoint == 0 || *transport == 0)