]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.4-20070224
authorWietse Venema <wietse@porcupine.org>
Sat, 24 Feb 2007 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:32:59 +0000 (06:32 +0000)
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/mbox_open.c
postfix/src/util/sys_defs.h

index 8c4507f2cda716c9186244a193067a1fe4680327..34c956f4e6ea650348834b68606f4815a1c2dbae 100644 (file)
@@ -13296,6 +13296,15 @@ Apologies for any names omitted.
        master/trigger_server.c, master/single_server.c,
        master/multi_server.c.
 
+20070224
+
+       Workaround: GNU POP3D creates a new mailbox and deletes the
+       old one. Postfix now backs off and retries delivery later,
+       instead of appending mail to a deleted file.  To minimize
+       the use of this workaround, Postfix now by default creates
+       mailbox dotlock files on all systems, and creates dotlock
+       files before opening mailbox files.  Files: util/sys_defs.h.
+
 Wish list:
 
        Update message content length when adding/removing headers.
index 8eecb2154ba931680936f823779957361e514f17..ffc0493d80ad4317c860e83dafa62cc366f42635 100644 (file)
@@ -17,6 +17,14 @@ Incompatibility with Postfix 2.2 and earlier
 If you upgrade from Postfix 2.2 or earlier, read RELEASE_NOTES-2.3
 before proceeding.
 
+Incompatibility with Postfix snapshot 200702224
+===============================================
+
+As a safety measure, Postfix now by default creates mailbox dotlock
+files on all systems. This prevents problems with GNU POP3D which
+subverts kernel locking by creating a new mailbox file and deleting
+the old one.
+
 Major changes with Postfix snapshot 20070212-event
 ==================================================
 
index ab4399f9803fe470bd54d226aeafbe7abe4efe4b..4c3c3f3ca2bf378514259b006a7cf4b1683a624b 100644 (file)
@@ -2112,7 +2112,7 @@ extern char *var_virt_mailbox_base;
 extern int var_virt_mailbox_limit;
 
 #define VAR_VIRT_MAILBOX_LOCK          "virtual_mailbox_lock"
-#define DEF_VIRT_MAILBOX_LOCK          "fcntl"
+#define DEF_VIRT_MAILBOX_LOCK          "fcntl, dotlock"
 extern char *var_virt_mailbox_lock;
 
  /*
index f2a3db154966a2b58ae01b847d42c985305f4e15..b19682762550397049d77b77715b8f6d52b12114 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      "20070223"
+#define MAIL_RELEASE_DATE      "20070224"
 #define MAIL_VERSION_NUMBER    "2.4"
 
 #ifdef SNAPSHOT
index de3d1551eb2794f38626fbdfbd8a71b2c4595413..42fae4ca17cbe550fbddecc9496d22d94b642b0f 100644 (file)
@@ -111,26 +111,8 @@ MBOX   *mbox_open(const char *path, int flags, mode_t mode, struct stat * st,
     int     locked = 0;
     VSTREAM *fp;
 
-    /*
-     * Open or create the target file. In case of a privileged open, the
-     * privileged user may be attacked with hard/soft link tricks in an
-     * unsafe parent directory. In case of an unprivileged open, the mail
-     * system may be attacked by a malicious user-specified path, or the
-     * unprivileged user may be attacked with hard/soft link tricks in an
-     * unsafe parent directory. Open non-blocking to fend off attacks
-     * involving non-file targets.
-     * 
-     * We open before locking, so that we can avoid attempts to dot-lock
-     * destinations such as /dev/null.
-     */
     if (st == 0)
        st = &local_statbuf;
-    if ((fp = safe_open(path, flags | O_NONBLOCK, mode, st,
-                       chown_uid, chown_gid, why->reason)) == 0) {
-       dsb_status(why, mbox_dsn(errno, def_dsn));
-       return (0);
-    }
-    close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
 
     /*
      * If this is a regular file, create a dotlock file. This locking method
@@ -143,26 +125,49 @@ MBOX   *mbox_open(const char *path, int flags, mode_t mode, struct stat * st,
      * for bass-awkward compatibility with existing installations that
      * deliver to files in non-writable directories.
      * 
-     * Alternatively, we could dot-lock the file before opening, but then we
-     * would be doing silly things like dot-locking /dev/null, something that
-     * an unprivileged user is not supposed to be able to do.
+     * We dot-lock the file before opening, so we must avoid doing silly things
+     * like dot-locking /dev/null. Fortunately, deliveries to non-mailbox
+     * files execute with recipient privileges, so we don't have to worry
+     * about creating dotlock files in places where the recipient would not
+     * be able to write.
+     * 
+     * Note: we use stat() to follow symlinks, because safe_open() allows the
+     * target to be a root-owned symlink, and we don't want to create dotlock
+     * files for /dev/null or other non-file objects.
      */
