mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
snapshot-20001203
This commit is contained in:
parent
a6f1137bf4
commit
d4d2268196
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -101,7 +101,6 @@
|
||||
#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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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...
|
||||
|
Loading…
x
Reference in New Issue
Block a user