]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20001203
authorWietse Venema <wietse@porcupine.org>
Sun, 3 Dec 2000 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:26:58 +0000 (06:26 +0000)
23 files changed:
postfix/HISTORY
postfix/src/bounce/bounce_append_service.c
postfix/src/global/deliver_flock.c
postfix/src/global/dot_lockfile.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/mbox_open.c
postfix/src/local/file.c
postfix/src/local/mailbox.c
postfix/src/master/master.c
postfix/src/master/multi_server.c
postfix/src/master/single_server.c
postfix/src/master/trigger_server.c
postfix/src/postalias/postalias.c
postfix/src/postlock/postlock.c
postfix/src/postmap/postmap.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_chat.c
postfix/src/smtp/smtp_proto.c
postfix/src/util/myflock.c
postfix/src/util/myflock.h
postfix/src/util/open_lock.c
postfix/src/util/safe_open.c

index 1125197cb3aac0627a02e81e5d433b33521c05ed..025415e5f568536e7a287fcde1cb9b09e79f8cf5 100644 (file)
@@ -4523,7 +4523,7 @@ Apologies for any names omitted.
        command is killed by a signal, because people expect such
        behavior from Sendmail. File: global/pipe_command.c.
 
-20001123-6
+20001123-30
 
        Feature: mailbox locking is now configurable. The configuration
        parameter name is "mailbox_delivery_lock". Depending on
@@ -4538,3 +4538,9 @@ Apologies for any names omitted.
        old sun_mailtool_compatibility parameter is being phased
        out (it just turns off flock/fcntl locks). It still works,
        but a warning is logged as a reminder that it goes away.
