Postfix3.3.1
alias.c
[詳解]
1 /*++
2 /* NAME
3 /* alias 3
4 /* SUMMARY
5 /* alias data base lookups
6 /* SYNOPSIS
7 /* #include "local.h"
8 /*
9 /* int deliver_alias(state, usr_attr, name, statusp)
10 /* LOCAL_STATE state;
11 /* USER_ATTR usr_attr;
12 /* char *name;
13 /* int *statusp;
14 /* DESCRIPTION
15 /* deliver_alias() looks up the expansion of the recipient in
16 /* the global alias database and delivers the message to the
17 /* listed destinations. The result is zero when no alias was found
18 /* or when the message should be delivered to the user instead.
19 /*
20 /* deliver_alias() has wired-in knowledge about a few reserved
21 /* recipient names.
22 /* .IP \(bu
23 /* When no alias is found for the local \fIpostmaster\fR or
24 /* \fImailer-daemon\fR a warning is issued and the message
25 /* is discarded.
26 /* .IP \(bu
27 /* When an alias exists for recipient \fIname\fR, and an alias
28 /* exists for \fIowner-name\fR, the sender address is changed
29 /* to \fIowner-name\fR, and the owner delivery attribute is
30 /* set accordingly. This feature is disabled with
31 /* "owner_request_special = no".
32 /* .PP
33 /* Arguments:
34 /* .IP state
35 /* Attributes that specify the message, recipient and more.
36 /* Expansion type (alias, include, .forward).
37 /* A table with the results from expanding aliases or lists.
38 /* A table with delivered-to: addresses taken from the message.
39 /* .IP usr_attr
40 /* User attributes (rights, environment).
41 /* .IP name
42 /* The alias to be looked up.
43 /* .IP statusp
44 /* Delivery status. See below.
45 /* DIAGNOSTICS
46 /* Fatal errors: out of memory. The delivery status is non-zero
47 /* when delivery should be tried again.
48 /* LICENSE
49 /* .ad
50 /* .fi
51 /* The Secure Mailer license must be distributed with this software.
52 /* AUTHOR(S)
53 /* Wietse Venema
54 /* IBM T.J. Watson Research
55 /* P.O. Box 704
56 /* Yorktown Heights, NY 10598, USA
57 /*--*/
58 
59 /* System library. */
60 
61 #include <sys_defs.h>
62 #include <sys/stat.h>
63 #include <unistd.h>
64 #include <string.h>
65 #include <fcntl.h>
66 #include <errno.h>
67 
68 /* Utility library. */
69 
70 #include <msg.h>
71 #include <htable.h>
72 #include <dict.h>
73 #include <argv.h>
74 #include <stringops.h>
75 #include <mymalloc.h>
76 #include <vstring.h>
77 #include <vstream.h>
78 
79 /* Global library. */
80 
81 #include <mail_params.h>
82 #include <defer.h>
83 #include <maps.h>
84 #include <bounce.h>
85 #include <mypwd.h>
86 #include <canon_addr.h>
87 #include <sent.h>
88 #include <trace.h>
89 #include <dsn_mask.h>
90 
91 /* Application-specific. */
92 
93 #include "local.h"
94 
95 /* Application-specific. */
96 
97 #define NO 0
98 #define YES 1
99 
100 /* deliver_alias - expand alias file entry */
101 
102 int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
103  char *name, int *statusp)
104 {
105  const char *myname = "deliver_alias";
106  const char *alias_result;
107  char *saved_alias_result;
108  char *owner;
109  char **cpp;
110  struct mypasswd *alias_pwd;
111  VSTRING *canon_owner;
112  DICT *dict;
113  const char *owner_rhs; /* owner alias, RHS */
114  int alias_count;
115  int dsn_notify;
116  char *dsn_envid;
117  int dsn_ret;
118  const char *dsn_orcpt;
119 
120  /*
121  * Make verbose logging easier to understand.
122  */
123  state.level++;
124  if (msg_verbose)
125  MSG_LOG_STATE(myname, state);
126 
127  /*
128  * DUPLICATE/LOOP ELIMINATION
129  *
130  * We cannot do duplicate elimination here. Sendmail compatibility requires
131  * that we allow multiple deliveries to the same alias, even recursively!
132  * For example, we must deliver to mailbox any messages that are addressed
133  * to the alias of a user that lists that same alias in her own .forward
134  * file. Yuck! This is just an example of some really perverse semantics
135  * that people will expect Postfix to implement just like sendmail.
136  *
137  * We can recognize one special case: when an alias includes its own name,
138  * deliver to the user instead, just like sendmail. Otherwise, we just
139  * bail out when nesting reaches some unreasonable depth, and blame it on
140  * a possible alias loop.
141  */
142  if (state.msg_attr.exp_from != 0
143  && strcasecmp_utf8(state.msg_attr.exp_from, name) == 0)
144  return (NO);
145  if (state.level > 100) {
146  msg_warn("alias database loop for %s", name);
147  dsb_simple(state.msg_attr.why, "5.4.6",
148  "alias database loop for %s", name);
149  *statusp = bounce_append(BOUNCE_FLAGS(state.request),
150  BOUNCE_ATTR(state.msg_attr));
151  return (YES);
152  }
153  state.msg_attr.exp_from = name;
154 
155  /*
156  * There are a bunch of roles that we're trying to keep track of.
157  *
158  * First, there's the issue of whose rights should be used when delivering
159  * to "|command" or to /file/name. With alias databases, the rights are
160  * those of who owns the alias, i.e. the database owner. With aliases
161  * owned by root, a default user is used instead. When an alias with
162  * default rights references an include file owned by an ordinary user,
163  * we must use the rights of the include file owner, otherwise the
164  * include file owner could take control of the default account.
165  *
166  * Secondly, there's the question of who to notify of delivery problems.
167  * With aliases that have an owner- alias, the latter is used to set the
168  * sender and owner attributes. Otherwise, the owner attribute is reset
169  * (the alias is globally visible and could be sent to by anyone).
170  */
171  for (cpp = alias_maps->argv->argv; *cpp; cpp++) {
172  if ((dict = dict_handle(*cpp)) == 0)
173  msg_panic("%s: dictionary not found: %s", myname, *cpp);
174  if ((alias_result = dict_get(dict, name)) != 0) {
175  if (msg_verbose)
176  msg_info("%s: %s: %s = %s", myname, *cpp, name, alias_result);
177 
178  /*
179  * Don't expand a verify-only request.
180  */
181  if (state.request->flags & DEL_REQ_FLAG_MTA_VRFY) {
182  dsb_simple(state.msg_attr.why, "2.0.0",
183  "aliased to %s", alias_result);
184  *statusp = sent(BOUNCE_FLAGS(state.request),
185  SENT_ATTR(state.msg_attr));
186  return (YES);
187  }
188 
189  /*
190  * DELIVERY POLICY
191  *
192  * Update the expansion type attribute, so we can decide if
193  * deliveries to |command and /file/name are allowed at all.
194  */
196 
197  /*
198  * DELIVERY RIGHTS
199  *
200  * What rights to use for |command and /file/name deliveries? The
201  * command and file code will use default rights when the alias
202  * database is owned by root, otherwise it will use the rights of
203  * the alias database owner.
204  */
205  if (dict->owner.status == DICT_OWNER_TRUSTED) {
206  alias_pwd = 0;
207  RESET_USER_ATTR(usr_attr, state.level);
208  } else {
209  if (dict->owner.status == DICT_OWNER_UNKNOWN) {
210  msg_warn("%s: no owner UID for alias database %s",
211  myname, *cpp);
212  dsb_simple(state.msg_attr.why, "4.3.0",
213  "mail system configuration error");
214  *statusp = defer_append(BOUNCE_FLAGS(state.request),
215  BOUNCE_ATTR(state.msg_attr));
216  return (YES);
217  }
218  if ((errno = mypwuid_err(dict->owner.uid, &alias_pwd)) != 0
219  || alias_pwd == 0) {
220  msg_warn(errno ?
221  "cannot find alias database owner for %s: %m" :
222  "cannot find alias database owner for %s", *cpp);
223  dsb_simple(state.msg_attr.why, "4.3.0",
224  "cannot find alias database owner");
225  *statusp = defer_append(BOUNCE_FLAGS(state.request),
226  BOUNCE_ATTR(state.msg_attr));
227  return (YES);
228  }
229  SET_USER_ATTR(usr_attr, alias_pwd, state.level);
230  }
231 
232  /*
233  * WHERE TO REPORT DELIVERY PROBLEMS.
234  *
235  * Use the owner- alias if one is specified, otherwise reset the
236  * owner attribute and use the include file ownership if we can.
237  * Save the dict_lookup() result before something clobbers it.
238  *
239  * Don't match aliases that are based on regexps.
240  */
241 #define OWNER_ASSIGN(own) \
242  (own = (var_ownreq_special == 0 ? 0 : \
243  concatenate("owner-", name, (char *) 0)))
244 
245  saved_alias_result = mystrdup(alias_result);
246  if (OWNER_ASSIGN(owner) != 0
247  && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) {
248  canon_owner = canon_addr_internal(vstring_alloc(10),
249  var_exp_own_alias ? owner_rhs : owner);
250  /* Set envelope sender and owner attribute. */
251  SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
252  } else {
253  canon_owner = 0;
254  /* Note: this does not reset the envelope sender. */
256  RESET_OWNER_ATTR(state.msg_attr, state.level);
257  }
258 
259  /*
260  * EXTERNAL LOOP CONTROL
261  *
262  * Set the delivered message attribute to the recipient, so that
263  * this message will list the correct forwarding address.
264  */
265  if (var_frozen_delivered == 0)
266  state.msg_attr.delivered = state.msg_attr.rcpt.address;
267 
268  /*
269  * Deliver.
270  */
271  alias_count = 0;
272  if (owner != 0 && alias_maps->error != 0) {
273  dsb_simple(state.msg_attr.why, "4.3.0",
274  "alias database unavailable");
275  *statusp = defer_append(BOUNCE_FLAGS(state.request),
276  BOUNCE_ATTR(state.msg_attr));
277  } else {
278 
279  /*
280  * XXX DSN
281  *
282  * When delivering to a mailing list (i.e. the envelope sender
283  * is replaced) the ENVID, NOTIFY, RET, and ORCPT parameters
284  * which accompany the redistributed message MUST NOT be
285  * derived from those of the original message.
286  *
287  * When delivering to an alias (i.e. the envelope sender is not
288  * replaced) any ENVID, RET, or ORCPT parameters are
289  * propagated to all forwarding addresses associated with
290  * that alias. The NOTIFY parameter is propagated to the
291  * forwarding addresses, except that any SUCCESS keyword is
292  * removed.
293  */
294 #define DSN_SAVE_UPDATE(saved, old, new) do { \
295  saved = old; \
296  old = new; \
297  } while (0)
298 
299  DSN_SAVE_UPDATE(dsn_notify, state.msg_attr.rcpt.dsn_notify,
300  dsn_notify == DSN_NOTIFY_SUCCESS ?
302  dsn_notify & ~DSN_NOTIFY_SUCCESS);
303  if (canon_owner != 0) {
304  DSN_SAVE_UPDATE(dsn_envid, state.msg_attr.dsn_envid, "");
305  DSN_SAVE_UPDATE(dsn_ret, state.msg_attr.dsn_ret, 0);
306  DSN_SAVE_UPDATE(dsn_orcpt, state.msg_attr.rcpt.dsn_orcpt, "");
307  state.msg_attr.rcpt.orig_addr = "";
308  }
309  *statusp =
310  deliver_token_string(state, usr_attr, saved_alias_result,
311  &alias_count);
312 #if 0
314  && strncmp("owner-", state.msg_attr.sender, 6) != 0
315  && alias_count > 10)
316  msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias",
317  name, name);
318 #endif
319  if (alias_count < 1) {
320  msg_warn("no recipient in alias lookup result for %s", name);
321  dsb_simple(state.msg_attr.why, "4.3.0",
322  "alias database unavailable");
323  *statusp = defer_append(BOUNCE_FLAGS(state.request),
324  BOUNCE_ATTR(state.msg_attr));
325  } else {
326 
327  /*
328  * XXX DSN
329  *
330  * When delivering to a mailing list (i.e. the envelope
331  * sender address is replaced) and NOTIFY=SUCCESS was
332  * specified, report a DSN of "delivered".
333  *
334  * When delivering to an alias (i.e. the envelope sender
335  * address is not replaced) and NOTIFY=SUCCESS was
336  * specified, report a DSN of "expanded".
337  */
338  if (dsn_notify & DSN_NOTIFY_SUCCESS) {
339  state.msg_attr.rcpt.dsn_notify = dsn_notify;
340  if (canon_owner != 0) {
341  state.msg_attr.dsn_envid = dsn_envid;
342  state.msg_attr.dsn_ret = dsn_ret;
343  state.msg_attr.rcpt.dsn_orcpt = dsn_orcpt;
344  }
345  dsb_update(state.msg_attr.why, "2.0.0", canon_owner ?
346  "delivered" : "expanded",
348  "alias expanded");
350  SENT_ATTR(state.msg_attr));
351  }
352  }
353  }
354  myfree(saved_alias_result);
355  if (owner)
356  myfree(owner);
357  if (canon_owner)
358  vstring_free(canon_owner);
359  if (alias_pwd)
360  mypwfree(alias_pwd);
361  return (YES);
362  }
363 
364  /*
365  * If the alias database was inaccessible for some reason, defer
366  * further delivery for the current top-level recipient.
367  */
368  if (alias_result == 0 && dict->error != 0) {
369  msg_warn("%s:%s: lookup of '%s' failed",
370  dict->type, dict->name, name);
371  dsb_simple(state.msg_attr.why, "4.3.0",
372  "alias database unavailable");
373  *statusp = defer_append(BOUNCE_FLAGS(state.request),
374  BOUNCE_ATTR(state.msg_attr));
375  return (YES);
376  } else {
377  if (msg_verbose)
378  msg_info("%s: %s: %s not found", myname, *cpp, name);
379  }
380  }
381 
382  /*
383  * Try delivery to a local user instead.
384  */
385  return (NO);
386 }
int msg_verbose
Definition: msg.c:177
int var_ownreq_special
Definition: mail_params.c:283
#define SENT_ATTR(attr)
Definition: local.h:142
const char * orig_addr
char * exp_from
Definition: local.h:90
#define BOUNCE_ATTR(attr)
Definition: local.h:134
void myfree(void *ptr)
Definition: mymalloc.c:207
#define SET_OWNER_ATTR(msg_attr, who, level)
Definition: local.h:122
int deliver_token_string(LOCAL_STATE, USER_ATTR, char *, int *)
Definition: token.c:174
MAPS * alias_maps
Definition: local.c:687
uid_t uid
Definition: dict.h:39
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define DSN_SAVE_UPDATE(saved, old, new)
int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, char *name, int *statusp)
Definition: alias.c:102
const char * address
#define RESET_OWNER_ATTR(msg_attr, level)
Definition: local.h:116
#define NO
Definition: alias.c:97
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
DSN_BUF * dsb_update(DSN_BUF *dsb, const char *status, const char *action, const char *mtype, const char *mname, const char *dtype, const char *dtext, const char *format,...)
Definition: dsn_buf.c:239
int mypwuid_err(uid_t uid, struct mypasswd **result)
Definition: mypwd.c:178
char * name
Definition: dict.h:80
int trace_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: trace.c:106
Definition: mypwd.h:17
char ** argv
Definition: argv.h:20
#define BOUNCE_FLAG_NONE
Definition: bounce.h:60
#define EXPAND_TYPE_ALIAS
Definition: local.h:99
#define DSB_SKIP_RMTA
Definition: dsn_buf.h:42
VSTRING * canon_addr_internal(VSTRING *result, const char *addr)
Definition: canon_addr.c:64
#define strcasecmp_utf8(s1, s2)
Definition: stringops.h:75
bool var_reset_owner_attr
Definition: local.c:679
#define DSN_NOTIFY_NEVER
Definition: dsn_mask.h:43
DELIVER_REQUEST * request
Definition: local.h:113
#define OWNER_ASSIGN(own)
#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
Definition: dict.h:78
#define DSB_SKIP_REPLY
Definition: dsn_buf.h:46
int exp_type
Definition: local.h:89
char * type
Definition: dict.h:79
#define DICT_OWNER_TRUSTED
Definition: dict.h:46
#define dict_get(dp, key)
Definition: dict.h:236
bool var_exp_own_alias
Definition: local.c:672
#define DICT_OWNER_UNKNOWN
Definition: dict.h:45
#define YES
Definition: alias.c:98
int dsn_ret
Definition: local.h:78
DICT * dict_handle(const char *dict_name)
Definition: dict.c:333
DELIVER_ATTR msg_attr
Definition: local.h:110
#define STR(x)
Definition: anvil.c:518
char * dsn_envid
Definition: local.h:77
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
struct ARGV * argv
Definition: maps.h:24
int error
Definition: dict.h:94
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
int status
Definition: dict.h:38
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
int level
Definition: local.h:109
#define DSN_NOTIFY_SUCCESS
Definition: dsn_mask.h:44
const char * dsn_orcpt
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
const char * sender
Definition: local.h:76
int defer_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: defer.c:187
#define RESET_USER_ATTR(usr_attr, level)
Definition: local.h:46
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
#define MSG_LOG_STATE(m, p)
Definition: local.h:150
#define DICT_FLAG_NONE
Definition: dict.h:109
const char * maps_find(MAPS *maps, const char *name, int flags)
Definition: maps.c:162
DICT_OWNER owner
Definition: dict.h:93
#define DEL_REQ_FLAG_MTA_VRFY
void msg_info(const char *fmt,...)
Definition: msg.c:199