9 /* #include "virtual.h"
11 /* int deliver_mailbox(state, usr_attr, statusp)
13 /* USER_ATTR usr_attr;
16 /* deliver_mailbox() delivers to UNIX-style mailbox or to maildir.
18 /* A zero result means that the named user was not found.
22 /* The attributes that specify the message, recipient and more.
24 /* Attributes describing user rights and mailbox location.
26 /* Delivery status: see below.
28 /* The message delivery status is non-zero when delivery should be tried
33 /* The Secure Mailer license must be distributed with this software.
36 /* IBM T.J. Watson Research
38 /* Yorktown Heights, NY 10598, USA
49 /* Utility library. */
55 #include <stringops.h>
56 #include <set_eugid.h>
60 #include <mail_copy.h>
61 #include <mbox_open.h>
64 #include <mail_params.h>
65 #include <mail_addr_find.h>
68 /* Application-specific. */
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
;
89 * Make verbose logging easier to understand.
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
);
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
);
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
);
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: ",
154 (STR(why
->status
)[0] == '4' ?
155 defer_append
: bounce_append
)
156 (BOUNCE_FLAGS(state
.request
),
157 BOUNCE_ATTR(state
.msg_attr
));
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
;
174 DSN_BUF
*why
= state
.msg_attr
.why
;
178 * Make verbose logging easier to understand.
182 MSG_LOG_STATE(myname
, state
);
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
195 #define IGNORE_EXTENSION ((char **) 0)
197 mailbox_res
= mail_addr_find(virtual_mailbox_maps
, state
.msg_attr
.user
,
199 if (mailbox_res
== 0) {
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
));
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
,
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
));
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
));
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
,
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
));
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
));
258 usr_attr
.gid
= (gid_t
) n
;
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
);
273 *statusp
= deliver_mailbox_file(state
, usr_attr
);