1 /*++
2 /* NAME
3 /* file 3
4 /* SUMMARY
5 /* mail delivery to arbitrary file
6 /* SYNOPSIS
7 /* #include "local.h"
8 /*
9 /* int deliver_file(state, usr_attr, path)
10 /* LOCAL_STATE state;
11 /* USER_ATTR usr_attr;
12 /* char *path;
13 /* DESCRIPTION
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
17 /* regular files.
18 /*
19 /* Arguments:
20 /* .IP state
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.
24 /* .IP usr_attr
25 /* Attributes describing user rights and environment information.
26 /* .IP path
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
29 /* format.
30 /* DIAGNOSTICS
31 /* deliver_file() returns non-zero when delivery should be tried again.
32 /* SEE ALSO
33 /* defer(3)
34 /* bounce(3)
35 /* LICENSE
36 /* .ad
37 /* .fi
38 /* The Secure Mailer license must be distributed with this software.
39 /* AUTHOR(S)
40 /* Wietse Venema
41 /* IBM T.J. Watson Research
42 /* P.O. Box 704
43 /* Yorktown Heights, NY 10598, USA
44 /*--*/
45
46 /* System library. */
47
48 #include <sys_defs.h>
49 #include <sys/stat.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <errno.h>
53 #include <string.h>
54
55 /* Utility library. */
56
57 #include <msg.h>
58 #include <htable.h>
59 #include <vstring.h>
60 #include <vstream.h>
61 #include <deliver_flock.h>
62 #include <set_eugid.h>
63
64 /* Global library. */
65
66 #include <mail_copy.h>
67 #include <bounce.h>
68 #include <defer.h>
69 #include <sent.h>
70 #include <been_here.h>
71 #include <mail_params.h>
72 #include <mbox_conf.h>
73 #include <mbox_open.h>
74 #include <dsn_util.h>
75
76 /* Application-specific. */
77
78 #include "local.h"
79
80 /* deliver_file - deliver to file */
81
deliver_file(LOCAL_STATE state,USER_ATTR usr_attr,char * path)82 int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
83 {
84 const char *myname = "deliver_file";
85 struct stat st;
86 MBOX *mp;
87 DSN_BUF *why = state.msg_attr.why;
88 int mail_copy_status = MAIL_COPY_STAT_WRITE;
89 int deliver_status;
90 int copy_flags;
91
92 /*
93 * Make verbose logging easier to understand.
94 */
95 state.level++;
96 if (msg_verbose)
97 MSG_LOG_STATE(myname, state);
98
99 /*
100 * DUPLICATE ELIMINATION
101 *
102 * Skip this file if it was already delivered to as this user.
103 */
104 if (been_here(state.dup_filter, "file %ld %s", (long) usr_attr.uid, path))
105 return (0);
106
107 /*
108 * DELIVERY POLICY
109 *
110 * Do we allow delivery to files?
111 */
112 if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0) {
113 dsb_simple(why, "5.7.1", "mail to file is restricted");
114 /* Account for possible owner- sender address override. */
115 return (bounce_workaround(state));
116 }
117
118 /*
119 * Don't deliver trace-only requests.
120 */
121 if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
122 dsb_simple(why, "2.0.0", "delivers to file: %s", path);
123 return (sent(BOUNCE_FLAGS(state.request),
124 SENT_ATTR(state.msg_attr)));
125 }
126
127 /*
128 * DELIVERY RIGHTS
129 *
130 * Use a default uid/gid when none are given.
131 */
132 if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0)
133 msg_panic("privileged default user id");
134 if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0)
135 msg_panic("privileged default group id");
136
137 /*
138 * If the name ends in /, use maildir-style delivery instead.
139 */
140 if (path[strlen(path) - 1] == '/')
141 return (deliver_maildir(state, usr_attr, path));
142
143 /*
144 * Deliver. From here on, no early returns or we have a memory leak.
145 */
146 if (msg_verbose)
147 msg_info("deliver_file (%ld,%ld): %s",
148 (long) usr_attr.uid, (long) usr_attr.gid, path);
149 if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
150 msg_fatal("seek queue file %s: %m", state.msg_attr.queue_id);
151
152 /*
153 * As the specified user, open or create the file, lock it, and append
154 * the message.
155 */
156 copy_flags = MAIL_COPY_MBOX;
157 if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0)
158 copy_flags &= ~MAIL_COPY_DELIVERED;
159
160 set_eugid(usr_attr.uid, usr_attr.gid);
161 mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
162 S_IRUSR | S_IWUSR, &st, -1, -1,
163 local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL,
164 "5.2.0", why);
165 if (mp != 0) {
166 if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
167 vstream_fclose(mp->fp);
168 dsb_simple(why, "5.7.1", "file is executable");
169 } else {
170 mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
171 S_ISREG(st.st_mode) ? copy_flags :
172 (copy_flags & ~MAIL_COPY_TOFILE),
173 "\n", why);
174 }
175 mbox_release(mp);
176 }
177 set_eugid(var_owner_uid, var_owner_gid);
178
179 /*
180 * As the mail system, bounce, defer delivery, or report success.
181 */
182 if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
183 deliver_status = DEL_STAT_DEFER;
184 } else if (mail_copy_status != 0) {
185 vstring_sprintf_prepend(why->reason,
186 "cannot append message to file %s: ", path);
187 /* Account for possible owner- sender address override. */
188 deliver_status = bounce_workaround(state);
189 } else {
190 dsb_simple(why, "2.0.0", "delivered to file: %s", path);
191 deliver_status = sent(BOUNCE_FLAGS(state.request),
192 SENT_ATTR(state.msg_attr));
193 }
194 return (deliver_status);
195 }
196