From d4d226819628d36b149182e128f2f77604e1805c Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sun, 3 Dec 2000 00:00:00 -0500 Subject: [PATCH] snapshot-20001203 --- postfix/HISTORY | 8 +- postfix/src/bounce/bounce_append_service.c | 2 +- postfix/src/global/deliver_flock.c | 19 ++-- postfix/src/global/dot_lockfile.c | 3 +- postfix/src/global/mail_params.h | 4 + postfix/src/global/mail_version.h | 2 +- postfix/src/global/mbox_open.c | 116 ++++++++++++--------- postfix/src/local/file.c | 46 ++++---- postfix/src/local/mailbox.c | 22 ++-- postfix/src/master/master.c | 3 +- postfix/src/master/multi_server.c | 2 +- postfix/src/master/single_server.c | 2 +- postfix/src/master/trigger_server.c | 2 +- postfix/src/postalias/postalias.c | 4 + postfix/src/postlock/postlock.c | 37 ++++--- postfix/src/postmap/postmap.c | 4 + postfix/src/smtp/smtp.c | 24 +++-- postfix/src/smtp/smtp_chat.c | 35 ++++--- postfix/src/smtp/smtp_proto.c | 2 + postfix/src/util/myflock.c | 69 ++++++------ postfix/src/util/myflock.h | 4 +- postfix/src/util/open_lock.c | 2 +- postfix/src/util/safe_open.c | 18 ++-- 23 files changed, 244 insertions(+), 186 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 1125197cb..025415e5f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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. diff --git a/postfix/src/bounce/bounce_append_service.c b/postfix/src/bounce/bounce_append_service.c index 09a2d87f1..a309ee997 100644 --- a/postfix/src/bounce/bounce_append_service.c +++ b/postfix/src/bounce/bounce_append_service.c @@ -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 diff --git a/postfix/src/global/deliver_flock.c b/postfix/src/global/deliver_flock.c index ca7a6afff..2fa2b8272 100644 --- a/postfix/src/global/deliver_flock.c +++ b/postfix/src/global/deliver_flock.c @@ -11,9 +11,10 @@ /* 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 @@ -58,17 +59,17 @@ /* 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"); diff --git a/postfix/src/global/dot_lockfile.c b/postfix/src/global/dot_lockfile.c index 41ffd4267..bb898948f 100644 --- a/postfix/src/global/dot_lockfile.c +++ b/postfix/src/global/dot_lockfile.c @@ -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); diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 4476010cb..53cbf5e4d 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index ea69a239b..f2fc3a596 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 diff --git a/postfix/src/global/mbox_open.c b/postfix/src/global/mbox_open.c index 6b512e662..e53373b91 100644 --- a/postfix/src/global/mbox_open.c +++ b/postfix/src/global/mbox_open.c @@ -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); diff --git a/postfix/src/local/file.c b/postfix/src/local/file.c index 75588ea61..e3a530ba8 100644 --- a/postfix/src/local/file.c +++ b/postfix/src/local/file.c @@ -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,26 +151,34 @@ 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) - (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)); - } else { - status = sent(SENT_ATTR(state.msg_attr), "%s", path); + 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); } - 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 append message to destination file %s: %s", + path, STR(why)); + } else { + sent(SENT_ATTR(state.msg_attr), "%s", path); + } + /* * Clean up. */ diff --git a/postfix/src/local/mailbox.c b/postfix/src/local/mailbox.c index 30d2ad80d..854590c11 100644 --- a/postfix/src/local/mailbox.c +++ b/postfix/src/local/mailbox.c @@ -65,9 +65,6 @@ /* Global library. */ #include -#include -#include -#include #include #include #include @@ -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); diff --git a/postfix/src/master/master.c b/postfix/src/master/master.c index 6c2ea49e0..83e71c1a7 100644 --- a/postfix/src/master/master.c +++ b/postfix/src/master/master.c @@ -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)) diff --git a/postfix/src/master/multi_server.c b/postfix/src/master/multi_server.c index 6006c0978..856d1e318 100644 --- a/postfix/src/master/multi_server.c +++ b/postfix/src/master/multi_server.c @@ -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); diff --git a/postfix/src/master/single_server.c b/postfix/src/master/single_server.c index 13f6f147c..583abd3b5 100644 --- a/postfix/src/master/single_server.c +++ b/postfix/src/master/single_server.c @@ -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); diff --git a/postfix/src/master/trigger_server.c b/postfix/src/master/trigger_server.c index 86dd40008..c6df3a99a 100644 --- a/postfix/src/master/trigger_server.c +++ b/postfix/src/master/trigger_server.c @@ -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); diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c index e38e183fc..0fe46f910 100644 --- a/postfix/src/postalias/postalias.c +++ b/postfix/src/postalias/postalias.c @@ -77,6 +77,10 @@ /* 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. diff --git a/postfix/src/postlock/postlock.c b/postfix/src/postlock/postlock.c index 44d7ecdea..21d9ef233 100644 --- a/postfix/src/postlock/postlock.c +++ b/postfix/src/postlock/postlock.c @@ -101,7 +101,6 @@ #include #include #include -#include /* 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); } diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c index 49dc87893..f82edfb14 100644 --- a/postfix/src/postmap/postmap.c +++ b/postfix/src/postmap/postmap.c @@ -94,6 +94,10 @@ /* 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. diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 82c5d9739..a81e4d3a7 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -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, }; diff --git a/postfix/src/smtp/smtp_chat.c b/postfix/src/smtp/smtp_chat.c index de11387a1..62c0de64f 100644 --- a/postfix/src/smtp/smtp_chat.c +++ b/postfix/src/smtp/smtp_chat.c @@ -91,6 +91,7 @@ #include #include #include +#include /* 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); diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 5d562ccdb..0f4394e9d 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -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 diff --git a/postfix/src/util/myflock.c b/postfix/src/util/myflock.c index 69688d48a..65814b255 100644 --- a/postfix/src/util/myflock.c +++ b/postfix/src/util/myflock.c @@ -10,22 +10,11 @@ /* 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 @@ -34,34 +23,34 @@ /* 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 @@ -91,13 +80,20 @@ /* 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); } diff --git a/postfix/src/util/myflock.h b/postfix/src/util/myflock.h index b65ed2962..624ea2d94 100644 --- a/postfix/src/util/myflock.h +++ b/postfix/src/util/myflock.h @@ -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) diff --git a/postfix/src/util/open_lock.c b/postfix/src/util/open_lock.c index 028b6604d..9a9273d5f 100644 --- a/postfix/src/util/open_lock.c +++ b/postfix/src/util/open_lock.c @@ -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); } diff --git a/postfix/src/util/safe_open.c b/postfix/src/util/safe_open.c index ca7bf8368..ac1aed3a8 100644 --- a/postfix/src/util/safe_open.c +++ b/postfix/src/util/safe_open.c @@ -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...