No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / virtual / mailbox.c
blob80af075ce689aede826fd5b9c222dc2aa8a59927
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* mailbox 3
6 /* SUMMARY
7 /* mailbox delivery
8 /* SYNOPSIS
9 /* #include "virtual.h"
11 /* int deliver_mailbox(state, usr_attr, statusp)
12 /* LOCAL_STATE state;
13 /* USER_ATTR usr_attr;
14 /* int *statusp;
15 /* DESCRIPTION
16 /* deliver_mailbox() delivers to UNIX-style mailbox or to maildir.
18 /* A zero result means that the named user was not found.
20 /* Arguments:
21 /* .IP state
22 /* The attributes that specify the message, recipient and more.
23 /* .IP usr_attr
24 /* Attributes describing user rights and mailbox location.
25 /* .IP statusp
26 /* Delivery status: see below.
27 /* DIAGNOSTICS
28 /* The message delivery status is non-zero when delivery should be tried
29 /* again.
30 /* LICENSE
31 /* .ad
32 /* .fi
33 /* The Secure Mailer license must be distributed with this software.
34 /* AUTHOR(S)
35 /* Wietse Venema
36 /* IBM T.J. Watson Research
37 /* P.O. Box 704
38 /* Yorktown Heights, NY 10598, USA
39 /*--*/
41 /* System library. */
43 #include <sys_defs.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <errno.h>
47 #include <string.h>
49 /* Utility library. */
51 #include <msg.h>
52 #include <vstring.h>
53 #include <vstream.h>
54 #include <mymalloc.h>
55 #include <stringops.h>
56 #include <set_eugid.h>
58 /* Global library. */
60 #include <mail_copy.h>
61 #include <mbox_open.h>
62 #include <defer.h>
63 #include <sent.h>
64 #include <mail_params.h>
65 #include <mail_addr_find.h>
66 #include <dsn_util.h>
68 /* Application-specific. */
70 #include "virtual.h"
72 #define YES 1
73 #define NO 0
75 /* deliver_mailbox_file - deliver to recipient mailbox */
77 static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
79 const char *myname = "deliver_mailbox_file";
80 DSN_BUF *why = state.msg_attr.why;
81 MBOX *mp;
82 int mail_copy_status;
83 int deliver_status;
84 int copy_flags;
85 long end;
86 struct stat st;
89 * Make verbose logging easier to understand.
91 state.level++;
92 if (msg_verbose)
93 MSG_LOG_STATE(myname, state);
96 * Don't deliver trace-only requests.
98 if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
99 dsb_simple(why, "2.0.0", "delivers to mailbox");
100 return (sent(BOUNCE_FLAGS(state.request),
101 SENT_ATTR(state.msg_attr)));
105 * Initialize. Assume the operation will fail. Set the delivered
106 * attribute to reflect the final recipient.
108 if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
109 msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
110 state.msg_attr.delivered = state.msg_attr.rcpt.address;
111 mail_copy_status = MAIL_COPY_STAT_WRITE;
114 * Lock the mailbox and open/create the mailbox file.
116 * Write the file as the recipient, so that file quota work.
118 copy_flags = MAIL_COPY_MBOX;
120 set_eugid(usr_attr.uid, usr_attr.gid);
121 mp = mbox_open(usr_attr.mailbox, O_APPEND | O_WRONLY | O_CREAT,
122 S_IRUSR | S_IWUSR, &st, -1, -1,
123 virtual_mbox_lock_mask, "4.2.0", why);
124 if (mp != 0) {
125 if (S_ISREG(st.st_mode) == 0) {
126 vstream_fclose(mp->fp);
127 msg_warn("recipient %s: destination %s is not a regular file",
128 state.msg_attr.rcpt.address, usr_attr.mailbox);
129 dsb_simple(why, "5.3.5", "mail system configuration error");
130 } else if (var_strict_mbox_owner && st.st_uid != usr_attr.uid) {
131 vstream_fclose(mp->fp);
132 dsb_simple(why, "4.2.0",
133 "destination %s is not owned by recipient", usr_attr.mailbox);
134 msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch",
135 VAR_STRICT_MBOX_OWNER);
136 } else {
137 end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
138 mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
139 copy_flags, "\n", why);
141 mbox_release(mp);
143 set_eugid(var_owner_uid, var_owner_gid);
146 * As the mail system, bounce, defer delivery, or report success.
148 if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
149 deliver_status = DEL_STAT_DEFER;
150 } else if (mail_copy_status != 0) {
151 vstring_sprintf_prepend(why->reason, "delivery failed to mailbox %s: ",
152 usr_attr.mailbox);
153 deliver_status =
154 (STR(why->status)[0] == '4' ?
155 defer_append : bounce_append)
156 (BOUNCE_FLAGS(state.request),
157 BOUNCE_ATTR(state.msg_attr));
158 } else {
159 dsb_simple(why, "2.0.0", "delivered to mailbox");
160 deliver_status = sent(BOUNCE_FLAGS(state.request),
161 SENT_ATTR(state.msg_attr));
163 return (deliver_status);
166 /* deliver_mailbox - deliver to recipient mailbox */
168 int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
170 const char *myname = "deliver_mailbox";
171 const char *mailbox_res;
172 const char *uid_res;
173 const char *gid_res;
174 DSN_BUF *why = state.msg_attr.why;
175 long n;
178 * Make verbose logging easier to understand.
180 state.level++;
181 if (msg_verbose)
182 MSG_LOG_STATE(myname, state);
185 * Sanity check.
187 if (*var_virt_mailbox_base != '/')
188 msg_fatal("do not specify relative pathname: %s = %s",
189 VAR_VIRT_MAILBOX_BASE, var_virt_mailbox_base);
192 * Look up the mailbox location. Bounce if not found, defer in case of
193 * trouble.
195 #define IGNORE_EXTENSION ((char **) 0)
197 mailbox_res = mail_addr_find(virtual_mailbox_maps, state.msg_attr.user,
198 IGNORE_EXTENSION);
199 if (mailbox_res == 0) {
200 if (dict_errno == 0)
201 return (NO);
202 msg_warn("table %s: lookup %s: %m", virtual_mailbox_maps->title,
203 state.msg_attr.user);
204 dsb_simple(why, "4.3.5", "mail system configuration error");
205 *statusp = defer_append(BOUNCE_FLAGS(state.request),
206 BOUNCE_ATTR(state.msg_attr));
207 return (YES);
209 usr_attr.mailbox = concatenate(var_virt_mailbox_base, "/",
210 mailbox_res, (char *) 0);
212 #define RETURN(res) { myfree(usr_attr.mailbox); return (res); }
215 * Look up the mailbox owner rights. Defer in case of trouble.
217 uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
218 IGNORE_EXTENSION);
219 if (uid_res == 0) {
220 msg_warn("recipient %s: not found in %s",
221 state.msg_attr.user, virtual_uid_maps->title);
222 dsb_simple(why, "4.3.5", "mail system configuration error");
223 *statusp = defer_append(BOUNCE_FLAGS(state.request),
224 BOUNCE_ATTR(state.msg_attr));
225 RETURN(YES);
227 if ((n = atol(uid_res)) < var_virt_minimum_uid) {
228 msg_warn("recipient %s: bad uid %s in %s",
229 state.msg_attr.user, uid_res, virtual_uid_maps->title);
230 dsb_simple(why, "4.3.5", "mail system configuration error");
231 *statusp = defer_append(BOUNCE_FLAGS(state.request),
232 BOUNCE_ATTR(state.msg_attr));
233 RETURN(YES);
235 usr_attr.uid = (uid_t) n;
238 * Look up the mailbox group rights. Defer in case of trouble.
240 gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
241 IGNORE_EXTENSION);
242 if (gid_res == 0) {
243 msg_warn("recipient %s: not found in %s",
244 state.msg_attr.user, virtual_gid_maps->title);
245 dsb_simple(why, "4.3.5", "mail system configuration error");
246 *statusp = defer_append(BOUNCE_FLAGS(state.request),
247 BOUNCE_ATTR(state.msg_attr));
248 RETURN(YES);
250 if ((n = atol(gid_res)) <= 0) {
251 msg_warn("recipient %s: bad gid %s in %s",
252 state.msg_attr.user, gid_res, virtual_gid_maps->title);
253 dsb_simple(why, "4.3.5", "mail system configuration error");
254 *statusp = defer_append(BOUNCE_FLAGS(state.request),
255 BOUNCE_ATTR(state.msg_attr));
256 RETURN(YES);
258 usr_attr.gid = (gid_t) n;
260 if (msg_verbose)
261 msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
262 myname, state.level, usr_attr.mailbox,
263 (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
266 * Deliver to mailbox or to maildir.
268 #define LAST_CHAR(s) (s[strlen(s) - 1])
270 if (LAST_CHAR(usr_attr.mailbox) == '/')
271 *statusp = deliver_maildir(state, usr_attr);
272 else
273 *statusp = deliver_mailbox_file(state, usr_attr);
276 * Cleanup.
278 RETURN(YES);