+
+20001202
+
+       Feature: specify "smtp_never_send_ehlo = no" to disable
+       ESMTP.  Someone asked for this long ago. Files:  smtp/smtp.c,
+       smtp/smtp_proto.c.
index 09a2d87f1f9c6a2ce46dbd4d5255e1202dc6696b..a309ee99778e75d1c773fd2d0f609aa7a3ad79ef 100644 (file)
@@ -83,7 +83,7 @@ int     bounce_append_service(char *service, char *queue_id,
      * case of trouble.
      */
     if (deliver_flock(vstream_fileno(log), INTERNAL_LOCK, (VSTRING *) 0) < 0)
-       msg_fatal("lock file  %s %s: %m", service, queue_id);
+       msg_fatal("lock file %s %s: %m", service, queue_id);
 
     /*
      * Now, go for it. Append a record. Truncate the log to the original
index ca7a6afff39a2afda12752cd8848f46b06b92764..2fa2b82728732ef93695d4ee8b489de530212af4 100644 (file)
 /*     int     lock_style;
 /*     VSTRING *why;
 /* DESCRIPTION
-/*     deliver_flock() sets one exclusive kernel lock on an open file
-/*     for the purpose of mail delivery. It attempts to acquire
-/*     the exclusive lock several times before giving up.
+/*     deliver_flock() sets one exclusive kernel lock on an open file,
+/*     for example in order to deliver mail.
+/*      It performs several non-blocking attempts to acquire an exclusive
+/*     lock before giving up.
 /*
 /*     Arguments:
 /* .IP fd
 
 /* deliver_flock - lock open file for mail delivery*/
 
-int     deliver_flock(int fd, int lock_style, VSTRING *why)
+int     deliver_flock(int fd, int lock_style, VSTRING * why)
 {
     int     i;
 
-    for (i = 0; /* void */ ; i++) {
+    for (i = 1; /* void */ ; i++) {
+       if (myflock(fd, lock_style,
+                   MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) == 0)
+           return (0);
        if (i >= var_flock_tries)
            break;
-       if (i > 0)
-           sleep(var_flock_delay);
-       if (myflock(fd, lock_style, MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) == 0)
-           return (0);
+       sleep(var_flock_delay);
     }
     if (why)
        vstring_sprintf(why, "unable to lock for exclusive access: %m");
index 41ffd4267f49ef977e46aaa666a89d419bd6ccd7..bb898948fce9561a06cbcb3ffcb0a93d418b58cc 100644 (file)
@@ -85,7 +85,8 @@ int     dot_lockfile(const char *path, VSTRING *why)
 
        /*
         * Attempt to create the lock. This code relies on O_EXCL | O_CREAT
-        * to not follow symlinks.
+        * to not follow symlinks. With NFS file systems this operation can
+        * at the same time succeed and fail with errno of EEXIST.
         */
        if ((fd = open(lock_file, O_WRONLY | O_EXCL | O_CREAT, 0)) >= 0) {
            close(fd);
index 4476010cb39039da1ed86908a90dbc0d48cc0e05..53cbf5e4d00d096b39cda73861109b08b90ba52b 100644 (file)
@@ -670,6 +670,10 @@ extern bool var_skip_quit_resp;
 #define DEF_SMTP_ALWAYS_EHLO   0
 extern bool var_smtp_always_ehlo;
 
+#define VAR_SMTP_NEVER_EHLO    "smtp_never_send_ehlo"
+#define DEF_SMTP_NEVER_EHLO    0
+extern bool var_smtp_never_ehlo;
+
 #define VAR_SMTP_BIND_ADDR     "smtp_bind_address"
 #define DEF_SMTP_BIND_ADDR     ""
 extern char *var_smtp_bind_addr;
index ea69a239beaa99d75c464c3be2347b1bfa355883..f2fc3a5969015041b84000dc5793fea4b4c52722 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20001127"
+#define DEF_MAIL_VERSION       "Snapshot-20001203"
 extern char *var_mail_version;
 
 /* LICENSE
index 6b512e6628c32a8afaeb1e75ef5d4d9803c39b2b..e53373b9109b186767398d916361a09f60e71c82 100644 (file)
@@ -34,7 +34,7 @@
 /*     file ownership will succeed only if the process runs with
 /*     adequate effective privileges.
 /*     The \fBlock_style\fR argument specifies a lock style from
-/*     mbox_lock_mask(). Kernel locks are applied to regular files only.
+/*     mbox_lock_mask(). 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
@@ -86,68 +86,79 @@ MBOX   *mbox_open(const char *path, int flags, int mode, struct stat * st,
     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) {
-       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);
-           }
-       }
-    }
+    int     saved_errno;
 
     /*
      * 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.
+     * 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, 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
-     * case we're running on some overly pedantic system. flock() locks do
-     * not work over NFS; fcntl() locks are supposed to work over NFS, but in
-     * the real world, NFS lock daemons often have serious problems.
+     * If this is a regular file, create a dotlock file. This locking method
+     * does not work well over NFS, but it is better than some alternatives.
+     * With NFS, creating files atomically is a problem, and a successful
+     * operation can fail with EEXIST.
+     * 
+     * If filename.lock can't be created for reasons other than "file exists",
+     * issue only a warning if the application says it is non-fatal. This is
+     * 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.
      */
-#define LOCK_FAIL(mbox_lock, myflock_style) ((lock_style & (mbox_lock)) != 0 \
-         && deliver_flock(vstream_fileno(fp), (myflock_style), why) < 0)
-
-    if (S_ISREG(st->st_mode)
-       && (LOCK_FAIL(MBOX_FLOCK_LOCK, MYFLOCK_STYLE_FLOCK)
-           || LOCK_FAIL(MBOX_FCNTL_LOCK, MYFLOCK_STYLE_FCNTL))) {
-       if (myflock_locked(vstream_fileno(fp)))
+    if (S_ISREG(st->st_mode) && (lock_style & MBOX_DOT_LOCK)) {
+       if (dot_lockfile(path, why) == 0) {
+           locked |= MBOX_DOT_LOCK;
+       } else if (errno == EEXIST) {
            errno = EAGAIN;
-       if (locked & MBOX_DOT_LOCK)
-           dot_unlockfile(path);
-       return (0);
+           vstream_fclose(fp);
+           return (0);
+       } else if (lock_style & MBOX_DOT_LOCK_MAY_FAIL) {
+           msg_warn("%s", vstring_str(why));
+       } else {
+           vstream_fclose(fp);
+           return (0);
+       }
+    }
+
+    /*
+     * 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
+     * over NFS, but in the real world, NFS lock daemons often have serious
+     * problems.
+     */
+#define HUNKY_DORY(lock_mask, myflock_style) ((lock_style & (lock_mask)) == 0 \
+         || deliver_flock(vstream_fileno(fp), (myflock_style), why) == 0)
+
+    if (S_ISREG(st->st_mode)) {
+       if (HUNKY_DORY(MBOX_FLOCK_LOCK, MYFLOCK_STYLE_FLOCK)
+           && HUNKY_DORY(MBOX_FCNTL_LOCK, MYFLOCK_STYLE_FCNTL)) {
+           locked |= lock_style;
+       } else {
+           saved_errno = errno;
+           if (locked & MBOX_DOT_LOCK)
+               dot_unlockfile(path);
+           vstream_fclose(fp);
+           errno = saved_errno;
+           return (0);
+       }
     }
     mp = (MBOX *) mymalloc(sizeof(*mp));
     mp->path = mystrdup(path);
@@ -160,6 +171,15 @@ MBOX   *mbox_open(const char *path, int flags, int mode, struct stat * st,
 
 void    mbox_release(MBOX *mp)
 {
+
+    /*
+     * Unfortunately we can't close the stream, because on some file systems
+     * (AFS), the only way to find out if a file was written successfully is
+     * to close it, and therefore the close() operation is in the mail_copy()
+     * routine. If we really insist on owning the vstream member, then we
+     * should export appropriate methods that mail_copy() can use in order
+     * to manipulate a message stream.
+     */
     if (mp->locked & MBOX_DOT_LOCK)
        dot_unlockfile(mp->path);
     myfree(mp->path);
index 75588ea618a0303743c114de08722b6697f38df1..e3a530ba8a119ed69c45797da004a646ec805a6b 100644 (file)
@@ -86,7 +86,7 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     struct stat st;
     MBOX   *mp;
     VSTRING *why;
-    int     status;
+    int     status = -1;
     int     copy_flags;
 
     /*
@@ -141,7 +141,7 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
 
     /*
      * As the specified user, open or create the file, lock it, and append
-     * the message. XXX We may attempt to create a lockfile for /dev/null.
+     * the message.
      */
     copy_flags = MAIL_COPY_MBOX;
     if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0)
@@ -151,25 +151,33 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     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)
+    if (mp != 0) {
+       if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+           vstream_fclose(mp->fp);
+           vstring_sprintf(why, "destination file is executable");
+           errno = 0;
+       } else {
+           status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
+                              S_ISREG(st.st_mode) ? copy_flags :
+                              (copy_flags & ~MAIL_COPY_TOFILE),
+                              "\n", why);
+       }
+       mbox_release(mp);
+    }
+    set_eugid(var_owner_uid, var_owner_gid);
+
+    /*
+     * As the mail system, bounce, defer delivery, or report success.
+     */
+    if (status != 0) {
+       status = (errno == EAGAIN || errno == ENOSPC ?
+                 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(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), 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));
+            "cannot append message to destination file %s: %s",
+            path, STR(why));
     } else {
-       status = sent(SENT_ATTR(state.msg_attr), "%s", path);
+       sent(SENT_ATTR(state.msg_attr), "%s", path);
     }
