5
/* deliver to addresses listed in include file
9
/* int deliver_include(state, usr_attr, path)
11
/* USER_ATTR usr_attr;
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.
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.
25
/* Attributes describing user rights and environment.
27
/* Pathname of the include file.
29
/* Fatal errors: out of memory. Warnings: bad include file type
30
/* or permissions. The result is non-zero when delivery should be
33
/* token(3) tokenize list
37
/* The Secure Mailer license must be distributed with this software.
40
/* IBM T.J. Watson Research
42
/* Yorktown Heights, NY 10598, USA
53
/* Utility library. */
68
#include <been_here.h>
69
#include <mail_params.h>
73
/* Application-specific. */
77
/* deliver_include - open include file and deliver */
79
int deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
81
char *myname = "deliver_include";
83
struct mypasswd *file_pwd = 0;
89
* Make verbose logging easier to understand.
93
MSG_LOG_STATE(myname, state);
96
* DUPLICATE ELIMINATION
98
* Don't process this include file more than once as this particular user.
100
if (been_here(state.dup_filter, "include %ld %s", (long) usr_attr.uid, path))
102
state.msg_attr.exp_from = state.msg_attr.local;
105
* Can of worms. Allow this include file to be symlinked, but disallow
106
* inclusion of special files or of files with world write permission
110
return (bounce_append(BOUNCE_FLAGS(state.request),
111
BOUNCE_ATTR(state.msg_attr),
112
":include:%s uses a relative path", path));
113
if (stat_as(path, &st, usr_attr.uid, usr_attr.gid) < 0)
114
return (bounce_append(BOUNCE_FLAGS(state.request),
115
BOUNCE_ATTR(state.msg_attr),
116
"unable to lookup include file %s: %m", path));
117
if (S_ISREG(st.st_mode) == 0)
118
return (bounce_append(BOUNCE_FLAGS(state.request),
119
BOUNCE_ATTR(state.msg_attr),
120
"not a regular include file: %s", path));
121
if (st.st_mode & S_IWOTH)
122
return (bounce_append(BOUNCE_FLAGS(state.request),
123
BOUNCE_ATTR(state.msg_attr),
124
"world writable include file: %s", path));
129
* Set the expansion type attribute so that we can decide if destinations
130
* such as /file/name and |command are allowed at all.
132
state.msg_attr.exp_type = EXPAND_TYPE_INCL;
137
* When a non-root include file is listed in a root-owned alias, use the
138
* rights of the include file owner. We do not want to give the include
139
* file owner control of the default account.
141
* When an include file is listed in a user-owned alias or .forward file,
142
* leave the delivery rights alone. Users should not be able to make
143
* things happen with someone else's rights just by including some file
144
* that is owned by their victim.
146
if (usr_attr.uid == 0) {
147
if ((file_pwd = mypwuid(st.st_uid)) == 0) {
148
msg_warn("cannot find username for uid %ld", (long) st.st_uid);
149
return (defer_append(BOUNCE_FLAGS(state.request),
150
BOUNCE_ATTR(state.msg_attr),
151
"%s: cannot find :include: file owner", path));
153
if (file_pwd->pw_uid != 0)
154
SET_USER_ATTR(usr_attr, file_pwd, state.level);
160
* When no owner attribute is set (either via an owner- alias, or as part of
161
* .forward file processing), set the owner attribute, to disable direct
162
* delivery of local recipients. By now it is clear that the owner
163
* attribute should have been called forwarder instead.
165
if (state.msg_attr.owner == 0)
166
state.msg_attr.owner = state.msg_attr.recipient;
169
* From here on no early returns or we have a memory leak.
173
* Use the delivery rights to open the include file. When no delivery rights
174
* were established sofar, the file containing the :include: is owned by
175
* root, so it should be OK to open any file that is accessible to root.
176
* The command and file delivery routines are responsible for setting the
177
* proper delivery rights. These are the rights of the default user, in
178
* case the :include: is in a root-owned alias.
180
* Don't propagate unmatched extensions unless permitted to do so.
182
#define FOPEN_AS(p,u,g) ((fd = open_as(p,O_RDONLY,0,u,g)) >= 0 ? \
183
vstream_fdopen(fd,O_RDONLY) : 0)
185
if ((fp = FOPEN_AS(path, usr_attr.uid, usr_attr.gid)) == 0) {
186
status = bounce_append(BOUNCE_FLAGS(state.request),
187
BOUNCE_ATTR(state.msg_attr),
188
"cannot open include file %s: %m", path);
190
if ((local_ext_prop_mask & EXT_PROP_INCLUDE) == 0)
191
state.msg_attr.unmatched = 0;
192
close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
193
status = deliver_token_stream(state, usr_attr, fp, (int *) 0);
194
if (vstream_fclose(fp))
195
msg_warn("close %s: %m", path);