mirror of
https://github.com/vdukhovni/postfix
synced 2025-09-01 22:55:29 +00:00
snapshot-20001203
This commit is contained in:
committed by
Viktor Dukhovni
parent
a6f1137bf4
commit
d4d2268196
@@ -4523,7 +4523,7 @@ Apologies for any names omitted.
|
|||||||
command is killed by a signal, because people expect such
|
command is killed by a signal, because people expect such
|
||||||
behavior from Sendmail. File: global/pipe_command.c.
|
behavior from Sendmail. File: global/pipe_command.c.
|
||||||
|
|
||||||
20001123-6
|
20001123-30
|
||||||
|
|
||||||
Feature: mailbox locking is now configurable. The configuration
|
Feature: mailbox locking is now configurable. The configuration
|
||||||
parameter name is "mailbox_delivery_lock". Depending on
|
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
|
old sun_mailtool_compatibility parameter is being phased
|
||||||
out (it just turns off flock/fcntl locks). It still works,
|
out (it just turns off flock/fcntl locks). It still works,
|
||||||
but a warning is logged as a reminder that it goes away.
|
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.
|
* case of trouble.
|
||||||
*/
|
*/
|
||||||
if (deliver_flock(vstream_fileno(log), INTERNAL_LOCK, (VSTRING *) 0) < 0)
|
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
|
* Now, go for it. Append a record. Truncate the log to the original
|
||||||
|
@@ -11,9 +11,10 @@
|
|||||||
/* int lock_style;
|
/* int lock_style;
|
||||||
/* VSTRING *why;
|
/* VSTRING *why;
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* deliver_flock() sets one exclusive kernel lock on an open file
|
/* deliver_flock() sets one exclusive kernel lock on an open file,
|
||||||
/* for the purpose of mail delivery. It attempts to acquire
|
/* for example in order to deliver mail.
|
||||||
/* the exclusive lock several times before giving up.
|
/* It performs several non-blocking attempts to acquire an exclusive
|
||||||
|
/* lock before giving up.
|
||||||
/*
|
/*
|
||||||
/* Arguments:
|
/* Arguments:
|
||||||
/* .IP fd
|
/* .IP fd
|
||||||
@@ -58,17 +59,17 @@
|
|||||||
|
|
||||||
/* deliver_flock - lock open file for mail delivery*/
|
/* 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;
|
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)
|
if (i >= var_flock_tries)
|
||||||
break;
|
break;
|
||||||
if (i > 0)
|
sleep(var_flock_delay);
|
||||||
sleep(var_flock_delay);
|
|
||||||
if (myflock(fd, lock_style, MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) == 0)
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
if (why)
|
if (why)
|
||||||
vstring_sprintf(why, "unable to lock for exclusive access: %m");
|
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
|
* 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) {
|
if ((fd = open(lock_file, O_WRONLY | O_EXCL | O_CREAT, 0)) >= 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@@ -670,6 +670,10 @@ extern bool var_skip_quit_resp;
|
|||||||
#define DEF_SMTP_ALWAYS_EHLO 0
|
#define DEF_SMTP_ALWAYS_EHLO 0
|
||||||
extern bool var_smtp_always_ehlo;
|
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 VAR_SMTP_BIND_ADDR "smtp_bind_address"
|
||||||
#define DEF_SMTP_BIND_ADDR ""
|
#define DEF_SMTP_BIND_ADDR ""
|
||||||
extern char *var_smtp_bind_addr;
|
extern char *var_smtp_bind_addr;
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* Version of this program.
|
* Version of this program.
|
||||||
*/
|
*/
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "Snapshot-20001127"
|
#define DEF_MAIL_VERSION "Snapshot-20001203"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
/* file ownership will succeed only if the process runs with
|
/* file ownership will succeed only if the process runs with
|
||||||
/* adequate effective privileges.
|
/* adequate effective privileges.
|
||||||
/* The \fBlock_style\fR argument specifies a lock style from
|
/* 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().
|
/* The result is a handle that must be destroyed by mbox_release().
|
||||||
/*
|
/*
|
||||||
/* mbox_release() releases the named mailbox. It is up to the
|
/* 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;
|
MBOX *mp;
|
||||||
int locked = 0;
|
int locked = 0;
|
||||||
VSTREAM *fp;
|
VSTREAM *fp;
|
||||||
|
int saved_errno;
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open or create the target file. In case of a privileged open, the
|
* Open or create the target file. In case of a privileged open, the
|
||||||
* privileged user may be attacked through an unsafe parent directory. In
|
* privileged user may be attacked with hard/soft link tricks in an
|
||||||
* case of an unprivileged open, the mail system may be attacked by a
|
* unsafe parent directory. In case of an unprivileged open, the mail
|
||||||
* malicious user-specified path, and the unprivileged user may be
|
* system may be attacked by a malicious user-specified path, or the
|
||||||
* attacked through an unsafe parent directory. Open non-blocking to fend
|
* unprivileged user may be attacked with hard/soft link tricks in an
|
||||||
* off attacks involving FIFOs and other weird targets.
|
* 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)
|
if (st == 0)
|
||||||
st = &local_statbuf;
|
st = &local_statbuf;
|
||||||
if ((fp = safe_open(path, flags, mode | O_NONBLOCK, st,
|
if ((fp = safe_open(path, flags, mode | O_NONBLOCK, st,
|
||||||
chown_uid, chown_gid, why)) == 0) {
|
chown_uid, chown_gid, why)) == 0) {
|
||||||
if (locked & MBOX_DOT_LOCK)
|
|
||||||
dot_unlockfile(path);
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
non_blocking(vstream_fileno(fp), BLOCKING);
|
|
||||||
close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
|
close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire kernel locks, but only if the target is a regular file, in
|
* If this is a regular file, create a dotlock file. This locking method
|
||||||
* case we're running on some overly pedantic system. flock() locks do
|
* does not work well over NFS, but it is better than some alternatives.
|
||||||
* not work over NFS; fcntl() locks are supposed to work over NFS, but in
|
* With NFS, creating files atomically is a problem, and a successful
|
||||||
* the real world, NFS lock daemons often have serious problems.
|
* 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 \
|
if (S_ISREG(st->st_mode) && (lock_style & MBOX_DOT_LOCK)) {
|
||||||
&& deliver_flock(vstream_fileno(fp), (myflock_style), why) < 0)
|
if (dot_lockfile(path, why) == 0) {
|
||||||
|
locked |= MBOX_DOT_LOCK;
|
||||||
if (S_ISREG(st->st_mode)
|
} else if (errno == EEXIST) {
|
||||||
&& (LOCK_FAIL(MBOX_FLOCK_LOCK, MYFLOCK_STYLE_FLOCK)
|
|
||||||
|| LOCK_FAIL(MBOX_FCNTL_LOCK, MYFLOCK_STYLE_FCNTL))) {
|
|
||||||
if (myflock_locked(vstream_fileno(fp)))
|
|
||||||
errno = EAGAIN;
|
errno = EAGAIN;
|
||||||
if (locked & MBOX_DOT_LOCK)
|
vstream_fclose(fp);
|
||||||
dot_unlockfile(path);
|
return (0);
|
||||||
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 = (MBOX *) mymalloc(sizeof(*mp));
|
||||||
mp->path = mystrdup(path);
|
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)
|
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)
|
if (mp->locked & MBOX_DOT_LOCK)
|
||||||
dot_unlockfile(mp->path);
|
dot_unlockfile(mp->path);
|
||||||
myfree(mp->path);
|
myfree(mp->path);
|
||||||
|
@@ -86,7 +86,7 @@ int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
MBOX *mp;
|
MBOX *mp;
|
||||||
VSTRING *why;
|
VSTRING *why;
|
||||||
int status;
|
int status = -1;
|
||||||
int copy_flags;
|
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
|
* 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;
|
copy_flags = MAIL_COPY_MBOX;
|
||||||
if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0)
|
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,
|
mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
|
||||||
S_IRUSR | S_IWUSR, &st, -1, -1,
|
S_IRUSR | S_IWUSR, &st, -1, -1,
|
||||||
local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL, why);
|
local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL, why);
|
||||||
if (mp == 0) {
|
if (mp != 0) {
|
||||||
status = (errno == EAGAIN ? defer_append : bounce_append)
|
if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
|
||||||
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
|
vstream_fclose(mp->fp);
|
||||||
"cannot access destination file %s: %s", path, STR(why));
|
vstring_sprintf(why, "destination file is executable");
|
||||||
} else if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
|
errno = 0;
|
||||||
vstream_fclose(mp->fp);
|
} else {
|
||||||
status = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
|
status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
|
||||||
"executable destination file %s", path);
|
S_ISREG(st.st_mode) ? copy_flags :
|
||||||
} else if (mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
|
(copy_flags & ~MAIL_COPY_TOFILE),
|
||||||
S_ISREG(st.st_mode) ? copy_flags : (copy_flags & ~MAIL_COPY_TOFILE),
|
"\n", why);
|
||||||
"\n", why)) {
|
}
|
||||||
status = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
|
mbox_release(mp);
|
||||||
"cannot append destination file %s: %s",
|
|
||||||
path, STR(why));
|
|
||||||
} else {
|
|
||||||
status = sent(SENT_ATTR(state.msg_attr), "%s", path);
|
|
||||||
}
|
}
|
||||||
mbox_release(mp);
|
|
||||||
set_eugid(var_owner_uid, var_owner_gid);
|
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.
|
* Clean up.
|
||||||
*/
|
*/
|
||||||
|
@@ -65,9 +65,6 @@
|
|||||||
/* Global library. */
|
/* Global library. */
|
||||||
|
|
||||||
#include <mail_copy.h>
|
#include <mail_copy.h>
|
||||||
#include <safe_open.h>
|
|
||||||
#include <deliver_flock.h>
|
|
||||||
#include <dot_lockfile.h>
|
|
||||||
#include <defer.h>
|
#include <defer.h>
|
||||||
#include <sent.h>
|
#include <sent.h>
|
||||||
#include <mypwd.h>
|
#include <mypwd.h>
|
||||||
@@ -96,7 +93,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
|
|||||||
char *spool_dir;
|
char *spool_dir;
|
||||||
char *mailbox;
|
char *mailbox;
|
||||||
VSTRING *why;
|
VSTRING *why;
|
||||||
MBOX *mp;
|
MBOX *mp;
|
||||||
int status;
|
int status;
|
||||||
int copy_flags;
|
int copy_flags;
|
||||||
VSTRING *biff;
|
VSTRING *biff;
|
||||||
@@ -181,14 +178,14 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
|
|||||||
|
|
||||||
set_eugid(spool_uid, spool_gid);
|
set_eugid(spool_uid, spool_gid);
|
||||||
mp = mbox_open(mailbox, O_APPEND | O_WRONLY | O_CREAT,
|
mp = mbox_open(mailbox, O_APPEND | O_WRONLY | O_CREAT,
|
||||||
S_IRUSR | S_IWUSR, &st, chown_uid, chown_gid,
|
S_IRUSR | S_IWUSR, &st, chown_uid, chown_gid,
|
||||||
local_mbox_lock_mask, why);
|
local_mbox_lock_mask, why);
|
||||||
if (mp != 0) {
|
if (mp != 0) {
|
||||||
if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
|
if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
|
||||||
set_eugid(usr_attr.uid, usr_attr.gid);
|
set_eugid(usr_attr.uid, usr_attr.gid);
|
||||||
if (S_ISREG(st.st_mode) == 0) {
|
if (S_ISREG(st.st_mode) == 0) {
|
||||||
vstream_fclose(mp->fp);
|
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;
|
errno = 0;
|
||||||
} else {
|
} else {
|
||||||
end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
|
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);
|
set_eugid(var_owner_uid, var_owner_gid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As the mail system, bounce, defer delivery, or report success.
|
||||||
|
*/
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
status = (errno == EAGAIN || errno == ENOSPC ?
|
status = (errno == EAGAIN || errno == ENOSPC ?
|
||||||
defer_append : bounce_append)
|
defer_append : bounce_append)
|
||||||
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
|
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
|
||||||
"cannot access mailbox for user %s. %s",
|
"cannot access mailbox %s for user %s. %s",
|
||||||
state.msg_attr.user, vstring_str(why));
|
mailbox, state.msg_attr.user, vstring_str(why));
|
||||||
} else {
|
} else {
|
||||||
sent(SENT_ATTR(state.msg_attr), "mailbox");
|
sent(SENT_ATTR(state.msg_attr), "mailbox");
|
||||||
if (var_biff) {
|
if (var_biff) {
|
||||||
@@ -216,6 +216,10 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
|
|||||||
vstring_free(biff);
|
vstring_free(biff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up.
|
||||||
|
*/
|
||||||
myfree(mailbox);
|
myfree(mailbox);
|
||||||
vstring_free(why);
|
vstring_free(why);
|
||||||
return (status);
|
return (status);
|
||||||
|
@@ -300,7 +300,8 @@ int main(int argc, char **argv)
|
|||||||
if (test_lock)
|
if (test_lock)
|
||||||
exit(lock_fp ? 0 : 1);
|
exit(lock_fp ? 0 : 1);
|
||||||
if (lock_fp == 0)
|
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,
|
vstream_fprintf(lock_fp, "%*lu\n", (int) sizeof(unsigned long) * 4,
|
||||||
(unsigned long) var_pid);
|
(unsigned long) var_pid);
|
||||||
if (vstream_fflush(lock_fp))
|
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);
|
why = vstring_alloc(1);
|
||||||
if ((multi_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
|
if ((multi_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
|
||||||
(struct stat *) 0, -1, -1, why)) == 0)
|
(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);
|
close_on_exec(vstream_fileno(multi_server_lock), CLOSE_ON_EXEC);
|
||||||
myfree(lock_path);
|
myfree(lock_path);
|
||||||
vstring_free(why);
|
vstring_free(why);
|
||||||
|
@@ -520,7 +520,7 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
|
|||||||
why = vstring_alloc(1);
|
why = vstring_alloc(1);
|
||||||
if ((single_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
|
if ((single_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
|
||||||
(struct stat *) 0, -1, -1, why)) == 0)
|
(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);
|
close_on_exec(vstream_fileno(single_server_lock), CLOSE_ON_EXEC);
|
||||||
myfree(lock_path);
|
myfree(lock_path);
|
||||||
vstring_free(why);
|
vstring_free(why);
|
||||||
|
@@ -534,7 +534,7 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
|
|||||||
why = vstring_alloc(1);
|
why = vstring_alloc(1);
|
||||||
if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
|
if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
|
||||||
(struct stat *) 0, -1, -1, why)) == 0)
|
(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);
|
close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
|
||||||
myfree(lock_path);
|
myfree(lock_path);
|
||||||
vstring_free(why);
|
vstring_free(why);
|
||||||
|
@@ -77,6 +77,10 @@
|
|||||||
/* Problems are logged to the standard error stream. No output means
|
/* Problems are logged to the standard error stream. No output means
|
||||||
/* no problems were detected. Duplicate entries are skipped and are
|
/* no problems were detected. Duplicate entries are skipped and are
|
||||||
/* flagged with a warning.
|
/* 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
|
/* BUGS
|
||||||
/* The "delete key" support is limited to one delete operation
|
/* The "delete key" support is limited to one delete operation
|
||||||
/* per command invocation.
|
/* per command invocation.
|
||||||
|
@@ -101,7 +101,6 @@
|
|||||||
#include <vstream.h>
|
#include <vstream.h>
|
||||||
#include <msg_vstream.h>
|
#include <msg_vstream.h>
|
||||||
#include <iostuff.h>
|
#include <iostuff.h>
|
||||||
#include <safe_open.h>
|
|
||||||
|
|
||||||
/* Global library. */
|
/* Global library. */
|
||||||
|
|
||||||
@@ -201,7 +200,8 @@ int main(int argc, char **argv)
|
|||||||
command = argv + optind + 1;
|
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();
|
mail_conf_read();
|
||||||
lock_mask = mbox_lock_mask(lock_style ? lock_style :
|
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,
|
if ((mp = mbox_open(folder, O_APPEND | O_WRONLY | O_CREAT,
|
||||||
S_IRUSR | S_IWUSR, (struct stat *) 0,
|
S_IRUSR | S_IWUSR, (struct stat *) 0,
|
||||||
-1, -1, lock_mask, why)) == 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.
|
* Run the command. Remove the lock after completion.
|
||||||
*/
|
*/
|
||||||
for (count = 0; count < var_fork_tries; count++) {
|
for (count = 1; (pid = fork()) == -1; count++) {
|
||||||
switch (pid = fork()) {
|
msg_warn("fork %s: %m", command[0]);
|
||||||
case -1:
|
if (count >= var_fork_tries) {
|
||||||
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");
|
|
||||||
mbox_release(mp);
|
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
|
/* Problems and transactions are logged to the standard error
|
||||||
/* stream. No output means no problems. Duplicate entries are
|
/* stream. No output means no problems. Duplicate entries are
|
||||||
/* skipped and are flagged with a warning.
|
/* 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
|
/* BUGS
|
||||||
/* The "delete key" support is limited to one delete operation
|
/* The "delete key" support is limited to one delete operation
|
||||||
/* per command invocation.
|
/* per command invocation.
|
||||||
|
@@ -81,7 +81,7 @@
|
|||||||
/* or if a destination is unreachable.
|
/* or if a destination is unreachable.
|
||||||
/* .IP \fBignore_mx_lookup_error\fR
|
/* .IP \fBignore_mx_lookup_error\fR
|
||||||
/* When a name server fails to respond to an MX query, search for an
|
/* 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
|
/* .IP \fBinet_interfaces\fR
|
||||||
/* The network interface addresses that this mail system receives
|
/* The network interface addresses that this mail system receives
|
||||||
/* mail on. When any of those addresses appears in the list of mail
|
/* 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.
|
/* postmaster with transcripts of SMTP sessions with protocol errors.
|
||||||
/* .IP \fBsmtp_always_send_ehlo\fR
|
/* .IP \fBsmtp_always_send_ehlo\fR
|
||||||
/* Always send EHLO at the start of a connection.
|
/* 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
|
/* .IP \fBsmtp_skip_4xx_greeting\fR
|
||||||
/* Skip servers that greet us with a 4xx status code.
|
/* Skip servers that greet us with a 4xx status code.
|
||||||
/* .IP \fBsmtp_skip_5xx_greeting\fR
|
/* .IP \fBsmtp_skip_5xx_greeting\fR
|
||||||
@@ -239,6 +241,7 @@ char *var_fallback_relay;
|
|||||||
char *var_bestmx_transp;
|
char *var_bestmx_transp;
|
||||||
char *var_error_rcpt;
|
char *var_error_rcpt;
|
||||||
int var_smtp_always_ehlo;
|
int var_smtp_always_ehlo;
|
||||||
|
int var_smtp_never_ehlo;
|
||||||
char *var_smtp_sasl_opts;
|
char *var_smtp_sasl_opts;
|
||||||
char *var_smtp_sasl_passwd;
|
char *var_smtp_sasl_passwd;
|
||||||
bool var_smtp_sasl_enable;
|
bool var_smtp_sasl_enable;
|
||||||
@@ -307,17 +310,17 @@ static int deliver_message(DELIVER_REQUEST *request)
|
|||||||
smtp_chat_notify(state);
|
smtp_chat_notify(state);
|
||||||
smtp_session_free(state->session);
|
smtp_session_free(state->session);
|
||||||
debug_peer_restore();
|
debug_peer_restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up.
|
* Clean up.
|
||||||
*/
|
*/
|
||||||
vstring_free(why);
|
vstring_free(why);
|
||||||
smtp_chat_reset(state);
|
smtp_chat_reset(state);
|
||||||
result = state->status;
|
result = state->status;
|
||||||
smtp_state_free(state);
|
smtp_state_free(state);
|
||||||
|
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* smtp_service - perform service for client */
|
/* 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_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_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_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,
|
VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
@@ -91,6 +91,7 @@
|
|||||||
#include <mail_params.h>
|
#include <mail_params.h>
|
||||||
#include <mail_addr.h>
|
#include <mail_addr.h>
|
||||||
#include <post_mail.h>
|
#include <post_mail.h>
|
||||||
|
#include <mail_error.h>
|
||||||
|
|
||||||
/* Application-specific. */
|
/* Application-specific. */
|
||||||
|
|
||||||
@@ -156,7 +157,6 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
|
|||||||
{
|
{
|
||||||
SMTP_SESSION *session = state->session;
|
SMTP_SESSION *session = state->session;
|
||||||
static SMTP_RESP rdata;
|
static SMTP_RESP rdata;
|
||||||
int more;
|
|
||||||
char *cp;
|
char *cp;
|
||||||
int last_char;
|
int last_char;
|
||||||
|
|
||||||
@@ -174,17 +174,12 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
|
|||||||
VSTRING_RESET(rdata.buf);
|
VSTRING_RESET(rdata.buf);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
last_char = smtp_get(state->buffer, session->stream, var_line_limit);
|
last_char = smtp_get(state->buffer, session->stream, var_line_limit);
|
||||||
cp = printable(STR(state->buffer), '?');
|
printable(STR(state->buffer), '?');
|
||||||
if (last_char != '\n')
|
if (last_char != '\n')
|
||||||
msg_warn("%s: response longer than %d: %.30s...",
|
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)
|
if (msg_verbose)
|
||||||
msg_info("< %s: %s", session->namaddr, cp);
|
msg_info("< %s: %s", session->namaddr, STR(state->buffer));
|
||||||
while (ISDIGIT(*cp))
|
|
||||||
cp++;
|
|
||||||
rdata.code = (cp - STR(state->buffer) == 3 ?
|
|
||||||
atoi(STR(state->buffer)) : 0);
|
|
||||||
more = (*cp == '-');
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defend against a denial of service attack by limiting the amount
|
* 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));
|
vstring_strcat(rdata.buf, STR(state->buffer));
|
||||||
smtp_chat_append(state, "In: ", 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 */
|
* Parse into code and text. Ignore unrecognized garbage. This means
|
||||||
continue;
|
* that any character except space (or end of line) will have the
|
||||||
if (more == 0)
|
* same effect as the '-' line continuation character.
|
||||||
break;
|
*/
|
||||||
|
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);
|
VSTRING_TERMINATE(rdata.buf);
|
||||||
rdata.str = STR(rdata.buf);
|
rdata.str = STR(rdata.buf);
|
||||||
return (&rdata);
|
return (&rdata);
|
||||||
|
@@ -186,6 +186,8 @@ int smtp_helo(SMTP_STATE *state)
|
|||||||
}
|
}
|
||||||
if (var_smtp_always_ehlo)
|
if (var_smtp_always_ehlo)
|
||||||
state->features |= SMTP_FEATURE_ESMTP;
|
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
|
* Return the compliment. Fall back to SMTP if our ESMTP recognition
|
||||||
|
@@ -10,22 +10,11 @@
|
|||||||
/* int fd;
|
/* int fd;
|
||||||
/* int lock_style;
|
/* int lock_style;
|
||||||
/* int operation;
|
/* int operation;
|
||||||
/*
|
|
||||||
/* int myflock_locked(err)
|
|
||||||
/* int err;
|
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* myflock() locks or unlocks an entire open file. Depending
|
/* myflock() locks or unlocks an entire open file.
|
||||||
/* on the value of the \fIlock_style\fR argument, this function uses
|
|
||||||
/* either the fcntl() or the flock() system call.
|
|
||||||
/*
|
/*
|
||||||
/* In the case of a blocking request, a call that fails due to
|
/* In the case of a blocking request, a call that fails due to
|
||||||
/* transient problems is tried again once per second.
|
/* forseeable transient problems is retried 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.
|
|
||||||
/*
|
/*
|
||||||
/* Arguments:
|
/* Arguments:
|
||||||
/* .IP fd
|
/* .IP fd
|
||||||
@@ -34,34 +23,34 @@
|
|||||||
/* One of the following values:
|
/* One of the following values:
|
||||||
/* .RS
|
/* .RS
|
||||||
/* .IP MYFLOCK_STYLE_FLOCK
|
/* .IP MYFLOCK_STYLE_FLOCK
|
||||||
/* Use BSD-style flock() locks.
|
/* Use BSD-style flock() locking.
|
||||||
/* .IP MYFLOCK_STYLE_FCNTL
|
/* .IP MYFLOCK_STYLE_FCNTL
|
||||||
/* Use POSIX-style fcntl() locks.
|
/* Use POSIX-style fcntl() locking.
|
||||||
/* .RE
|
/* .RE
|
||||||
/* .IP operation
|
/* .IP operation
|
||||||
/* One of the following values:
|
/* One of the following values:
|
||||||
/* .RS
|
/* .RS
|
||||||
/* .IP MYFLOCK_OP_NONE
|
/* .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
|
/* .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.
|
/* This is appropriate for read-only access.
|
||||||
/* .IP MYFLOCK_OP_EXCLUSIVE
|
/* .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.
|
/* file. This is appropriate for write access.
|
||||||
/* .PP
|
/* .PP
|
||||||
/* In addition, setting the MYFLOCK_OP_NOWAIT bit causes the
|
/* In addition, setting the MYFLOCK_OP_NOWAIT bit causes the
|
||||||
/* call to return immediately when the requested lock cannot
|
/* call to return immediately when the requested lock cannot
|
||||||
/* be acquired. See the myflock_locked() function on lock_style to deal
|
/* be acquired.
|
||||||
/* with a negative result.
|
|
||||||
/* .RE
|
/* .RE
|
||||||
/* DIAGNOSTICS
|
/* DIAGNOSTICS
|
||||||
/* myflock() returns 0 in case of success, -1 in case of failure.
|
/* myflock() returns 0 in case of success, -1 in case of failure.
|
||||||
/* A problem description is returned via the global \fIerrno\fR
|
/* 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.
|
/* Panic: attempts to use an unsupported file locking method or
|
||||||
/* to use multiple locking methods, or none.
|
/* to implement an unsupported operation.
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@@ -91,13 +80,20 @@
|
|||||||
/* Utility library. */
|
/* Utility library. */
|
||||||
|
|
||||||
#include "msg.h"
|
#include "msg.h"
|
||||||
#include "vstring.h"
|
|
||||||
#include "myflock.h"
|
#include "myflock.h"
|
||||||
|
|
||||||
/* myflock - lock/unlock entire open file */
|
/* myflock - lock/unlock entire open file */
|
||||||
|
|
||||||
int myflock(int fd, int lock_style, int operation)
|
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) {
|
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
|
-1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((operation & (MYFLOCK_OP_BITS)) != operation)
|
status = flock(fd, lock_ops[operation]);
|
||||||
msg_panic("myflock: improper operation type: 0x%x", operation);
|
break;
|
||||||
return (flock(fd, lock_ops[operation]));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -129,28 +124,28 @@ int myflock(int fd, int lock_style, int operation)
|
|||||||
static int lock_ops[] = {
|
static int lock_ops[] = {
|
||||||
F_UNLCK, F_RDLCK, F_WRLCK
|
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));
|
memset((char *) &lock, 0, sizeof(lock));
|
||||||
lock.l_type = lock_ops[operation & ~MYFLOCK_OP_NOWAIT];
|
lock.l_type = lock_ops[operation & ~MYFLOCK_OP_NOWAIT];
|
||||||
request = (operation & MYFLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW;
|
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
|
&& request == F_SETLKW
|
||||||
&& (errno == EINTR || errno == ENOLCK || errno == EDEADLK))
|
&& (errno == EINTR || errno == ENOLCK || errno == EDEADLK))
|
||||||
sleep(1);
|
sleep(1);
|
||||||
return (ret);
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
msg_panic("myflock: unsupported lock style: 0x%x", lock_style);
|
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 (status);
|
||||||
{
|
|
||||||
return (err == EAGAIN || err == EWOULDBLOCK || err == EACCES);
|
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
* External interface.
|
* External interface.
|
||||||
*/
|
*/
|
||||||
extern int myflock(int, int, int);
|
extern int myflock(int, int, int);
|
||||||
extern int myflock_locked(int);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock styles.
|
* Lock styles.
|
||||||
@@ -26,10 +25,11 @@ extern int myflock_locked(int);
|
|||||||
/*
|
/*
|
||||||
* Lock request types.
|
* Lock request types.
|
||||||
*/
|
*/
|
||||||
#define MYFLOCK_OP_NONE 0
|
#define MYFLOCK_OP_NONE 0
|
||||||
#define MYFLOCK_OP_SHARED 1
|
#define MYFLOCK_OP_SHARED 1
|
||||||
#define MYFLOCK_OP_EXCLUSIVE 2
|
#define MYFLOCK_OP_EXCLUSIVE 2
|
||||||
#define MYFLOCK_OP_NOWAIT 4
|
#define MYFLOCK_OP_NOWAIT 4
|
||||||
|
|
||||||
#define MYFLOCK_OP_BITS \
|
#define MYFLOCK_OP_BITS \
|
||||||
(MYFLOCK_OP_SHARED | MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)
|
(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);
|
return (0);
|
||||||
if (myflock(vstream_fileno(fp), INTERNAL_LOCK,
|
if (myflock(vstream_fileno(fp), INTERNAL_LOCK,
|
||||||
MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) < 0) {
|
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);
|
vstream_fclose(fp);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@@ -97,7 +97,7 @@ static VSTREAM *safe_open_exist(const char *path, int flags,
|
|||||||
* Open an existing file.
|
* Open an existing file.
|
||||||
*/
|
*/
|
||||||
if ((fp = vstream_fopen(path, flags & ~(O_CREAT | O_EXCL), 0)) == 0) {
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,11 +109,11 @@ static VSTREAM *safe_open_exist(const char *path, int flags,
|
|||||||
if (fstat_st == 0)
|
if (fstat_st == 0)
|
||||||
fstat_st = &local_statbuf;
|
fstat_st = &local_statbuf;
|
||||||
if (fstat(vstream_fileno(fp), fstat_st) < 0) {
|
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) {
|
} 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)) {
|
} 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
|
#endif
|
||||||
|| fstat_st->st_nlink != lstat_st.st_nlink
|
|| fstat_st->st_nlink != lstat_st.st_nlink
|
||||||
|| fstat_st->st_mode != lstat_st.st_mode) {
|
|| fstat_st->st_mode != lstat_st.st_mode) {
|
||||||
vstring_sprintf(why, "file %s: %s", path, S_ISLNK(lstat_st.st_mode) ?
|
vstring_sprintf(why, "%s", S_ISLNK(lstat_st.st_mode) ?
|
||||||
"should not be a symbolic link" : "status changed after opening");
|
"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.
|
* follow symbolic links.
|
||||||
*/
|
*/
|
||||||
if ((fp = vstream_fopen(path, flags | (O_CREAT | O_EXCL), mode)) == 0) {
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,14 +180,14 @@ static VSTREAM *safe_open_create(const char *path, int flags, int mode,
|
|||||||
|
|
||||||
if (CHANGE_OWNER(user, group)
|
if (CHANGE_OWNER(user, group)
|
||||||
&& fchown(vstream_fileno(fp), user, group) < 0) {
|
&& 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.
|
* Optionally look up the file attributes.
|
||||||
*/
|
*/
|
||||||
if (st != 0 && fstat(vstream_fileno(fp), st) < 0)
|
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...
|
* We are almost there...
|
||||||
|
Reference in New Issue
Block a user