-    mbox_release(mp);
-    set_eugid(var_owner_uid, var_owner_gid);
 
     /*
      * Clean up.
index 30d2ad80d706b276ff0c8f552aa947a85b2fe31d..854590c111a63e0f32eb4242e420396d022cf993 100644 (file)
@@ -65,9 +65,6 @@
 /* Global library. */
 
 #include <mail_copy.h>
-#include <safe_open.h>
-#include <deliver_flock.h>
-#include <dot_lockfile.h>
 #include <defer.h>
 #include <sent.h>
 #include <mypwd.h>
@@ -96,7 +93,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     char   *spool_dir;
     char   *mailbox;
     VSTRING *why;
-    MBOX *mp;
+    MBOX   *mp;
     int     status;
     int     copy_flags;
     VSTRING *biff;
@@ -181,14 +178,14 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
 
     set_eugid(spool_uid, spool_gid);
     mp = mbox_open(mailbox, O_APPEND | O_WRONLY | O_CREAT,
-                   S_IRUSR | S_IWUSR, &st, chown_uid, chown_gid,
-                   local_mbox_lock_mask, why);
+                  S_IRUSR | S_IWUSR, &st, chown_uid, chown_gid,
+                  local_mbox_lock_mask, why);
     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);
+           vstring_sprintf(why, "destination is not a regular file");
            errno = 0;
        } else {
            end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
@@ -201,12 +198,15 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     }
     set_eugid(var_owner_uid, var_owner_gid);
 
