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