From b1040b6d72802f606bab5049a3fdea02de2bf35d Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sat, 24 Feb 2007 00:00:00 -0500 Subject: [PATCH] postfix-2.4-20070224 --- postfix/HISTORY | 9 ++++ postfix/RELEASE_NOTES | 8 ++++ postfix/src/global/mail_params.h | 2 +- postfix/src/global/mail_version.h | 2 +- postfix/src/global/mbox_open.c | 75 +++++++++++++++++++++---------- postfix/src/util/sys_defs.h | 14 +++--- 6 files changed, 77 insertions(+), 33 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 8c4507f2c..34c956f4e 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 8eecb2154..ffc0493d8 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -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 ================================================== diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index ab4399f98..4c3c3f3ca 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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; /* diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index f2a3db154..b19682762 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 "20070223" +#define MAIL_RELEASE_DATE "20070224" #define MAIL_VERSION_NUMBER "2.4" #ifdef SNAPSHOT diff --git a/postfix/src/global/mbox_open.c b/postfix/src/global/mbox_open.c index de3d1551e..42fae4ca1 100644 --- a/postfix/src/global/mbox_open.c +++ b/postfix/src/global/mbox_open.c @@ -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; diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index f99405119..96608aa4c 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -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 @@ -179,7 +179,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 @@ -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; /* 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; /* 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