Home | History | Annotate | Line # | Download | only in smtp
      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 
     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 
    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 
    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 
    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 
    165 static NORETURN usage(const char *progname)
    166 {
    167     msg_fatal("usage: %s [-v]", progname);
    168 }
    169 
    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