1 /*	$NetBSD: smtp_map11.c,v 1.3 2020/03/18 19:05:20 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	smtp_map11 3
6 /* SUMMARY
7 /*	one-to-one address mapping
8 /* SYNOPSIS
9 /*	#include <smtp.h>
10 /*
11 /*	int	smtp_map11_internal(addr, maps, propagate)
12 /*	VSTRING	*addr;
13 /*	MAPS	*maps;
14 /*	int	propagate;
15 /*
16 /*	int	smtp_map11_external(addr, maps, propagate)
17 /*	VSTRING	*addr;
18 /*	MAPS	*maps;
19 /*	int	propagate;
20 /*
21 /*	int	smtp_map11_tree(tree, maps, propagate)
22 /*	TOK822	*tree;
23 /*	MAPS	*maps;
24 /*	int	propagate;
25 /* DESCRIPTION
26 /*	This module performs non-recursive one-to-one address mapping.
27 /*	An unmatched address extension is propagated when
28 /*	\fIpropagate\fR is non-zero.
29 /*
30 /*	smtp_map11_internal() looks up the RFC 822 internal (unquoted)
31 /*	string form of an address in the maps specified via the
32 /*	\fImaps\fR argument.
33 /*
34 /*	smtp_map11_external() is a wrapper around the smtp_map11_internal()
35 /*	routine that transforms from external (quoted) string form
36 /*	to internal form and back.
37 /*
38 /*	smtp_map11_tree() is a wrapper around the smtp_map11_internal()
39 /*	routine that transforms from internal parse tree form to
40 /*	internal form and back.
41 /* DIAGNOSTICS
42 /*	Table lookup errors are fatal.
43 /* SEE ALSO
44 /*	mail_addr_map(3) address mappings
45 /* LICENSE
46 /* .ad
47 /* .fi
48 /*	The Secure Mailer license must be distributed with this software.
49 /* AUTHOR(S)
50 /*	Wietse Venema
51 /*	IBM T.J. Watson Research
52 /*	P.O. Box 704
53 /*	Yorktown Heights, NY 10598, USA
54 /*
55 /*	Wietse Venema
56 /*	Google, Inc.
57 /*	111 8th Avenue
58 /*	New York, NY 10011, USA
59 /*--*/
60 
61 /* System library. */
62 
63 #include <sys_defs.h>
64 #include <string.h>
65 
66 /* Utility library. */
67 
68 #include <msg.h>
69 #include <vstring.h>
70 #include <dict.h>
71 #include <argv.h>
72 #include <tok822.h>
73 
74 /* Global library. */
75 
76 #include <mail_addr_map.h>
77 #include <quote_822_local.h>
78 
79 /* Application-specific. */
80 
81 #include <smtp.h>
82 
83 /* smtp_map11_internal - one-to-one table lookups */
84 
smtp_map11_internal(VSTRING * addr,MAPS * maps,int propagate)85 int     smtp_map11_internal(VSTRING *addr, MAPS *maps, int propagate)
86 {
87     const char *myname = "smtp_map11_internal";
88     ARGV   *new_addr;
89     const char *result;
90 
91     if ((new_addr = mail_addr_map_internal(maps, STR(addr), propagate)) != 0) {
92 	if (new_addr->argc > 1)
93 	    msg_warn("multi-valued %s result for %s", maps->title, STR(addr));
94 	result = new_addr->argv[0];
95 	if (msg_verbose)
96 	    msg_info("%s: %s -> %s", myname, STR(addr), result);
97 	vstring_strcpy(addr, result);
98 	argv_free(new_addr);
99 	return (1);
100     } else {
101 	if (maps->error != 0)
102 	    msg_fatal("%s map lookup problem for %s", maps->title, STR(addr));
103 	if (msg_verbose)
104 	    msg_info("%s: %s not found", myname, STR(addr));
105 	return (0);
106     }
107 }
108 
109 /* smtp_map11_tree - rewrite address node */
110 
smtp_map11_tree(TOK822 * tree,MAPS * maps,int propagate)111 int     smtp_map11_tree(TOK822 *tree, MAPS *maps, int propagate)
112 {
113     VSTRING *int_buf = vstring_alloc(100);
114     VSTRING *ext_buf = vstring_alloc(100);
115     int     ret;
116 
117     tok822_internalize(int_buf, tree->head, TOK822_STR_DEFL);
118     ret = smtp_map11_internal(int_buf, maps, propagate);
119     tok822_free_tree(tree->head);
120     quote_822_local(ext_buf, STR(int_buf));
121     tree->head = tok822_scan(STR(ext_buf), &tree->tail);
122     vstring_free(int_buf);
123     vstring_free(ext_buf);
124     return (ret);
125 }
126 
127 /* smtp_map11_external - rewrite address external form */
128 
smtp_map11_external(VSTRING * addr,MAPS * maps,int propagate)129 int     smtp_map11_external(VSTRING *addr, MAPS *maps, int propagate)
130 {
131     VSTRING *temp = vstring_alloc(100);
132     int     ret;
133 
134     unquote_822_local(temp, STR(addr));
135     ret = smtp_map11_internal(temp, maps, propagate);
136     quote_822_local(addr, STR(temp));
137     vstring_free(temp);
138     return (ret);
139 }
140 
141 #ifdef TEST
142 #include <ctype.h>
143 
144 #include <msg_vstream.h>
145 #include <readlline.h>
146 #include <stringops.h>
147 #include <vstring_vstream.h>
148 
149 #include <canon_addr.h>
150 #include <mail_params.h>
151 
152 /* canon_addr_external - surrogate to avoid trivial-rewrite dependency */
153 
canon_addr_external(VSTRING * result,const char * addr)154 VSTRING *canon_addr_external(VSTRING *result, const char *addr)
155 {
156     char   *at;
157 
158     vstring_strcpy(result, addr);
159     if ((at = strrchr(addr, '@')) == 0
160 	|| (at + 1)[strcspn(at + 1, "\"\\")] != 0)
161 	vstring_sprintf_append(result, "@%s", var_myorigin);
162     return (result);
163 }
164 
usage(const char * progname)165 static NORETURN usage(const char *progname)
166 {
167     msg_fatal("usage: %s [-v]", progname);
168 }
169 
main(int argc,char ** argv)170 int     main(int argc, char **argv)
171 {
172     VSTRING *read_buf = vstring_alloc(100);
173     MAPS   *maps = 0;
174     int     lineno;
175     int     first_line;
176     char   *bp;
177     char   *cmd;
178     VSTRING *addr_buf = vstring_alloc(100);
179     char   *addr_field;
180     char   *res_field;
181     int     ch;
182     int     errs = 0;
183 
184     /*
185      * Initialize.
186      */
187     msg_vstream_init(basename(argv[0]), VSTREAM_ERR);
188 
189     /*
190      * Parse JCL.
191      */
192     while ((ch = GETOPT(argc, argv, "v")) > 0) {
193 	switch (ch) {
194 	case 'v':
195 	    msg_verbose++;
196 	    break;
197 	default:
198 	    usage(argv[0]);
199 	}
200     }
201     if (argc != optind)
202 	usage(argv[0]);
203 
204     util_utf8_enable = 1;
205     mail_params_init();
206 
207     /*
208      * TODO: Data-driven parameter settings.
209      */
210 #define UPDATE(var, val) do { myfree(var); var = mystrdup(val); } while (0)
211 
212     UPDATE(var_myhostname, "localhost.localdomain");
213     UPDATE(var_mydomain, "localdomain");
214     UPDATE(var_myorigin, "localdomain");
215     UPDATE(var_mydest, "localhost.localdomain");
216     UPDATE(var_rcpt_delim, "+");
217 
218     /*
219      * The read-eval-print loop.
220      */
221     while (readllines(read_buf, VSTREAM_IN, &lineno, &first_line)) {
222 	bp = STR(read_buf);
223 	if (msg_verbose)
224 	    msg_info("> %s", bp);
225 	if ((cmd = mystrtok(&bp, CHARS_SPACE)) == 0 || *cmd == '#')
226 	    continue;
227 	while (ISSPACE(*bp))
228 	    bp++;
229 	if (*bp == 0)
230 	    msg_fatal("missing parameter for command %s", cmd);
231 
232 	/*
233 	 * Open maps.
234 	 */
235 	if (strcmp(cmd, "maps") == 0) {
236 	    if (maps)
237 		maps_free(maps);
238 	    maps = maps_create(bp, bp, DICT_FLAG_FOLD_FIX
239 			       | DICT_FLAG_UTF8_REQUEST);
240 	    vstream_printf("%s\n", bp);
241 	    continue;
242 	}
243 
244 	/*
245 	 * Lookup and verify.
246 	 */
247 	else if (maps != 0 && (strcmp(cmd, "external") == 0
248 			       || strcmp(cmd, "internal") == 0
249 			       || strcmp(cmd, "tree") == 0)) {
250 	    int     have_result = 0;
251 
252 
253 	    /*
254 	     * Parse the input and expectations.
255 	     */
256 	    if ((addr_field = mystrtok(&bp, ":")) == 0)
257 		msg_fatal("missing address field");
258 	    res_field = mystrtok(&bp, ":");
259 	    if (mystrtok(&bp, ":") != 0)
260 		msg_fatal("garbage after result field");
261 
262 	    /*
263 	     * Perform the mapping.
264 	     */
265 	    if (strcmp(cmd, "external") == 0) {
266 		vstring_strcpy(addr_buf, addr_field);
267 		have_result = smtp_map11_external(addr_buf, maps, 1);
268 	    } else if (maps && strcmp(cmd, "internal") == 0) {
269 		vstring_strcpy(addr_buf, addr_field);
270 		have_result = smtp_map11_internal(addr_buf, maps, 1);
271 	    } else if (maps && strcmp(cmd, "tree") == 0) {
272 		TOK822 *tree;
273 		TOK822 **addr_list;
274 		TOK822 **tpp;
275 
276 		tree = tok822_parse(addr_field);
277 		addr_list = tok822_grep(tree, TOK822_ADDR);
278 		for (tpp = addr_list; *tpp; tpp++)
279 		    have_result |= smtp_map11_tree(tpp[0], maps, 1);
280 		myfree((void *) addr_list);
281 		if (have_result)
282 		    tok822_externalize(addr_buf, tree, TOK822_STR_DEFL);
283 		tok822_free_tree(tree);
284 	    }
285 
286 	    /*
287 	     * Summarize.
288 	     */
289 	    vstream_printf("%s:%s -> %s\n",
290 			   cmd, addr_field, have_result ?
291 			   STR(addr_buf) : maps->error ?
292 			   "(error)" : "(no match)");
293 	    vstream_fflush(VSTREAM_OUT);
294 
295 	    /*
296 	     * Enforce expectations.
297 	     */
298 	    if (res_field && have_result) {
299 		if (strcmp(res_field, STR(addr_buf)) != 0) {
300 		    msg_warn("expect result '%s' but got '%s'",
301 			     res_field, STR(addr_buf));
302 		    errs = 1;
303 		}
304 	    } else if (res_field && !have_result) {
305 		msg_warn("expect result '%s' but got none", res_field);
306 		errs = 1;
307 	    } else if (!res_field && have_result) {
308 		msg_warn("expected no result but got '%s'", STR(addr_buf));
309 		errs = 1;
310 	    }
311 	    vstream_fflush(VSTREAM_OUT);
312 	}
313 
314 	/*
315 	 * Unknown request.
316 	 */
317 	else {
318 	    msg_fatal("bad request: %s", cmd);
319 	}
320     }
321     vstring_free(addr_buf);
322     vstring_free(read_buf);
323     maps_free(maps);
324     return (errs != 0);
325 }
326 
327 #endif
328