7 /* mail address rewriter
9 /* #include "trivial-rewrite.h"
11 /* void rewrite_init(void)
13 /* void rewrite_proto(stream)
16 /* void rewrite_addr(context, addr, result)
17 /* RWR_CONTEXT *context;
21 /* void rewrite_tree(context, tree)
22 /* RWR_CONTEXT *context;
25 /* RWR_CONTEXT local_context;
26 /* RWR_CONTEXT remote_context;
28 /* This module implements the trivial address rewriting engine.
30 /* rewrite_init() initializes data structures that are private
31 /* to this module. It should be called once before using the
32 /* actual rewriting routines.
34 /* rewrite_proto() implements the client-server protocol: read
35 /* one rule set name and one address in external (quoted) form,
36 /* reply with the rewritten address in external form.
38 /* rewrite_addr() rewrites an address string to another string.
39 /* Both input and output are in external (quoted) form.
41 /* rewrite_tree() rewrites a parse tree with a single address to
42 /* another tree. A tree is a dummy node on top of a token list.
44 /* local_context and remote_context provide domain names for
45 /* completing incomplete address forms.
48 /* Problems and transactions are logged to the syslog daemon.
54 /* The Secure Mailer license must be distributed with this software.
57 /* IBM T.J. Watson Research
59 /* Yorktown Heights, NY 10598, USA
68 /* Utility library. */
73 #include <vstring_vstream.h>
78 #include <mail_params.h>
79 #include <mail_proto.h>
80 #include <resolve_local.h>
82 #include <mail_conf.h>
84 /* Application-specific. */
86 #include "trivial-rewrite.h"
88 RWR_CONTEXT local_context
= {
89 VAR_MYORIGIN
, &var_myorigin
,
90 VAR_MYDOMAIN
, &var_mydomain
,
93 RWR_CONTEXT remote_context
= {
94 VAR_REM_RWR_DOMAIN
, &var_remote_rwr_domain
,
95 VAR_REM_RWR_DOMAIN
, &var_remote_rwr_domain
,
98 static VSTRING
*ruleset
;
99 static VSTRING
*address
;
100 static VSTRING
*result
;
102 /* rewrite_tree - rewrite address according to rule set */
104 void rewrite_tree(RWR_CONTEXT
*context
, TOK822
*tree
)
112 * XXX If you change this module, quote_822_local.c, or tok822_parse.c,
113 * be sure to re-run the tests under "make rewrite_clnt_test" and "make
114 * resolve_clnt_test" in the global directory.
121 msg_panic("rewrite_tree: empty tree");
124 * An empty address is a special case.
126 if (tree
->head
== tree
->tail
127 && tree
->tail
->type
== TOK822_QSTRING
128 && VSTRING_LEN(tree
->tail
->vstr
) == 0)
132 * Treat a lone @ as if it were an empty address.
134 if (tree
->head
== tree
->tail
135 && tree
->tail
->type
== '@') {
136 tok822_free_tree(tok822_sub_keep_before(tree
, tree
->tail
));
137 tok822_sub_append(tree
, tok822_alloc(TOK822_QSTRING
, ""));
142 * Strip source route.
144 if (tree
->head
->type
== '@'
145 && (colon
= tok822_find_type(tree
->head
, ':')) != 0
146 && colon
!= tree
->tail
)
147 tok822_free_tree(tok822_sub_keep_after(tree
, colon
));
150 * Optionally, transform address forms without @.
152 if ((domain
= tok822_rfind_type(tree
->tail
, '@')) == 0) {
155 * Swap domain!user to user@domain.
157 if (var_swap_bangpath
!= 0
158 && (bang
= tok822_find_type(tree
->head
, '!')) != 0) {
159 tok822_sub_keep_before(tree
, bang
);
160 local
= tok822_cut_after(bang
);
162 tok822_sub_prepend(tree
, tok822_alloc('@', (char *) 0));
164 tok822_sub_prepend(tree
, local
);
168 * Promote user%domain to user@domain.
170 else if (var_percent_hack
!= 0
171 && (domain
= tok822_rfind_type(tree
->tail
, '%')) != 0) {
176 * Append missing @origin
178 else if (var_append_at_myorigin
!= 0
179 && REW_PARAM_VALUE(context
->origin
) != 0
180 && REW_PARAM_VALUE(context
->origin
)[0] != 0) {
181 domain
= tok822_sub_append(tree
, tok822_alloc('@', (char *) 0));
182 tok822_sub_append(tree
, tok822_scan(REW_PARAM_VALUE(context
->origin
),
188 * Append missing .domain, but leave broken forms ending in @ alone. This
189 * merely makes diagnostics more accurate by leaving bogus addresses
192 if (var_append_dot_mydomain
!= 0
193 && REW_PARAM_VALUE(context
->domain
) != 0
194 && REW_PARAM_VALUE(context
->domain
)[0] != 0
195 && (domain
= tok822_rfind_type(tree
->tail
, '@')) != 0
196 && domain
!= tree
->tail
197 && tok822_find_type(domain
, TOK822_DOMLIT
) == 0
198 && tok822_find_type(domain
, '.') == 0) {
199 tok822_sub_append(tree
, tok822_alloc('.', (char *) 0));
200 tok822_sub_append(tree
, tok822_scan(REW_PARAM_VALUE(context
->domain
),
205 * Strip trailing dot at end of domain, but not dot-dot or @-dot. This
206 * merely makes diagnostics more accurate by leaving bogus addresses
209 if (tree
->tail
->type
== '.'
211 && tree
->tail
->prev
->type
!= '.'
212 && tree
->tail
->prev
->type
!= '@')
213 tok822_free_tree(tok822_sub_keep_before(tree
, tree
->tail
));
216 /* rewrite_proto - read request and send reply */
218 int rewrite_proto(VSTREAM
*stream
)
220 RWR_CONTEXT
*context
;
223 if (attr_scan(stream
, ATTR_FLAG_STRICT
,
224 ATTR_TYPE_STR
, MAIL_ATTR_RULE
, ruleset
,
225 ATTR_TYPE_STR
, MAIL_ATTR_ADDR
, address
,
229 if (strcmp(vstring_str(ruleset
), MAIL_ATTR_RWR_LOCAL
) == 0)
230 context
= &local_context
;
231 else if (strcmp(vstring_str(ruleset
), MAIL_ATTR_RWR_REMOTE
) == 0)
232 context
= &remote_context
;
234 msg_warn("unknown context: %s", vstring_str(ruleset
));
239 * Sanity check. An address is supposed to be in externalized form.
241 if (*vstring_str(address
) == 0) {
242 msg_warn("rewrite_addr: null address");
243 vstring_strcpy(result
, vstring_str(address
));
247 * Convert the address from externalized (quoted) form to token list,
248 * rewrite it, and convert back.
251 tree
= tok822_scan_addr(vstring_str(address
));
252 rewrite_tree(context
, tree
);
253 tok822_externalize(result
, tree
, TOK822_STR_DEFL
);
254 tok822_free_tree(tree
);
257 msg_info("`%s' `%s' -> `%s'", vstring_str(ruleset
),
258 vstring_str(address
), vstring_str(result
));
260 attr_print(stream
, ATTR_FLAG_NONE
,
261 ATTR_TYPE_INT
, MAIL_ATTR_FLAGS
, server_flags
,
262 ATTR_TYPE_STR
, MAIL_ATTR_ADDR
, vstring_str(result
),
265 if (vstream_fflush(stream
) != 0) {
266 msg_warn("write rewrite reply: %m");
272 /* rewrite_init - module initializations */
274 void rewrite_init(void)
276 ruleset
= vstring_alloc(100);
277 address
= vstring_alloc(100);
278 result
= vstring_alloc(100);