+    /*
+     * As the mail system, bounce, defer delivery, or report success.
+     */
     if (status != 0) {
        status = (errno == EAGAIN || errno == ENOSPC ?
                  defer_append : bounce_append)
            (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
-            "cannot access mailbox for user %s. %s",
-            state.msg_attr.user, vstring_str(why));
+            "cannot access mailbox %s for user %s. %s",
+            mailbox, state.msg_attr.user, vstring_str(why));
     } else {
        sent(SENT_ATTR(state.msg_attr), "mailbox");
        if (var_biff) {
@@ -216,6 +216,10 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
            vstring_free(biff);
        }
     }
+
+    /*
+     * Clean up.
+     */
     myfree(mailbox);
     vstring_free(why);
     return (status);
index 6c2ea49e07c0525b8c00a0044297f55e88426dd9..83e71c1a7b9eb6fea5393f6dc6888bb103128889 100644 (file)
@@ -300,7 +300,8 @@ int     main(int argc, char **argv)
     if (test_lock)
        exit(lock_fp ? 0 : 1);
     if (lock_fp == 0)
-       msg_fatal("%s", vstring_str(why));
+       msg_fatal("open lock file %s: %s",
+                 vstring_str(lock_path), vstring_str(why));
     vstream_fprintf(lock_fp, "%*lu\n", (int) sizeof(unsigned long) * 4,
                    (unsigned long) var_pid);
     if (vstream_fflush(lock_fp))
index 6006c0978de694aae6d1986fea9f414da422b4f9..856d1e318036ea16cf5635998436d50b85c54fae 100644 (file)
@@ -549,7 +549,7 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
        why = vstring_alloc(1);
        if ((multi_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
                                           (struct stat *) 0, -1, -1, why)) == 0)
-           msg_fatal("%s", vstring_str(why));
+           msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
        close_on_exec(vstream_fileno(multi_server_lock), CLOSE_ON_EXEC);
        myfree(lock_path);
        vstring_free(why);
index 13f6f147c64f8f7e95199a46f446606ae7269fbc..583abd3b5a0470cce299dd73e5c277cf6da3b6da 100644 (file)
@@ -520,7 +520,7 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
        why = vstring_alloc(1);
        if ((single_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
                                            (struct stat *) 0, -1, -1, why)) == 0)
-           msg_fatal("%s", vstring_str(why));
+           msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
        close_on_exec(vstream_fileno(single_server_lock), CLOSE_ON_EXEC);
        myfree(lock_path);
        vstring_free(why);
index 86dd4000835e5d11c4f85e4c9157b10a1d575afb..c6df3a99a4b0c9763a8f5f725e316b5e641470a2 100644 (file)
@@ -534,7 +534,7 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
        why = vstring_alloc(1);
        if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
                                             (struct stat *) 0, -1, -1, why)) == 0)
-           msg_fatal("%s", vstring_str(why));
+           msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
        close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
        myfree(lock_path);
        vstring_free(why);
index e38e183fcadd4f3a6c51541458fc7b690fad8369..0fe46f910f511913a4449ab90d983f8b56f251a2 100644 (file)
 /*     Problems are logged to the standard error stream. No output means
 /*     no problems were detected. Duplicate entries are skipped and are
 /*     flagged with a warning.
+/*
+/*     \fBpostalias\fR terminates with zero exit status in case of success
+/*     (including successful \fBpostmap -q\fR lookup) and terminates
+/*     with non-zero exit status in case of failure.
 /* BUGS
 /*     The "delete key" support is limited to one delete operation
 /*     per command invocation.
index 44d7ecdeae36c9098f20f5e2e4405046b51a368b..21d9ef23329ef56b155d1b941bdbe61e4089a748 100644 (file)
 #include <vstream.h>
 #include <msg_vstream.h>
 #include <iostuff.h>
-#include <safe_open.h>
 
 /* Global library. */
 
