Postfix3.3.1
include.c
[詳解]
1 /*++
2 /* NAME
3 /* deliver_include 3
4 /* SUMMARY
5 /* deliver to addresses listed in include file
6 /* SYNOPSIS
7 /* #include "local.h"
8 /*
9 /* int deliver_include(state, usr_attr, path)
10 /* LOCAL_STATE state;
11 /* USER_ATTR usr_attr;
12 /* char *path;
13 /* DESCRIPTION
14 /* deliver_include() processes the contents of the named include
15 /* file and delivers to each address listed. Some sanity checks
16 /* are done on the include file permissions and type.
17 /*
18 /* Arguments:
19 /* .IP state
20 /* The attributes that specify the message, recipient and more.
21 /* Attributes describing alias, include, or forward expansion.
22 /* A table with the results from expanding aliases or lists.
23 /* A table with delivered-to: addresses taken from the message.
24 /* .IP usr_attr
25 /* Attributes describing user rights and environment.
26 /* .IP path
27 /* Pathname of the include file.
28 /* DIAGNOSTICS
29 /* Fatal errors: out of memory. Warnings: bad include file type
30 /* or permissions. The result is non-zero when delivery should be
31 /* tried again.
32 /* SEE ALSO
33 /* token(3) tokenize list
34 /* LICENSE
35 /* .ad
36 /* .fi
37 /* The Secure Mailer license must be distributed with this software.
38 /* AUTHOR(S)
39 /* Wietse Venema
40 /* IBM T.J. Watson Research
41 /* P.O. Box 704
42 /* Yorktown Heights, NY 10598, USA
43 /*--*/
44 
45 /* System library. */
46 
47 #include <sys_defs.h>
48 #include <sys/stat.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <fcntl.h>
52 #include <errno.h>
53 
54 /* Utility library. */
55 
56 #include <msg.h>
57 #include <htable.h>
58 #include <mymalloc.h>
59 #include <vstream.h>
60 #include <open_as.h>
61 #include <stat_as.h>
62 #include <iostuff.h>
63 #include <mypwd.h>
64 
65 /* Global library. */
66 
67 #include <bounce.h>
68 #include <defer.h>
69 #include <been_here.h>
70 #include <mail_params.h>
71 #include <ext_prop.h>
72 #include <sent.h>
73 
74 /* Application-specific. */
75 
76 #include "local.h"
77 
78 /* deliver_include - open include file and deliver */
79 
80 int deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
81 {
82  const char *myname = "deliver_include";
83  struct stat st;
84  struct mypasswd *file_pwd = 0;
85  int status;
86  VSTREAM *fp;
87  int fd;
88 
89  /*
90  * Make verbose logging easier to understand.
91  */
92  state.level++;
93  if (msg_verbose)
94  MSG_LOG_STATE(myname, state);
95 
96  /*
97  * DUPLICATE ELIMINATION
98  *
99  * Don't process this include file more than once as this particular user.
100  */
101  if (been_here(state.dup_filter, "include %ld %s", (long) usr_attr.uid, path))
102  return (0);
103  state.msg_attr.exp_from = state.msg_attr.local;
104 
105  /*
106  * Can of worms. Allow this include file to be symlinked, but disallow
107  * inclusion of special files or of files with world write permission
108  * enabled.
109  */
110  if (*path != '/') {
111  msg_warn(":include:%s uses a relative path", path);
112  dsb_simple(state.msg_attr.why, "5.3.5",
113  "mail system configuration error");
114  return (bounce_append(BOUNCE_FLAGS(state.request),
115  BOUNCE_ATTR(state.msg_attr)));
116  }
117  if (stat_as(path, &st, usr_attr.uid, usr_attr.gid) < 0) {
118  msg_warn("unable to lookup :include: file %s: %m", path);
119  dsb_simple(state.msg_attr.why, "5.3.5",
120  "mail system configuration error");
121  return (bounce_append(BOUNCE_FLAGS(state.request),
122  BOUNCE_ATTR(state.msg_attr)));
123  }
124  if (S_ISREG(st.st_mode) == 0) {
125  msg_warn(":include: file %s is not a regular file", path);
126  dsb_simple(state.msg_attr.why, "5.3.5",
127  "mail system configuration error");
128  return (bounce_append(BOUNCE_FLAGS(state.request),
129  BOUNCE_ATTR(state.msg_attr)));
130  }
131  if (st.st_mode & S_IWOTH) {
132  msg_warn(":include: file %s is world writable", path);
133  dsb_simple(state.msg_attr.why, "5.3.5",
134  "mail system configuration error");
135  return (bounce_append(BOUNCE_FLAGS(state.request),
136  BOUNCE_ATTR(state.msg_attr)));
137  }
138 
139  /*
140  * DELIVERY POLICY
141  *
142  * Set the expansion type attribute so that we can decide if destinations
143  * such as /file/name and |command are allowed at all.
144  */
146 
147  /*
148  * DELIVERY RIGHTS
149  *
150  * When a non-root include file is listed in a root-owned alias, use the
151  * rights of the include file owner. We do not want to give the include
152  * file owner control of the default account.
153  *
154  * When an include file is listed in a user-owned alias or .forward file,
155  * leave the delivery rights alone. Users should not be able to make
156  * things happen with someone else's rights just by including some file
157  * that is owned by their victim.
158  */
159  if (usr_attr.uid == 0) {
160  if ((errno = mypwuid_err(st.st_uid, &file_pwd)) != 0 || file_pwd == 0) {
161  msg_warn(errno ? "cannot find username for uid %ld: %m" :
162  "cannot find username for uid %ld", (long) st.st_uid);
163  msg_warn("%s: cannot find :include: file owner username", path);
164  dsb_simple(state.msg_attr.why, "4.3.5",
165  "mail system configuration error");
166  return (defer_append(BOUNCE_FLAGS(state.request),
167  BOUNCE_ATTR(state.msg_attr)));
168  }
169  if (file_pwd->pw_uid != 0)
170  SET_USER_ATTR(usr_attr, file_pwd, state.level);
171  }
172 
173  /*
174  * MESSAGE FORWARDING
175  *
176  * When no owner attribute is set (either via an owner- alias, or as part of
177  * .forward file processing), set the owner attribute, to disable direct
178  * delivery of local recipients. By now it is clear that the owner
179  * attribute should have been called forwarder instead.
180  */
181  if (state.msg_attr.owner == 0)
182  state.msg_attr.owner = state.msg_attr.rcpt.address;
183 
184  /*
185  * From here on no early returns or we have a memory leak.
186  *
187  * FILE OPEN RIGHTS
188  *
189  * Use the delivery rights to open the include file. When no delivery rights
190  * were established sofar, the file containing the :include: is owned by
191  * root, so it should be OK to open any file that is accessible to root.
192  * The command and file delivery routines are responsible for setting the
193  * proper delivery rights. These are the rights of the default user, in
194  * case the :include: is in a root-owned alias.
195  *
196  * Don't propagate unmatched extensions unless permitted to do so.
197  */
198 #define FOPEN_AS(p,u,g) ((fd = open_as(p,O_RDONLY,0,u,g)) >= 0 ? \
199  vstream_fdopen(fd,O_RDONLY) : 0)
200 
201  if ((fp = FOPEN_AS(path, usr_attr.uid, usr_attr.gid)) == 0) {
202  msg_warn("cannot open include file %s: %m", path);
203  dsb_simple(state.msg_attr.why, "5.3.5",
204  "mail system configuration error");
205  status = bounce_append(BOUNCE_FLAGS(state.request),
206  BOUNCE_ATTR(state.msg_attr));
207  } else {
209  state.msg_attr.unmatched = 0;
211  status = deliver_token_stream(state, usr_attr, fp, (int *) 0);
212  if (vstream_fclose(fp))
213  msg_warn("close %s: %m", path);
214  }
215 
216  /*
217  * Cleanup.
218  */
219  if (file_pwd)
220  mypwfree(file_pwd);
221 
222  return (status);
223 }
int msg_verbose
Definition: msg.c:177
char * exp_from
Definition: local.h:90
#define BOUNCE_ATTR(attr)
Definition: local.h:134
const char * address
int mypwuid_err(uid_t uid, struct mypasswd **result)
Definition: mypwd.c:178
#define stat(p, s)
Definition: warn_stat.h:18
Definition: mypwd.h:17
char * local
Definition: local.h:81
int deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
Definition: include.c:80
DELIVER_REQUEST * request
Definition: local.h:113
#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 EXT_PROP_INCLUDE
Definition: ext_prop.h:21
int exp_type
Definition: local.h:89
int stat_as(const char *path, struct stat *st, uid_t euid, gid_t egid)
Definition: stat_as.c:51
BH_TABLE * dup_filter
Definition: local.h:111
char * unmatched
Definition: local.h:84
int been_here(BH_TABLE *dup_filter, const char *fmt,...)
Definition: been_here.c:124
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
uid_t pw_uid
Definition: mypwd.h:21
DELIVER_ATTR msg_attr
Definition: local.h:110
void msg_warn(const char *fmt,...)
Definition: msg.c:215
const char * owner
Definition: local.h:85
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
gid_t gid
Definition: local.h:37
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
int level
Definition: local.h:109
#define FOPEN_AS(p, u, g)
uid_t uid
Definition: local.h:36
#define vstream_fileno(vp)
Definition: vstream.h:115
int defer_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: defer.c:187
#define CLOSE_ON_EXEC
Definition: iostuff.h:51
RECIPIENT rcpt
Definition: local.h:79
int local_ext_prop_mask
Definition: local.c:684
#define MSG_LOG_STATE(m, p)
Definition: local.h:150
int close_on_exec(int fd, int on)
Definition: close_on_exec.c:49
int deliver_token_stream(LOCAL_STATE, USER_ATTR, VSTREAM *, int *)
Definition: token.c:198
#define EXPAND_TYPE_INCL
Definition: local.h:101