mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
snapshot-20001127
This commit is contained in:
committed by
Viktor Dukhovni
parent
3c2727d996
commit
a6f1137bf4
1
postfix/.indent.pro
vendored
1
postfix/.indent.pro
vendored
@@ -68,6 +68,7 @@
|
||||
-TMASTER_SERV
|
||||
-TMASTER_STATUS
|
||||
-TMBLOCK
|
||||
-TMBOX
|
||||
-TMKMAP
|
||||
-TMKMAP_OPEN_INFO
|
||||
-TMULTI_SERVER
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20001126"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20001127"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@@ -6,7 +6,14 @@
|
||||
/* SYNOPSIS
|
||||
/* #include <mbox_open.h>
|
||||
/*
|
||||
/* int mbox_open(path, flags, mode, st, user, group, lock_style, why)
|
||||
/* typedef struct {
|
||||
/* .in +4
|
||||
/* /* public members... */
|
||||
/* VSTREAM *fp;
|
||||
/* .in -4
|
||||
/* } MBOX;
|
||||
/*
|
||||
/* MBOX *mbox_open(path, flags, mode, st, user, group, lock_style, why)
|
||||
/* const char *path;
|
||||
/* int flags;
|
||||
/* int mode;
|
||||
@@ -16,9 +23,8 @@
|
||||
/* int lock_style;
|
||||
/* VSTRING *why;
|
||||
/*
|
||||
/* void mbox_release(path, lock_style)
|
||||
/* const char *path;
|
||||
/* int lock_style;
|
||||
/* void mbox_release(mbox)
|
||||
/* MBOX *mbox;
|
||||
/* DESCRIPTION
|
||||
/* This module manages access to UNIX mailbox-style files.
|
||||
/*
|
||||
@@ -29,9 +35,10 @@
|
||||
/* adequate effective privileges.
|
||||
/* The \fBlock_style\fR argument specifies a lock style from
|
||||
/* mbox_lock_mask(). Kernel 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
|
||||
/* application to close the file.
|
||||
/* application to close the stream.
|
||||
/* DIAGNOSTICS
|
||||
/* mbox_open() returns a null pointer in case of problems, and
|
||||
/* sets errno to EAGAIN if someone else has exclusive access.
|
||||
@@ -59,6 +66,8 @@
|
||||
#include <vstream.h>
|
||||
#include <vstring.h>
|
||||
#include <safe_open.h>
|
||||
#include <iostuff.h>
|
||||
#include <mymalloc.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
@@ -69,43 +78,58 @@
|
||||
|
||||
/* mbox_open - open mailbox-style file for exclusive access */
|
||||
|
||||
VSTREAM *mbox_open(const char *path, int flags, int mode, struct stat * st,
|
||||
uid_t chown_uid, gid_t chown_gid,
|
||||
int lock_style, VSTRING *why)
|
||||
MBOX *mbox_open(const char *path, int flags, int mode, struct stat * st,
|
||||
uid_t chown_uid, gid_t chown_gid,
|
||||
int lock_style, VSTRING *why)
|
||||
{
|
||||
struct stat local_statbuf;
|
||||
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) && dot_lockfile(path, why) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
errno = EAGAIN;
|
||||
return (0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If file.lock can't be created, ignore the problem. We need this so
|
||||
* that Postfix can deliver as unprivileged user to /dev/null
|
||||
* aliases.
|
||||
*/
|
||||
if ((lock_style & MBOX_DOT_LOCK_MAY_FAIL) == 0)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open or create the target file.
|
||||
* 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.
|
||||
*/
|
||||
if (st == 0)
|
||||
st = &local_statbuf;
|
||||
if ((fp = safe_open(path, flags, mode, st, chown_uid, chown_gid, why)) == 0) {
|
||||
if (lock_style & MBOX_DOT_LOCK)
|
||||
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
|
||||
@@ -121,17 +145,23 @@ VSTREAM *mbox_open(const char *path, int flags, int mode, struct stat * st,
|
||||
|| LOCK_FAIL(MBOX_FCNTL_LOCK, MYFLOCK_STYLE_FCNTL))) {
|
||||
if (myflock_locked(vstream_fileno(fp)))
|
||||
errno = EAGAIN;
|
||||
if (lock_style & MBOX_DOT_LOCK)
|
||||
if (locked & MBOX_DOT_LOCK)
|
||||
dot_unlockfile(path);
|
||||
return (0);
|
||||
}
|
||||
return (fp);
|
||||
mp = (MBOX *) mymalloc(sizeof(*mp));
|
||||
mp->path = mystrdup(path);
|
||||
mp->fp = fp;
|
||||
mp->locked = locked;
|
||||
return (mp);
|
||||
}
|
||||
|
||||
/* mbox_release - release mailbox exclusive access */
|
||||
|
||||
void mbox_release(const char *path, int lock_style)
|
||||
void mbox_release(MBOX *mp)
|
||||
{
|
||||
if (lock_style & MBOX_DOT_LOCK)
|
||||
dot_unlockfile(path);
|
||||
if (mp->locked & MBOX_DOT_LOCK)
|
||||
dot_unlockfile(mp->path);
|
||||
myfree(mp->path);
|
||||
myfree((char *) mp);
|
||||
}
|
||||
|
@@ -21,8 +21,13 @@
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern VSTREAM *mbox_open(const char *, int, int, struct stat *, uid_t, gid_t, int, VSTRING *);
|
||||
extern void mbox_release(const char *, int);
|
||||
typedef struct {
|
||||
char *path; /* saved path, for dot_unlock */
|
||||
VSTREAM *fp; /* open stream or null */
|
||||
int locked; /* what locks were set */
|
||||
} MBOX;
|
||||
extern MBOX *mbox_open(const char *, int, int, struct stat *, uid_t, gid_t, int, VSTRING *);
|
||||
extern void mbox_release(MBOX *);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
@@ -84,7 +84,7 @@ int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
|
||||
{
|
||||
char *myname = "deliver_file";
|
||||
struct stat st;
|
||||
VSTREAM *dst;
|
||||
MBOX *mp;
|
||||
VSTRING *why;
|
||||
int status;
|
||||
int copy_flags;
|
||||
@@ -148,26 +148,27 @@ int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
|
||||
copy_flags &= ~MAIL_COPY_DELIVERED;
|
||||
|
||||
set_eugid(usr_attr.uid, usr_attr.gid);
|
||||
dst = 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 (dst == 0) {
|
||||
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(dst);
|
||||
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), dst, S_ISREG(st.st_mode) ?
|
||||
copy_flags : (copy_flags & ~MAIL_COPY_TOFILE), "\n", why)) {
|
||||
} 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);
|
||||
}
|
||||
mbox_release(path, local_mbox_lock_mask);
|
||||
mbox_release(mp);
|
||||
set_eugid(var_owner_uid, var_owner_gid);
|
||||
|
||||
/*
|
||||
|
@@ -96,7 +96,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
|
||||
char *spool_dir;
|
||||
char *mailbox;
|
||||
VSTRING *why;
|
||||
VSTREAM *dst;
|
||||
MBOX *mp;
|
||||
int status;
|
||||
int copy_flags;
|
||||
VSTRING *biff;
|
||||
@@ -180,23 +180,24 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
|
||||
copy_flags &= ~MAIL_COPY_DELIVERED;
|
||||
|
||||
set_eugid(spool_uid, spool_gid);
|
||||
dst = 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,
|
||||
local_mbox_lock_mask, why);
|
||||
if (dst != 0) {
|
||||
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);
|
||||
errno = 0;
|
||||
} else {
|
||||
end = vstream_fseek(dst, (off_t) 0, SEEK_END);
|
||||
status = mail_copy(COPY_ATTR(state.msg_attr), dst,
|
||||
end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
|
||||
status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
|
||||
copy_flags, "\n", why);
|
||||
}
|
||||
if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
|
||||
set_eugid(spool_uid, spool_gid);
|
||||
mbox_release(mailbox, local_mbox_lock_mask);
|
||||
mbox_release(mp);
|
||||
}
|
||||
set_eugid(var_owner_uid, var_owner_gid);
|
||||
|
||||
|
@@ -142,9 +142,9 @@ int main(int argc, char **argv)
|
||||
int count;
|
||||
WAIT_STATUS_T status;
|
||||
pid_t pid;
|
||||
int mbox_lock;
|
||||
int lock_mask;
|
||||
char *lock_style = 0;
|
||||
VSTREAM *fp;
|
||||
MBOX *mp;
|
||||
|
||||
/*
|
||||
* Be consistent with file permissions.
|
||||
@@ -204,7 +204,7 @@ int main(int argc, char **argv)
|
||||
* Read the config file.
|
||||
*/
|
||||
mail_conf_read();
|
||||
mbox_lock = mbox_lock_mask(lock_style ? lock_style :
|
||||
lock_mask = mbox_lock_mask(lock_style ? lock_style :
|
||||
get_mail_conf_str(VAR_MAILBOX_LOCK, DEF_MAILBOX_LOCK, 1, 0));
|
||||
|
||||
/*
|
||||
@@ -212,11 +212,10 @@ int main(int argc, char **argv)
|
||||
* command is not supposed to disappear into the background.
|
||||
*/
|
||||
why = vstring_alloc(1);
|
||||
if ((fp = 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,
|
||||
-1, -1, mbox_lock, why)) == 0)
|
||||
-1, -1, lock_mask, why)) == 0)
|
||||
msg_fatal("%s", vstring_str(why));
|
||||
close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
|
||||
|
||||
/*
|
||||
* Run the command. Remove the lock after completion.
|
||||
@@ -232,12 +231,12 @@ int main(int argc, char **argv)
|
||||
default:
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
msg_fatal("waitpid: %m");
|
||||
mbox_release(folder, mbox_lock);
|
||||
mbox_release(mp);
|
||||
exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
|
||||
}
|
||||
if (count + 1 < var_fork_tries)
|
||||
sleep(var_fork_delay);
|
||||
}
|
||||
mbox_release(folder, mbox_lock);
|
||||
mbox_release(mp);
|
||||
exit(EX_TEMPFAIL);
|
||||
}
|
||||
|
Reference in New Issue
Block a user