1 /* $OpenBSD: smtp_client.c,v 1.10 2019/06/12 17:42:53 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2018 Eric Faurot <eric@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 22 #include <netinet/in.h> 23 24 #include <ctype.h> 25 #include <errno.h> 26 #include <limits.h> 27 #include <resolv.h> 28 #include <stdarg.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "log.h" 34 #include "ioev.h" 35 #include "smtp.h" 36 37 #define TRACE_SMTPCLT 2 38 #define TRACE_IO 3 39 40 enum { 41 STATE_INIT = 0, 42 STATE_BANNER, 43 STATE_EHLO, 44 STATE_HELO, 45 STATE_LHLO, 46 STATE_STARTTLS, 47 STATE_AUTH, 48 STATE_AUTH_PLAIN, 49 STATE_AUTH_LOGIN, 50 STATE_AUTH_LOGIN_USER, 51 STATE_AUTH_LOGIN_PASS, 52 STATE_READY, 53 STATE_MAIL, 54 STATE_RCPT, 55 STATE_DATA, 56 STATE_BODY, 57 STATE_EOM, 58 STATE_RSET, 59 STATE_QUIT, 60 61 STATE_LAST 62 }; 63 64 #define base64_encode __b64_ntop 65 #define base64_decode __b64_pton 66 67 #define FLAG_TLS 0x01 68 #define FLAG_TLS_VERIFIED 0x02 69 70 #define SMTP_EXT_STARTTLS 0x01 71 #define SMTP_EXT_PIPELINING 0x02 72 #define SMTP_EXT_AUTH 0x04 73 #define SMTP_EXT_AUTH_PLAIN 0x08 74 #define SMTP_EXT_AUTH_LOGIN 0x10 75 #define SMTP_EXT_DSN 0x20 76 #define SMTP_EXT_SIZE 0x40 77 78 struct smtp_client { 79 void *tag; 80 struct smtp_params params; 81 82 int state; 83 int flags; 84 int ext; 85 size_t ext_size; 86 87 struct io *io; 88 char *reply; 89 size_t replysz; 90 91 struct smtp_mail *mail; 92 int rcptidx; 93 int rcptok; 94 }; 95 96 void log_trace_verbose(int); 97 void log_trace(int, const char *, ...) 98 __attribute__((format (printf, 2, 3))); 99 100 static void smtp_client_io(struct io *, int, void *); 101 static void smtp_client_free(struct smtp_client *); 102 static void smtp_client_state(struct smtp_client *, int); 103 static void smtp_client_abort(struct smtp_client *, int, const char *); 104 static void smtp_client_cancel(struct smtp_client *, int, const char *); 105 static void smtp_client_sendcmd(struct smtp_client *, char *, ...); 106 static void smtp_client_sendbody(struct smtp_client *); 107 static int smtp_client_readline(struct smtp_client *); 108 static int smtp_client_replycat(struct smtp_client *, const char *); 109 static void smtp_client_response(struct smtp_client *, const char *); 110 static void smtp_client_mail_abort(struct smtp_client *); 111 static void smtp_client_mail_status(struct smtp_client *, const char *); 112 static void smtp_client_rcpt_status(struct smtp_client *, struct smtp_rcpt *, const char *); 113 114 static const char *strstate[STATE_LAST] = { 115 "INIT", 116 "BANNER", 117 "EHLO", 118 "HELO", 119 "LHLO", 120 "STARTTLS", 121 "AUTH", 122 "AUTH_PLAIN", 123 "AUTH_LOGIN", 124 "AUTH_LOGIN_USER", 125 "AUTH_LOGIN_PASS", 126 "READY", 127 "MAIL", 128 "RCPT", 129 "DATA", 130 "BODY", 131 "EOM", 132 "RSET", 133 "QUIT", 134 }; 135 136 struct smtp_client * 137 smtp_connect(const struct smtp_params *params, void *tag) 138 { 139 struct smtp_client *proto; 140 141 proto = calloc(1, sizeof *proto); 142 if (proto == NULL) 143 return NULL; 144 145 memmove(&proto->params, params, sizeof(*params)); 146 proto->tag = tag; 147 proto->io = io_new(); 148 if (proto->io == NULL) { 149 free(proto); 150 return NULL; 151 } 152 io_set_callback(proto->io, smtp_client_io, proto); 153 io_set_timeout(proto->io, proto->params.timeout); 154 155 if (io_connect(proto->io, proto->params.dst, proto->params.src) == -1) { 156 smtp_client_abort(proto, FAIL_CONN, io_error(proto->io)); 157 return NULL; 158 } 159 160 return proto; 161 } 162 163 void 164 smtp_cert_verified(struct smtp_client *proto, int verified) 165 { 166 if (verified == CERT_OK) 167 proto->flags |= FLAG_TLS_VERIFIED; 168 169 else if (proto->params.tls_verify) { 170 errno = EAUTH; 171 smtp_client_cancel(proto, FAIL_CONN, 172 "Invalid server certificate"); 173 return; 174 } 175 176 io_resume(proto->io, IO_IN); 177 178 if (proto->state == STATE_INIT) 179 smtp_client_state(proto, STATE_BANNER); 180 else { 181 /* Clear extensions before re-issueing an EHLO command. */ 182 proto->ext = 0; 183 smtp_client_state(proto, STATE_EHLO); 184 } 185 } 186 187 void 188 smtp_quit(struct smtp_client *proto) 189 { 190 if (proto->state != STATE_READY) 191 fatalx("connection is not ready"); 192 193 smtp_client_state(proto, STATE_QUIT); 194 } 195 196 void 197 smtp_sendmail(struct smtp_client *proto, struct smtp_mail *mail) 198 { 199 if (proto->state != STATE_READY) 200 fatalx("connection is not ready"); 201 202 proto->mail = mail; 203 smtp_client_state(proto, STATE_MAIL); 204 } 205 206 static void 207 smtp_client_free(struct smtp_client *proto) 208 { 209 if (proto->mail) 210 fatalx("current task should have been deleted already"); 211 212 smtp_closed(proto->tag, proto); 213 214 if (proto->io) 215 io_free(proto->io); 216 217 free(proto->reply); 218 free(proto); 219 } 220 221 /* 222 * End the session immediatly. 223 */ 224 static void 225 smtp_client_abort(struct smtp_client *proto, int err, const char *reason) 226 { 227 smtp_failed(proto->tag, proto, err, reason); 228 229 if (proto->mail) 230 smtp_client_mail_abort(proto); 231 232 smtp_client_free(proto); 233 } 234 235 /* 236 * Properly close the session. 237 */ 238 static void 239 smtp_client_cancel(struct smtp_client *proto, int err, const char *reason) 240 { 241 if (proto->mail) 242 fatal("not supposed to have a mail"); 243 244 smtp_failed(proto->tag, proto, err, reason); 245 246 smtp_client_state(proto, STATE_QUIT); 247 } 248 249 static void 250 smtp_client_state(struct smtp_client *proto, int newstate) 251 { 252 struct smtp_rcpt *rcpt; 253 char ibuf[LINE_MAX], obuf[LINE_MAX]; 254 size_t n; 255 int oldstate; 256 257 if (proto->reply) 258 proto->reply[0] = '\0'; 259 260 again: 261 oldstate = proto->state; 262 proto->state = newstate; 263 264 log_trace(TRACE_SMTPCLT, "%p: %s -> %s", proto, 265 strstate[oldstate], 266 strstate[newstate]); 267 268 /* don't try this at home! */ 269 #define smtp_client_state(_s, _st) do { newstate = _st; goto again; } while (0) 270 271 switch (proto->state) { 272 case STATE_BANNER: 273 io_set_read(proto->io); 274 break; 275 276 case STATE_EHLO: 277 smtp_client_sendcmd(proto, "EHLO %s", proto->params.helo); 278 break; 279 280 case STATE_HELO: 281 smtp_client_sendcmd(proto, "HELO %s", proto->params.helo); 282 break; 283 284 case STATE_LHLO: 285 smtp_client_sendcmd(proto, "LHLO %s", proto->params.helo); 286 break; 287 288 case STATE_STARTTLS: 289 if (proto->params.tls_req == TLS_NO || proto->flags & FLAG_TLS) 290 smtp_client_state(proto, STATE_AUTH); 291 else if (proto->ext & SMTP_EXT_STARTTLS) 292 smtp_client_sendcmd(proto, "STARTTLS"); 293 else if (proto->params.tls_req == TLS_FORCE) 294 smtp_client_cancel(proto, FAIL_IMPL, 295 "TLS not supported by remote host"); 296 else 297 smtp_client_state(proto, STATE_AUTH); 298 break; 299 300 case STATE_AUTH: 301 if (!proto->params.auth_user) 302 smtp_client_state(proto, STATE_READY); 303 else if ((proto->flags & FLAG_TLS) == 0) 304 smtp_client_cancel(proto, FAIL_IMPL, 305 "Authentication requires TLS"); 306 else if ((proto->ext & SMTP_EXT_AUTH) == 0) 307 smtp_client_cancel(proto, FAIL_IMPL, 308 "AUTH not supported by remote host"); 309 else if (proto->ext & SMTP_EXT_AUTH_PLAIN) 310 smtp_client_state(proto, STATE_AUTH_PLAIN); 311 else if (proto->ext & SMTP_EXT_AUTH_LOGIN) 312 smtp_client_state(proto, STATE_AUTH_LOGIN); 313 else 314 smtp_client_cancel(proto, FAIL_IMPL, 315 "No supported AUTH method"); 316 break; 317 318 case STATE_AUTH_PLAIN: 319 (void)strlcpy(ibuf, "-", sizeof(ibuf)); 320 (void)strlcat(ibuf, proto->params.auth_user, sizeof(ibuf)); 321 if (strlcat(ibuf, ":", sizeof(ibuf)) >= sizeof(ibuf)) { 322 errno = EMSGSIZE; 323 smtp_client_cancel(proto, FAIL_INTERNAL, 324 "credentials too large"); 325 break; 326 } 327 n = strlcat(ibuf, proto->params.auth_pass, sizeof(ibuf)); 328 if (n >= sizeof(ibuf)) { 329 errno = EMSGSIZE; 330 smtp_client_cancel(proto, FAIL_INTERNAL, 331 "credentials too large"); 332 break; 333 } 334 *strchr(ibuf, ':') = '\0'; 335 ibuf[0] = '\0'; 336 if (base64_encode(ibuf, n, obuf, sizeof(obuf)) == -1) { 337 errno = EMSGSIZE; 338 smtp_client_cancel(proto, FAIL_INTERNAL, 339 "credentials too large"); 340 break; 341 } 342 smtp_client_sendcmd(proto, "AUTH PLAIN %s", obuf); 343 explicit_bzero(ibuf, sizeof ibuf); 344 explicit_bzero(obuf, sizeof obuf); 345 break; 346 347 case STATE_AUTH_LOGIN: 348 smtp_client_sendcmd(proto, "AUTH LOGIN"); 349 break; 350 351 case STATE_AUTH_LOGIN_USER: 352 if (base64_encode(proto->params.auth_user, 353 strlen(proto->params.auth_user), obuf, 354 sizeof(obuf)) == -1) { 355 errno = EMSGSIZE; 356 smtp_client_cancel(proto, FAIL_INTERNAL, 357 "credentials too large"); 358 break; 359 } 360 smtp_client_sendcmd(proto, "%s", obuf); 361 explicit_bzero(obuf, sizeof obuf); 362 break; 363 364 case STATE_AUTH_LOGIN_PASS: 365 if (base64_encode(proto->params.auth_pass, 366 strlen(proto->params.auth_pass), obuf, 367 sizeof(obuf)) == -1) { 368 errno = EMSGSIZE; 369 smtp_client_cancel(proto, FAIL_INTERNAL, 370 "credentials too large"); 371 break; 372 } 373 smtp_client_sendcmd(proto, "%s", obuf); 374 explicit_bzero(obuf, sizeof obuf); 375 break; 376 377 case STATE_READY: 378 smtp_ready(proto->tag, proto); 379 break; 380 381 case STATE_MAIL: 382 if (proto->ext & SMTP_EXT_DSN) 383 smtp_client_sendcmd(proto, "MAIL FROM:<%s>%s%s%s%s", 384 proto->mail->from, 385 proto->mail->dsn_ret ? " RET=" : "", 386 proto->mail->dsn_ret ? proto->mail->dsn_ret : "", 387 proto->mail->dsn_envid ? " ENVID=" : "", 388 proto->mail->dsn_envid ? proto->mail->dsn_envid : ""); 389 else 390 smtp_client_sendcmd(proto, "MAIL FROM:<%s>", 391 proto->mail->from); 392 break; 393 394 case STATE_RCPT: 395 if (proto->rcptidx == proto->mail->rcptcount) { 396 smtp_client_state(proto, STATE_DATA); 397 break; 398 } 399 rcpt = &proto->mail->rcpt[proto->rcptidx]; 400 if (proto->ext & SMTP_EXT_DSN) 401 smtp_client_sendcmd(proto, "RCPT TO:<%s>%s%s%s%s", 402 rcpt->to, 403 rcpt->dsn_notify ? " NOTIFY=" : "", 404 rcpt->dsn_notify ? rcpt->dsn_notify : "", 405 rcpt->dsn_orcpt ? " ORCPT=" : "", 406 rcpt->dsn_orcpt ? rcpt->dsn_orcpt : ""); 407 else 408 smtp_client_sendcmd(proto, "RCPT TO:<%s>", rcpt->to); 409 break; 410 411 case STATE_DATA: 412 if (proto->rcptok == 0) { 413 smtp_client_mail_abort(proto); 414 smtp_client_state(proto, STATE_RSET); 415 } 416 else 417 smtp_client_sendcmd(proto, "DATA"); 418 break; 419 420 case STATE_BODY: 421 fseek(proto->mail->fp, 0, SEEK_SET); 422 smtp_client_sendbody(proto); 423 break; 424 425 case STATE_EOM: 426 smtp_client_sendcmd(proto, "."); 427 break; 428 429 case STATE_RSET: 430 smtp_client_sendcmd(proto, "RSET"); 431 break; 432 433 case STATE_QUIT: 434 smtp_client_sendcmd(proto, "QUIT"); 435 break; 436 437 default: 438 fatalx("%s: bad state %d", __func__, proto->state); 439 } 440 #undef smtp_client_state 441 } 442 443 /* 444 * Handle a response to an SMTP command 445 */ 446 static void 447 smtp_client_response(struct smtp_client *proto, const char *line) 448 { 449 struct smtp_rcpt *rcpt; 450 int i, seen; 451 452 switch (proto->state) { 453 case STATE_BANNER: 454 if (line[0] != '2') 455 smtp_client_abort(proto, FAIL_RESP, line); 456 else if (proto->params.lmtp) 457 smtp_client_state(proto, STATE_LHLO); 458 else 459 smtp_client_state(proto, STATE_EHLO); 460 break; 461 462 case STATE_EHLO: 463 if (line[0] != '2') { 464 /* 465 * Either rejected or not implemented. If we want to 466 * use EHLO extensions, report an SMTP error. 467 * Otherwise, fallback to using HELO. 468 */ 469 if ((proto->params.tls_req == TLS_FORCE) || 470 (proto->params.auth_user)) 471 smtp_client_cancel(proto, FAIL_RESP, line); 472 else 473 smtp_client_state(proto, STATE_HELO); 474 break; 475 } 476 smtp_client_state(proto, STATE_STARTTLS); 477 break; 478 479 case STATE_HELO: 480 if (line[0] != '2') 481 smtp_client_cancel(proto, FAIL_RESP, line); 482 else 483 smtp_client_state(proto, STATE_READY); 484 break; 485 486 case STATE_LHLO: 487 if (line[0] != '2') 488 smtp_client_cancel(proto, FAIL_RESP, line); 489 else 490 smtp_client_state(proto, STATE_READY); 491 break; 492 493 case STATE_STARTTLS: 494 if (line[0] != '2') { 495 if ((proto->params.tls_req == TLS_FORCE) || 496 (proto->params.auth_user)) { 497 smtp_client_cancel(proto, FAIL_RESP, line); 498 break; 499 } 500 smtp_client_state(proto, STATE_AUTH); 501 } 502 else 503 io_start_tls(proto->io, proto->params.tls_ctx); 504 break; 505 506 case STATE_AUTH_PLAIN: 507 if (line[0] != '2') 508 smtp_client_cancel(proto, FAIL_RESP, line); 509 else 510 smtp_client_state(proto, STATE_READY); 511 break; 512 513 case STATE_AUTH_LOGIN: 514 if (strncmp(line, "334 ", 4)) 515 smtp_client_cancel(proto, FAIL_RESP, line); 516 else 517 smtp_client_state(proto, STATE_AUTH_LOGIN_USER); 518 break; 519 520 case STATE_AUTH_LOGIN_USER: 521 if (strncmp(line, "334 ", 4)) 522 smtp_client_cancel(proto, FAIL_RESP, line); 523 else 524 smtp_client_state(proto, STATE_AUTH_LOGIN_PASS); 525 break; 526 527 case STATE_AUTH_LOGIN_PASS: 528 if (line[0] != '2') 529 smtp_client_cancel(proto, FAIL_RESP, line); 530 else 531 smtp_client_state(proto, STATE_READY); 532 break; 533 534 case STATE_MAIL: 535 if (line[0] != '2') { 536 smtp_client_mail_status(proto, line); 537 smtp_client_state(proto, STATE_RSET); 538 } 539 else 540 smtp_client_state(proto, STATE_RCPT); 541 break; 542 543 case STATE_RCPT: 544 rcpt = &proto->mail->rcpt[proto->rcptidx++]; 545 if (line[0] != '2') 546 smtp_client_rcpt_status(proto, rcpt, line); 547 else { 548 proto->rcptok++; 549 smtp_client_state(proto, STATE_RCPT); 550 } 551 break; 552 553 case STATE_DATA: 554 if (line[0] != '2' && line[0] != '3') { 555 smtp_client_mail_status(proto, line); 556 smtp_client_state(proto, STATE_RSET); 557 } 558 else 559 smtp_client_state(proto, STATE_BODY); 560 break; 561 562 case STATE_EOM: 563 if (proto->params.lmtp) { 564 /* 565 * LMTP reports a status of each accepted RCPT. 566 * Report status for the first pending RCPT and read 567 * more lines if another rcpt needs a status. 568 */ 569 for (i = 0, seen = 0; i < proto->mail->rcptcount; i++) { 570 rcpt = &proto->mail->rcpt[i]; 571 if (rcpt->done) 572 continue; 573 if (seen) { 574 io_set_read(proto->io); 575 return; 576 } 577 smtp_client_rcpt_status(proto, 578 &proto->mail->rcpt[i], line); 579 seen = 1; 580 } 581 } 582 smtp_client_mail_status(proto, line); 583 smtp_client_state(proto, STATE_READY); 584 break; 585 586 case STATE_RSET: 587 if (line[0] != '2') 588 smtp_client_cancel(proto, FAIL_RESP, line); 589 else 590 smtp_client_state(proto, STATE_READY); 591 break; 592 593 case STATE_QUIT: 594 smtp_client_free(proto); 595 break; 596 597 default: 598 fatalx("%s: bad state %d", __func__, proto->state); 599 } 600 } 601 602 static void 603 smtp_client_io(struct io *io, int evt, void *arg) 604 { 605 struct smtp_client *proto = arg; 606 607 log_trace(TRACE_IO, "%p: %s %s", proto, io_strevent(evt), io_strio(io)); 608 609 switch (evt) { 610 case IO_CONNECTED: 611 if (proto->params.tls_req == TLS_SMTPS) { 612 io_set_write(io); 613 io_start_tls(proto->io, proto->params.tls_ctx); 614 } 615 else 616 smtp_client_state(proto, STATE_BANNER); 617 break; 618 619 case IO_TLSREADY: 620 proto->flags |= FLAG_TLS; 621 io_pause(proto->io, IO_IN); 622 smtp_verify_server_cert(proto->tag, proto, io_tls(proto->io)); 623 break; 624 625 case IO_DATAIN: 626 while (smtp_client_readline(proto)) 627 ; 628 break; 629 630 case IO_LOWAT: 631 if (proto->state == STATE_BODY) 632 smtp_client_sendbody(proto); 633 else 634 io_set_read(io); 635 break; 636 637 case IO_TIMEOUT: 638 errno = ETIMEDOUT; 639 smtp_client_abort(proto, FAIL_CONN, "Connection timeout"); 640 break; 641 642 case IO_ERROR: 643 smtp_client_abort(proto, FAIL_CONN, io_error(io)); 644 break; 645 646 case IO_TLSERROR: 647 smtp_client_abort(proto, FAIL_CONN, io_error(io)); 648 break; 649 650 case IO_DISCONNECTED: 651 smtp_client_abort(proto, FAIL_CONN, io_error(io)); 652 break; 653 654 default: 655 fatalx("%s: bad event %d", __func__, evt); 656 } 657 } 658 659 /* 660 * return 1 if a new line is expected. 661 */ 662 static int 663 smtp_client_readline(struct smtp_client *proto) 664 { 665 const char *e; 666 size_t len; 667 char *line, *msg, *p; 668 int cont; 669 670 line = io_getline(proto->io, &len); 671 if (line == NULL) { 672 if (io_datalen(proto->io) >= proto->params.linemax) 673 smtp_client_abort(proto, FAIL_PROTO, "Line too long"); 674 return 0; 675 } 676 677 log_trace(TRACE_SMTPCLT, "%p: <<< %s", proto, line); 678 679 /* Validate SMTP */ 680 if (len > 3) { 681 msg = line + 4; 682 cont = (line[3] == '-'); 683 } else if (len == 3) { 684 msg = line + 3; 685 cont = 0; 686 } else { 687 smtp_client_abort(proto, FAIL_PROTO, "Response too short"); 688 return 0; 689 } 690 691 /* Validate reply code. */ 692 if (line[0] < '2' || line[0] > '5' || !isdigit((unsigned char)line[1]) || 693 !isdigit((unsigned char)line[2])) { 694 smtp_client_abort(proto, FAIL_PROTO, "Invalid reply code"); 695 return 0; 696 } 697 698 /* Validate reply message. */ 699 for (p = msg; *p; p++) 700 if (!isprint((unsigned char)*p)) { 701 smtp_client_abort(proto, FAIL_PROTO, 702 "Non-printable characters in response"); 703 return 0; 704 } 705 706 /* Read extensions. */ 707 if (proto->state == STATE_EHLO) { 708 if (strcmp(msg, "STARTTLS") == 0) 709 proto->ext |= SMTP_EXT_STARTTLS; 710 else if (strncmp(msg, "AUTH ", 5) == 0) { 711 proto->ext |= SMTP_EXT_AUTH; 712 if ((p = strstr(msg, " PLAIN")) && 713 (*(p+6) == '\0' || *(p+6) == ' ')) 714 proto->ext |= SMTP_EXT_AUTH_PLAIN; 715 if ((p = strstr(msg, " LOGIN")) && 716 (*(p+6) == '\0' || *(p+6) == ' ')) 717 proto->ext |= SMTP_EXT_AUTH_LOGIN; 718 } 719 else if (strcmp(msg, "PIPELINING") == 0) 720 proto->ext |= SMTP_EXT_PIPELINING; 721 else if (strcmp(msg, "DSN") == 0) 722 proto->ext |= SMTP_EXT_DSN; 723 else if (strncmp(msg, "SIZE ", 5) == 0) { 724 proto->ext_size = strtonum(msg + 5, 0, SIZE_T_MAX, &e); 725 if (e == NULL) 726 proto->ext |= SMTP_EXT_SIZE; 727 } 728 } 729 730 if (smtp_client_replycat(proto, line) == -1) { 731 smtp_client_abort(proto, FAIL_INTERNAL, NULL); 732 return 0; 733 } 734 735 if (cont) 736 return 1; 737 738 if (io_datalen(proto->io)) { 739 /* 740 * There should be no pending data after a response is read, 741 * except for the multiple status lines after a LMTP message. 742 * It can also happen with pipelineing, but we don't do that 743 * for now. 744 */ 745 if (!(proto->params.lmtp && proto->state == STATE_EOM)) { 746 smtp_client_abort(proto, FAIL_PROTO, "Trailing data"); 747 return 0; 748 } 749 } 750 751 io_set_write(proto->io); 752 smtp_client_response(proto, proto->reply); 753 return 0; 754 } 755 756 /* 757 * Concatenate the given response line. 758 */ 759 static int 760 smtp_client_replycat(struct smtp_client *proto, const char *line) 761 { 762 size_t len; 763 char *tmp; 764 int first; 765 766 if (proto->reply && proto->reply[0]) { 767 /* 768 * If the line is the continuation of an multi-line response, 769 * skip the status and ESC parts. First, skip the status, then 770 * skip the separator amd ESC if found. 771 */ 772 first = 0; 773 line += 3; 774 if (line[0]) { 775 line += 1; 776 if (isdigit((int)line[0]) && line[1] == '.' && 777 isdigit((int)line[2]) && line[3] == '.' && 778 isdigit((int)line[4]) && isspace((int)line[5])) 779 line += 5; 780 } 781 } else 782 first = 1; 783 784 if (proto->reply) { 785 len = strlcat(proto->reply, line, proto->replysz); 786 if (len < proto->replysz) 787 return 0; 788 } 789 else 790 len = strlen(line); 791 792 if (len > proto->params.ibufmax) { 793 errno = EMSGSIZE; 794 return -1; 795 } 796 797 /* Allocate by multiples of 2^8 */ 798 len += (len % 256) ? (256 - (len % 256)) : 0; 799 800 tmp = realloc(proto->reply, len); 801 if (tmp == NULL) 802 return -1; 803 if (proto->reply == NULL) 804 tmp[0] = '\0'; 805 806 proto->reply = tmp; 807 proto->replysz = len; 808 (void)strlcat(proto->reply, line, proto->replysz); 809 810 /* Replace the separator with a space for the first line. */ 811 if (first && proto->reply[3]) 812 proto->reply[3] = ' '; 813 814 return 0; 815 } 816 817 static void 818 smtp_client_sendbody(struct smtp_client *proto) 819 { 820 ssize_t len; 821 size_t sz = 0, total, w; 822 char *ln = NULL; 823 int n; 824 825 total = io_queued(proto->io); 826 w = 0; 827 828 while (total < proto->params.obufmax) { 829 if ((len = getline(&ln, &sz, proto->mail->fp)) == -1) 830 break; 831 if (ln[len - 1] == '\n') 832 ln[len - 1] = '\0'; 833 n = io_printf(proto->io, "%s%s\r\n", *ln == '.'?".":"", ln); 834 if (n == -1) { 835 free(ln); 836 smtp_client_abort(proto, FAIL_INTERNAL, NULL); 837 return; 838 } 839 total += n; 840 w += n; 841 } 842 free(ln); 843 844 if (ferror(proto->mail->fp)) { 845 smtp_client_abort(proto, FAIL_INTERNAL, "Cannot read message"); 846 return; 847 } 848 849 log_trace(TRACE_SMTPCLT, "%p: >>> [...%zd bytes...]", proto, w); 850 851 if (feof(proto->mail->fp)) 852 smtp_client_state(proto, STATE_EOM); 853 } 854 855 static void 856 smtp_client_sendcmd(struct smtp_client *proto, char *fmt, ...) 857 { 858 va_list ap; 859 char *p; 860 int len; 861 862 va_start(ap, fmt); 863 len = vasprintf(&p, fmt, ap); 864 va_end(ap); 865 866 if (len == -1) { 867 smtp_client_abort(proto, FAIL_INTERNAL, NULL); 868 return; 869 } 870 871 log_trace(TRACE_SMTPCLT, "mta: %p: >>> %s", proto, p); 872 873 len = io_printf(proto->io, "%s\r\n", p); 874 free(p); 875 876 if (len == -1) 877 smtp_client_abort(proto, FAIL_INTERNAL, NULL); 878 } 879 880 static void 881 smtp_client_mail_status(struct smtp_client *proto, const char *status) 882 { 883 int i; 884 885 for (i = 0; i < proto->mail->rcptcount; i++) 886 smtp_client_rcpt_status(proto, &proto->mail->rcpt[i], status); 887 888 smtp_done(proto->tag, proto, proto->mail); 889 proto->mail = NULL; 890 } 891 892 static void 893 smtp_client_mail_abort(struct smtp_client *proto) 894 { 895 smtp_done(proto->tag, proto, proto->mail); 896 proto->mail = NULL; 897 } 898 899 static void 900 smtp_client_rcpt_status(struct smtp_client *proto, struct smtp_rcpt *rcpt, const char *line) 901 { 902 struct smtp_status status; 903 904 if (rcpt->done) 905 return; 906 907 rcpt->done = 1; 908 status.rcpt = rcpt; 909 status.cmd = strstate[proto->state]; 910 status.status = line; 911 smtp_status(proto->tag, proto, &status); 912 } 913