Postfix3.3.1
mailbox.c
[詳解]
1 /*++
2 /* NAME
3 /* mailbox 3
4 /* SUMMARY
5 /* mailbox delivery
6 /* SYNOPSIS
7 /* #include "local.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 mailbox, with duplicate
15 /* suppression. The default is direct mailbox delivery to
16 /* /var/[spool/]mail/\fIuser\fR; when a \fIhome_mailbox\fR
17 /* has been configured, mail is delivered to ~/$\fIhome_mailbox\fR;
18 /* and when a \fImailbox_command\fR has been configured, the message
19 /* is piped into the command instead.
20 /*
21 /* A zero result means that the named user was not found.
22 /*
23 /* Arguments:
24 /* .IP state
25 /* The attributes that specify the message, recipient and more.
26 /* Attributes describing alias, include or forward expansion.
27 /* A table with the results from expanding aliases or lists.
28 /* .IP usr_attr
29 /* Attributes describing user rights and environment.
30 /* .IP statusp
31 /* Delivery status: see below.
32 /* DIAGNOSTICS
33 /* The message delivery status is non-zero when delivery should be tried
34 /* again.
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 <fcntl.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <errno.h>
54 
55 /* Utility library. */
56 
57 #include <msg.h>
58 #include <htable.h>
59 #include <vstring.h>
60 #include <vstream.h>
61 #include <mymalloc.h>
62 #include <stringops.h>
63 #include <set_eugid.h>
64 #include <warn_stat.h>
65 
66 /* Global library. */
67 
68 #include <mail_copy.h>
69 #include <defer.h>
70 #include <sent.h>
71 #include <mypwd.h>
72 #include <been_here.h>
73 #include <mail_params.h>
74 #include <deliver_pass.h>
75 #include <mbox_open.h>
76 #include <maps.h>
77 #include <dsn_util.h>
78 
79 /* Application-specific. */
80 
81 #include "local.h"
82 #include "biff_notify.h"
83 
84 #define YES 1
85 #define NO 0
86 
87 /* deliver_mailbox_file - deliver to recipient mailbox */
88 
89 static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
90 {
91  const char *myname = "deliver_mailbox_file";
92  char *spool_dir;
93  char *mailbox;
94  DSN_BUF *why = state.msg_attr.why;
95  MBOX *mp;
96  int mail_copy_status;
97  int deliver_status;
98  int copy_flags;
99  VSTRING *biff;
100  off_t end;
101  struct stat st;
102  uid_t spool_uid;
103  gid_t spool_gid;
104  uid_t chown_uid;
105  gid_t chown_gid;
106 
107  /*
108  * Make verbose logging easier to understand.
109  */
110  state.level++;
111  if (msg_verbose)
112  MSG_LOG_STATE(myname, state);
113 
114  /*
115  * Don't deliver trace-only requests.
116  */
117  if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
118  dsb_simple(why, "2.0.0", "delivers to mailbox");
119  return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)));
120  }
121 
122  /*
123  * Initialize. Assume the operation will fail. Set the delivered
124  * attribute to reflect the final recipient.
125  */
126  if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
127  msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
128  if (var_frozen_delivered == 0)
129  state.msg_attr.delivered = state.msg_attr.rcpt.address;
130  mail_copy_status = MAIL_COPY_STAT_WRITE;
131  if (*var_home_mailbox) {
132  spool_dir = 0;
133  mailbox = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0);
134  } else {
135  spool_dir = var_mail_spool_dir;
136  mailbox = concatenate(spool_dir, "/", state.msg_attr.user, (char *) 0);
137  }
138 
139  /*
140  * Mailbox delivery with least privilege. As long as we do not use root
141  * privileges this code may also work over NFS.
142  *
143  * If delivering to the recipient's home directory, perform all operations
144  * (including file locking) as that user (Mike Muuss, Army Research
145  * Laboratory, USA).
146  *
147  * If delivering to the mail spool directory, and the spool directory is
148  * world-writable, deliver as the recipient; if the spool directory is
149  * group-writable, use the recipient user id and the mail spool group id.
150  *
151  * Otherwise, use root privileges and chown the mailbox.
152  */
153  if (spool_dir == 0
154  || stat(spool_dir, &st) < 0
155  || (st.st_mode & S_IWOTH) != 0) {
156  spool_uid = usr_attr.uid;
157  spool_gid = usr_attr.gid;
158  } else if ((st.st_mode & S_IWGRP) != 0) {
159  spool_uid = usr_attr.uid;
160  spool_gid = st.st_gid;
161  } else {
162  spool_uid = 0;
163  spool_gid = 0;
164  }
165  if (spool_uid == usr_attr.uid) {
166  chown_uid = -1;
167  chown_gid = -1;
168  } else {
169  chown_uid = usr_attr.uid;
170  chown_gid = usr_attr.gid;
171  }
172  if (msg_verbose)
173  msg_info("spool_uid/gid %ld/%ld chown_uid/gid %ld/%ld",
174  (long) spool_uid, (long) spool_gid,
175  (long) chown_uid, (long) chown_gid);
176 
177  /*
178  * Lock the mailbox and open/create the mailbox file. Depending on the
179  * type of locking used, we lock first or we open first.
180  *
181  * Write the file as the recipient, so that file quota work.
182  */
183  copy_flags = MAIL_COPY_MBOX;
185  copy_flags &= ~MAIL_COPY_DELIVERED;
186 
187  set_eugid(spool_uid, spool_gid);
188  mp = mbox_open(mailbox, O_APPEND | O_WRONLY | O_CREAT,
189  S_IRUSR | S_IWUSR, &st, chown_uid, chown_gid,
190  local_mbox_lock_mask, "5.2.0", why);
191  if (mp != 0) {
192  if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
193  set_eugid(usr_attr.uid, usr_attr.gid);
194  if (S_ISREG(st.st_mode) == 0) {
195  vstream_fclose(mp->fp);
196  dsb_simple(why, "5.2.0",
197  "destination %s is not a regular file", mailbox);
198  } else if (var_strict_mbox_owner && st.st_uid != usr_attr.uid) {
199  vstream_fclose(mp->fp);
200  dsb_simple(why, "4.2.0",
201  "destination %s is not owned by recipient", mailbox);
202  msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch",
204  } else {
205  if ((end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END)) < 0)
206  msg_fatal("seek mailbox file %s: %m", mailbox);
207  mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
208  copy_flags, "\n", why);
209  }
210  if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
211  set_eugid(spool_uid, spool_gid);
212  mbox_release(mp);
213  }
215 
216  /*
217  * As the mail system, bounce, defer delivery, or report success.
218  */
219  if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
220  deliver_status = DEL_STAT_DEFER;
221  } else if (mail_copy_status != 0) {
223  "cannot update mailbox %s for user %s. ",
224  mailbox, state.msg_attr.user);
225  deliver_status =
226  (STR(why->status)[0] == '4' ?
228  (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
229  } else {
230  dsb_simple(why, "2.0.0", "delivered to mailbox");
231  deliver_status = sent(BOUNCE_FLAGS(state.request),
232  SENT_ATTR(state.msg_attr));
233  if (var_biff) {
234  biff = vstring_alloc(100);
235  vstring_sprintf(biff, "%s@%ld", usr_attr.logname, (long) end);
236  biff_notify(STR(biff), VSTRING_LEN(biff) + 1);
237  vstring_free(biff);
238  }
239  }
240 
241  /*
242  * Clean up.
243  */
244  myfree(mailbox);
245  return (deliver_status);
246 }
247 
248 /* deliver_mailbox - deliver to recipient mailbox */
249 
250 int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
251 {
252  const char *myname = "deliver_mailbox";
253  int status;
254  struct mypasswd *mbox_pwd;
255  char *path;
256  static MAPS *transp_maps;
257  const char *map_transport;
258  static MAPS *cmd_maps;
259  const char *map_command;
260 
261  /*
262  * Make verbose logging easier to understand.
263  */
264  state.level++;
265  if (msg_verbose)
266  MSG_LOG_STATE(myname, state);
267 
268  /*
269  * DUPLICATE ELIMINATION
270  *
271  * Don't come here more than once, whether or not the recipient exists.
272  */
273  if (been_here(state.dup_filter, "mailbox %s", state.msg_attr.local))
274  return (YES);
275 
276  /*
277  * Delegate mailbox delivery to another message transport.
278  */
279  if (*var_mbox_transp_maps && transp_maps == 0)
283  /* The -1 is a hint for the down-stream deliver_completed() function. */
284  if (transp_maps
285  && (map_transport = maps_find(transp_maps, state.msg_attr.user,
286  DICT_FLAG_NONE)) != 0) {
287  state.msg_attr.rcpt.offset = -1L;
288  *statusp = deliver_pass(MAIL_CLASS_PRIVATE, map_transport,
289  state.request, &state.msg_attr.rcpt);
290  return (YES);
291  } else if (transp_maps && transp_maps->error != 0) {
292  /* Details in the logfile. */
293  dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
294  *statusp = defer_append(BOUNCE_FLAGS(state.request),
295  BOUNCE_ATTR(state.msg_attr));
296  return (YES);
297  }
298  if (*var_mailbox_transport) {
299  state.msg_attr.rcpt.offset = -1L;
301  state.request, &state.msg_attr.rcpt);
302  return (YES);
303  }
304 
305  /*
306  * Skip delivery when this recipient does not exist.
307  */
308  if ((errno = mypwnam_err(state.msg_attr.user, &mbox_pwd)) != 0) {
309  msg_warn("error looking up passwd info for %s: %m",
310  state.msg_attr.user);
311  dsb_simple(state.msg_attr.why, "4.0.0", "user lookup error");
312  *statusp = defer_append(BOUNCE_FLAGS(state.request),
313  BOUNCE_ATTR(state.msg_attr));
314  return (YES);
315  }
316  if (mbox_pwd == 0)
317  return (NO);
318 
319  /*
320  * No early returns or we have a memory leak.
321  */
322 
323  /*
324  * DELIVERY RIGHTS
325  *
326  * Use the rights of the recipient user.
327  */
328  SET_USER_ATTR(usr_attr, mbox_pwd, state.level);
329 
330  /*
331  * Deliver to mailbox, maildir or to external command.
332  */
333 #define LAST_CHAR(s) (s[strlen(s) - 1])
334 
335  if (*var_mailbox_cmd_maps && cmd_maps == 0)
339 
340  if (cmd_maps && (map_command = maps_find(cmd_maps, state.msg_attr.user,
341  DICT_FLAG_NONE)) != 0) {
342  status = deliver_command(state, usr_attr, map_command);
343  } else if (cmd_maps && cmd_maps->error != 0) {
344  /* Details in the logfile. */
345  dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
346  status = defer_append(BOUNCE_FLAGS(state.request),
347  BOUNCE_ATTR(state.msg_attr));
348  } else if (*var_mailbox_command) {
349  status = deliver_command(state, usr_attr, var_mailbox_command);
350  } else if (*var_home_mailbox && LAST_CHAR(var_home_mailbox) == '/') {
351  path = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0);
352  status = deliver_maildir(state, usr_attr, path);
353  myfree(path);
354  } else if (*var_mail_spool_dir && LAST_CHAR(var_mail_spool_dir) == '/') {
356  "/", (char *) 0);
357  status = deliver_maildir(state, usr_attr, path);
358  myfree(path);
359  } else
360  status = deliver_mailbox_file(state, usr_attr);
361 
362  /*
363  * Cleanup.
364  */
365  mypwfree(mbox_pwd);
366  *statusp = status;
367  return (YES);
368 }
int msg_verbose
Definition: msg.c:177
#define SENT_ATTR(attr)
Definition: local.h:142
int mypwnam_err(const char *name, struct mypasswd **result)
Definition: mypwd.c:242
#define DELIVER_HDR_FILE
Definition: local.h:203
#define BOUNCE_ATTR(attr)
Definition: local.h:134
void myfree(void *ptr)
Definition: mymalloc.c:207
char * var_mailbox_transport
Definition: local.c:662
#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
#define LAST_CHAR(s)
int local_mbox_lock_mask
Definition: local.c:686
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
Definition: mypwd.h:17
char * local
Definition: local.h:81
int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *command)
Definition: command.c:85
#define VAR_MAILBOX_CMD_MAPS
Definition: mail_params.h:583
Definition: maps.h:22
#define DEL_REQ_TRACE_ONLY(f)
char * var_home_mailbox
Definition: local.c:654
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
bool var_biff
Definition: local.c:660
#define DICT_FLAG_UTF8_REQUEST
Definition: dict.h:130
#define VAR_MBOX_TRANSP_MAPS
Definition: mail_params.h:591
bool var_strict_mbox_owner
Definition: local.c:680
#define VSTRING_LEN(vp)
Definition: vstring.h:72
VSTREAM * fp
Definition: mbox_open.h:31
DELIVER_REQUEST * request
Definition: local.h:113
#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
char * var_mailbox_cmd_maps
Definition: local.c:656
#define VAR_STRICT_MBOX_OWNER
Definition: mail_params.h:3539
BH_TABLE * dup_filter
Definition: local.h:111
gid_t var_owner_gid
Definition: mail_params.c:235
uid_t var_owner_uid
Definition: mail_params.c:234
int been_here(BH_TABLE *dup_filter, const char *fmt,...)
Definition: been_here.c:124
MAPS * maps_create(const char *title, const char *map_names, int dict_flags)
Definition: maps.c:112
char * var_mbox_transp_maps
Definition: local.c:663
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
Definition: mbox_open.h:29
#define MAIL_COPY_MBOX
Definition: mail_copy.h:40
char * var_mailbox_command
Definition: local.c:655
#define DICT_FLAG_LOCK
Definition: dict.h:116
DELIVER_ATTR msg_attr
Definition: local.h:110
#define STR(x)
Definition: anvil.c:518
#define DICT_FLAG_PARANOID
Definition: dict.h:158
void msg_warn(const char *fmt,...)
Definition: msg.c:215
void mbox_release(MBOX *mp)
Definition: mbox_open.c:224
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define YES
Definition: mailbox.c:84
int deliver_pass(const char *class, const char *service, DELIVER_REQUEST *request, RECIPIENT *rcpt)
Definition: deliver_pass.c:160
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
bool var_frozen_delivered
Definition: local.c:678
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
#define MAIL_COPY_DELIVERED
Definition: mail_copy.h:35
char * home
Definition: local.h:38
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
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
DSN_BUF * why
Definition: local.h:92
void mypwfree(struct mypasswd *mypwd)
Definition: mypwd.c:292
#define SET_USER_ATTR(usr_attr, pwd, level)
Definition: local.h:53
const char * delivered
Definition: local.h:86
char * logname
Definition: local.h:39
int level
Definition: local.h:109
VSTRING * reason
Definition: dsn_buf.h:37
uid_t uid
Definition: local.h:36
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define DICT_FLAG_NO_REGSUB
Definition: dict.h:121
#define NO
Definition: mailbox.c:85
int deliver_maildir(LOCAL_STATE, USER_ATTR, char *)
Definition: maildir.c:78
char * var_mail_spool_dir
Definition: local.c:661
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
void biff_notify(const char *text, ssize_t len)
Definition: biff_notify.c:54
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
#define DICT_FLAG_NONE
Definition: dict.h:109
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
const char * maps_find(MAPS *maps, const char *name, int flags)
Definition: maps.c:162
int local_deliver_hdr_mask
Definition: local.c:685
VSTRING * status
Definition: dsn_buf.h:30
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
void msg_info(const char *fmt,...)
Definition: msg.c:199