]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20001127
authorWietse Venema <wietse@porcupine.org>
Mon, 27 Nov 2000 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:26:57 +0000 (06:26 +0000)
postfix/.indent.pro
postfix/src/global/mail_version.h
postfix/src/global/mbox_open.c
postfix/src/global/mbox_open.h
postfix/src/local/file.c
postfix/src/local/mailbox.c
postfix/src/postlock/postlock.c

index 8c52cbf791a690ddcdad4df48197f0d33e82a127..dd75ae0bd902db80d2c202857dde14e4e814d899 100644 (file)
@@ -68,6 +68,7 @@
 -TMASTER_SERV
 -TMASTER_STATUS
 -TMBLOCK
+-TMBOX
 -TMKMAP
 -TMKMAP_OPEN_INFO
 -TMULTI_SERVER
index e0067e4afdbf643927bbfc4e2237fb299d66c846..ea69a239beaa99d75c464c3be2347b1bfa355883 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20001126"
+#define DEF_MAIL_VERSION       "Snapshot-20001127"
 extern char *var_mail_version;
 
 /* LICENSE
index 36474482f5cea500ae2bde1f9840618a097cfdc6..6b512e6628c32a8afaeb1e75ef5d4d9803c39b2b 100644 (file)
@@ -6,7 +6,14 @@
 /* SYNOPSIS
 /*     #include <mbox_open.h>
 /*
-/*     int     mbox_open(path, flags, mode, st, user, group, lock_style, why)
+/*     typedef struct {
+/* .in +4
+/*     /* public members... */
+/*     VSTREAM *fp;
+/* .in -4
+/*     } MBOX;
+/*
+/*     MBOX    *mbox_open(path, flags, mode, st, user, group, lock_style, why)
 /*     const char *path;
 /*     int     flags;
 /*     int     mode;
@@ -16,9 +23,8 @@
 /*     int     lock_style;
 /*     VSTRING *why;
 /*
-/*     void    mbox_release(path, lock_style)
-/*     const char *path;
-/*     int     lock_style;
+/*     void    mbox_release(mbox)
+/*     MBOX    *mbox;
 /* DESCRIPTION
 /*     This module manages access to UNIX mailbox-style files.
 /*
 /*     adequate effective privileges.
 /*     The \fBlock_style\fR argument specifies a lock style from
 /*     mbox_lock_mask(). Kernel locks are applied to regular files only.
+/*     The result is a handle that must be destroyed by mbox_release().
 /*
 /*     mbox_release() releases the named mailbox. It is up to the
-/*     application to close the file.
+/*     application to close the stream.
 /* DIAGNOSTICS
 /*     mbox_open() returns a null pointer in case of problems, and
 /*     sets errno to EAGAIN if someone else has exclusive access.
@@ -59,6 +66,8 @@
 #include <vstream.h>
 #include <vstring.h>
 #include <safe_open.h>
+#include <iostuff.h>
+#include <mymalloc.h>
 
 /* Global library. */
 
 
 /* mbox_open - open mailbox-style file for exclusive access */
 
