usersmtp.c revision 42575
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 17static char sccsid[] = "@(#)usersmtp.c 8.108 (Berkeley) 10/6/1998 (with SMTP)"; 18#else 19static char sccsid[] = "@(#)usersmtp.c 8.108 (Berkeley) 10/6/1998 (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 38char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 39char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 40char SmtpError[MAXLINE] = ""; /* save failure error messages */ 41bool SmtpNeedIntro; /* need "while talking" in transcript */ 42 43extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); 44extern 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 62void 63smtpinit(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 138tryhelo: 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 252void 253esmtp_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 279void 280helo_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 323int 324smtpmailfrom(m, mci, e) 325 MAILER *m; 326 MCI *mci; 327 ENVELOPE *e; 328{ 329 int r; 330 int l; 331 char *bufp; 332 char *bodytype; 333 char buf[MAXNAME + 1]; 334 char optbuf[MAXLINE]; 335 336 if (tTd(18, 2)) 337 printf("smtpmailfrom: CurHost=%s\n", CurHostName); 338 339 /* set up appropriate options to include */ 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 l = sizeof optbuf - strlen(optbuf) - 1; 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 && strlen(bodytype) + 7 < l) 356 { 357 strcat(optbuf, " BODY="); 358 strcat(optbuf, bodytype); 359 l -= strlen(optbuf); 360 } 361 } 362 else if (bitnset(M_8BITS, m->m_flags) || 363 !bitset(EF_HAS8BIT, e->e_flags) || 364 bitset(MCIF_8BITOK, mci->mci_flags)) 365 { 366 /* just pass it through */ 367 } 368#if MIME8TO7 369 else if (bitset(MM_CVTMIME, MimeMode) && 370 !bitset(EF_DONT_MIME, e->e_flags) && 371 (!bitset(MM_PASS8BIT, MimeMode) || 372 bitset(EF_IS_MIME, e->e_flags))) 373 { 374 /* must convert from 8bit MIME format to 7bit encoded */ 375 mci->mci_flags |= MCIF_CVT8TO7; 376 } 377#endif 378 else if (!bitset(MM_PASS8BIT, MimeMode)) 379 { 380 /* cannot just send a 8-bit version */ 381 extern char MsgBuf[]; 382 383 usrerr("%s does not support 8BITMIME", CurHostName); 384 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf); 385 return EX_DATAERR; 386 } 387 388 if (bitset(MCIF_DSN, mci->mci_flags)) 389 { 390 if (e->e_envid != NULL && strlen(e->e_envid) < (SIZE_T) (l - 7)) 391 { 392 strcat(optbuf, " ENVID="); 393 strcat(optbuf, e->e_envid); 394 l -= strlen(optbuf); 395 } 396 397 /* RET= parameter */ 398 if (bitset(EF_RET_PARAM, e->e_flags) && l >= 9) 399 { 400 strcat(optbuf, " RET="); 401 if (bitset(EF_NO_BODY_RETN, e->e_flags)) 402 strcat(optbuf, "HDRS"); 403 else 404 strcat(optbuf, "FULL"); 405 l -= 9; 406 } 407 } 408 409 /* 410 ** Send the MAIL command. 411 ** Designates the sender. 412 */ 413 414 mci->mci_state = MCIS_ACTIVE; 415 416 if (bitset(EF_RESPONSE, e->e_flags) && 417 !bitnset(M_NO_NULL_FROM, m->m_flags)) 418 (void) strcpy(buf, ""); 419 else 420 expand("\201g", buf, sizeof buf, e); 421 if (buf[0] == '<') 422 { 423 /* strip off <angle brackets> (put back on below) */ 424 bufp = &buf[strlen(buf) - 1]; 425 if (*bufp == '>') 426 *bufp = '\0'; 427 bufp = &buf[1]; 428 } 429 else 430 bufp = buf; 431 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 432 !bitnset(M_FROMPATH, m->m_flags)) 433 { 434 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 435 } 436 else 437 { 438 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 439 *bufp == '@' ? ',' : ':', bufp, optbuf); 440 } 441 SmtpPhase = mci->mci_phase = "client MAIL"; 442 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 443 r = reply(m, mci, e, TimeOuts.to_mail, NULL); 444 if (r < 0) 445 { 446 /* communications failure */ 447 mci->mci_errno = errno; 448 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 449 smtpquit(m, mci, e); 450 return EX_TEMPFAIL; 451 } 452 else if (r == 421) 453 { 454 /* service shutting down */ 455 mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer); 456 smtpquit(m, mci, e); 457 return EX_TEMPFAIL; 458 } 459 else if (REPLYTYPE(r) == 4) 460 { 461 mci_setstat(mci, EX_NOTSTICKY, smtptodsn(r), SmtpReplyBuffer); 462 return EX_TEMPFAIL; 463 } 464 else if (REPLYTYPE(r) == 2) 465 { 466 return EX_OK; 467 } 468 else if (r == 501) 469 { 470 /* syntax error in arguments */ 471 mci_setstat(mci, EX_NOTSTICKY, "5.5.2", SmtpReplyBuffer); 472 return EX_DATAERR; 473 } 474 else if (r == 553) 475 { 476 /* mailbox name not allowed */ 477 mci_setstat(mci, EX_NOTSTICKY, "5.1.3", SmtpReplyBuffer); 478 return EX_DATAERR; 479 } 480 else if (r == 552) 481 { 482 /* exceeded storage allocation */ 483 mci_setstat(mci, EX_NOTSTICKY, "5.3.4", SmtpReplyBuffer); 484 if (bitset(MCIF_SIZE, mci->mci_flags)) 485 e->e_flags |= EF_NO_BODY_RETN; 486 return EX_UNAVAILABLE; 487 } 488 else if (REPLYTYPE(r) == 5) 489 { 490 /* unknown error */ 491 mci_setstat(mci, EX_NOTSTICKY, "5.0.0", SmtpReplyBuffer); 492 return EX_UNAVAILABLE; 493 } 494 495 if (LogLevel > 1) 496 { 497 sm_syslog(LOG_CRIT, e->e_id, 498 "%.100s: SMTP MAIL protocol error: %s", 499 CurHostName, 500 shortenstring(SmtpReplyBuffer, 403)); 501 } 502 503 /* protocol error -- close up */ 504 mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); 505 smtpquit(m, mci, e); 506 return EX_PROTOCOL; 507} 508/* 509** SMTPRCPT -- designate recipient. 510** 511** Parameters: 512** to -- address of recipient. 513** m -- the mailer we are sending to. 514** mci -- the connection info for this transaction. 515** e -- the envelope for this transaction. 516** 517** Returns: 518** exit status corresponding to recipient status. 519** 520** Side Effects: 521** Sends the mail via SMTP. 522*/ 523 524int 525smtprcpt(to, m, mci, e) 526 ADDRESS *to; 527 register MAILER *m; 528 MCI *mci; 529 ENVELOPE *e; 530{ 531 register int r; 532 int l; 533 char optbuf[MAXLINE]; 534 535 strcpy(optbuf, ""); 536 l = sizeof optbuf - 1; 537 if (bitset(MCIF_DSN, mci->mci_flags)) 538 { 539 /* NOTIFY= parameter */ 540 if (bitset(QHASNOTIFY, to->q_flags) && 541 bitset(QPRIMARY, to->q_flags) && 542 !bitnset(M_LOCALMAILER, m->m_flags)) 543 { 544 bool firstone = TRUE; 545 546 strcat(optbuf, " NOTIFY="); 547 if (bitset(QPINGONSUCCESS, to->q_flags)) 548 { 549 strcat(optbuf, "SUCCESS"); 550 firstone = FALSE; 551 } 552 if (bitset(QPINGONFAILURE, to->q_flags)) 553 { 554 if (!firstone) 555 strcat(optbuf, ","); 556 strcat(optbuf, "FAILURE"); 557 firstone = FALSE; 558 } 559 if (bitset(QPINGONDELAY, to->q_flags)) 560 { 561 if (!firstone) 562 strcat(optbuf, ","); 563 strcat(optbuf, "DELAY"); 564 firstone = FALSE; 565 } 566 if (firstone) 567 strcat(optbuf, "NEVER"); 568 l -= strlen(optbuf); 569 } 570 571 /* ORCPT= parameter */ 572 if (to->q_orcpt != NULL && strlen(to->q_orcpt) + 7 < l) 573 { 574 strcat(optbuf, " ORCPT="); 575 strcat(optbuf, to->q_orcpt); 576 l -= strlen(optbuf); 577 } 578 } 579 580 smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 581 582 SmtpPhase = mci->mci_phase = "client RCPT"; 583 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 584 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 585 to->q_rstatus = newstr(SmtpReplyBuffer); 586 to->q_status = smtptodsn(r); 587 to->q_statmta = mci->mci_host; 588 if (r < 0 || REPLYTYPE(r) == 4) 589 return EX_TEMPFAIL; 590 else if (REPLYTYPE(r) == 2) 591 return EX_OK; 592 else if (r == 550) 593 { 594 to->q_status = "5.1.1"; 595 return EX_NOUSER; 596 } 597 else if (r == 551) 598 { 599 to->q_status = "5.1.6"; 600 return EX_NOUSER; 601 } 602 else if (r == 553) 603 { 604 to->q_status = "5.1.3"; 605 return EX_NOUSER; 606 } 607 else if (REPLYTYPE(r) == 5) 608 { 609 return EX_UNAVAILABLE; 610 } 611 612 if (LogLevel > 1) 613 { 614 sm_syslog(LOG_CRIT, e->e_id, 615 "%.100s: SMTP RCPT protocol error: %s", 616 CurHostName, 617 shortenstring(SmtpReplyBuffer, 403)); 618 } 619 620 mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); 621 return EX_PROTOCOL; 622} 623/* 624** SMTPDATA -- send the data and clean up the transaction. 625** 626** Parameters: 627** m -- mailer being sent to. 628** mci -- the mailer connection information. 629** e -- the envelope for this message. 630** 631** Returns: 632** exit status corresponding to DATA command. 633** 634** Side Effects: 635** none. 636*/ 637 638static jmp_buf CtxDataTimeout; 639static void datatimeout __P((void)); 640 641int 642smtpdata(m, mci, e) 643 MAILER *m; 644 register MCI *mci; 645 register ENVELOPE *e; 646{ 647 register int r; 648 register EVENT *ev; 649 int rstat; 650 int xstat; 651 time_t timeout; 652 653 /* 654 ** Send the data. 655 ** First send the command and check that it is ok. 656 ** Then send the data. 657 ** Follow it up with a dot to terminate. 658 ** Finally get the results of the transaction. 659 */ 660 661 /* send the command and check ok to proceed */ 662 smtpmessage("DATA", m, mci); 663 SmtpPhase = mci->mci_phase = "client DATA 354"; 664 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 665 r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 666 if (r < 0 || REPLYTYPE(r) == 4) 667 { 668 smtpquit(m, mci, e); 669 return EX_TEMPFAIL; 670 } 671 else if (REPLYTYPE(r) == 5) 672 { 673 smtprset(m, mci, e); 674 return EX_UNAVAILABLE; 675 } 676 else if (r != 354) 677 { 678 if (LogLevel > 1) 679 { 680 sm_syslog(LOG_CRIT, e->e_id, 681 "%.100s: SMTP DATA-1 protocol error: %s", 682 CurHostName, 683 shortenstring(SmtpReplyBuffer, 403)); 684 } 685 smtprset(m, mci, e); 686 mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); 687 return (EX_PROTOCOL); 688 } 689 690 /* 691 ** Set timeout around data writes. Make it at least large 692 ** enough for DNS timeouts on all recipients plus some fudge 693 ** factor. The main thing is that it should not be infinite. 694 */ 695 696 if (setjmp(CtxDataTimeout) != 0) 697 { 698 mci->mci_errno = errno; 699 mci->mci_state = MCIS_ERROR; 700 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 701 syserr("451 timeout writing message to %s", CurHostName); 702 smtpquit(m, mci, e); 703 return EX_TEMPFAIL; 704 } 705 706 timeout = e->e_msgsize / 16; 707 if (timeout < (time_t) 600) 708 timeout = (time_t) 600; 709 timeout += e->e_nrcpts * 300; 710 ev = setevent(timeout, datatimeout, 0); 711 712 /* 713 ** Output the actual message. 714 */ 715 716 (*e->e_puthdr)(mci, e->e_header, e); 717 (*e->e_putbody)(mci, e, NULL); 718 719 /* 720 ** Cleanup after sending message. 721 */ 722 723 clrevent(ev); 724 725 if (ferror(mci->mci_out)) 726 { 727 /* error during processing -- don't send the dot */ 728 mci->mci_errno = EIO; 729 mci->mci_state = MCIS_ERROR; 730 mci_setstat(mci, EX_IOERR, "4.4.2", NULL); 731 smtpquit(m, mci, e); 732 return EX_IOERR; 733 } 734 735 /* terminate the message */ 736 fprintf(mci->mci_out, ".%s", m->m_eol); 737 if (TrafficLogFile != NULL) 738 fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid()); 739 if (Verbose) 740 nmessage(">>> ."); 741 742 /* check for the results of the transaction */ 743 SmtpPhase = mci->mci_phase = "client DATA status"; 744 sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 745 if (bitnset(M_LMTP, m->m_flags)) 746 return EX_OK; 747 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 748 if (r < 0) 749 { 750 smtpquit(m, mci, e); 751 return EX_TEMPFAIL; 752 } 753 mci->mci_state = MCIS_OPEN; 754 xstat = EX_NOTSTICKY; 755 if (r == 452) 756 rstat = EX_TEMPFAIL; 757 else if (REPLYTYPE(r) == 4) 758 rstat = xstat = EX_TEMPFAIL; 759 else if (REPLYCLASS(r) != 5) 760 rstat = xstat = EX_PROTOCOL; 761 else if (REPLYTYPE(r) == 2) 762 rstat = xstat = EX_OK; 763 else if (REPLYTYPE(r) == 5) 764 rstat = EX_UNAVAILABLE; 765 else 766 rstat = EX_PROTOCOL; 767 mci_setstat(mci, xstat, smtptodsn(r), SmtpReplyBuffer); 768 if (e->e_statmsg != NULL) 769 free(e->e_statmsg); 770 e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 771 if (rstat != EX_PROTOCOL) 772 return rstat; 773 if (LogLevel > 1) 774 { 775 sm_syslog(LOG_CRIT, e->e_id, 776 "%.100s: SMTP DATA-2 protocol error: %s", 777 CurHostName, 778 shortenstring(SmtpReplyBuffer, 403)); 779 } 780 return rstat; 781} 782 783 784static void 785datatimeout() 786{ 787 longjmp(CtxDataTimeout, 1); 788} 789/* 790** SMTPGETSTAT -- get status code from DATA in LMTP 791** 792** Parameters: 793** m -- the mailer to which we are sending the message. 794** mci -- the mailer connection structure. 795** e -- the current envelope. 796** 797** Returns: 798** The exit status corresponding to the reply code. 799*/ 800 801int 802smtpgetstat(m, mci, e) 803 MAILER *m; 804 MCI *mci; 805 ENVELOPE *e; 806{ 807 int r; 808 int stat; 809 810 /* check for the results of the transaction */ 811 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 812 if (r < 0) 813 { 814 smtpquit(m, mci, e); 815 return EX_TEMPFAIL; 816 } 817 if (e->e_statmsg != NULL) 818 free(e->e_statmsg); 819 e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 820 if (REPLYTYPE(r) == 4) 821 stat = EX_TEMPFAIL; 822 else if (REPLYCLASS(r) != 5) 823 stat = EX_PROTOCOL; 824 else if (REPLYTYPE(r) == 2) 825 stat = EX_OK; 826 else if (REPLYTYPE(r) == 5) 827 stat = EX_UNAVAILABLE; 828 else 829 stat = EX_PROTOCOL; 830 mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer); 831 if (LogLevel > 1 && stat == EX_PROTOCOL) 832 { 833 sm_syslog(LOG_CRIT, e->e_id, 834 "%.100s: SMTP DATA-3 protocol error: %s", 835 CurHostName, 836 shortenstring(SmtpReplyBuffer, 403)); 837 } 838 return stat; 839} 840/* 841** SMTPQUIT -- close the SMTP connection. 842** 843** Parameters: 844** m -- a pointer to the mailer. 845** mci -- the mailer connection information. 846** e -- the current envelope. 847** 848** Returns: 849** none. 850** 851** Side Effects: 852** sends the final protocol and closes the connection. 853*/ 854 855void 856smtpquit(m, mci, e) 857 register MAILER *m; 858 register MCI *mci; 859 ENVELOPE *e; 860{ 861 bool oldSuprErrs = SuprErrs; 862 863 /* 864 ** Suppress errors here -- we may be processing a different 865 ** job when we do the quit connection, and we don't want the 866 ** new job to be penalized for something that isn't it's 867 ** problem. 868 */ 869 870 SuprErrs = TRUE; 871 872 /* send the quit message if we haven't gotten I/O error */ 873 if (mci->mci_state != MCIS_ERROR) 874 { 875 SmtpPhase = "client QUIT"; 876 smtpmessage("QUIT", m, mci); 877 (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 878 SuprErrs = oldSuprErrs; 879 if (mci->mci_state == MCIS_CLOSED) 880 return; 881 } 882 883 /* now actually close the connection and pick up the zombie */ 884 (void) endmailer(mci, e, NULL); 885 886 SuprErrs = oldSuprErrs; 887} 888/* 889** SMTPRSET -- send a RSET (reset) command 890*/ 891 892void 893smtprset(m, mci, e) 894 register MAILER *m; 895 register MCI *mci; 896 ENVELOPE *e; 897{ 898 int r; 899 900 SmtpPhase = "client RSET"; 901 smtpmessage("RSET", m, mci); 902 r = reply(m, mci, e, TimeOuts.to_rset, NULL); 903 if (r < 0) 904 mci->mci_state = MCIS_ERROR; 905 else if (REPLYTYPE(r) == 2) 906 { 907 mci->mci_state = MCIS_OPEN; 908 return; 909 } 910 smtpquit(m, mci, e); 911} 912/* 913** SMTPPROBE -- check the connection state 914*/ 915 916int 917smtpprobe(mci) 918 register MCI *mci; 919{ 920 int r; 921 MAILER *m = mci->mci_mailer; 922 extern ENVELOPE BlankEnvelope; 923 ENVELOPE *e = &BlankEnvelope; 924 925 SmtpPhase = "client probe"; 926 smtpmessage("RSET", m, mci); 927 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 928 if (r < 0 || REPLYTYPE(r) != 2) 929 smtpquit(m, mci, e); 930 return r; 931} 932/* 933** REPLY -- read arpanet reply 934** 935** Parameters: 936** m -- the mailer we are reading the reply from. 937** mci -- the mailer connection info structure. 938** e -- the current envelope. 939** timeout -- the timeout for reads. 940** pfunc -- processing function called on each line of response. 941** If null, no special processing is done. 942** 943** Returns: 944** reply code it reads. 945** 946** Side Effects: 947** flushes the mail file. 948*/ 949 950int 951reply(m, mci, e, timeout, pfunc) 952 MAILER *m; 953 MCI *mci; 954 ENVELOPE *e; 955 time_t timeout; 956 void (*pfunc)(); 957{ 958 register char *bufp; 959 register int r; 960 bool firstline = TRUE; 961 char junkbuf[MAXLINE]; 962 963 if (mci->mci_out != NULL) 964 (void) fflush(mci->mci_out); 965 966 if (tTd(18, 1)) 967 printf("reply\n"); 968 969 /* 970 ** Read the input line, being careful not to hang. 971 */ 972 973 bufp = SmtpReplyBuffer; 974 for (;;) 975 { 976 register char *p; 977 978 /* actually do the read */ 979 if (e->e_xfp != NULL) 980 (void) fflush(e->e_xfp); /* for debugging */ 981 982 /* if we are in the process of closing just give the code */ 983 if (mci->mci_state == MCIS_CLOSED) 984 return (SMTPCLOSING); 985 986 if (mci->mci_out != NULL) 987 fflush(mci->mci_out); 988 989 /* get the line from the other side */ 990 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 991 mci->mci_lastuse = curtime(); 992 993 if (p == NULL) 994 { 995 bool oldholderrs; 996 extern char MsgBuf[]; 997 998 /* if the remote end closed early, fake an error */ 999 if (errno == 0) 1000# ifdef ECONNRESET 1001 errno = ECONNRESET; 1002# else /* ECONNRESET */ 1003 errno = EPIPE; 1004# endif /* ECONNRESET */ 1005 1006 mci->mci_errno = errno; 1007 oldholderrs = HoldErrs; 1008 HoldErrs = TRUE; 1009 usrerr("451 reply: read error from %s", CurHostName); 1010 1011 /* errors on QUIT should not be persistent */ 1012 if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0) 1013 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); 1014 1015 /* if debugging, pause so we can see state */ 1016 if (tTd(18, 100)) 1017 pause(); 1018 mci->mci_state = MCIS_ERROR; 1019 smtpquit(m, mci, e); 1020#if XDEBUG 1021 { 1022 char wbuf[MAXLINE]; 1023 char *p = wbuf; 1024 int wbufleft = sizeof wbuf; 1025 1026 if (e->e_to != NULL) 1027 { 1028 int plen; 1029 1030 snprintf(p, wbufleft, "%s... ", 1031 shortenstring(e->e_to, MAXSHORTSTR)); 1032 plen = strlen(p); 1033 p += plen; 1034 wbufleft -= plen; 1035 } 1036 snprintf(p, wbufleft, "reply(%.100s) during %s", 1037 CurHostName == NULL ? "NO_HOST" : CurHostName, 1038 SmtpPhase); 1039 checkfd012(wbuf); 1040 } 1041#endif 1042 HoldErrs = oldholderrs; 1043 return (-1); 1044 } 1045 fixcrlf(bufp, TRUE); 1046 1047 /* EHLO failure is not a real error */ 1048 if (e->e_xfp != NULL && (bufp[0] == '4' || 1049 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 1050 { 1051 /* serious error -- log the previous command */ 1052 if (SmtpNeedIntro) 1053 { 1054 /* inform user who we are chatting with */ 1055 fprintf(CurEnv->e_xfp, 1056 "... while talking to %s:\n", 1057 CurHostName); 1058 SmtpNeedIntro = FALSE; 1059 } 1060 if (SmtpMsgBuffer[0] != '\0') 1061 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 1062 SmtpMsgBuffer[0] = '\0'; 1063 1064 /* now log the message as from the other side */ 1065 fprintf(e->e_xfp, "<<< %s\n", bufp); 1066 } 1067 1068 /* display the input for verbose mode */ 1069 if (Verbose) 1070 nmessage("050 %s", bufp); 1071 1072 /* ignore improperly formated input */ 1073 if (!(isascii(bufp[0]) && isdigit(bufp[0])) || 1074 !(isascii(bufp[1]) && isdigit(bufp[1])) || 1075 !(isascii(bufp[2]) && isdigit(bufp[2])) || 1076 !(bufp[3] == ' ' || bufp[3] == '-' || bufp[3] == '\0')) 1077 continue; 1078 1079 /* process the line */ 1080 if (pfunc != NULL) 1081 (*pfunc)(bufp, firstline, m, mci, e); 1082 1083 firstline = FALSE; 1084 1085 /* decode the reply code */ 1086 r = atoi(bufp); 1087 1088 /* extra semantics: 0xx codes are "informational" */ 1089 if (r < 100) 1090 continue; 1091 1092 /* if no continuation lines, return this line */ 1093 if (bufp[3] != '-') 1094 break; 1095 1096 /* first line of real reply -- ignore rest */ 1097 bufp = junkbuf; 1098 } 1099 1100 /* 1101 ** Now look at SmtpReplyBuffer -- only care about the first 1102 ** line of the response from here on out. 1103 */ 1104 1105 /* save temporary failure messages for posterity */ 1106 if (SmtpReplyBuffer[0] == '4' && 1107 (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0')) 1108 snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer); 1109 1110 /* reply code 421 is "Service Shutting Down" */ 1111 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 1112 { 1113 /* send the quit protocol */ 1114 mci->mci_state = MCIS_SSD; 1115 smtpquit(m, mci, e); 1116 } 1117 1118 return (r); 1119} 1120/* 1121** SMTPMESSAGE -- send message to server 1122** 1123** Parameters: 1124** f -- format 1125** m -- the mailer to control formatting. 1126** a, b, c -- parameters 1127** 1128** Returns: 1129** none. 1130** 1131** Side Effects: 1132** writes message to mci->mci_out. 1133*/ 1134 1135/*VARARGS1*/ 1136void 1137#ifdef __STDC__ 1138smtpmessage(char *f, MAILER *m, MCI *mci, ...) 1139#else 1140smtpmessage(f, m, mci, va_alist) 1141 char *f; 1142 MAILER *m; 1143 MCI *mci; 1144 va_dcl 1145#endif 1146{ 1147 VA_LOCAL_DECL 1148 1149 VA_START(mci); 1150 (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap); 1151 VA_END; 1152 1153 if (tTd(18, 1) || Verbose) 1154 nmessage(">>> %s", SmtpMsgBuffer); 1155 if (TrafficLogFile != NULL) 1156 fprintf(TrafficLogFile, "%05d >>> %s\n", 1157 (int) getpid(), SmtpMsgBuffer); 1158 if (mci->mci_out != NULL) 1159 { 1160 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 1161 m == NULL ? "\r\n" : m->m_eol); 1162 } 1163 else if (tTd(18, 1)) 1164 { 1165 printf("smtpmessage: NULL mci_out\n"); 1166 } 1167} 1168 1169# endif /* SMTP */ 1170