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