1 /* $OpenBSD: envelope.c,v 1.29 2014/04/19 12:30:54 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> 5 * Copyright (c) 2011-2013 Gilles Chehade <gilles@poolp.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/socket.h> 24 #include <sys/stat.h> 25 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 29 #include <ctype.h> 30 #include <err.h> 31 #include <errno.h> 32 #include <event.h> 33 #include <fcntl.h> 34 #include <imsg.h> 35 #include <inttypes.h> 36 #include <libgen.h> 37 #include <pwd.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <time.h> 42 #include <unistd.h> 43 44 #include "smtpd.h" 45 #include "log.h" 46 47 static int envelope_upgrade_v1(struct dict *); 48 static int envelope_ascii_load(struct envelope *, struct dict *); 49 static void envelope_ascii_dump(const struct envelope *, char **, size_t *, 50 const char *); 51 52 void 53 envelope_set_errormsg(struct envelope *e, char *fmt, ...) 54 { 55 int ret; 56 va_list ap; 57 58 va_start(ap, fmt); 59 ret = vsnprintf(e->errorline, sizeof(e->errorline), fmt, ap); 60 va_end(ap); 61 62 /* this should not happen */ 63 if (ret == -1) 64 err(1, "vsnprintf"); 65 66 if ((size_t)ret >= sizeof(e->errorline)) 67 (void)strlcpy(e->errorline + (sizeof(e->errorline) - 4), "...", 4); 68 } 69 70 void 71 envelope_set_esc_class(struct envelope *e, enum enhanced_status_class class) 72 { 73 e->esc_class = class; 74 } 75 76 void 77 envelope_set_esc_code(struct envelope *e, enum enhanced_status_code code) 78 { 79 e->esc_code = code; 80 } 81 82 static int 83 envelope_buffer_to_dict(struct dict *d, const char *ibuf, size_t buflen) 84 { 85 static char lbuf[sizeof(struct envelope)]; 86 size_t len; 87 char *buf, *field, *nextline; 88 89 memset(lbuf, 0, sizeof lbuf); 90 if (strlcpy(lbuf, ibuf, sizeof lbuf) >= sizeof lbuf) 91 goto err; 92 buf = lbuf; 93 94 while (buflen > 0) { 95 len = strcspn(buf, "\n"); 96 buf[len] = '\0'; 97 nextline = buf + len + 1; 98 buflen -= (nextline - buf); 99 100 field = buf; 101 while (*buf && (isalnum((unsigned char)*buf) || *buf == '-')) 102 buf++; 103 if (! *buf) 104 goto err; 105 106 /* skip whitespaces before separator */ 107 while (*buf && isspace((unsigned char)*buf)) 108 *buf++ = 0; 109 110 /* we *want* ':' */ 111 if (*buf != ':') 112 goto err; 113 *buf++ = 0; 114 115 /* skip whitespaces after separator */ 116 while (*buf && isspace((unsigned char)*buf)) 117 *buf++ = 0; 118 dict_set(d, field, buf); 119 buf = nextline; 120 } 121 122 return (1); 123 124 err: 125 return (0); 126 } 127 128 int 129 envelope_load_buffer(struct envelope *ep, const char *ibuf, size_t buflen) 130 { 131 struct dict d; 132 const char *val, *errstr; 133 long long version; 134 int ret = 0; 135 136 dict_init(&d); 137 if (! envelope_buffer_to_dict(&d, ibuf, buflen)) { 138 log_debug("debug: cannot parse envelope to dict"); 139 goto end; 140 } 141 142 val = dict_get(&d, "version"); 143 if (val == NULL) { 144 log_debug("debug: envelope version not found"); 145 goto end; 146 } 147 version = strtonum(val, 1, 64, &errstr); 148 if (errstr) { 149 log_debug("debug: cannot parse envelope version: %s", val); 150 goto end; 151 } 152 153 switch (version) { 154 case 1: 155 log_debug("debug: upgrading envelope to version 1"); 156 if (!envelope_upgrade_v1(&d)) { 157 log_debug("debug: failed to upgrade envelope to version 1"); 158 goto end; 159 } 160 /* FALLTRHOUGH */ 161 case 2: 162 /* Can be missing in some v2 envelopes */ 163 if (dict_get(&d, "smtpname") == NULL) 164 dict_xset(&d, "smtpname", env->sc_hostname); 165 break; 166 default: 167 log_debug("debug: bad envelope version %lld", version); 168 goto end; 169 } 170 171 memset(ep, 0, sizeof *ep); 172 ret = envelope_ascii_load(ep, &d); 173 if (ret) 174 ep->version = SMTPD_ENVELOPE_VERSION; 175 end: 176 while (dict_poproot(&d, NULL)) 177 ; 178 return (ret); 179 } 180 181 int 182 envelope_dump_buffer(const struct envelope *ep, char *dest, size_t len) 183 { 184 char *p = dest; 185 186 envelope_ascii_dump(ep, &dest, &len, "version"); 187 envelope_ascii_dump(ep, &dest, &len, "tag"); 188 envelope_ascii_dump(ep, &dest, &len, "type"); 189 envelope_ascii_dump(ep, &dest, &len, "smtpname"); 190 envelope_ascii_dump(ep, &dest, &len, "helo"); 191 envelope_ascii_dump(ep, &dest, &len, "hostname"); 192 envelope_ascii_dump(ep, &dest, &len, "errorline"); 193 envelope_ascii_dump(ep, &dest, &len, "sockaddr"); 194 envelope_ascii_dump(ep, &dest, &len, "sender"); 195 envelope_ascii_dump(ep, &dest, &len, "rcpt"); 196 envelope_ascii_dump(ep, &dest, &len, "dest"); 197 envelope_ascii_dump(ep, &dest, &len, "ctime"); 198 envelope_ascii_dump(ep, &dest, &len, "last-try"); 199 envelope_ascii_dump(ep, &dest, &len, "last-bounce"); 200 envelope_ascii_dump(ep, &dest, &len, "expire"); 201 envelope_ascii_dump(ep, &dest, &len, "retry"); 202 envelope_ascii_dump(ep, &dest, &len, "flags"); 203 envelope_ascii_dump(ep, &dest, &len, "dsn-notify"); 204 envelope_ascii_dump(ep, &dest, &len, "dsn-ret"); 205 envelope_ascii_dump(ep, &dest, &len, "dsn-envid"); 206 envelope_ascii_dump(ep, &dest, &len, "dsn-orcpt"); 207 envelope_ascii_dump(ep, &dest, &len, "esc-class"); 208 envelope_ascii_dump(ep, &dest, &len, "esc-code"); 209 210 switch (ep->type) { 211 case D_MDA: 212 envelope_ascii_dump(ep, &dest, &len, "mda-buffer"); 213 envelope_ascii_dump(ep, &dest, &len, "mda-method"); 214 envelope_ascii_dump(ep, &dest, &len, "mda-user"); 215 envelope_ascii_dump(ep, &dest, &len, "mda-usertable"); 216 break; 217 case D_MTA: 218 envelope_ascii_dump(ep, &dest, &len, "mta-relay"); 219 envelope_ascii_dump(ep, &dest, &len, "mta-relay-auth"); 220 envelope_ascii_dump(ep, &dest, &len, "mta-relay-cert"); 221 envelope_ascii_dump(ep, &dest, &len, "mta-relay-flags"); 222 envelope_ascii_dump(ep, &dest, &len, "mta-relay-heloname"); 223 envelope_ascii_dump(ep, &dest, &len, "mta-relay-helotable"); 224 envelope_ascii_dump(ep, &dest, &len, "mta-relay-source"); 225 break; 226 case D_BOUNCE: 227 envelope_ascii_dump(ep, &dest, &len, "bounce-expire"); 228 envelope_ascii_dump(ep, &dest, &len, "bounce-delay"); 229 envelope_ascii_dump(ep, &dest, &len, "bounce-type"); 230 break; 231 default: 232 return (0); 233 } 234 235 if (dest == NULL) 236 return (0); 237 238 return (dest - p); 239 } 240 241 static int 242 ascii_load_uint8(uint8_t *dest, char *buf) 243 { 244 const char *errstr; 245 246 *dest = strtonum(buf, 0, 0xff, &errstr); 247 if (errstr) 248 return 0; 249 return 1; 250 } 251 252 static int 253 ascii_load_uint16(uint16_t *dest, char *buf) 254 { 255 const char *errstr; 256 257 *dest = strtonum(buf, 0, 0xffff, &errstr); 258 if (errstr) 259 return 0; 260 return 1; 261 } 262 263 static int 264 ascii_load_uint32(uint32_t *dest, char *buf) 265 { 266 const char *errstr; 267 268 *dest = strtonum(buf, 0, 0xffffffff, &errstr); 269 if (errstr) 270 return 0; 271 return 1; 272 } 273 274 static int 275 ascii_load_time(time_t *dest, char *buf) 276 { 277 const char *errstr; 278 279 *dest = strtonum(buf, 0, LLONG_MAX, &errstr); 280 if (errstr) 281 return 0; 282 return 1; 283 } 284 285 static int 286 ascii_load_type(enum delivery_type *dest, char *buf) 287 { 288 if (strcasecmp(buf, "mda") == 0) 289 *dest = D_MDA; 290 else if (strcasecmp(buf, "mta") == 0) 291 *dest = D_MTA; 292 else if (strcasecmp(buf, "bounce") == 0) 293 *dest = D_BOUNCE; 294 else 295 return 0; 296 return 1; 297 } 298 299 static int 300 ascii_load_string(char *dest, char *buf, size_t len) 301 { 302 if (strlcpy(dest, buf, len) >= len) 303 return 0; 304 return 1; 305 } 306 307 static int 308 ascii_load_sockaddr(struct sockaddr_storage *ss, char *buf) 309 { 310 struct sockaddr_in6 ssin6; 311 struct sockaddr_in ssin; 312 313 memset(&ssin, 0, sizeof ssin); 314 memset(&ssin6, 0, sizeof ssin6); 315 316 if (!strcmp("local", buf)) { 317 ss->ss_family = AF_LOCAL; 318 } 319 else if (strncasecmp("IPv6:", buf, 5) == 0) { 320 if (inet_pton(AF_INET6, buf + 5, &ssin6.sin6_addr) != 1) 321 return 0; 322 ssin6.sin6_family = AF_INET6; 323 memcpy(ss, &ssin6, sizeof(ssin6)); 324 ss->ss_len = sizeof(struct sockaddr_in6); 325 } 326 else { 327 if (inet_pton(AF_INET, buf, &ssin.sin_addr) != 1) 328 return 0; 329 ssin.sin_family = AF_INET; 330 memcpy(ss, &ssin, sizeof(ssin)); 331 ss->ss_len = sizeof(struct sockaddr_in); 332 } 333 return 1; 334 } 335 336 static int 337 ascii_load_mda_method(enum action_type *dest, char *buf) 338 { 339 if (strcasecmp(buf, "mbox") == 0) 340 *dest = A_MBOX; 341 else if (strcasecmp(buf, "maildir") == 0) 342 *dest = A_MAILDIR; 343 else if (strcasecmp(buf, "filename") == 0) 344 *dest = A_FILENAME; 345 else if (strcasecmp(buf, "mda") == 0) 346 *dest = A_MDA; 347 else if (strcasecmp(buf, "lmtp") == 0) 348 *dest = A_LMTP; 349 else 350 return 0; 351 return 1; 352 } 353 354 static int 355 ascii_load_mailaddr(struct mailaddr *dest, char *buf) 356 { 357 if (! text_to_mailaddr(dest, buf)) 358 return 0; 359 return 1; 360 } 361 362 static int 363 ascii_load_flags(enum envelope_flags *dest, char *buf) 364 { 365 char *flag; 366 367 while ((flag = strsep(&buf, " ,|")) != NULL) { 368 if (strcasecmp(flag, "authenticated") == 0) 369 *dest |= EF_AUTHENTICATED; 370 else if (strcasecmp(flag, "enqueued") == 0) 371 ; 372 else if (strcasecmp(flag, "bounce") == 0) 373 *dest |= EF_BOUNCE; 374 else if (strcasecmp(flag, "internal") == 0) 375 *dest |= EF_INTERNAL; 376 else 377 return 0; 378 } 379 return 1; 380 } 381 382 static int 383 ascii_load_mta_relay_url(struct relayhost *relay, char *buf) 384 { 385 if (! text_to_relayhost(relay, buf)) 386 return 0; 387 return 1; 388 } 389 390 static int 391 ascii_load_mta_relay_flags(uint16_t *dest, char *buf) 392 { 393 char *flag; 394 395 while ((flag = strsep(&buf, " ,|")) != NULL) { 396 if (strcasecmp(flag, "verify") == 0) 397 *dest |= F_TLS_VERIFY; 398 else if (strcasecmp(flag, "tls") == 0) 399 *dest |= F_STARTTLS; 400 else 401 return 0; 402 } 403 404 return 1; 405 } 406 407 static int 408 ascii_load_bounce_type(enum bounce_type *dest, char *buf) 409 { 410 if (strcasecmp(buf, "error") == 0) 411 *dest = B_ERROR; 412 else if (strcasecmp(buf, "warn") == 0) 413 *dest = B_WARNING; 414 else if (strcasecmp(buf, "dsn") == 0) 415 *dest = B_DSN; 416 else 417 return 0; 418 return 1; 419 } 420 421 static int 422 ascii_load_dsn_ret(enum dsn_ret *ret, char *buf) 423 { 424 if (strcasecmp(buf, "HDRS") == 0) 425 *ret = DSN_RETHDRS; 426 else if (strcasecmp(buf, "FULL") == 0) 427 *ret = DSN_RETFULL; 428 else 429 return 0; 430 return 1; 431 } 432 433 static int 434 ascii_load_field(const char *field, struct envelope *ep, char *buf) 435 { 436 if (strcasecmp("bounce-delay", field) == 0) 437 return ascii_load_time(&ep->agent.bounce.delay, buf); 438 439 if (strcasecmp("bounce-expire", field) == 0) 440 return ascii_load_time(&ep->agent.bounce.expire, buf); 441 442 if (strcasecmp("bounce-type", field) == 0) 443 return ascii_load_bounce_type(&ep->agent.bounce.type, buf); 444 445 if (strcasecmp("ctime", field) == 0) 446 return ascii_load_time(&ep->creation, buf); 447 448 if (strcasecmp("dest", field) == 0) 449 return ascii_load_mailaddr(&ep->dest, buf); 450 451 if (strcasecmp("errorline", field) == 0) 452 return ascii_load_string(ep->errorline, buf, 453 sizeof ep->errorline); 454 455 if (strcasecmp("expire", field) == 0) 456 return ascii_load_time(&ep->expire, buf); 457 458 if (strcasecmp("flags", field) == 0) 459 return ascii_load_flags(&ep->flags, buf); 460 461 if (strcasecmp("helo", field) == 0) 462 return ascii_load_string(ep->helo, buf, sizeof ep->helo); 463 464 if (strcasecmp("hostname", field) == 0) 465 return ascii_load_string(ep->hostname, buf, 466 sizeof ep->hostname); 467 468 if (strcasecmp("last-bounce", field) == 0) 469 return ascii_load_time(&ep->lastbounce, buf); 470 471 if (strcasecmp("last-try", field) == 0) 472 return ascii_load_time(&ep->lasttry, buf); 473 474 if (strcasecmp("mda-buffer", field) == 0) 475 return ascii_load_string(ep->agent.mda.buffer, buf, 476 sizeof ep->agent.mda.buffer); 477 478 if (strcasecmp("mda-method", field) == 0) 479 return ascii_load_mda_method(&ep->agent.mda.method, buf); 480 481 if (strcasecmp("mda-user", field) == 0) 482 return ascii_load_string(ep->agent.mda.username, buf, 483 sizeof ep->agent.mda.username); 484 485 if (strcasecmp("mda-usertable", field) == 0) 486 return ascii_load_string(ep->agent.mda.usertable, buf, 487 sizeof ep->agent.mda.usertable); 488 489 if (strcasecmp("mta-relay", field) == 0) { 490 int ret; 491 uint16_t flags = ep->agent.mta.relay.flags; 492 ret = ascii_load_mta_relay_url(&ep->agent.mta.relay, buf); 493 if (! ret) 494 return (0); 495 ep->agent.mta.relay.flags |= flags; 496 return ret; 497 } 498 499 if (strcasecmp("mta-relay-auth", field) == 0) 500 return ascii_load_string(ep->agent.mta.relay.authtable, buf, 501 sizeof ep->agent.mta.relay.authtable); 502 503 if (strcasecmp("mta-relay-cert", field) == 0) 504 return ascii_load_string(ep->agent.mta.relay.pki_name, buf, 505 sizeof ep->agent.mta.relay.pki_name); 506 507 if (strcasecmp("mta-relay-flags", field) == 0) 508 return ascii_load_mta_relay_flags(&ep->agent.mta.relay.flags, buf); 509 510 if (strcasecmp("mta-relay-heloname", field) == 0) 511 return ascii_load_string(ep->agent.mta.relay.heloname, buf, 512 sizeof ep->agent.mta.relay.heloname); 513 514 if (strcasecmp("mta-relay-helotable", field) == 0) 515 return ascii_load_string(ep->agent.mta.relay.helotable, buf, 516 sizeof ep->agent.mta.relay.helotable); 517 518 if (strcasecmp("mta-relay-source", field) == 0) 519 return ascii_load_string(ep->agent.mta.relay.sourcetable, buf, 520 sizeof ep->agent.mta.relay.sourcetable); 521 522 if (strcasecmp("retry", field) == 0) 523 return ascii_load_uint16(&ep->retry, buf); 524 525 if (strcasecmp("rcpt", field) == 0) 526 return ascii_load_mailaddr(&ep->rcpt, buf); 527 528 if (strcasecmp("sender", field) == 0) 529 return ascii_load_mailaddr(&ep->sender, buf); 530 531 if (strcasecmp("smtpname", field) == 0) 532 return ascii_load_string(ep->smtpname, buf, sizeof(ep->smtpname)); 533 534 if (strcasecmp("sockaddr", field) == 0) 535 return ascii_load_sockaddr(&ep->ss, buf); 536 537 if (strcasecmp("tag", field) == 0) 538 return ascii_load_string(ep->tag, buf, sizeof ep->tag); 539 540 if (strcasecmp("type", field) == 0) 541 return ascii_load_type(&ep->type, buf); 542 543 if (strcasecmp("version", field) == 0) 544 return ascii_load_uint32(&ep->version, buf); 545 546 if (strcasecmp("dsn-notify", field) == 0) 547 return ascii_load_uint8(&ep->dsn_notify, buf); 548 549 if (strcasecmp("dsn-orcpt", field) == 0) 550 return ascii_load_mailaddr(&ep->dsn_orcpt, buf); 551 552 if (strcasecmp("dsn-ret", field) == 0) 553 return ascii_load_dsn_ret(&ep->dsn_ret, buf); 554 555 if (strcasecmp("dsn-envid", field) == 0) 556 return ascii_load_string(ep->dsn_envid, buf, sizeof(ep->dsn_envid)); 557 558 if (strcasecmp("esc-class", field) == 0) 559 return ascii_load_uint8(&ep->esc_class, buf); 560 561 if (strcasecmp("esc-code", field) == 0) 562 return ascii_load_uint8(&ep->esc_code, buf); 563 564 return (0); 565 } 566 567 static int 568 envelope_ascii_load(struct envelope *ep, struct dict *d) 569 { 570 const char *field; 571 char *value; 572 void *hdl; 573 574 hdl = NULL; 575 while (dict_iter(d, &hdl, &field, (void **)&value)) 576 if (! ascii_load_field(field, ep, value)) 577 goto err; 578 579 return (1); 580 581 err: 582 log_warnx("envelope: invalid field \"%s\"", field); 583 return (0); 584 } 585 586 587 static int 588 ascii_dump_uint8(uint8_t src, char *dest, size_t len) 589 { 590 return bsnprintf(dest, len, "%d", src); 591 } 592 593 static int 594 ascii_dump_uint16(uint16_t src, char *dest, size_t len) 595 { 596 return bsnprintf(dest, len, "%d", src); 597 } 598 599 static int 600 ascii_dump_uint32(uint32_t src, char *dest, size_t len) 601 { 602 return bsnprintf(dest, len, "%d", src); 603 } 604 605 static int 606 ascii_dump_time(time_t src, char *dest, size_t len) 607 { 608 return bsnprintf(dest, len, "%lld", (long long) src); 609 } 610 611 static int 612 ascii_dump_string(const char *src, char *dest, size_t len) 613 { 614 return bsnprintf(dest, len, "%s", src); 615 } 616 617 static int 618 ascii_dump_type(enum delivery_type type, char *dest, size_t len) 619 { 620 char *p = NULL; 621 622 switch (type) { 623 case D_MDA: 624 p = "mda"; 625 break; 626 case D_MTA: 627 p = "mta"; 628 break; 629 case D_BOUNCE: 630 p = "bounce"; 631 break; 632 default: 633 return 0; 634 } 635 636 return bsnprintf(dest, len, "%s", p); 637 } 638 639 static int 640 ascii_dump_mda_method(enum action_type type, char *dest, size_t len) 641 { 642 char *p = NULL; 643 644 switch (type) { 645 case A_LMTP: 646 p = "lmtp"; 647 break; 648 case A_MAILDIR: 649 p = "maildir"; 650 break; 651 case A_MBOX: 652 p = "mbox"; 653 break; 654 case A_FILENAME: 655 p = "filename"; 656 break; 657 case A_MDA: 658 p = "mda"; 659 break; 660 default: 661 return 0; 662 } 663 return bsnprintf(dest, len, "%s", p); 664 } 665 666 static int 667 ascii_dump_mailaddr(const struct mailaddr *addr, char *dest, size_t len) 668 { 669 return bsnprintf(dest, len, "%s@%s", 670 addr->user, addr->domain); 671 } 672 673 static int 674 ascii_dump_flags(enum envelope_flags flags, char *buf, size_t len) 675 { 676 size_t cpylen = 0; 677 678 buf[0] = '\0'; 679 if (flags) { 680 if (flags & EF_AUTHENTICATED) 681 cpylen = strlcat(buf, "authenticated", len); 682 if (flags & EF_BOUNCE) { 683 if (buf[0] != '\0') 684 (void)strlcat(buf, " ", len); 685 cpylen = strlcat(buf, "bounce", len); 686 } 687 if (flags & EF_INTERNAL) { 688 if (buf[0] != '\0') 689 (void)strlcat(buf, " ", len); 690 cpylen = strlcat(buf, "internal", len); 691 } 692 } 693 694 return cpylen < len ? 1 : 0; 695 } 696 697 static int 698 ascii_dump_mta_relay_url(const struct relayhost *relay, char *buf, size_t len) 699 { 700 return bsnprintf(buf, len, "%s", relayhost_to_text(relay)); 701 } 702 703 static int 704 ascii_dump_mta_relay_flags(uint16_t flags, char *buf, size_t len) 705 { 706 size_t cpylen = 0; 707 708 buf[0] = '\0'; 709 if (flags) { 710 if (flags & F_TLS_VERIFY) { 711 if (buf[0] != '\0') 712 (void)strlcat(buf, " ", len); 713 cpylen = strlcat(buf, "verify", len); 714 } 715 if (flags & F_STARTTLS) { 716 if (buf[0] != '\0') 717 (void)strlcat(buf, " ", len); 718 cpylen = strlcat(buf, "tls", len); 719 } 720 } 721 722 return cpylen < len ? 1 : 0; 723 } 724 725 static int 726 ascii_dump_bounce_type(enum bounce_type type, char *dest, size_t len) 727 { 728 char *p = NULL; 729 730 switch (type) { 731 case B_ERROR: 732 p = "error"; 733 break; 734 case B_WARNING: 735 p = "warn"; 736 break; 737 case B_DSN: 738 p = "dsn"; 739 break; 740 default: 741 return 0; 742 } 743 return bsnprintf(dest, len, "%s", p); 744 } 745 746 747 static int 748 ascii_dump_dsn_ret(enum dsn_ret flag, char *dest, size_t len) 749 { 750 size_t cpylen = 0; 751 752 dest[0] = '\0'; 753 if (flag == DSN_RETFULL) 754 cpylen = strlcat(dest, "FULL", len); 755 else if (flag == DSN_RETHDRS) 756 cpylen = strlcat(dest, "HDRS", len); 757 758 return cpylen < len ? 1 : 0; 759 } 760 761 static int 762 ascii_dump_field(const char *field, const struct envelope *ep, 763 char *buf, size_t len) 764 { 765 if (strcasecmp(field, "bounce-delay") == 0) { 766 if (ep->agent.bounce.type != B_WARNING) 767 return (1); 768 return ascii_dump_time(ep->agent.bounce.delay, buf, len); 769 } 770 771 if (strcasecmp(field, "bounce-expire") == 0) { 772 if (ep->agent.bounce.type != B_WARNING) 773 return (1); 774 return ascii_dump_time(ep->agent.bounce.expire, buf, len); 775 } 776 777 if (strcasecmp(field, "bounce-type") == 0) 778 return ascii_dump_bounce_type(ep->agent.bounce.type, buf, len); 779 780 if (strcasecmp(field, "ctime") == 0) 781 return ascii_dump_time(ep->creation, buf, len); 782 783 if (strcasecmp(field, "dest") == 0) 784 return ascii_dump_mailaddr(&ep->dest, buf, len); 785 786 if (strcasecmp(field, "errorline") == 0) 787 return ascii_dump_string(ep->errorline, buf, len); 788 789 if (strcasecmp(field, "expire") == 0) 790 return ascii_dump_time(ep->expire, buf, len); 791 792 if (strcasecmp(field, "flags") == 0) 793 return ascii_dump_flags(ep->flags, buf, len); 794 795 if (strcasecmp(field, "helo") == 0) 796 return ascii_dump_string(ep->helo, buf, len); 797 798 if (strcasecmp(field, "hostname") == 0) 799 return ascii_dump_string(ep->hostname, buf, len); 800 801 if (strcasecmp(field, "last-bounce") == 0) 802 return ascii_dump_time(ep->lastbounce, buf, len); 803 804 if (strcasecmp(field, "last-try") == 0) 805 return ascii_dump_time(ep->lasttry, buf, len); 806 807 if (strcasecmp(field, "mda-buffer") == 0) 808 return ascii_dump_string(ep->agent.mda.buffer, buf, len); 809 810 if (strcasecmp(field, "mda-method") == 0) 811 return ascii_dump_mda_method(ep->agent.mda.method, buf, len); 812 813 if (strcasecmp(field, "mda-user") == 0) 814 return ascii_dump_string(ep->agent.mda.username, buf, len); 815 816 if (strcasecmp(field, "mda-usertable") == 0) 817 return ascii_dump_string(ep->agent.mda.usertable, buf, len); 818 819 if (strcasecmp(field, "mta-relay") == 0) { 820 if (ep->agent.mta.relay.hostname[0]) 821 return ascii_dump_mta_relay_url(&ep->agent.mta.relay, buf, len); 822 return (1); 823 } 824 825 if (strcasecmp(field, "mta-relay-auth") == 0) 826 return ascii_dump_string(ep->agent.mta.relay.authtable, 827 buf, len); 828 829 if (strcasecmp(field, "mta-relay-cert") == 0) 830 return ascii_dump_string(ep->agent.mta.relay.pki_name, 831 buf, len); 832 833 if (strcasecmp(field, "mta-relay-flags") == 0) 834 return ascii_dump_mta_relay_flags(ep->agent.mta.relay.flags, 835 buf, len); 836 837 if (strcasecmp(field, "mta-relay-heloname") == 0) 838 return ascii_dump_string(ep->agent.mta.relay.heloname, 839 buf, len); 840 841 if (strcasecmp(field, "mta-relay-helotable") == 0) 842 return ascii_dump_string(ep->agent.mta.relay.helotable, 843 buf, len); 844 845 if (strcasecmp(field, "mta-relay-source") == 0) 846 return ascii_dump_string(ep->agent.mta.relay.sourcetable, 847 buf, len); 848 849 if (strcasecmp(field, "retry") == 0) 850 return ascii_dump_uint16(ep->retry, buf, len); 851 852 if (strcasecmp(field, "rcpt") == 0) 853 return ascii_dump_mailaddr(&ep->rcpt, buf, len); 854 855 if (strcasecmp(field, "sender") == 0) 856 return ascii_dump_mailaddr(&ep->sender, buf, len); 857 858 if (strcasecmp(field, "smtpname") == 0) 859 return ascii_dump_string(ep->smtpname, buf, len); 860 861 if (strcasecmp(field, "sockaddr") == 0) 862 return ascii_dump_string(ss_to_text(&ep->ss), buf, len); 863 864 if (strcasecmp(field, "tag") == 0) 865 return ascii_dump_string(ep->tag, buf, len); 866 867 if (strcasecmp(field, "type") == 0) 868 return ascii_dump_type(ep->type, buf, len); 869 870 if (strcasecmp(field, "version") == 0) 871 return ascii_dump_uint32(SMTPD_ENVELOPE_VERSION, buf, len); 872 873 if (strcasecmp(field, "dsn-notify") == 0) 874 return ascii_dump_uint8(ep->dsn_notify, buf, len); 875 876 if (strcasecmp(field, "dsn-ret") == 0) 877 return ascii_dump_dsn_ret(ep->dsn_ret, buf, len); 878 879 if (strcasecmp(field, "dsn-orcpt") == 0) { 880 if (ep->dsn_orcpt.user[0] && ep->dsn_orcpt.domain[0]) 881 return ascii_dump_mailaddr(&ep->dsn_orcpt, buf, len); 882 return 1; 883 } 884 885 if (strcasecmp(field, "dsn-envid") == 0) 886 return ascii_dump_string(ep->dsn_envid, buf, len); 887 888 if (strcasecmp(field, "esc-class") == 0) { 889 if (ep->esc_class) 890 return ascii_dump_uint8(ep->esc_class, buf, len); 891 return 1; 892 } 893 894 if (strcasecmp(field, "esc-code") == 0) { 895 if (ep->esc_class) 896 return ascii_dump_uint8(ep->esc_code, buf, len); 897 return 1; 898 } 899 900 return (0); 901 } 902 903 static void 904 envelope_ascii_dump(const struct envelope *ep, char **dest, size_t *len, const char *field) 905 { 906 char buf[8192]; 907 int l; 908 909 if (*dest == NULL) 910 return; 911 912 memset(buf, 0, sizeof buf); 913 if (! ascii_dump_field(field, ep, buf, sizeof buf)) 914 goto err; 915 if (buf[0] == '\0') 916 return; 917 918 l = snprintf(*dest, *len, "%s: %s\n", field, buf); 919 if (l == -1 || (size_t) l >= *len) 920 goto err; 921 *dest += l; 922 *len -= l; 923 924 return; 925 err: 926 *dest = NULL; 927 } 928 929 static int 930 envelope_upgrade_v1(struct dict *d) 931 { 932 static char buf_relay[1024]; 933 char *val; 934 935 /* 936 * very very old envelopes had a "msgid" field 937 */ 938 dict_pop(d, "msgid"); 939 940 /* 941 * rename "mta-relay-helo" field to "mta-relay-helotable" 942 */ 943 if ((val = dict_get(d, "mta-relay-helo"))) { 944 dict_xset(d, "mta-relay-helotable", val); 945 dict_xpop(d, "mta-relay-helo"); 946 } 947 948 /* 949 * "ssl" becomes "secure" in "mta-relay" scheme 950 */ 951 if ((val = dict_get(d, "mta-relay"))) { 952 if (strncasecmp("ssl://", val, 6) == 0) { 953 if (! bsnprintf(buf_relay, sizeof(buf_relay), "secure://%s", val+6)) 954 return (0); 955 dict_set(d, "mta-relay", buf_relay); 956 } 957 else if (strncasecmp("ssl+auth://", val, 11) == 0) { 958 if (! bsnprintf(buf_relay, sizeof(buf_relay), "secure+auth://%s", val+11)) 959 return (0); 960 dict_set(d, "mta-relay", buf_relay); 961 } 962 } 963 964 return (1); 965 } 966