@@ -201,7 +200,8 @@ int     main(int argc, char **argv)
     command = argv + optind + 1;
 
     /*
-     * Read the config file.
+     * Read the config file. The command line lock style can override the
+     * configured lock style.
      */
     mail_conf_read();
     lock_mask = mbox_lock_mask(lock_style ? lock_style :
@@ -215,28 +215,27 @@ int     main(int argc, char **argv)
     if ((mp = mbox_open(folder, O_APPEND | O_WRONLY | O_CREAT,
                        S_IRUSR | S_IWUSR, (struct stat *) 0,
                        -1, -1, lock_mask, why)) == 0)
-       msg_fatal("%s", vstring_str(why));
+       msg_fatal("open file %s: %s", folder, vstring_str(why));
 
     /*
      * Run the command. Remove the lock after completion.
      */
-    for (count = 0; count < var_fork_tries; count++) {
-       switch (pid = fork()) {
-       case -1:
-           msg_warn("fork %s: %m", command[0]);
-           break;
-       case 0:
-           execvp(command[0], command);
-           msg_fatal("execvp %s: %m", command[0]);
-       default:
-           if (waitpid(pid, &status, 0) < 0)
-               msg_fatal("waitpid: %m");
+    for (count = 1; (pid = fork()) == -1; count++) {
+       msg_warn("fork %s: %m", command[0]);
+       if (count >= var_fork_tries) {
            mbox_release(mp);
-           exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
+           exit(EX_TEMPFAIL);
        }
-       if (count + 1 < var_fork_tries)
-           sleep(var_fork_delay);
+       sleep(var_fork_delay);
+    }
+    switch (pid) {
+    case 0:
+       execvp(command[0], command);
+       msg_fatal("execvp %s: %m", command[0]);
+    default:
+       if (waitpid(pid, &status, 0) < 0)
+           msg_fatal("waitpid: %m");
+       mbox_release(mp);
+       exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
     }
-    mbox_release(mp);
-    exit(EX_TEMPFAIL);
 }
index 49dc87893afb980f9e2b52998fa2a534f60d9165..f82edfb1443bd1e16d36c12d0194d8e246b3f731 100644 (file)
 /*     Problems and transactions are logged to the standard error
 /*     stream. No output means no problems. Duplicate entries are
 /*     skipped and are flagged with a warning.
+/*
+/*     \fBpostmap\fR terminates with zero exit status in case of success
+/*     (including successful \fBpostmap -q\fR lookup) and terminates
+/*     with non-zero exit status in case of failure.
 /* BUGS
 /*     The "delete key" support is limited to one delete operation
 /*     per command invocation.
index 82c5d973969f75df8cc3d78a0d7f749e97f2f241..a81e4d3a76226cc995be80970c2f2fe5c6c86f27 100644 (file)
@@ -81,7 +81,7 @@
 /*     or if a destination is unreachable.
 /* .IP \fBignore_mx_lookup_error\fR
 /*     When a name server fails to respond to an MX query, search for an
-/*     A record instead of assuming that the name server will recover.
+/*     A record instead deferring mail delivery.
 /* .IP \fBinet_interfaces\fR
 /*     The network interface addresses that this mail system receives
 /*     mail on. When any of those addresses appears in the list of mail
@@ -92,6 +92,8 @@
 /*     postmaster with transcripts of SMTP sessions with protocol errors.
 /* .IP \fBsmtp_always_send_ehlo\fR
 /*     Always send EHLO at the start of a connection.
+/* .IP \fBsmtp_never_send_ehlo\fR
+/*     Never send EHLO at the start of a connection.
 /* .IP \fBsmtp_skip_4xx_greeting\fR
 /*     Skip servers that greet us with a 4xx status code.
 /* .IP \fBsmtp_skip_5xx_greeting\fR
@@ -239,6 +241,7 @@ char   *var_fallback_relay;
 char   *var_bestmx_transp;
 char   *var_error_rcpt;
 int     var_smtp_always_ehlo;
+int     var_smtp_never_ehlo;
 char   *var_smtp_sasl_opts;
 char   *var_smtp_sasl_passwd;
 bool    var_smtp_sasl_enable;
@@ -307,17 +310,17 @@ static int deliver_message(DELIVER_REQUEST *request)
            smtp_chat_notify(state);
        smtp_session_free(state->session);
        debug_peer_restore();
-}
+    }
 
- /*
-  * Clean up.
-  */
-vstring_free(why);
-smtp_chat_reset(state);
-result = state->status;
-smtp_state_free(state);
   /*
+     * Clean up.
+     */
+    vstring_free(why);
+    smtp_chat_reset(state);
+    result = state->status;
+    smtp_state_free(state);
 
-return (result);
+    return (result);
 }
 
 /* smtp_service - perform service for client */
@@ -412,6 +415,7 @@ int     main(int argc, char **argv)
        VAR_IGN_MX_LOOKUP_ERR, DEF_IGN_MX_LOOKUP_ERR, &var_ign_mx_lookup_err,
        VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
        VAR_SMTP_ALWAYS_EHLO, DEF_SMTP_ALWAYS_EHLO, &var_smtp_always_ehlo,
+       VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo,
        VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
        0,
     };