-VSTREAM *mbox_open(const char *path, int flags, int mode, struct stat * st,
-                          uid_t chown_uid, gid_t chown_gid,
-                          int lock_style, VSTRING *why)
+MBOX   *mbox_open(const char *path, int flags, int mode, struct stat * st,
+                         uid_t chown_uid, gid_t chown_gid,
+                         int lock_style, VSTRING *why)
 {
     struct stat local_statbuf;
+    MBOX   *mp;
+    int     locked = 0;
     VSTREAM *fp;
 
     /*
      * Create dotlock file. This locking method does not work well over NFS:
      * creating files atomically is a problem, and a successful operation can
      * fail with EEXIST.
+     * 
+     * If file.lock can't be created, ignore the problem if the application says
+     * so. We need this so that Postfix can deliver as unprivileged user to
+     * /dev/null style aliases. Alternatively, we could open the file first,
+     * and dot-lock the file only if it is a regular file, just like we do
+     * with kernel locks.
      */
-    if ((lock_style & MBOX_DOT_LOCK) && dot_lockfile(path, why) < 0) {
-       if (errno == EEXIST) {
-           errno = EAGAIN;
-           return (0);
+    if (lock_style & MBOX_DOT_LOCK) {
+       if (dot_lockfile(path, why) == 0) {
+           locked |= MBOX_DOT_LOCK;
+       } else {
+           if (errno == EEXIST) {
+               errno = EAGAIN;
+               return (0);
+           }
+           if ((lock_style & MBOX_DOT_LOCK_MAY_FAIL) == 0) {
+               return (0);
+           }
        }
-
-       /*
-        * If file.lock can't be created, ignore the problem. We need this so
-        * that Postfix can deliver as unprivileged user to /dev/null
-        * aliases.
-        */
-       if ((lock_style & MBOX_DOT_LOCK_MAY_FAIL) == 0)
-           return (0);
     }
 
     /*
-     * Open or create the target file.
+     * Open or create the target file. In case of a privileged open, the
+     * privileged user may be attacked through an unsafe parent directory. In
+     * case of an unprivileged open, the mail system may be attacked by a
+     * malicious user-specified path, and the unprivileged user may be
+     * attacked through an unsafe parent directory. Open non-blocking to fend
+     * off attacks involving FIFOs and other weird targets.
      */
     if (st == 0)
        st = &local_statbuf;
-    if ((fp = safe_open(path, flags, mode, st, chown_uid, chown_gid, why)) == 0) {
-       if (lock_style & MBOX_DOT_LOCK)
+    if ((fp = safe_open(path, flags, mode | O_NONBLOCK, st,
+                       chown_uid, chown_gid, why)) == 0) {
+       if (locked & MBOX_DOT_LOCK)
            dot_unlockfile(path);
        return (0);
     }
+    non_blocking(vstream_fileno(fp), BLOCKING);
+    close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
 
     /*
      * Acquire kernel locks, but only if the target is a regular file, in
@@ -121,17 +145,23 @@ VSTREAM *mbox_open(const char *path, int flags, int mode, struct stat * st,
            || LOCK_FAIL(MBOX_FCNTL_LOCK, MYFLOCK_STYLE_FCNTL))) {
        if (myflock_locked(vstream_fileno(fp)))
            errno = EAGAIN;
-       if (lock_style & MBOX_DOT_LOCK)
+       if (locked & MBOX_DOT_LOCK)
            dot_unlockfile(path);
        return (0);
     }
-    return (fp);
+    mp = (MBOX *) mymalloc(sizeof(*mp));
+    mp->path = mystrdup(path);
+    mp->fp = fp;
+    mp->locked = locked;
+    return (mp);
 }
 
 /* mbox_release - release mailbox exclusive access */
 
-void    mbox_release(const char *path, int lock_style)
+void    mbox_release(MBOX *mp)
 {
-    if (lock_style & MBOX_DOT_LOCK)
-       dot_unlockfile(path);
+    if (mp->locked & MBOX_DOT_LOCK)
+       dot_unlockfile(mp->path);
+    myfree(mp->path);
+    myfree((char *) mp);
 }
index 7e98772ab758e9b77f419140eb2017626b21d1b5..940f04b52233b7c4f1955720b2033135ec7cfd46 100644 (file)
  /*
   * External interface.
   */
-extern VSTREAM *mbox_open(const char *, int, int, struct stat *, uid_t, gid_t, int, VSTRING *);
-extern void mbox_release(const char *, int);
+typedef struct {
+    char    *path;                     /* saved path, for dot_unlock */
+    VSTREAM *fp;                       /* open stream or null */
+    int     locked;                    /* what locks were set */
+} MBOX;
+extern MBOX *mbox_open(const char *, int, int, struct stat *, uid_t, gid_t, int, VSTRING *);
+extern void mbox_release(MBOX *);
 
 /* LICENSE
 /* .ad
index f3b0af1c14481b294e31bdebc02330868e0098ec..75588ea618a0303743c114de08722b6697f38df1 100644 (file)
@@ -84,7 +84,7 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
 {
     char   *myname = "deliver_file";
     struct stat st;
-    VSTREAM *dst;
+    MBOX   *mp;
     VSTRING *why;
     int     status;
     int     copy_flags;
@@ -148,26 +148,27 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
        copy_flags &= ~MAIL_COPY_DELIVERED;
 
     set_eugid(usr_attr.uid, usr_attr.gid);
-    dst = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
-                   S_IRUSR | S_IWUSR, &st, -1, -1,
-                   local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL, why);
-    if (dst == 0) {
+    mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
+                  S_IRUSR | S_IWUSR, &st, -1, -1,
+                  local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL, why);
+    if (mp == 0) {
        status = (errno == EAGAIN ? defer_append : bounce_append)
            (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
             "cannot access destination file %s: %s", path, STR(why));
     } else if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
-       vstream_fclose(dst);
+       vstream_fclose(mp->fp);
        status = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
                               "executable destination file %s", path);
-    } else if (mail_copy(COPY_ATTR(state.msg_attr), dst, S_ISREG(st.st_mode) ?
-               copy_flags : (copy_flags & ~MAIL_COPY_TOFILE), "\n", why)) {
+    } else if (mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
+       S_ISREG(st.st_mode) ? copy_flags : (copy_flags & ~MAIL_COPY_TOFILE),
+                        "\n", why)) {
        status = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
                              "cannot append destination file %s: %s",
                              path, STR(why));
     } else {
        status = sent(SENT_ATTR(state.msg_attr), "%s", path);
     }
-    mbox_release(path, local_mbox_lock_mask);
+    mbox_release(mp);
     set_eugid(var_owner_uid, var_owner_gid);
 
     /*
index cc8267a07864638b2bd24196e48a9cb28e119300..30d2ad80d706b276ff0c8f552aa947a85b2fe31d 100644 (file)
@@ -96,7 +96,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     char   *spool_dir;
     char   *mailbox;
     VSTRING *why;
-    VSTREAM *dst;
+    MBOX *mp;
     int     status;
     int     copy_flags;
     VSTRING *biff;
@@ -180,23 +180,24 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
        copy_flags &= ~MAIL_COPY_DELIVERED;
 
     set_eugid(spool_uid, spool_gid);
-    dst = mbox_open(mailbox, O_APPEND | O_WRONLY | O_CREAT,
+    mp = mbox_open(mailbox, O_APPEND | O_WRONLY | O_CREAT,
                    S_IRUSR | S_IWUSR, &st, chown_uid, chown_gid,
                    local_mbox_lock_mask, why);
-    if (dst != 0) {
+    if (mp != 0) {
        if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
            set_eugid(usr_attr.uid, usr_attr.gid);
        if (S_ISREG(st.st_mode) == 0) {
+           vstream_fclose(mp->fp);
            vstring_sprintf(why, "file %s should be a regular file", mailbox);
            errno = 0;
        } else {
-           end = vstream_fseek(dst, (off_t) 0, SEEK_END);
-           status = mail_copy(COPY_ATTR(state.msg_attr), dst,
+           end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
+           status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
                               copy_flags, "\n", why);
        }
        if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
            set_eugid(spool_uid, spool_gid);
-       mbox_release(mailbox, local_mbox_lock_mask);
+       mbox_release(mp);
     }
     set_eugid(var_owner_uid, var_owner_gid);
 
index c721db84da9a72d8ae09d0dcfeaaaad9f0cc1de2..44d7ecdeae36c9098f20f5e2e4405046b51a368b 100644 (file)
@@ -142,9 +142,9 @@ int     main(int argc, char **argv)
     int     count;
     WAIT_STATUS_T status;
     pid_t   pid;
-    int     mbox_lock;
+    int     lock_mask;
     char   *lock_style = 0;
-    VSTREAM *fp;
+    MBOX   *mp;
 
     /*
      * Be consistent with file permissions.
@@ -204,7 +204,7 @@ int     main(int argc, char **argv)
      * Read the config file.
      */
     mail_conf_read();
-    mbox_lock = mbox_lock_mask(lock_style ? lock_style :
+    lock_mask = mbox_lock_mask(lock_style ? lock_style :
               get_mail_conf_str(VAR_MAILBOX_LOCK, DEF_MAILBOX_LOCK, 1, 0));
 
     /*
@@ -212,11 +212,10 @@ int     main(int argc, char **argv)
      * command is not supposed to disappear into the background.
      */
     why = vstring_alloc(1);
-    if ((fp = mbox_open(folder, O_APPEND | O_WRONLY | O_CREAT,
+    if ((mp = mbox_open(folder, O_APPEND | O_WRONLY | O_CREAT,
                        S_IRUSR | S_IWUSR, (struct stat *) 0,
-                       -1, -1, mbox_lock, why)) == 0)
+                       -1, -1, lock_mask, why)) == 0)
        msg_fatal("%s", vstring_str(why));
-    close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
 
     /*
      * Run the command. Remove the lock after completion.
@@ -232,12 +231,12 @@ int     main(int argc, char **argv)
        default:
            if (waitpid(pid, &status, 0) < 0)
                msg_fatal("waitpid: %m");
-           mbox_release(folder, mbox_lock);
+           mbox_release(mp);
            exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
        }
        if (count + 1 < var_fork_tries)
            sleep(var_fork_delay);
     }
-    mbox_release(folder, mbox_lock);
+    mbox_release(mp);
     exit(EX_TEMPFAIL);
 }