Sync usage with man page.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / local / file.c
blob86caf06319bec2bbba058e6bd3c3ce46dc204d4a
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* file 3
6 /* SUMMARY
7 /* mail delivery to arbitrary file
8 /* SYNOPSIS
9 /* #include "local.h"
11 /* int deliver_file(state, usr_attr, path)
12 /* LOCAL_STATE state;
13 /* USER_ATTR usr_attr;
14 /* char *path;
15 /* DESCRIPTION
16 /* deliver_file() appends a message to a file, UNIX mailbox format,
17 /* or qmail maildir format,
18 /* with duplicate suppression. It will deliver only to non-executable
19 /* regular files.
21 /* Arguments:
22 /* .IP state
23 /* The attributes that specify the message, recipient and more.
24 /* Attributes describing alias, include or forward expansion.
25 /* A table with the results from expanding aliases or lists.
26 /* .IP usr_attr
27 /* Attributes describing user rights and environment information.
28 /* .IP path
29 /* The file to deliver to. If the name ends in '/', delivery is done
30 /* in qmail maildir format, otherwise delivery is done in UNIX mailbox
31 /* format.
32 /* DIAGNOSTICS
33 /* deliver_file() returns non-zero when delivery should be tried again.
34 /* SEE ALSO
35 /* defer(3)
36 /* bounce(3)
37 /* LICENSE
38 /* .ad
39 /* .fi
40 /* The Secure Mailer license must be distributed with this software.
41 /* AUTHOR(S)
42 /* Wietse Venema
43 /* IBM T.J. Watson Research
44 /* P.O. Box 704
45 /* Yorktown Heights, NY 10598, USA
46 /*--*/
48 /* System library. */
50 #include <sys_defs.h>
51 #include <sys/stat.h>
52 #include <unistd.h>
53 #include <fcntl.h>
54 #include <errno.h>
55 #include <string.h>
57 /* Utility library. */
59 #include <msg.h>
60 #include <htable.h>
61 #include <vstring.h>
62 #include <vstream.h>
63 #include <deliver_flock.h>
64 #include <set_eugid.h>
66 /* Global library. */
68 #include <mail_copy.h>
69 #include <bounce.h>
70 #include <defer.h>
71 #include <sent.h>
72 #include <been_here.h>
73 #include <mail_params.h>
74 #include <mbox_conf.h>
75 #include <mbox_open.h>
76 #include <dsn_util.h>
78 /* Application-specific. */
80 #include "local.h"
82 /* deliver_file - deliver to file */
84 int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
86 const char *myname = "deliver_file";
87 struct stat st;
88 MBOX *mp;
89 DSN_BUF *why = state.msg_attr.why;
90 int mail_copy_status = MAIL_COPY_STAT_WRITE;
91 int deliver_status;
92 int copy_flags;
95 * Make verbose logging easier to understand.
97 state.level++;
98 if (msg_verbose)
99 MSG_LOG_STATE(myname, state);
102 * DUPLICATE ELIMINATION
104 * Skip this file if it was already delivered to as this user.
106 if (been_here(state.dup_filter, "file %ld %s", (long) usr_attr.uid, path))
107 return (0);
110 * DELIVERY POLICY
112 * Do we allow delivery to files?
114 if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0) {
115 dsb_simple(why, "5.7.1", "mail to file is restricted");
116 return (bounce_append(BOUNCE_FLAGS(state.request),
117 BOUNCE_ATTR(state.msg_attr)));
121 * Don't deliver trace-only requests.
123 if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
124 dsb_simple(why, "2.0.0", "delivers to file: %s", path);
125 return (sent(BOUNCE_FLAGS(state.request),
126 SENT_ATTR(state.msg_attr)));
130 * DELIVERY RIGHTS
132 * Use a default uid/gid when none are given.
134 if (usr_attr.uid == 0 && (usr_attr.uid = var_default_uid) == 0)
135 msg_panic("privileged default user id");
136 if (usr_attr.gid == 0 && (usr_attr.gid = var_default_gid) == 0)
137 msg_panic("privileged default group id");
140 * If the name ends in /, use maildir-style delivery instead.
142 if (path[strlen(path) - 1] == '/')
143 return (deliver_maildir(state, usr_attr, path));
146 * Deliver. From here on, no early returns or we have a memory leak.
148 if (msg_verbose)
149 msg_info("deliver_file (%ld,%ld): %s",
150 (long) usr_attr.uid, (long) usr_attr.gid, path);
151 if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
152 msg_fatal("seek queue file %s: %m", state.msg_attr.queue_id);
155 * As the specified user, open or create the file, lock it, and append
156 * the message.
158 copy_flags = MAIL_COPY_MBOX;
159 if ((local_deliver_hdr_mask & DELIVER_HDR_FILE) == 0)
160 copy_flags &= ~MAIL_COPY_DELIVERED;
162 set_eugid(usr_attr.uid, usr_attr.gid);
163 mp = mbox_open(path, O_APPEND | O_CREAT | O_WRONLY,
164 S_IRUSR | S_IWUSR, &st, -1, -1,
165 local_mbox_lock_mask | MBOX_DOT_LOCK_MAY_FAIL,
166 "5.2.0", why);
167 if (mp != 0) {
168 if (S_ISREG(st.st_mode) && st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
169 vstream_fclose(mp->fp);
170 dsb_simple(why, "5.7.1", "file is executable");
171 } else {
172 mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
173 S_ISREG(st.st_mode) ? copy_flags :
174 (copy_flags & ~MAIL_COPY_TOFILE),
175 "\n", why);
177 mbox_release(mp);
179 set_eugid(var_owner_uid, var_owner_gid);
182 * As the mail system, bounce, defer delivery, or report success.
184 if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
185 deliver_status = DEL_STAT_DEFER;
186 } else if (mail_copy_status != 0) {
187 vstring_sprintf_prepend(why->reason,
188 "cannot append message to file %s: ", path);
189 deliver_status =
190 (STR(why->status)[0] == '4' ?
191 defer_append : bounce_append)
192 (BOUNCE_FLAGS(state.request),
193 BOUNCE_ATTR(state.msg_attr));
194 } else {
195 dsb_simple(why, "2.0.0", "delivered to file: %s", path);
196 deliver_status = sent(BOUNCE_FLAGS(state.request),
197 SENT_ATTR(state.msg_attr));
199 return (deliver_status);