index de11387a122625ccf8a81d8a660610bbfd1267a9..62c0de64f3f4cf84442a582970f5aa3fe0d79fc2 100644 (file)
@@ -91,6 +91,7 @@
 #include <mail_params.h>
 #include <mail_addr.h>
 #include <post_mail.h>
+#include <mail_error.h>
 
 /* Application-specific. */
 
@@ -156,7 +157,6 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
 {
     SMTP_SESSION *session = state->session;
     static SMTP_RESP rdata;
-    int     more;
     char   *cp;
     int     last_char;
 
@@ -174,17 +174,12 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
     VSTRING_RESET(rdata.buf);
     for (;;) {
        last_char = smtp_get(state->buffer, session->stream, var_line_limit);
-       cp = printable(STR(state->buffer), '?');
+       printable(STR(state->buffer), '?');
        if (last_char != '\n')
            msg_warn("%s: response longer than %d: %.30s...",
-                    session->namaddr, var_line_limit, cp);
+                    session->namaddr, var_line_limit, STR(state->buffer));
        if (msg_verbose)
-           msg_info("< %s: %s", session->namaddr, cp);
-       while (ISDIGIT(*cp))
-           cp++;
-       rdata.code = (cp - STR(state->buffer) == 3 ?
-                     atoi(STR(state->buffer)) : 0);
-       more = (*cp == '-');
+           msg_info("< %s: %s", session->namaddr, STR(state->buffer));
 
        /*
         * Defend against a denial of service attack by limiting the amount
@@ -196,13 +191,23 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
            vstring_strcat(rdata.buf, STR(state->buffer));
            smtp_chat_append(state, "In:  ", STR(state->buffer));
        }
-       if (VSTRING_LEN(state->buffer) == 0)    /* XXX remote brain damage */
-           continue;
-       if (!ISDIGIT(STR(state->buffer)[0]))    /* XXX remote brain damage */
-           continue;
-       if (more == 0)
-           break;
+
+       /*
+        * Parse into code and text. Ignore unrecognized garbage. This means
+        * that any character except space (or end of line) will have the
+        * same effect as the '-' line continuation character.
+        */
+       for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++)
+            /* void */ ;
+       if (cp - STR(state->buffer) == 3) {
+           if (*cp == '-')
+               continue;
+           if (*cp == ' ' || *cp == 0)
+               break;
+       }
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
     }
+    rdata.code = atoi(STR(state->buffer));
     VSTRING_TERMINATE(rdata.buf);
     rdata.str = STR(rdata.buf);
     return (&rdata);
index 5d562ccdba3d7ce10a460c09dce055893b99b965..0f4394e9d3dde27314cba7ed2ad31b26dd7a70e5 100644 (file)
@@ -186,6 +186,8 @@ int     smtp_helo(SMTP_STATE *state)
     }
     if (var_smtp_always_ehlo)
        state->features |= SMTP_FEATURE_ESMTP;
