1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 # include "sendmail.h" 14 15 #ifndef lint 16 #if SMTP 17 static char sccsid[] = "@(#)usersmtp.c 8.111 (Berkeley) 2/3/1999 (with SMTP)"; 18 #else 19 static char sccsid[] = "@(#)usersmtp.c 8.111 (Berkeley) 2/3/1999 (without SMTP)"; 20 #endif 21 #endif /* not lint */ 22 23 # include <sysexits.h> 24 # include <errno.h> 25 26 # if SMTP 27 28 /* 29 ** USERSMTP -- run SMTP protocol from the user end. 30 ** 31 ** This protocol is described in RFC821. 32 */ 33 34 #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 35 #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 36 #define SMTPCLOSING 421 /* "Service Shutting Down" */ 37 38 char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 39 char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 40 char SmtpError[MAXLINE] = ""; /* save failure error messages */ 41 bool SmtpNeedIntro; /* need "while talking" in transcript */ 42 43 extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); 44 extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)())); 45 /* 46 ** SMTPINIT -- initialize SMTP. 47 ** 48 ** Opens the connection and sends the initial protocol. 49 ** 50 ** Parameters: 51 ** m -- mailer to create connection to. 52 ** pvp -- pointer to parameter vector to pass to 53 ** the mailer. 54 ** 55 ** Returns: 56 ** none. 57 ** 58 ** Side Effects: 59 ** creates connection and sends initial protocol. 60 */ 61 62 void 63 smtpinit(m, mci, e) 64 MAILER *m; 65 register MCI *mci; 66 ENVELOPE *e; 67 { 68 register int r; 69 register char *p; 70 extern void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 71 extern void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 72 73 if (tTd(18, 1)) 74 { 75 printf("smtpinit "); 76 mci_dump(mci, FALSE); 77 } 78 79 /* 80 ** Open the connection to the mailer. 81 */ 82 83 SmtpError[0] = '\0'; 84 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 85 if (CurHostName == NULL) 86 CurHostName = MyHostName; 87 SmtpNeedIntro = TRUE; 88 switch (mci->mci_state) 89 { 90 case MCIS_ACTIVE: 91 /* need to clear old information */ 92 smtprset(m, mci, e); 93 /* fall through */ 94 95 case MCIS_OPEN: 96 return; 97 98 case MCIS_ERROR: 99 case MCIS_SSD: 100 /* shouldn't happen */ 101 smtpquit(m, mci, e); 102 /* fall through */ 103 104 case MCIS_CLOSED: 105 syserr("451 smtpinit: state CLOSED"); 106 return; 107 108 case MCIS_OPENING: 109 break; 110 } 111 112 mci->mci_state = MCIS_OPENING; 113 114 /* 115 ** Get the greeting message. 116 ** This should appear spontaneously. Give it five minutes to 117 ** happen. 118 */ 119 120 SmtpPhase = mci->mci_phase = "client greeting"; 121 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 122 r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); 123 if (r < 0) 124 goto tempfail1; 125 if (REPLYTYPE(r) == 4) 126 goto tempfail2; 127 if (REPLYTYPE(r) != 2) 128 goto unavailable; 129 130 /* 131 ** Send the HELO command. 132 ** My mother taught me to always introduce myself. 133 */ 134 135 if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags)) 136 mci->mci_flags |= MCIF_ESMTP; 137 138 tryhelo: 139 if (bitnset(M_LMTP, m->m_flags)) 140 { 141 smtpmessage("LHLO %s", m, mci, MyHostName); 142 SmtpPhase = mci->mci_phase = "client LHLO"; 143 } 144 else if (bitset(MCIF_ESMTP, mci->mci_flags)) 145 { 146 smtpmessage("EHLO %s", m, mci, MyHostName); 147 SmtpPhase = mci->mci_phase = "client EHLO"; 148 } 149 else 150 { 151 smtpmessage("HELO %s", m, mci, MyHostName); 152 SmtpPhase = mci->mci_phase = "client HELO"; 153 } 154 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 155 r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 156 if (r < 0) 157 goto tempfail1; 158 else if (REPLYTYPE(r) == 5) 159 { 160 if (bitset(MCIF_ESMTP, mci->mci_flags) && 161 !bitnset(M_LMTP, m->m_flags)) 162 { 163 /* try old SMTP instead */ 164 mci->mci_flags &= ~MCIF_ESMTP; 165 goto tryhelo; 166 } 167 goto unavailable; 168 } 169 else if (REPLYTYPE(r) != 2) 170 goto tempfail2; 171 172 /* 173 ** Check to see if we actually ended up talking to ourself. 174 ** This means we didn't know about an alias or MX, or we managed 175 ** to connect to an echo server. 176 */ 177 178 p = strchr(&SmtpReplyBuffer[4], ' '); 179 if (p != NULL) 180 *p = '\0'; 181 if (!bitnset(M_NOLOOPCHECK, m->m_flags) && 182 !bitnset(M_LMTP, m->m_flags) && 183 strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 184 { 185 syserr("553 %s config error: mail loops back to me (MX problem?)", 186 CurHostName); 187 mci_setstat(mci, EX_CONFIG, NULL, NULL); 188 mci->mci_errno = 0; 189 smtpquit(m, mci, e); 190 return; 191 } 192 193 /* 194 ** If this is expected to be another sendmail, send some internal 195 ** commands. 196 */ 197 198 if (bitnset(M_INTERNAL, m->m_flags)) 199 { 200 /* tell it to be verbose */ 201 smtpmessage("VERB", m, mci); 202 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 203 if (r < 0) 204 goto tempfail1; 205 } 206 207 if (mci->mci_state != MCIS_CLOSED) 208 { 209 mci->mci_state = MCIS_OPEN; 210 return; 211 } 212 213 /* got a 421 error code during startup */ 214 215 tempfail1: 216 if (mci->mci_errno == 0) 217 mci->mci_errno = errno; 218 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 219 if (mci->mci_state != MCIS_CLOSED) 220 smtpquit(m, mci, e); 221 return; 222 223 tempfail2: 224 if (mci->mci_errno == 0) 225 mci->mci_errno = errno; 226 /* XXX should use code from other end iff ENHANCEDSTATUSCODES */ 227 mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer); 228 if (mci->mci_state != MCIS_CLOSED) 229 smtpquit(m, mci, e); 230 return; 231 232 unavailable: 233 mci->mci_errno = errno; 234 mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer); 235 smtpquit(m, mci, e); 236 return; 237 } 238 /* 239 ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 240 ** 241 ** Parameters: 242 ** line -- the response line. 243 ** firstline -- set if this is the first line of the reply. 244 ** m -- the mailer. 245 ** mci -- the mailer connection info. 246 ** e -- the envelope. 247 ** 248 ** Returns: 249 ** none. 250 */ 251 252 void 253 esmtp_check(line, firstline, m, mci, e) 254 char *line; 255 bool firstline; 256 MAILER *m; 257 register MCI *mci; 258 ENVELOPE *e; 259 { 260 if (strstr(line, "ESMTP") != NULL) 261 mci->mci_flags |= MCIF_ESMTP; 262 if (strstr(line, "8BIT-OK") != NULL) 263 mci->mci_flags |= MCIF_8BITOK; 264 } 265 /* 266 ** HELO_OPTIONS -- process the options on a HELO line. 267 ** 268 ** Parameters: 269 ** line -- the response line. 270 ** firstline -- set if this is the first line of the reply. 271 ** m -- the mailer. 272 ** mci -- the mailer connection info. 273 ** e -- the envelope. 274 ** 275 ** Returns: 276 ** none. 277 */ 278 279 void 280 helo_options(line, firstline, m, mci, e) 281 char *line; 282 bool firstline; 283 MAILER *m; 284 register MCI *mci; 285 ENVELOPE *e; 286 { 287 register char *p; 288 289 if (firstline) 290 return; 291 292 if (strlen(line) < (SIZE_T) 5) 293 return; 294 line += 4; 295 p = strchr(line, ' '); 296 if (p != NULL) 297 *p++ = '\0'; 298 if (strcasecmp(line, "size") == 0) 299 { 300 mci->mci_flags |= MCIF_SIZE; 301 if (p != NULL) 302 mci->mci_maxsize = atol(p); 303 } 304 else if (strcasecmp(line, "8bitmime") == 0) 305 { 306 mci->mci_flags |= MCIF_8BITMIME; 307 mci->mci_flags &= ~MCIF_7BIT; 308 } 309 else if (strcasecmp(line, "expn") == 0) 310 mci->mci_flags |= MCIF_EXPN; 311 else if (strcasecmp(line, "dsn") == 0) 312 mci->mci_flags |= MCIF_DSN; 313 } 314 /* 315 ** SMTPMAILFROM -- send MAIL command 316 ** 317 ** Parameters: 318 ** m -- the mailer. 319 ** mci -- the mailer connection structure. 320 ** e -- the envelope (including the sender to specify). 321 */ 322 323 int 324 smtpmailfrom(m, mci, e) 325 MAILER *m; 326 MCI *mci; 327 ENVELOPE *e; 328 { 329 int r; 330 char *bufp; 331 char *bodytype; 332 char buf[MAXNAME + 1]; 333 char optbuf[MAXLINE]; 334 335 if (tTd(18, 2)) 336 printf("smtpmailfrom: CurHost=%s\n", CurHostName); 337 338 /* set up appropriate options to include */ 339 bufp = optbuf; 340 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 341 snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize); 342 else 343 strcpy(optbuf, ""); 344 bufp = &optbuf[strlen(optbuf)]; 345 346 bodytype = e->e_bodytype; 347 if (bitset(MCIF_8BITMIME, mci->mci_flags)) 348 { 349 if (bodytype == NULL && 350 bitset(MM_MIME8BIT, MimeMode) && 351 bitset(EF_HAS8BIT, e->e_flags) && 352 !bitset(EF_DONT_MIME, e->e_flags) && 353 !bitnset(M_8BITS, m->m_flags)) 354 bodytype = "8BITMIME"; 355 if (bodytype != NULL && 356 SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7) 357 { 358 snprintf(bufp, SPACELEFT(optbuf, bufp), 359 " BODY=%s", bodytype); 360 bufp += strlen(bufp); 361 } 362 } 363 else if (bitnset(M_8BITS, m->m_flags) || 364 !bitset(EF_HAS8BIT, e->e_flags) || 365 bitset(MCIF_8BITOK, mci->mci_flags)) 366 { 367 /* just pass it through */ 368 } 369 #if MIME8TO7 370 else if (bitset(MM_CVTMIME, MimeMode) && 371 !bitset(EF_DONT_MIME, e->e_flags) && 372 (!bitset(MM_PASS8BIT, MimeMode) || 373 bitset(EF_IS_MIME, e->e_flags))) 374 { 375 /* must convert from 8bit MIME format to 7bit encoded */ 376 mci->mci_flags |= MCIF_CVT8TO7; 377 } 378 #endif 379 else if (!bitset(MM_PASS8BIT, MimeMode)) 380 { 381 /* cannot just send a 8-bit version */ 382 extern char MsgBuf[]; 383 384 usrerr("%s does not support 8BITMIME", CurHostName); 385 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf); 386 return EX_DATAERR; 387 } 388 389 if (bitset(MCIF_DSN, mci->mci_flags)) 390 { 391 if (e->e_envid != NULL && 392 SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7) 393 { 394 snprintf(bufp, SPACELEFT(optbuf, bufp), 395 " ENVID=%s", e->e_envid); 396 bufp += strlen(bufp); 397 } 398 399 /* RET= parameter */ 400 if (bitset(EF_RET_PARAM, e->e_flags) && 401 SPACELEFT(optbuf, bufp) > 9) 402 { 403 snprintf(bufp, SPACELEFT(optbuf, bufp), 404 " RET=%s", 405 bitset(EF_NO_BODY_RETN, e->e_flags) ? 406 "HDRS" : "FULL"); 407 bufp += strlen(bufp); 408 } 409 } 410 411 /* 412 ** Send the MAIL command. 413 ** Designates the sender. 414 */ 415 416 mci->mci_state = MCIS_ACTIVE; 417 418 if (bitset(EF_RESPONSE, e->e_flags) && 419 !bitnset(M_NO_NULL_FROM, m->m_flags)) 420 (void) strcpy(buf, ""); 421 else 422 expand("\201g", buf, sizeof buf, e); 423 if (buf[0] == '<') 424 { 425 /* strip off <angle brackets> (put back on below) */ 426 bufp = &buf[strlen(buf) - 1]; 427 if (*bufp == '>') 428 *bufp = '\0'; 429 bufp = &buf[1]; 430 } 431 else 432 bufp = buf; 433 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 434 !bitnset(M_FROMPATH, m->m_flags)) 435 { 436 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 437 } 438 else 439 { 440 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 441 *bufp == '@' ? ',' : ':', bufp, optbuf); 442 } 443 SmtpPhase = mci->mci_phase = "client MAIL"; 444 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 445 r = reply(m, mci, e, TimeOuts.to_mail, NULL); 446 if (r < 0) 447 { 448 /* communications failure */ 449 mci->mci_errno = errno; 450 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 451 smtpquit(m, mci, e); 452 return EX_TEMPFAIL; 453 } 454 else if (r == 421) 455 { 456 /* service shutting down */ 457 mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer); 458 smtpquit(m, mci, e); 459 return EX_TEMPFAIL; 460 } 461 else if (REPLYTYPE(r) == 4) 462 { 463 mci_setstat(mci, EX_NOTSTICKY, smtptodsn(r), SmtpReplyBuffer); 464 return EX_TEMPFAIL; 465 } 466 else if (REPLYTYPE(r) == 2) 467 { 468 return EX_OK; 469 } 470 else if (r == 501) 471 { 472 /* syntax error in arguments */ 473 mci_setstat(mci, EX_NOTSTICKY, "5.5.2", SmtpReplyBuffer); 474 return EX_DATAERR; 475 } 476 else if (r == 553) 477 { 478 /* mailbox name not allowed */ 479 mci_setstat(mci, EX_NOTSTICKY, "5.1.3", SmtpReplyBuffer); 480 return EX_DATAERR; 481 } 482 else if (r == 552) 483 { 484 /* exceeded storage allocation */ 485 mci_setstat(mci, EX_NOTSTICKY, "5.3.4", SmtpReplyBuffer); 486 if (bitset(MCIF_SIZE, mci->mci_flags)) 487 e->e_flags |= EF_NO_BODY_RETN; 488 return EX_UNAVAILABLE; 489 } 490 else if (REPLYTYPE(r) == 5) 491 { 492 /* unknown error */ 493 mci_setstat(mci, EX_NOTSTICKY, "5.0.0", SmtpReplyBuffer); 494 return EX_UNAVAILABLE; 495 } 496 497 if (LogLevel > 1) 498 { 499 sm_syslog(LOG_CRIT, e->e_id, 500 "%.100s: SMTP MAIL protocol error: %s", 501 CurHostName, 502 shortenstring(SmtpReplyBuffer, 403)); 503 } 504 505 /* protocol error -- close up */ 506 mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); 507 smtpquit(m, mci, e); 508 return EX_PROTOCOL; 509 } 510 /* 511 ** SMTPRCPT -- designate recipient. 512 ** 513 ** Parameters: 514 ** to -- address of recipient. 515 ** m -- the mailer we are sending to. 516 ** mci -- the connection info for this transaction. 517 ** e -- the envelope for this transaction. 518 ** 519 ** Returns: 520 ** exit status corresponding to recipient status. 521 ** 522 ** Side Effects: 523 ** Sends the mail via SMTP. 524 */ 525 526 int 527 smtprcpt(to, m, mci, e) 528 ADDRESS *to; 529 register MAILER *m; 530 MCI *mci; 531 ENVELOPE *e; 532 { 533 register int r; 534 char *bufp; 535 char optbuf[MAXLINE]; 536 537 strcpy(optbuf, ""); 538 bufp = &optbuf[strlen(optbuf)]; 539 if (bitset(MCIF_DSN, mci->mci_flags)) 540 { 541 /* NOTIFY= parameter */ 542 if (bitset(QHASNOTIFY, to->q_flags) && 543 bitset(QPRIMARY, to->q_flags) && 544 !bitnset(M_LOCALMAILER, m->m_flags)) 545 { 546 bool firstone = TRUE; 547 548 strcat(bufp, " NOTIFY="); 549 if (bitset(QPINGONSUCCESS, to->q_flags)) 550 { 551 strcat(bufp, "SUCCESS"); 552 firstone = FALSE; 553 } 554 if (bitset(QPINGONFAILURE, to->q_flags)) 555 { 556 if (!firstone) 557 strcat(bufp, ","); 558 strcat(bufp, "FAILURE"); 559 firstone = FALSE; 560 } 561 if (bitset(QPINGONDELAY, to->q_flags)) 562 { 563 if (!firstone) 564 strcat(bufp, ","); 565 strcat(bufp, "DELAY"); 566 firstone = FALSE; 567 } 568 if (firstone) 569 strcat(bufp, "NEVER"); 570 bufp += strlen(bufp); 571 } 572 573 /* ORCPT= parameter */ 574 if (to->q_orcpt != NULL && 575 SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7) 576 { 577 snprintf(bufp, SPACELEFT(optbuf, bufp), 578 " ORCPT=%s", to->q_orcpt); 579 bufp += strlen(bufp); 580 } 581 } 582 583 smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 584 585 SmtpPhase = mci->mci_phase = "client RCPT"; 586 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 587 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 588 to->q_rstatus = newstr(SmtpReplyBuffer); 589 to->q_status = smtptodsn(r); 590 to->q_statmta = mci->mci_host; 591 if (r < 0 || REPLYTYPE(r) == 4) 592 return EX_TEMPFAIL; 593 else if (REPLYTYPE(r) == 2) 594 return EX_OK; 595 else if (r == 550) 596 { 597 to->q_status = "5.1.1"; 598 return EX_NOUSER; 599 } 600 else if (r == 551) 601 { 602 to->q_status = "5.1.6"; 603 return EX_NOUSER; 604 } 605 else if (r == 553) 606 { 607 to->q_status = "5.1.3"; 608 return EX_NOUSER; 609 } 610 else if (REPLYTYPE(r) == 5) 611 { 612 return EX_UNAVAILABLE; 613 } 614 615 if (LogLevel > 1) 616 { 617 sm_syslog(LOG_CRIT, e->e_id, 618 "%.100s: SMTP RCPT protocol error: %s", 619 CurHostName, 620 shortenstring(SmtpReplyBuffer, 403)); 621 } 622 623 mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); 624 return EX_PROTOCOL; 625 } 626 /* 627 ** SMTPDATA -- send the data and clean up the transaction. 628 ** 629 ** Parameters: 630 ** m -- mailer being sent to. 631 ** mci -- the mailer connection information. 632 ** e -- the envelope for this message. 633 ** 634 ** Returns: 635 ** exit status corresponding to DATA command. 636 ** 637 ** Side Effects: 638 ** none. 639 */ 640 641 static jmp_buf CtxDataTimeout; 642 static void datatimeout __P((void)); 643 644 int 645 smtpdata(m, mci, e) 646 MAILER *m; 647 register MCI *mci; 648 register ENVELOPE *e; 649 { 650 register int r; 651 register EVENT *ev; 652 int rstat; 653 int xstat; 654 time_t timeout; 655 656 /* 657 ** Send the data. 658 ** First send the command and check that it is ok. 659 ** Then send the data. 660 ** Follow it up with a dot to terminate. 661 ** Finally get the results of the transaction. 662 */ 663 664 /* send the command and check ok to proceed */ 665 smtpmessage("DATA", m, mci); 666 SmtpPhase = mci->mci_phase = "client DATA 354"; 667 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 668 r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 669 if (r < 0 || REPLYTYPE(r) == 4) 670 { 671 smtpquit(m, mci, e); 672 return EX_TEMPFAIL; 673 } 674 else if (REPLYTYPE(r) == 5) 675 { 676 smtprset(m, mci, e); 677 return EX_UNAVAILABLE; 678 } 679 else if (REPLYTYPE(r) != 3) 680 { 681 if (LogLevel > 1) 682 { 683 sm_syslog(LOG_CRIT, e->e_id, 684 "%.100s: SMTP DATA-1 protocol error: %s", 685 CurHostName, 686 shortenstring(SmtpReplyBuffer, 403)); 687 } 688 smtprset(m, mci, e); 689 mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); 690 return (EX_PROTOCOL); 691 } 692 693 /* 694 ** Set timeout around data writes. Make it at least large 695 ** enough for DNS timeouts on all recipients plus some fudge 696 ** factor. The main thing is that it should not be infinite. 697 */ 698 699 if (setjmp(CtxDataTimeout) != 0) 700 { 701 mci->mci_errno = errno; 702 mci->mci_state = MCIS_ERROR; 703 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 704 syserr("451 timeout writing message to %s", CurHostName); 705 smtpquit(m, mci, e); 706 return EX_TEMPFAIL; 707 } 708 709 timeout = e->e_msgsize / 16; 710 if (timeout < (time_t) 600) 711 timeout = (time_t) 600; 712 timeout += e->e_nrcpts * 300; 713 ev = setevent(timeout, datatimeout, 0); 714 715 /* 716 ** Output the actual message. 717 */ 718 719 (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 720 (*e->e_putbody)(mci, e, NULL); 721 722 /* 723 ** Cleanup after sending message. 724 */ 725 726 clrevent(ev); 727 728 if (ferror(mci->mci_out)) 729 { 730 /* error during processing -- don't send the dot */ 731 mci->mci_errno = EIO; 732 mci->mci_state = MCIS_ERROR; 733 mci_setstat(mci, EX_IOERR, "4.4.2", NULL); 734 smtpquit(m, mci, e); 735 return EX_IOERR; 736 } 737 738 /* terminate the message */ 739 fprintf(mci->mci_out, ".%s", m->m_eol); 740 if (TrafficLogFile != NULL) 741 fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid()); 742 if (Verbose) 743 nmessage(">>> ."); 744 745 /* check for the results of the transaction */ 746 SmtpPhase = mci->mci_phase = "client DATA status"; 747 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 748 if (bitnset(M_LMTP, m->m_flags)) 749 return EX_OK; 750 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 751 if (r < 0) 752 { 753 smtpquit(m, mci, e); 754 return EX_TEMPFAIL; 755 } 756 mci->mci_state = MCIS_OPEN; 757 xstat = EX_NOTSTICKY; 758 if (r == 452) 759 rstat = EX_TEMPFAIL; 760 else if (REPLYTYPE(r) == 4) 761 rstat = xstat = EX_TEMPFAIL; 762 else if (REPLYCLASS(r) != 5) 763 rstat = xstat = EX_PROTOCOL; 764 else if (REPLYTYPE(r) == 2) 765 rstat = xstat = EX_OK; 766 else if (REPLYTYPE(r) == 5) 767 rstat = EX_UNAVAILABLE; 768 else 769 rstat = EX_PROTOCOL; 770 mci_setstat(mci, xstat, smtptodsn(r), SmtpReplyBuffer); 771 if (e->e_statmsg != NULL) 772 free(e->e_statmsg); 773 e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 774 if (rstat != EX_PROTOCOL) 775 return rstat; 776 if (LogLevel > 1) 777 { 778 sm_syslog(LOG_CRIT, e->e_id, 779 "%.100s: SMTP DATA-2 protocol error: %s", 780 CurHostName, 781 shortenstring(SmtpReplyBuffer, 403)); 782 } 783 return rstat; 784 } 785 786 787 static void 788 datatimeout() 789 { 790 longjmp(CtxDataTimeout, 1); 791 } 792 /* 793 ** SMTPGETSTAT -- get status code from DATA in LMTP 794 ** 795 ** Parameters: 796 ** m -- the mailer to which we are sending the message. 797 ** mci -- the mailer connection structure. 798 ** e -- the current envelope. 799 ** 800 ** Returns: 801 ** The exit status corresponding to the reply code. 802 */ 803 804 int 805 smtpgetstat(m, mci, e) 806 MAILER *m; 807 MCI *mci; 808 ENVELOPE *e; 809 { 810 int r; 811 int stat; 812 813 /* check for the results of the transaction */ 814 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 815 if (r < 0) 816 { 817 smtpquit(m, mci, e); 818 return EX_TEMPFAIL; 819 } 820 if (e->e_statmsg != NULL) 821 free(e->e_statmsg); 822 e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 823 if (REPLYTYPE(r) == 4) 824 stat = EX_TEMPFAIL; 825 else if (REPLYCLASS(r) != 5) 826 stat = EX_PROTOCOL; 827 else if (REPLYTYPE(r) == 2) 828 stat = EX_OK; 829 else if (REPLYTYPE(r) == 5) 830 stat = EX_UNAVAILABLE; 831 else 832 stat = EX_PROTOCOL; 833 mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer); 834 if (LogLevel > 1 && stat == EX_PROTOCOL) 835 { 836 sm_syslog(LOG_CRIT, e->e_id, 837 "%.100s: SMTP DATA-3 protocol error: %s", 838 CurHostName, 839 shortenstring(SmtpReplyBuffer, 403)); 840 } 841 return stat; 842 } 843 /* 844 ** SMTPQUIT -- close the SMTP connection. 845 ** 846 ** Parameters: 847 ** m -- a pointer to the mailer. 848 ** mci -- the mailer connection information. 849 ** e -- the current envelope. 850 ** 851 ** Returns: 852 ** none. 853 ** 854 ** Side Effects: 855 ** sends the final protocol and closes the connection. 856 */ 857 858 void 859 smtpquit(m, mci, e) 860 register MAILER *m; 861 register MCI *mci; 862 ENVELOPE *e; 863 { 864 bool oldSuprErrs = SuprErrs; 865 866 /* 867 ** Suppress errors here -- we may be processing a different 868 ** job when we do the quit connection, and we don't want the 869 ** new job to be penalized for something that isn't it's 870 ** problem. 871 */ 872 873 SuprErrs = TRUE; 874 875 /* send the quit message if we haven't gotten I/O error */ 876 if (mci->mci_state != MCIS_ERROR) 877 { 878 SmtpPhase = "client QUIT"; 879 smtpmessage("QUIT", m, mci); 880 (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 881 SuprErrs = oldSuprErrs; 882 if (mci->mci_state == MCIS_CLOSED) 883 return; 884 } 885 886 /* now actually close the connection and pick up the zombie */ 887 (void) endmailer(mci, e, NULL); 888 889 SuprErrs = oldSuprErrs; 890 } 891 /* 892 ** SMTPRSET -- send a RSET (reset) command 893 */ 894 895 void 896 smtprset(m, mci, e) 897 register MAILER *m; 898 register MCI *mci; 899 ENVELOPE *e; 900 { 901 int r; 902 903 SmtpPhase = "client RSET"; 904 smtpmessage("RSET", m, mci); 905 r = reply(m, mci, e, TimeOuts.to_rset, NULL); 906 if (r < 0) 907 mci->mci_state = MCIS_ERROR; 908 else if (REPLYTYPE(r) == 2) 909 { 910 mci->mci_state = MCIS_OPEN; 911 return; 912 } 913 smtpquit(m, mci, e); 914 } 915 /* 916 ** SMTPPROBE -- check the connection state 917 */ 918 919 int 920 smtpprobe(mci) 921 register MCI *mci; 922 { 923 int r; 924 MAILER *m = mci->mci_mailer; 925 extern ENVELOPE BlankEnvelope; 926 ENVELOPE *e = &BlankEnvelope; 927 928 SmtpPhase = "client probe"; 929 smtpmessage("RSET", m, mci); 930 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 931 if (r < 0 || REPLYTYPE(r) != 2) 932 smtpquit(m, mci, e); 933 return r; 934 } 935 /* 936 ** REPLY -- read arpanet reply 937 ** 938 ** Parameters: 939 ** m -- the mailer we are reading the reply from. 940 ** mci -- the mailer connection info structure. 941 ** e -- the current envelope. 942 ** timeout -- the timeout for reads. 943 ** pfunc -- processing function called on each line of response. 944 ** If null, no special processing is done. 945 ** 946 ** Returns: 947 ** reply code it reads. 948 ** 949 ** Side Effects: 950 ** flushes the mail file. 951 */ 952 953 int 954 reply(m, mci, e, timeout, pfunc) 955 MAILER *m; 956 MCI *mci; 957 ENVELOPE *e; 958 time_t timeout; 959 void (*pfunc)(); 960 { 961 register char *bufp; 962 register int r; 963 bool firstline = TRUE; 964 char junkbuf[MAXLINE]; 965 966 if (mci->mci_out != NULL) 967 (void) fflush(mci->mci_out); 968 969 if (tTd(18, 1)) 970 printf("reply\n"); 971 972 /* 973 ** Read the input line, being careful not to hang. 974 */ 975 976 bufp = SmtpReplyBuffer; 977 for (;;) 978 { 979 register char *p; 980 981 /* actually do the read */ 982 if (e->e_xfp != NULL) 983 (void) fflush(e->e_xfp); /* for debugging */ 984 985 /* if we are in the process of closing just give the code */ 986 if (mci->mci_state == MCIS_CLOSED) 987 return (SMTPCLOSING); 988 989 if (mci->mci_out != NULL) 990 fflush(mci->mci_out); 991 992 /* get the line from the other side */ 993 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 994 mci->mci_lastuse = curtime(); 995 996 if (p == NULL) 997 { 998 bool oldholderrs; 999 extern char MsgBuf[]; 1000 1001 /* if the remote end closed early, fake an error */ 1002 if (errno == 0) 1003 # ifdef ECONNRESET 1004 errno = ECONNRESET; 1005 # else /* ECONNRESET */ 1006 errno = EPIPE; 1007 # endif /* ECONNRESET */ 1008 1009 mci->mci_errno = errno; 1010 oldholderrs = HoldErrs; 1011 HoldErrs = TRUE; 1012 usrerr("451 reply: read error from %s", CurHostName); 1013 1014 /* errors on QUIT should not be persistent */ 1015 if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0) 1016 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); 1017 1018 /* if debugging, pause so we can see state */ 1019 if (tTd(18, 100)) 1020 pause(); 1021 mci->mci_state = MCIS_ERROR; 1022 smtpquit(m, mci, e); 1023 #if XDEBUG 1024 { 1025 char wbuf[MAXLINE]; 1026 char *p = wbuf; 1027 int wbufleft = sizeof wbuf; 1028 1029 if (e->e_to != NULL) 1030 { 1031 int plen; 1032 1033 snprintf(p, wbufleft, "%s... ", 1034 shortenstring(e->e_to, MAXSHORTSTR)); 1035 plen = strlen(p); 1036 p += plen; 1037 wbufleft -= plen; 1038 } 1039 snprintf(p, wbufleft, "reply(%.100s) during %s", 1040 CurHostName == NULL ? "NO_HOST" : CurHostName, 1041 SmtpPhase); 1042 checkfd012(wbuf); 1043 } 1044 #endif 1045 HoldErrs = oldholderrs; 1046 return (-1); 1047 } 1048 fixcrlf(bufp, TRUE); 1049 1050 /* EHLO failure is not a real error */ 1051 if (e->e_xfp != NULL && (bufp[0] == '4' || 1052 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 1053 { 1054 /* serious error -- log the previous command */ 1055 if (SmtpNeedIntro) 1056 { 1057 /* inform user who we are chatting with */ 1058 fprintf(CurEnv->e_xfp, 1059 "... while talking to %s:\n", 1060 CurHostName); 1061 SmtpNeedIntro = FALSE; 1062 } 1063 if (SmtpMsgBuffer[0] != '\0') 1064 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 1065 SmtpMsgBuffer[0] = '\0'; 1066 1067 /* now log the message as from the other side */ 1068 fprintf(e->e_xfp, "<<< %s\n", bufp); 1069 } 1070 1071 /* display the input for verbose mode */ 1072 if (Verbose) 1073 nmessage("050 %s", bufp); 1074 1075 /* ignore improperly formated input */ 1076 if (!(isascii(bufp[0]) && isdigit(bufp[0])) || 1077 !(isascii(bufp[1]) && isdigit(bufp[1])) || 1078 !(isascii(bufp[2]) && isdigit(bufp[2])) || 1079 !(bufp[3] == ' ' || bufp[3] == '-' || bufp[3] == '\0')) 1080 continue; 1081 1082 /* process the line */ 1083 if (pfunc != NULL) 1084 (*pfunc)(bufp, firstline, m, mci, e); 1085 1086 firstline = FALSE; 1087 1088 /* decode the reply code */ 1089 r = atoi(bufp); 1090 1091 /* extra semantics: 0xx codes are "informational" */ 1092 if (r < 100) 1093 continue; 1094 1095 /* if no continuation lines, return this line */ 1096 if (bufp[3] != '-') 1097 break; 1098 1099 /* first line of real reply -- ignore rest */ 1100 bufp = junkbuf; 1101 } 1102 1103 /* 1104 ** Now look at SmtpReplyBuffer -- only care about the first 1105 ** line of the response from here on out. 1106 */ 1107 1108 /* save temporary failure messages for posterity */ 1109 if (SmtpReplyBuffer[0] == '4' && 1110 (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0')) 1111 snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer); 1112 1113 /* reply code 421 is "Service Shutting Down" */ 1114 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 1115 { 1116 /* send the quit protocol */ 1117 mci->mci_state = MCIS_SSD; 1118 smtpquit(m, mci, e); 1119 } 1120 1121 return (r); 1122 } 1123 /* 1124 ** SMTPMESSAGE -- send message to server 1125 ** 1126 ** Parameters: 1127 ** f -- format 1128 ** m -- the mailer to control formatting. 1129 ** a, b, c -- parameters 1130 ** 1131 ** Returns: 1132 ** none. 1133 ** 1134 ** Side Effects: 1135 ** writes message to mci->mci_out. 1136 */ 1137 1138 /*VARARGS1*/ 1139 void 1140 #ifdef __STDC__ 1141 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 1142 #else 1143 smtpmessage(f, m, mci, va_alist) 1144 char *f; 1145 MAILER *m; 1146 MCI *mci; 1147 va_dcl 1148 #endif 1149 { 1150 VA_LOCAL_DECL 1151 1152 VA_START(mci); 1153 (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap); 1154 VA_END; 1155 1156 if (tTd(18, 1) || Verbose) 1157 nmessage(">>> %s", SmtpMsgBuffer); 1158 if (TrafficLogFile != NULL) 1159 fprintf(TrafficLogFile, "%05d >>> %s\n", 1160 (int) getpid(), SmtpMsgBuffer); 1161 if (mci->mci_out != NULL) 1162 { 1163 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 1164 m == NULL ? "\r\n" : m->m_eol); 1165 } 1166 else if (tTd(18, 1)) 1167 { 1168 printf("smtpmessage: NULL mci_out\n"); 1169 } 1170 } 1171 1172 # endif /* SMTP */ 1173