/*++ /* NAME /* smtp_map11 3 /* SUMMARY /* one-to-one address mapping /* SYNOPSIS /* #include /* /* int smtp_map11_internal(addr, maps, propagate) /* VSTRING *addr; /* MAPS *maps; /* int propagate; /* /* int smtp_map11_external(addr, maps, propagate) /* VSTRING *addr; /* MAPS *maps; /* int propagate; /* /* int smtp_map11_tree(tree, maps, propagate) /* TOK822 *tree; /* MAPS *maps; /* int propagate; /* DESCRIPTION /* This module performs non-recursive one-to-one address mapping. /* An unmatched address extension is propagated when /* \fIpropagate\fR is non-zero. /* /* smtp_map11_internal() looks up the RFC 822 internal (unquoted) /* string form of an address in the maps specified via the /* \fImaps\fR argument. /* /* smtp_map11_external() is a wrapper around the smtp_map11_internal() /* routine that transforms from external (quoted) string form /* to internal form and back. /* /* smtp_map11_tree() is a wrapper around the smtp_map11_internal() /* routine that transforms from internal parse tree form to /* internal form and back. /* DIAGNOSTICS /* Table lookup errors are fatal. /* SEE ALSO /* mail_addr_map(3) address mappings /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* /* Wietse Venema /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA /*--*/ /* System library. */ #include #include /* Utility library. */ #include #include #include #include #include /* Global library. */ #include #include /* Application-specific. */ #include /* smtp_map11_internal - one-to-one table lookups */ int smtp_map11_internal(VSTRING *addr, MAPS *maps, int propagate) { const char *myname = "smtp_map11_internal"; ARGV *new_addr; const char *result; if ((new_addr = mail_addr_map_internal(maps, STR(addr), propagate)) != 0) { if (new_addr->argc > 1) msg_warn("multi-valued %s result for %s", maps->title, STR(addr)); result = new_addr->argv[0]; if (msg_verbose) msg_info("%s: %s -> %s", myname, STR(addr), result); vstring_strcpy(addr, result); argv_free(new_addr); return (1); } else { if (maps->error != 0) msg_fatal("%s map lookup problem for %s", maps->title, STR(addr)); if (msg_verbose) msg_info("%s: %s not found", myname, STR(addr)); return (0); } } /* smtp_map11_tree - rewrite address node */ int smtp_map11_tree(TOK822 *tree, MAPS *maps, int propagate) { VSTRING *int_buf = vstring_alloc(100); VSTRING *ext_buf = vstring_alloc(100); int ret; tok822_internalize(int_buf, tree->head, TOK822_STR_DEFL); ret = smtp_map11_internal(int_buf, maps, propagate); tok822_free_tree(tree->head); quote_822_local(ext_buf, STR(int_buf)); tree->head = tok822_scan(STR(ext_buf), &tree->tail); vstring_free(int_buf); vstring_free(ext_buf); return (ret); } /* smtp_map11_external - rewrite address external form */ int smtp_map11_external(VSTRING *addr, MAPS *maps, int propagate) { VSTRING *temp = vstring_alloc(100); int ret; unquote_822_local(temp, STR(addr)); ret = smtp_map11_internal(temp, maps, propagate); quote_822_local(addr, STR(temp)); vstring_free(temp); return (ret); } #ifdef TEST #include #include #include #include #include #include #include /* canon_addr_external - surrogate to avoid trivial-rewrite dependency */ VSTRING *canon_addr_external(VSTRING *result, const char *addr) { char *at; vstring_strcpy(result, addr); if ((at = strrchr(addr, '@')) == 0 || (at + 1)[strcspn(at + 1, "\"\\")] != 0) vstring_sprintf_append(result, "@%s", var_myorigin); return (result); } static NORETURN usage(const char *progname) { msg_fatal("usage: %s [-v]", progname); } int main(int argc, char **argv) { VSTRING *read_buf = vstring_alloc(100); MAPS *maps = 0; int lineno; int first_line; char *bp; char *cmd; VSTRING *addr_buf = vstring_alloc(100); char *addr_field; char *res_field; int ch; int errs = 0; /* * Initialize. */ msg_vstream_init(basename(argv[0]), VSTREAM_ERR); /* * Parse JCL. */ while ((ch = GETOPT(argc, argv, "v")) > 0) { switch (ch) { case 'v': msg_verbose++; break; default: usage(argv[0]); } } if (argc != optind) usage(argv[0]); util_utf8_enable = 1; mail_params_init(); /* * TODO: Data-driven parameter settings. */ #define UPDATE(var, val) do { myfree(var); var = mystrdup(val); } while (0) UPDATE(var_myhostname, "localhost.localdomain"); UPDATE(var_mydomain, "localdomain"); UPDATE(var_myorigin, "localdomain"); UPDATE(var_mydest, "localhost.localdomain"); UPDATE(var_rcpt_delim, "+"); /* * The read-eval-print loop. */ while (readllines(read_buf, VSTREAM_IN, &lineno, &first_line)) { bp = STR(read_buf); if (msg_verbose) msg_info("> %s", bp); if ((cmd = mystrtok(&bp, CHARS_SPACE)) == 0 || *cmd == '#') continue; while (ISSPACE(*bp)) bp++; if (*bp == 0) msg_fatal("missing parameter for command %s", cmd); /* * Open maps. */ if (strcmp(cmd, "maps") == 0) { if (maps) maps_free(maps); maps = maps_create(bp, bp, DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST); vstream_printf("%s\n", bp); continue; } /* * Lookup and verify. */ else if (maps != 0 && (strcmp(cmd, "external") == 0 || strcmp(cmd, "internal") == 0 || strcmp(cmd, "tree") == 0)) { int have_result = 0; /* * Parse the input and expectations. */ if ((addr_field = mystrtok(&bp, ":")) == 0) msg_fatal("missing address field"); res_field = mystrtok(&bp, ":"); if (mystrtok(&bp, ":") != 0) msg_fatal("garbage after result field"); /* * Perform the mapping. */ if (strcmp(cmd, "external") == 0) { vstring_strcpy(addr_buf, addr_field); have_result = smtp_map11_external(addr_buf, maps, 1); } else if (maps && strcmp(cmd, "internal") == 0) { vstring_strcpy(addr_buf, addr_field); have_result = smtp_map11_internal(addr_buf, maps, 1); } else if (maps && strcmp(cmd, "tree") == 0) { TOK822 *tree; TOK822 **addr_list; TOK822 **tpp; tree = tok822_parse(addr_field); addr_list = tok822_grep(tree, TOK822_ADDR); for (tpp = addr_list; *tpp; tpp++) have_result |= smtp_map11_tree(tpp[0], maps, 1); myfree((void *) addr_list); if (have_result) tok822_externalize(addr_buf, tree, TOK822_STR_DEFL); tok822_free_tree(tree); } /* * Summarize. */ vstream_printf("%s:%s -> %s\n", cmd, addr_field, have_result ? STR(addr_buf) : maps->error ? "(error)" : "(no match)"); vstream_fflush(VSTREAM_OUT); /* * Enforce expectations. */ if (res_field && have_result) { if (strcmp(res_field, STR(addr_buf)) != 0) { msg_warn("expect result '%s' but got '%s'", res_field, STR(addr_buf)); errs = 1; } } else if (res_field && !have_result) { msg_warn("expect result '%s' but got none", res_field); errs = 1; } else if (!res_field && have_result) { msg_warn("expected no result but got '%s'", STR(addr_buf)); errs = 1; } vstream_fflush(VSTREAM_OUT); } /* * Unknown request. */ else { msg_fatal("bad request: %s", cmd); } } vstring_free(addr_buf); vstring_free(read_buf); maps_free(maps); return (errs != 0); } #endif