+    if (var_smtp_never_ehlo)
+       state->features &= ~SMTP_FEATURE_ESMTP;
 
     /*
      * Return the compliment. Fall back to SMTP if our ESMTP recognition
index 69688d48ab2e94172e99462e65c14f4168034e63..65814b255606ba992897eed2cdfd2c4038c64df6 100644 (file)
 /*     int     fd;
 /*     int     lock_style;
 /*     int     operation;
-/*
-/*     int     myflock_locked(err)
-/*     int     err;
 /* DESCRIPTION
-/*     myflock() locks or unlocks an entire open file. Depending
-/*     on the value of the \fIlock_style\fR argument, this function uses
-/*     either the fcntl() or the flock() system call.
+/*     myflock() locks or unlocks an entire open file.
 /*
 /*     In the case of a blocking request, a call that fails due to
-/*     transient problems is tried again once per second.
-/*     In the case of a non-blocking request, use the myflock_locked()
-/*     call to distinguish between expected and unexpected failures.
-/*
-/*     myflock_locked() examines the errno result from a failed
-/*     non-blocking lock request, and returns non-zero (true)
-/*     when the lock failed because someone else holds it.
+/*     forseeable transient problems is retried once per second.
 /*
 /*     Arguments:
 /* .IP fd
 /*     One of the following values:
 /* .RS
 /* .IP MYFLOCK_STYLE_FLOCK
-/*     Use BSD-style flock() locks.
+/*     Use BSD-style flock() locking.
 /* .IP MYFLOCK_STYLE_FCNTL
-/*     Use POSIX-style fcntl() locks.
+/*     Use POSIX-style fcntl() locking.
 /* .RE
 /* .IP operation
 /*     One of the following values:
 /* .RS
 /* .IP MYFLOCK_OP_NONE
-/*     Releases any locks the process has on the specified open file.
+/*     Release any locks the process has on the specified open file.
 /* .IP MYFLOCK_OP_SHARED
-/*     Attempts to acquire a shared lock on the specified open file.
+/*     Attempt to acquire a shared lock on the specified open file.
 /*     This is appropriate for read-only access.
 /* .IP MYFLOCK_OP_EXCLUSIVE
-/*     Attempts to acquire an exclusive lock on the specified open
+/*     Attempt to acquire an exclusive lock on the specified open
 /*     file. This is appropriate for write access.
 /* .PP
 /*     In addition, setting the MYFLOCK_OP_NOWAIT bit causes the
 /*     call to return immediately when the requested lock cannot
-/*     be acquired. See the myflock_locked() function on lock_style to deal
-/*     with a negative result.
+/*     be acquired.
 /* .RE
 /* DIAGNOSTICS
 /*     myflock() returns 0 in case of success, -1 in case of failure.
 /*     A problem description is returned via the global \fIerrno\fR
-/*     variable.
+/*     variable. In the case of a non-blocking lock request the value
+/*     EAGAIN means that a lock is claimed by someone else.
 /*
-/*     Panic: attempts to use an unsupported file locking method.
-/*     to use multiple locking methods, or none.
+/*     Panic: attempts to use an unsupported file locking method or
+/*     to implement an unsupported operation.
 /* LICENSE
 /* .ad
 /* .fi
 /* Utility library. */
 
 #include "msg.h"
