diff options
Diffstat (limited to 'src/smtp/smtp_map11.c')
-rw-r--r-- | src/smtp/smtp_map11.c | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/src/smtp/smtp_map11.c b/src/smtp/smtp_map11.c new file mode 100644 index 0000000..bca8641 --- /dev/null +++ b/src/smtp/smtp_map11.c @@ -0,0 +1,325 @@ +/*++ +/* NAME +/* smtp_map11 3 +/* SUMMARY +/* one-to-one address mapping +/* SYNOPSIS +/* #include <smtp.h> +/* +/* 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 <sys_defs.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <dict.h> +#include <argv.h> +#include <tok822.h> + +/* Global library. */ + +#include <mail_addr_map.h> +#include <quote_822_local.h> + +/* Application-specific. */ + +#include <smtp.h> + +/* 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 <ctype.h> + +#include <msg_vstream.h> +#include <readlline.h> +#include <stringops.h> +#include <vstring_vstream.h> + +#include <canon_addr.h> +#include <mail_params.h> + +/* 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 |