Postfix3.3.1
mailbox.c
[詳解]
1 /*++
2 /* NAME
3 /* mailbox 3
4 /* SUMMARY
5 /* mailbox delivery
6 /* SYNOPSIS
7 /* #include "virtual.h"
8 /*
9 /* int deliver_mailbox(state, usr_attr, statusp)
10 /* LOCAL_STATE state;
11 /* USER_ATTR usr_attr;
12 /* int *statusp;
13 /* DESCRIPTION
14 /* deliver_mailbox() delivers to UNIX-style mailbox or to maildir.
15 /*
16 /* A zero result means that the named user was not found.
17 /*
18 /* Arguments:
19 /* .IP state
20 /* The attributes that specify the message, recipient and more.
21 /* .IP usr_attr
22 /* Attributes describing user rights and mailbox location.
23 /* .IP statusp
24 /* Delivery status: see below.
25 /* DIAGNOSTICS
26 /* The message delivery status is non-zero when delivery should be tried
27 /* again.
28 /* LICENSE
29 /* .ad
30 /* .fi
31 /* The Secure Mailer license must be distributed with this software.
32 /* AUTHOR(S)
33 /* Wietse Venema
34 /* IBM T.J. Watson Research
35 /* P.O. Box 704
36 /* Yorktown Heights, NY 10598, USA
37 /*
38 /* Wietse Venema
39 /* Google, Inc.
40 /* 111 8th Avenue
41 /* New York, NY 10011, USA
42 /*--*/
43 
44 /* System library. */
45 
46 #include <sys_defs.h>
47 #include <sys/stat.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 #include <string.h>
51 
52 /* Utility library. */
53 
54 #include <msg.h>
55 #include <vstring.h>
56 #include <vstream.h>
57 #include <mymalloc.h>
58 #include <stringops.h>
59 #include <set_eugid.h>
60 
61 /* Global library. */
62 
63 #include <mail_copy.h>
64 #include <mbox_open.h>
65 #include <defer.h>
66 #include <sent.h>
67 #include <mail_params.h>
68 #include <mail_addr_find.h>
69 #include <dsn_util.h>
70 
71 /* Application-specific. */
72 
73 #include "virtual.h"
74 
75 #define YES 1
76 #define NO 0
77 
78 /* deliver_mailbox_file - deliver to recipient mailbox */
79 
80 static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
81 {
82  const char *myname = "deliver_mailbox_file";
83  DSN_BUF *why = state.msg_attr.why;
84  MBOX *mp;
85  int mail_copy_status;
86  int deliver_status;
87  int copy_flags;
88  struct stat st;
89 
90  /*
91  * Make verbose logging easier to understand.
92  */
93  state.level++;
94  if (msg_verbose)
95  MSG_LOG_STATE(myname, state);
96 
97  /*
98  * Don't deliver trace-only requests.
99  */
100  if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
101  dsb_simple(why, "2.0.0", "delivers to mailbox");
102  return (sent(BOUNCE_FLAGS(state.request),
103  SENT_ATTR(state.msg_attr)));
104  }
105 
106  /*
107  * Initialize. Assume the operation will fail. Set the delivered
108  * attribute to reflect the final recipient.
109  */
110  if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
111  msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
112  state.msg_attr.delivered = state.msg_attr.rcpt.address;
113  mail_copy_status = MAIL_COPY_STAT_WRITE;
114 
115  /*
116  * Lock the mailbox and open/create the mailbox file.
117  *
118  * Write the file as the recipient, so that file quota work.
119  */
120  copy_flags = MAIL_COPY_MBOX;
121 
122  set_eugid(usr_attr.uid, usr_attr.gid);
123  mp = mbox_open(usr_attr.mailbox, O_APPEND | O_WRONLY | O_CREAT,
124  S_IRUSR | S_IWUSR, &st, -1, -1,
125  virtual_mbox_lock_mask, "4.2.0", why);
126  if (mp != 0) {
127  if (S_ISREG(st.st_mode) == 0) {
128  vstream_fclose(mp->fp);
129  msg_warn("recipient %s: destination %s is not a regular file",
130  state.msg_attr.rcpt.address, usr_attr.mailbox);
131  dsb_simple(why, "5.3.5", "mail system configuration error");
132  } else if (var_strict_mbox_owner && st.st_uid != usr_attr.uid) {
133  vstream_fclose(mp->fp);
134  dsb_simple(why, "4.2.0",
135  "destination %s is not owned by recipient", usr_attr.mailbox);
136  msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch",
138  } else {
139  if (vstream_fseek(mp->fp, (off_t) 0, SEEK_END) < 0)
140  msg_fatal("%s: seek mailbox file %s: %m",
141  myname, VSTREAM_PATH(mp->fp));
142  mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
143  copy_flags, "\n", why);
144  }
145  mbox_release(mp);
146  }
148 
149  /*
150  * As the mail system, bounce, defer delivery, or report success.
151  */
152  if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
153  deliver_status = DEL_STAT_DEFER;
154  } else if (mail_copy_status != 0) {
155  vstring_sprintf_prepend(why->reason, "delivery failed to mailbox %s: ",
156  usr_attr.mailbox);
157  deliver_status =
158  (STR(why->status)[0] == '4' ?
160  (BOUNCE_FLAGS(state.request),
161  BOUNCE_ATTR(state.msg_attr));
162  } else {
163  dsb_simple(why, "2.0.0", "delivered to mailbox");
164  deliver_status = sent(BOUNCE_FLAGS(state.request),
165  SENT_ATTR(state.msg_attr));
166  }
167  return (deliver_status);
168 }
169 
170 /* deliver_mailbox - deliver to recipient mailbox */
171 
172 int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
173 {
174  const char *myname = "deliver_mailbox";
175  const char *mailbox_res;
176  const char *uid_res;
177  const char *gid_res;
178  DSN_BUF *why = state.msg_attr.why;
179  long n;
180 
181  /*
182  * Make verbose logging easier to understand.
183  */
184  state.level++;
185  if (msg_verbose)
186  MSG_LOG_STATE(myname, state);
187 
188  /*
189  * Sanity check.
190  */
191  if (*var_virt_mailbox_base != '/')
192  msg_fatal("do not specify relative pathname: %s = %s",
194 
195  /*
196  * Look up the mailbox location. Bounce if not found, defer in case of
197  * trouble.
198  */
199 #define IGNORE_EXTENSION ((char **) 0)
200 
201  mailbox_res = mail_addr_find(virtual_mailbox_maps, state.msg_attr.user,
203  if (mailbox_res == 0) {
204  if (virtual_mailbox_maps->error == 0)
205  return (NO);
206  msg_warn("table %s: lookup %s: %m", virtual_mailbox_maps->title,
207  state.msg_attr.user);
208  dsb_simple(why, "4.3.5", "mail system configuration error");
209  *statusp = defer_append(BOUNCE_FLAGS(state.request),
210  BOUNCE_ATTR(state.msg_attr));
211  return (YES);
212  }
213  usr_attr.mailbox = concatenate(var_virt_mailbox_base, "/",
214  mailbox_res, (char *) 0);
215 
216 #define RETURN(res) { myfree(usr_attr.mailbox); return (res); }
217 
218  /*
219  * Look up the mailbox owner rights. Defer in case of trouble.
220  */
221  uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
223  if (uid_res == 0) {
224  msg_warn("recipient %s: not found in %s",
226  dsb_simple(why, "4.3.5", "mail system configuration error");
227  *statusp = defer_append(BOUNCE_FLAGS(state.request),
228  BOUNCE_ATTR(state.msg_attr));
229  RETURN(YES);
230  }
231  if ((n = atol(uid_res)) < var_virt_minimum_uid) {
232  msg_warn("recipient %s: bad uid %s in %s",
233  state.msg_attr.user, uid_res, virtual_uid_maps->title);
234  dsb_simple(why, "4.3.5", "mail system configuration error");
235  *statusp = defer_append(BOUNCE_FLAGS(state.request),
236  BOUNCE_ATTR(state.msg_attr));
237  RETURN(YES);
238  }
239  usr_attr.uid = (uid_t) n;
240 
241  /*
242  * Look up the mailbox group rights. Defer in case of trouble.
243  */
244  gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
246  if (gid_res == 0) {
247  msg_warn("recipient %s: not found in %s",
249  dsb_simple(why, "4.3.5", "mail system configuration error");
250  *statusp = defer_append(BOUNCE_FLAGS(state.request),
251  BOUNCE_ATTR(state.msg_attr));
252  RETURN(YES);
253  }
254  if ((n = atol(gid_res)) <= 0) {
255  msg_warn("recipient %s: bad gid %s in %s",
256  state.msg_attr.user, gid_res, virtual_gid_maps->title);
257  dsb_simple(why, "4.3.5", "mail system configuration error");
258  *statusp = defer_append(BOUNCE_FLAGS(state.request),
259  BOUNCE_ATTR(state.msg_attr));
260  RETURN(YES);
261  }
262  usr_attr.gid = (gid_t) n;
263 
264  if (msg_verbose)
265  msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
266  myname, state.level, usr_attr.mailbox,
267  (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
268 
269  /*
270  * Deliver to mailbox or to maildir.
271  */
272 #define LAST_CHAR(s) (s[strlen(s) - 1])
273 
274  if (LAST_CHAR(usr_attr.mailbox) == '/')
275  *statusp = deliver_maildir(state, usr_attr);
276  else
277  *statusp = deliver_mailbox_file(state, usr_attr);
278 
279  /*
280  * Cleanup.
281  */
282  RETURN(YES);
283 }
int msg_verbose
Definition: msg.c:177
#define SENT_ATTR(attr)
Definition: local.h:142
#define LAST_CHAR(s)
#define BOUNCE_ATTR(attr)
Definition: local.h:134
#define MAIL_COPY_STAT_WRITE
Definition: mail_copy.h:50
VSTRING * vstring_sprintf_prepend(VSTRING *vp, const char *format,...)
Definition: vstring.c:645
const char * address
MAPS * virtual_uid_maps
Definition: virtual.c:364
int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
Definition: mailbox.c:250
#define stat(p, s)
Definition: warn_stat.h:18
MAPS * virtual_mailbox_maps
Definition: virtual.c:363
#define NO
Definition: mailbox.c:76
#define DEL_REQ_TRACE_ONLY(f)
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
bool var_strict_mbox_owner
Definition: local.c:680
VSTREAM * fp
Definition: mbox_open.h:31
DELIVER_REQUEST * request
Definition: local.h:113
#define YES
Definition: mailbox.c:75
#define COPY_ATTR(attr)
Definition: local.h:147
#define BOUNCE_FLAGS(request)
int bounce_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:222
#define VAR_STRICT_MBOX_OWNER
Definition: mail_params.h:3539
#define IGNORE_EXTENSION
gid_t var_owner_gid
Definition: mail_params.c:235
uid_t var_owner_uid
Definition: mail_params.c:234
MAPS * virtual_gid_maps
Definition: virtual.c:365
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
char * user
Definition: local.h:82
int mail_copy(const char *sender, const char *orig_rcpt, const char *delivered, VSTREAM *src, VSTREAM *dst, int flags, const char *eol, DSN_BUF *why)
Definition: mail_copy.c:134
#define mail_addr_find(maps, address, extension)
char * title
Definition: maps.h:23
Definition: mbox_open.h:29
#define MAIL_COPY_MBOX
Definition: mail_copy.h:40
char * mailbox
Definition: virtual.h:46
DELIVER_ATTR msg_attr
Definition: local.h:110
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
void mbox_release(MBOX *mp)
Definition: mbox_open.c:224
int var_virt_minimum_uid
Definition: virtual.c:352
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
VSTREAM * fp
Definition: local.h:70
#define DEL_STAT_DEFER
#define RETURN(res)
gid_t gid
Definition: local.h:37
void set_eugid(uid_t euid, gid_t egid)
Definition: set_eugid.c:54
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
int error
Definition: maps.h:25
char * var_virt_mailbox_base
Definition: virtual.c:353
DSN_BUF * why
Definition: local.h:92
const char * delivered
Definition: local.h:86
int level
Definition: local.h:109
VSTRING * reason
Definition: dsn_buf.h:37
int virtual_mbox_lock_mask
Definition: virtual.c:370
uid_t uid
Definition: local.h:36
int deliver_maildir(LOCAL_STATE, USER_ATTR, char *)
Definition: maildir.c:78
int defer_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: defer.c:187
#define MAIL_COPY_STAT_CORRUPT
Definition: mail_copy.h:48
RECIPIENT rcpt
Definition: local.h:79
int sent(int flags, const char *id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn)
Definition: sent.c:95
long offset
Definition: local.h:73
#define MSG_LOG_STATE(m, p)
Definition: local.h:150
MBOX * mbox_open(const char *path, int flags, mode_t mode, struct stat *st, uid_t chown_uid, gid_t chown_gid, int lock_style, const char *def_dsn, DSN_BUF *why)
Definition: mbox_open.c:105
VSTRING * status
Definition: dsn_buf.h:30
#define VAR_VIRT_MAILBOX_BASE
Definition: mail_params.h:2545
void msg_info(const char *fmt,...)
Definition: msg.c:199