-#include "vstring.h"
 #include "myflock.h"
 
 /* myflock - lock/unlock entire open file */
 
 int     myflock(int fd, int lock_style, int operation)
 {
+    int     status;
+
+    /*
+     * Sanity check.
+     */
+    if ((operation & (MYFLOCK_OP_BITS)) != operation)
+       msg_panic("myflock: improper operation type: 0x%x", operation);
+
     switch (lock_style) {
 
        /*
@@ -111,9 +107,8 @@ int     myflock(int fd, int lock_style, int operation)
                -1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1
            };
 
-           if ((operation & (MYFLOCK_OP_BITS)) != operation)
-               msg_panic("myflock: improper operation type: 0x%x", operation);
-           return (flock(fd, lock_ops[operation]));
+           status = flock(fd, lock_ops[operation]);
+           break;
        }
 #endif
 
@@ -129,28 +124,28 @@ int     myflock(int fd, int lock_style, int operation)
            static int lock_ops[] = {
                F_UNLCK, F_RDLCK, F_WRLCK
            };
-           int     ret;
 
-           if ((operation & (MYFLOCK_OP_BITS)) != operation)
-               msg_panic("myflock: improper operation type: 0x%x", operation);
            memset((char *) &lock, 0, sizeof(lock));
            lock.l_type = lock_ops[operation & ~MYFLOCK_OP_NOWAIT];
            request = (operation & MYFLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW;
-           while ((ret = fcntl(fd, request, &lock)) < 0
+           while ((status = fcntl(fd, request, &lock)) < 0
                   && request == F_SETLKW
                 && (errno == EINTR || errno == ENOLCK || errno == EDEADLK))
                sleep(1);
-           return (ret);
+           break;
        }
 #endif
     default:
        msg_panic("myflock: unsupported lock style: 0x%x", lock_style);
     }
-}
 
-/* myflock_locked - were we locked out or what? */
+    /*
+     * Return a consistent result. Some systems return EACCES when a lock is
+     * taken by someone else, and that would complicate error processing.
+     */
+    if (status < 0 && (operation & MYFLOCK_OP_NOWAIT) != 0)
+       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EACCES)
+           errno = EAGAIN;
 
-int     myflock_locked(int err)
-{
-    return (err == EAGAIN || err == EWOULDBLOCK || err == EACCES);
+    return (status);
 }
index b65ed2962cc7d22748a9a3a8505334eb138c779c..624ea2d9404050a02f51ac3574535e099c52dac8 100644 (file)
@@ -15,7 +15,6 @@
   * External interface.
   */
 extern int myflock(int, int, int);
-extern int myflock_locked(int);
 
  /*
   * Lock styles.
@@ -26,10 +25,11 @@ extern int myflock_locked(int);
  /*
   * Lock request types.
   */
-#define MYFLOCK_OP_NONE        0
+#define MYFLOCK_OP_NONE                0
 #define MYFLOCK_OP_SHARED      1
 #define MYFLOCK_OP_EXCLUSIVE   2
 #define MYFLOCK_OP_NOWAIT      4
+
 #define MYFLOCK_OP_BITS \
        (MYFLOCK_OP_SHARED | MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)
 
index 028b6604d761e575c411c0c3dc1ed5b5f82df2ec..9a9273d5fc5710387e44ab93810f88e7abd6321d 100644 (file)
@@ -68,7 +68,7 @@ VSTREAM *open_lock(const char *path, int flags, int mode, VSTRING *why)
        return (0);
     if (myflock(vstream_fileno(fp), INTERNAL_LOCK,
                MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) < 0) {
-       vstring_sprintf(why, "file %s: unable to lock: %m", path);
+       vstring_sprintf(why, "unable to set exclusive lock: %m");
        vstream_fclose(fp);
        return (0);
     }
index ca7bf8368048a72c705553be6e505f07d10b02c1..ac1aed3a8aa6f17fabc45c415e0c77a5f4bd06d7 100644 (file)
@@ -97,7 +97,7 @@ static VSTREAM *safe_open_exist(const char *path, int flags,
      * Open an existing file.
      */
     if ((fp = vstream_fopen(path, flags & ~(O_CREAT | O_EXCL), 0)) == 0) {
-       vstring_sprintf(why, "error opening file %s: %m", path);
+       vstring_sprintf(why, "cannot open existing file: %m");
        return (0);
     }
 
@@ -109,11 +109,11 @@ static VSTREAM *safe_open_exist(const char *path, int flags,
     if (fstat_st == 0)
        fstat_st = &local_statbuf;
     if (fstat(vstream_fileno(fp), fstat_st) < 0) {
-       msg_fatal("file %s: bad status after open: %m", path);
+       msg_fatal("bad open file status: %m");
     } else if (fstat_st->st_nlink != 1) {
-       vstring_sprintf(why, "file %s: should not have multiple links", path);
+       vstring_sprintf(why, "file has multiple hard links");
     } else if (S_ISDIR(fstat_st->st_mode)) {
-       vstring_sprintf(why, "file %s: should not be a directory", path);
+       vstring_sprintf(why, "file is a directory");
     }
 
     /*
@@ -135,8 +135,8 @@ static VSTREAM *safe_open_exist(const char *path, int flags,
 #endif
             || fstat_st->st_nlink != lstat_st.st_nlink
             || fstat_st->st_mode != lstat_st.st_mode) {
-       vstring_sprintf(why, "file %s: %s", path, S_ISLNK(lstat_st.st_mode) ?
-         "should not be a symbolic link" : "status changed after opening");
+       vstring_sprintf(why, "%s", S_ISLNK(lstat_st.st_mode) ?
+           "file is a symbolic link" : "file status changed unexpectedly");
     }
 
     /*
@@ -167,7 +167,7 @@ static VSTREAM *safe_open_create(const char *path, int flags, int mode,
      * follow symbolic links.
      */
     if ((fp = vstream_fopen(path, flags | (O_CREAT | O_EXCL), mode)) == 0) {
-       vstring_sprintf(why, "file %s: cannot open: %m", path);
+       vstring_sprintf(why, "cannot create file exclusively: %m");
        return (0);
     }
 
@@ -180,14 +180,14 @@ static VSTREAM *safe_open_create(const char *path, int flags, int mode,
 
     if (CHANGE_OWNER(user, group)
        && fchown(vstream_fileno(fp), user, group) < 0) {
-       vstring_sprintf(why, "file %s: cannot change ownership: %m", path);
+       vstring_sprintf(why, "cannot change file ownership: %m");
     }
 
     /*
      * Optionally look up the file attributes.
      */
     if (st != 0 && fstat(vstream_fileno(fp), st) < 0)
-       msg_fatal("file %s: cannot get status after open: %m", path);
+       msg_fatal("bad open file status: %m");
 
     /*
      * We are almost there...