-    if (S_ISREG(st->st_mode) && (lock_style & MBOX_DOT_LOCK)) {
+    if ((lock_style & MBOX_DOT_LOCK)
+       && (stat(path, st) < 0 || S_ISREG(st->st_mode))) {
        if (dot_lockfile(path, why->reason) == 0) {
            locked |= MBOX_DOT_LOCK;
        } else if (errno == EEXIST) {
            dsb_status(why, mbox_dsn(EAGAIN, def_dsn));
-           vstream_fclose(fp);
            return (0);
        } else if (lock_style & MBOX_DOT_LOCK_MAY_FAIL) {
            msg_warn("%s", vstring_str(why->reason));
        } else {
            dsb_status(why, mbox_dsn(errno, def_dsn));
-           vstream_fclose(fp);
            return (0);
        }
     }
 
+    /*
+     * Open or create the target file. In case of a privileged open, the
+     * privileged user may be attacked with hard/soft link tricks in an
+     * unsafe parent directory. In case of an unprivileged open, the mail
+     * system may be attacked by a malicious user-specified path, or the
+     * unprivileged user may be attacked with hard/soft link tricks in an
+     * unsafe parent directory. Open non-blocking to fend off attacks
+     * involving non-file targets.
+     */
+    if ((fp = safe_open(path, flags | O_NONBLOCK, mode, st,
+                       chown_uid, chown_gid, why->reason)) == 0) {
+       if (locked & MBOX_DOT_LOCK)
+           dot_unlockfile(path);
+       dsb_status(why, mbox_dsn(errno, def_dsn));
+       return (0);
+    }
+    close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
+
     /*
      * If this is a regular file, acquire kernel locks. flock() locks are not
      * intended to work across a network; fcntl() locks are supposed to work
@@ -184,6 +189,28 @@ MBOX   *mbox_open(const char *path, int flags, mode_t mode, struct stat * st,
            return (0);
        }
     }
+
+    /*
+     * Sanity check: reportedly, GNU POP3D creates a new mailbox file and
+     * deletes the old one. This does not play well with software that opens
+     * the mailbox first and then locks it, such as software that that uses
+     * FCNTL or FLOCK locks on open file descriptors (some UNIX systems don't
+     * use dotlock files).
+     * 
+     * To detect that GNU POP3D deletes the mailbox file we look at the target
+     * file hard-link count. Note that safe_open() guarantees a hard-link
+     * count of 1, so any change in this count is a sign of trouble.
+     */
+    if (S_ISREG(st->st_mode)
+       && (fstat(vstream_fileno(fp), st) < 0 || st->st_nlink != 1)) {
+       vstring_sprintf(why->reason, "target file status changed unexpectedly");
+       dsb_status(why, mbox_dsn(EAGAIN, def_dsn));
+       msg_warn("%s: file status changed unexpectedly", path);
+       if (locked & MBOX_DOT_LOCK)
+           dot_unlockfile(path);
+       vstream_fclose(fp);
+       return (0);
+    }
     mp = (MBOX *) mymalloc(sizeof(*mp));
     mp->path = mystrdup(path);
     mp->fp = fp;
index f99405119129d9e8ad1674fca6be76ecbaeca95c..96608aa4cbae8e335a14ec555326dce39b291af6 100644 (file)
@@ -39,7 +39,7 @@
 #define HAS_FLOCK_LOCK
 #define HAS_FCNTL_LOCK
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FLOCK
-#define DEF_MAILBOX_LOCK "flock"
+#define DEF_MAILBOX_LOCK "flock, dotlock"
 #define HAS_SUN_LEN
 #define HAS_FSYNC
 #define HAS_DB
 #define HAS_FLOCK_LOCK
 #define HAS_FCNTL_LOCK
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FLOCK
-#define DEF_MAILBOX_LOCK "flock"
+#define DEF_MAILBOX_LOCK "flock, dotlock"
 #define HAS_SUN_LEN
 #define HAS_FSYNC
 #define HAS_DB
@@ -836,7 +836,7 @@ extern int initgroups(const char *, int);
 #define HAS_DBM
 #define HAS_FCNTL_LOCK
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FCNTL
-#define DEF_MAILBOX_LOCK "fcntl"
+#define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define DEF_DB_TYPE    "dbm"
 #define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
@@ -873,7 +873,7 @@ extern int h_errno;                 /* <netdb.h> imports too much stuff */
 #define HAS_DBM
 #define HAS_FCNTL_LOCK
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FCNTL
-#define DEF_MAILBOX_LOCK "fcntl"
+#define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define DEF_DB_TYPE    "dbm"
 #define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
@@ -910,7 +910,7 @@ extern int h_errno;                 /* <netdb.h> imports too much stuff */
 #define HAS_DBM
 #define HAS_FCNTL_LOCK
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FCNTL
-#define DEF_MAILBOX_LOCK "fcntl"
+#define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define HAS_NIS
 #define MISSING_SETENV
@@ -950,7 +950,7 @@ extern int h_errno;
 #define HAS_DBM
 #define HAS_FLOCK_LOCK
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FLOCK
-#define DEF_MAILBOX_LOCK "flock"
+#define DEF_MAILBOX_LOCK "flock, dotlock"
 #define USE_STATFS
 #define HAVE_SYS_DIR_H
 #define STATFS_IN_SYS_VFS_H
@@ -1003,7 +1003,7 @@ typedef unsigned short mode_t;
 #define HAS_DBM
 #define HAS_FLOCK_LOCK
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FLOCK
-#define DEF_MAILBOX_LOCK "flock"
+#define DEF_MAILBOX_LOCK "flock, dotlock"
 #define USE_STATFS
 #define HAVE_SYS_DIR_H
 #define STATFS_IN_SYS_VFS_H