Postfix3.3.1
rewrite.c
[詳解]
1 /*++
2 /* NAME
3 /* rewrite 3
4 /* SUMMARY
5 /* mail address rewriter
6 /* SYNOPSIS
7 /* #include "trivial-rewrite.h"
8 /*
9 /* void rewrite_init(void)
10 /*
11 /* void rewrite_proto(stream)
12 /* VSTREAM *stream;
13 /*
14 /* void rewrite_addr(context, addr, result)
15 /* RWR_CONTEXT *context;
16 /* char *addr;
17 /* VSTRING *result;
18 /*
19 /* void rewrite_tree(context, tree)
20 /* RWR_CONTEXT *context;
21 /* TOK822 *tree;
22 /*
23 /* RWR_CONTEXT local_context;
24 /* RWR_CONTEXT remote_context;
25 /* DESCRIPTION
26 /* This module implements the trivial address rewriting engine.
27 /*
28 /* rewrite_init() initializes data structures that are private
29 /* to this module. It should be called once before using the
30 /* actual rewriting routines.
31 /*
32 /* rewrite_proto() implements the client-server protocol: read
33 /* one rule set name and one address in external (quoted) form,
34 /* reply with the rewritten address in external form.
35 /*
36 /* rewrite_addr() rewrites an address string to another string.
37 /* Both input and output are in external (quoted) form.
38 /*
39 /* rewrite_tree() rewrites a parse tree with a single address to
40 /* another tree. A tree is a dummy node on top of a token list.
41 /*
42 /* local_context and remote_context provide domain names for
43 /* completing incomplete address forms.
44 /* STANDARDS
45 /* DIAGNOSTICS
46 /* Problems and transactions are logged to the syslog daemon.
47 /* BUGS
48 /* SEE ALSO
49 /* LICENSE
50 /* .ad
51 /* .fi
52 /* The Secure Mailer license must be distributed with this software.
53 /* AUTHOR(S)
54 /* Wietse Venema
55 /* IBM T.J. Watson Research
56 /* P.O. Box 704
57 /* Yorktown Heights, NY 10598, USA
58 /*--*/
59 
60 /* System library. */
61 
62 #include <sys_defs.h>
63 #include <stdlib.h>
64 #include <string.h>
65 
66 #ifdef STRCASECMP_IN_STRINGS_H
67 #include <strings.h>
68 #endif
69 
70 /* Utility library. */
71 
72 #include <msg.h>
73 #include <vstring.h>
74 #include <vstream.h>
75 #include <vstring_vstream.h>
76 #include <split_at.h>
77 
78 /* Global library. */
79 
80 #include <mail_params.h>
81 #include <mail_proto.h>
82 #include <resolve_local.h>
83 #include <tok822.h>
84 #include <mail_conf.h>
85 
86 /* Application-specific. */
87 
88 #include "trivial-rewrite.h"
89 
93 };
94 
98 };
99 
100 static VSTRING *ruleset;
101 static VSTRING *address;
102 static VSTRING *result;
103 
104 /* rewrite_tree - rewrite address according to rule set */
105 
106 void rewrite_tree(RWR_CONTEXT *context, TOK822 *tree)
107 {
108  TOK822 *colon;
109  TOK822 *domain;
110  TOK822 *bang;
111  TOK822 *local;
112  VSTRING *vstringval;
113 
114  /*
115  * XXX If you change this module, quote_822_local.c, or tok822_parse.c,
116  * be sure to re-run the tests under "make rewrite_clnt_test" and "make
117  * resolve_clnt_test" in the global directory.
118  */
119 
120  /*
121  * Sanity check.
122  */
123  if (tree->head == 0)
124  msg_panic("rewrite_tree: empty tree");
125 
126  /*
127  * An empty address is a special case.
128  */
129  if (tree->head == tree->tail
130  && tree->tail->type == TOK822_QSTRING
131  && VSTRING_LEN(tree->tail->vstr) == 0)
132  return;
133 
134  /*
135  * Treat a lone @ as if it were an empty address.
136  */
137  if (tree->head == tree->tail
138  && tree->tail->type == '@') {
141  return;
142  }
143 
144  /*
145  * Strip source route.
146  */
147  if (tree->head->type == '@'
148  && (colon = tok822_find_type(tree->head, ':')) != 0
149  && colon != tree->tail)
151 
152  /*
153  * Optionally, transform address forms without @.
154  */
155  if ((domain = tok822_rfind_type(tree->tail, '@')) == 0) {
156 
157  /*
158  * Swap domain!user to user@domain.
159  */
160  if (var_swap_bangpath != 0
161  && (bang = tok822_find_type(tree->head, '!')) != 0) {
162  tok822_sub_keep_before(tree, bang);
163  local = tok822_cut_after(bang);
164  tok822_free(bang);
165  tok822_sub_prepend(tree, tok822_alloc('@', (char *) 0));
166  if (local)
167  tok822_sub_prepend(tree, local);
168  }
169 
170  /*
171  * Promote user%domain to user@domain.
172  */
173  else if (var_percent_hack != 0
174  && (domain = tok822_rfind_type(tree->tail, '%')) != 0) {
175  domain->type = '@';
176  }
177 
178  /*
179  * Append missing @origin
180  */
181  else if (var_append_at_myorigin != 0
182  && REW_PARAM_VALUE(context->origin) != 0
183  && REW_PARAM_VALUE(context->origin)[0] != 0) {
184  domain = tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
186  (TOK822 **) 0));
187  }
188  }
189 
190  /*
191  * Append missing .domain, but leave broken forms ending in @ alone. This
192  * merely makes diagnostics more accurate by leaving bogus addresses
193  * alone.
194  *
195  * Backwards-compatibility warning: warn for "user@localhost" when there is
196  * no "localhost" in mydestination or in any other address class with an
197  * explicit domain list.
198  */
199  if (var_append_dot_mydomain != 0
200  && REW_PARAM_VALUE(context->domain) != 0
201  && REW_PARAM_VALUE(context->domain)[0] != 0
202  && (domain = tok822_rfind_type(tree->tail, '@')) != 0
203  && domain != tree->tail
204  && tok822_find_type(domain, TOK822_DOMLIT) == 0
205  && tok822_find_type(domain, '.') == 0) {
207  && (vstringval = domain->next->vstr) != 0) {
208  if (strcasecmp(vstring_str(vstringval), "localhost") != 0) {
209  msg_info("using backwards-compatible default setting "
210  VAR_APP_DOT_MYDOMAIN "=yes to rewrite \"%s\" to "
211  "\"%s.%s\"", vstring_str(vstringval),
212  vstring_str(vstringval), var_mydomain);
213  } else if (resolve_class("localhost") == RESOLVE_CLASS_DEFAULT) {
214  msg_info("using backwards-compatible default setting "
215  VAR_APP_DOT_MYDOMAIN "=yes to rewrite \"%s\" to "
216  "\"%s.%s\"; please add \"localhost\" to "
217  "mydestination or other address class",
218  vstring_str(vstringval), vstring_str(vstringval),
219  var_mydomain);
220  }
221  }
222  tok822_sub_append(tree, tok822_alloc('.', (char *) 0));
224  (TOK822 **) 0));
225  }
226 
227  /*
228  * Strip trailing dot at end of domain, but not dot-dot or @-dot. This
229  * merely makes diagnostics more accurate by leaving bogus addresses
230  * alone.
231  */
232  if (tree->tail->type == '.'
233  && tree->tail->prev
234  && tree->tail->prev->type != '.'
235  && tree->tail->prev->type != '@')
237 }
238 
239 /* rewrite_proto - read request and send reply */
240 
241 int rewrite_proto(VSTREAM *stream)
242 {
243  RWR_CONTEXT *context;
244  TOK822 *tree;
245 
246  if (attr_scan(stream, ATTR_FLAG_STRICT,
247  RECV_ATTR_STR(MAIL_ATTR_RULE, ruleset),
248  RECV_ATTR_STR(MAIL_ATTR_ADDR, address),
249  ATTR_TYPE_END) != 2)
250  return (-1);
251 
252  if (strcmp(vstring_str(ruleset), MAIL_ATTR_RWR_LOCAL) == 0)
253  context = &local_context;
254  else if (strcmp(vstring_str(ruleset), MAIL_ATTR_RWR_REMOTE) == 0)
255  context = &remote_context;
256  else {
257  msg_warn("unknown context: %s", vstring_str(ruleset));
258  return (-1);
259  }
260 
261  /*
262  * Sanity check. An address is supposed to be in externalized form.
263  */
264  if (*vstring_str(address) == 0) {
265  msg_warn("rewrite_addr: null address");
266  vstring_strcpy(result, vstring_str(address));
267  }
268 
269  /*
270  * Convert the address from externalized (quoted) form to token list,
271  * rewrite it, and convert back.
272  */
273  else {
274  tree = tok822_scan_addr(vstring_str(address));
275  rewrite_tree(context, tree);
276  tok822_externalize(result, tree, TOK822_STR_DEFL);
277  tok822_free_tree(tree);
278  }
279  if (msg_verbose)
280  msg_info("`%s' `%s' -> `%s'", vstring_str(ruleset),
281  vstring_str(address), vstring_str(result));
282 
283  attr_print(stream, ATTR_FLAG_NONE,
286  ATTR_TYPE_END);
287 
288  if (vstream_fflush(stream) != 0) {
289  msg_warn("write rewrite reply: %m");
290  return (-1);
291  }
292  return (0);
293 }
294 
295 /* rewrite_init - module initializations */
296 
297 void rewrite_init(void)
298 {
299  ruleset = vstring_alloc(100);
300  address = vstring_alloc(100);
301  result = vstring_alloc(100);
302 }
int msg_verbose
Definition: msg.c:177
void rewrite_tree(RWR_CONTEXT *context, TOK822 *tree)
Definition: rewrite.c:106
#define ATTR_FLAG_NONE
Definition: attr.h:98
TOK822 * tok822_sub_keep_before(TOK822 *, TOK822 *)
Definition: tok822_tree.c:240
char ** domain
bool var_percent_hack
bool var_append_dot_mydomain
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
TOK822 * tok822_rfind_type(TOK822 *, int)
Definition: tok822_find.c:62
#define vstring_str(vp)
Definition: vstring.h:71
TOK822 * tok822_sub_keep_after(TOK822 *, TOK822 *)
Definition: tok822_tree.c:251
#define tok822_scan(cp, ptr)
Definition: tok822.h:83
Definition: tok822.h:27
int resolve_class(const char *domain)
Definition: resolve.c:149
#define ATTR_TYPE_END
Definition: attr.h:39
#define MAIL_ATTR_RWR_LOCAL
Definition: mail_proto.h:166
char * var_mydomain
Definition: mail_params.c:224
#define MAIL_ATTR_RULE
Definition: mail_proto.h:145
#define MAIL_ATTR_RWR_REMOTE
Definition: mail_proto.h:167
char * var_myorigin
Definition: mail_params.c:225
bool var_swap_bangpath
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define MAIL_ATTR_ADDR
Definition: mail_proto.h:146
#define VAR_REM_RWR_DOMAIN
Definition: mail_params.h:3108
TOK822 * tok822_sub_append(TOK822 *, TOK822 *)
Definition: tok822_tree.c:206
int rewrite_proto(VSTREAM *stream)
Definition: rewrite.c:241
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
TOK822 * tok822_free_tree(TOK822 *)
Definition: tok822_tree.c:262
#define TOK822_DOMLIT
Definition: tok822.h:45
#define attr_print
Definition: attr.h:109
void rewrite_init(void)
Definition: rewrite.c:297
VSTRING * vstr
Definition: tok822.h:29
struct TOK822 * head
Definition: tok822.h:32
int type
Definition: tok822.h:28
RWR_CONTEXT local_context
Definition: rewrite.c:90
TOK822 * tok822_find_type(TOK822 *, int)
Definition: tok822_find.c:51
TOK822 * tok822_sub_prepend(TOK822 *, TOK822 *)
Definition: tok822_tree.c:221
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define VAR_MYORIGIN
Definition: mail_params.h:125
VSTRING * tok822_externalize(VSTRING *, TOK822 *, int)
Definition: tok822_parse.c:270
int warn_compat_break_app_dot_mydomain
Definition: mail_params.c:363
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
RWR_CONTEXT remote_context
Definition: rewrite.c:95
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
TOK822 * tok822_alloc(int, const char *)
Definition: tok822_node.c:55
TOK822 * tok822_free(TOK822 *)
Definition: tok822_node.c:73
#define VAR_MYDOMAIN
Definition: mail_params.h:143
#define TOK822_STR_DEFL
Definition: tok822.h:91
#define TOK822_QSTRING
Definition: tok822.h:43
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:41
TOK822 * tok822_scan_addr(const char *)
Definition: tok822_parse.c:648
bool var_append_at_myorigin
TOK822 * tok822_cut_after(TOK822 *)
Definition: tok822_tree.c:178
#define REW_PARAM_VALUE(x)
char ** origin
#define VAR_APP_DOT_MYDOMAIN
Definition: mail_params.h:511
#define RESOLVE_CLASS_DEFAULT
Definition: resolve_clnt.h:34
int server_flags
#define attr_scan
Definition: attr.h:111
char * var_remote_rwr_domain
Definition: cleanup_init.c:149
struct TOK822 * prev
Definition: tok822.h:30
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
struct TOK822 * next
Definition: tok822.h:31
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103
void msg_info(const char *fmt,...)
Definition: msg.c:199
struct TOK822 * tail
Definition: tok822.h:33