5
/* mail delivery to arbitrary file
9
/* int deliver_file(state, usr_attr, path)
11
/* USER_ATTR usr_attr;
14
/* deliver_file() appends a message to a file, UNIX mailbox format,
15
/* or qmail maildir format,
16
/* with duplicate suppression. It will deliver only to non-executable
21
/* The attributes that specify the message, recipient and more.
22
/* Attributes describing alias, include or forward expansion.
23
/* A table with the results from expanding aliases or lists.
25
/* Attributes describing user rights and environment information.
27
/* The file to deliver to. If the name ends in '/', delivery is done
28
/* in qmail maildir format, otherwise delivery is done in UNIX mailbox
31
/* deliver_file() returns non-zero when delivery should be tried again.
38
/* The Secure Mailer license must be distributed with this software.
41
/* IBM T.J. Watson Research
43
/* Yorktown Heights, NY 10598, USA
55
/* Utility library. */
61
#include <deliver_flock.h>
62
#include <set_eugid.h>
66
#include <mail_copy.h>
70
#include <been_here.h>
71
#include <mail_params.h>
72
#include <mbox_conf.h>
73
#include <mbox_open.h>
75
/* Application-specific. */
79
#define STR vstring_str
81
/* deliver_file - deliver to file */
83
int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
85
char *myname = "deliver_file";
89
int mail_copy_status = MAIL_COPY_STAT_WRITE;
94
* Make verbose logging easier to understand.
98
MSG_LOG_STATE(myname, state);
101
* DUPLICATE ELIMINATION
103
* Skip this file if it was already delivered to as this user.
105
if (been_here(state.dup_filter, "file %ld %s", (long) usr_attr.uid, path))
111
* Do we allow delivery to files?
113
if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0)
114
return (bounce_append(BOUNCE_FLAGS(state.request),
115
BOUNCE_ATTR(state.msg_attr),
116
"mail to file is restricted"));
119
* Don't deliver trace-only requests.
121
if (DEL_REQ_TRACE_ONLY(state.request->flags))
122
return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
123
"delivers to file: %s", path));
128
* Use a default uid/gid when none are given.
130
if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0)
131
msg_panic("privileged default user id");
132
if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0)
133
msg_panic("privileged default group id");
136
* If the name ends in /, use maildir-style delivery instead.
138
if (path[strlen(path) - 1] == '/')
139
return (deliver_maildir(state, usr_attr, path));
142
* Deliver. From here on, no early returns or we have a memory leak.
145
msg_info("deliver_file (%ld,%ld): %s",
146
(long) usr_attr.uid, (long) usr_attr.gid, path);
147
if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
148
msg_fatal("seek queue file %s: %m", state.msg_attr.queue_id);
149
why = vstring_alloc(100);
152
* As the specified user, open or create the file, lock it, and append
155
copy_flags = MAIL_COPY_MBOX;
156
if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0)
157
copy_flags &= ~MAIL_COPY_DELIVERED;
159
set_eugid(usr_attr.uid, usr_attr.gid);
160
mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
161
S_IRUSR | S_IWUSR, &st, -1, -1,
162
local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL, why);
164
if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
165
vstream_fclose(mp->fp);
166
vstring_sprintf(why, "destination file is executable");
169
mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
170
S_ISREG(st.st_mode) ? copy_flags :
171
(copy_flags & ~MAIL_COPY_TOFILE),
176
set_eugid(var_owner_uid, var_owner_gid);
179
* As the mail system, bounce, defer delivery, or report success.
181
if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
182
deliver_status = DEL_STAT_DEFER;
183
} else if (mail_copy_status != 0) {
184
deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
185
defer_append : bounce_append)
186
(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
187
"cannot append message to destination file %s: %s",
190
deliver_status = sent(BOUNCE_FLAGS(state.request),
191
SENT_ATTR(state.msg_attr),
192
"delivered to file: %s", path);
199
return (deliver_status);