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