2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 13:48:06 +00:00

snapshot-20001203

This commit is contained in:
Wietse Venema 2000-12-03 00:00:00 -05:00 committed by Viktor Dukhovni
parent a6f1137bf4
commit d4d2268196
23 changed files with 244 additions and 186 deletions

View 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.

View 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

View File

@ -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");

View 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);

View 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;

View 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

View 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);

View 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,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.
*/

View 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);

View 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))

View 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);

View 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);

View 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);

View File

@ -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.

View File

@ -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);
}

View File

@ -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.

View 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,
};

View 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);

View 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

View File

@ -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);
}

View 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)

View 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);
}

View 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...