122716Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 362532Sbostic * Copyright (c) 1988, 1993 462532Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642831Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822716Sdist 933731Sbostic # include "sendmail.h" 1022716Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef SMTP 13*67880Seric static char sccsid[] = "@(#)usersmtp.c 8.23 (Berkeley) 11/04/94 (with SMTP)"; 1433731Sbostic #else 15*67880Seric static char sccsid[] = "@(#)usersmtp.c 8.23 (Berkeley) 11/04/94 (without SMTP)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 194684Seric # include <sysexits.h> 2021065Seric # include <errno.h> 214684Seric 2233731Sbostic # ifdef SMTP 234684Seric 244684Seric /* 259391Seric ** USERSMTP -- run SMTP protocol from the user end. 269391Seric ** 279391Seric ** This protocol is described in RFC821. 289391Seric */ 299391Seric 309391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 319391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 329391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 339391Seric 3414900Seric char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 3510054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 3621065Seric char SmtpError[MAXLINE] = ""; /* save failure error messages */ 3710054Seric int SmtpPid; /* pid of mailer */ 3864071Seric bool SmtpNeedIntro; /* need "while talking" in transcript */ 3958671Seric 4058671Seric #ifdef __STDC__ 4158671Seric extern smtpmessage(char *f, MAILER *m, MCI *mci, ...); 4258671Seric #endif 439391Seric /* 444865Seric ** SMTPINIT -- initialize SMTP. 454684Seric ** 464865Seric ** Opens the connection and sends the initial protocol. 474684Seric ** 484684Seric ** Parameters: 494865Seric ** m -- mailer to create connection to. 504865Seric ** pvp -- pointer to parameter vector to pass to 514865Seric ** the mailer. 524684Seric ** 534684Seric ** Returns: 5454967Seric ** none. 554684Seric ** 564684Seric ** Side Effects: 574865Seric ** creates connection and sends initial protocol. 584684Seric */ 594684Seric 6054967Seric smtpinit(m, mci, e) 614865Seric struct mailer *m; 6254967Seric register MCI *mci; 6353751Seric ENVELOPE *e; 644684Seric { 654865Seric register int r; 6658957Seric register char *p; 6760210Seric extern void esmtp_check(); 6859285Seric extern void helo_options(); 694684Seric 7063753Seric if (tTd(18, 1)) 7157379Seric { 7257379Seric printf("smtpinit "); 7364731Seric mci_dump(mci, FALSE); 7457379Seric } 7557379Seric 764865Seric /* 774865Seric ** Open the connection to the mailer. 784865Seric */ 794684Seric 8021065Seric SmtpError[0] = '\0'; 8157379Seric CurHostName = mci->mci_host; /* XXX UGLY XXX */ 8264071Seric SmtpNeedIntro = TRUE; 8354967Seric switch (mci->mci_state) 846051Seric { 8554967Seric case MCIS_ACTIVE: 8654967Seric /* need to clear old information */ 8754967Seric smtprset(m, mci, e); 8857734Seric /* fall through */ 8915139Seric 9054967Seric case MCIS_OPEN: 9154967Seric return; 9254967Seric 9354967Seric case MCIS_ERROR: 9454967Seric case MCIS_SSD: 9554967Seric /* shouldn't happen */ 9654967Seric smtpquit(m, mci, e); 9757734Seric /* fall through */ 9854967Seric 9954967Seric case MCIS_CLOSED: 10058151Seric syserr("451 smtpinit: state CLOSED"); 10154967Seric return; 10254967Seric 10354967Seric case MCIS_OPENING: 10454967Seric break; 1056051Seric } 1064796Seric 10754967Seric mci->mci_state = MCIS_OPENING; 10854967Seric 1094865Seric /* 1104865Seric ** Get the greeting message. 11114913Seric ** This should appear spontaneously. Give it five minutes to 11214886Seric ** happen. 1134865Seric */ 1144797Seric 11561093Seric SmtpPhase = mci->mci_phase = "client greeting"; 11653751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 11760210Seric r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); 11864750Seric if (r < 0 || REPLYTYPE(r) == 4) 11952104Seric goto tempfail1; 12064750Seric if (REPLYTYPE(r) != 2) 12164750Seric goto unavailable; 1224684Seric 1234865Seric /* 1244976Seric ** Send the HELO command. 1257963Seric ** My mother taught me to always introduce myself. 1264976Seric */ 1274976Seric 12859285Seric if (bitnset(M_ESMTP, m->m_flags)) 12959285Seric mci->mci_flags |= MCIF_ESMTP; 13059285Seric 13159285Seric tryhelo: 13259285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 13359285Seric { 13459285Seric smtpmessage("EHLO %s", m, mci, MyHostName); 13561093Seric SmtpPhase = mci->mci_phase = "client EHLO"; 13659285Seric } 13759285Seric else 13859285Seric { 13959285Seric smtpmessage("HELO %s", m, mci, MyHostName); 14061093Seric SmtpPhase = mci->mci_phase = "client HELO"; 14159285Seric } 14253751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 14359285Seric r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 1448005Seric if (r < 0) 14552104Seric goto tempfail1; 1468005Seric else if (REPLYTYPE(r) == 5) 14759285Seric { 14859285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 14959285Seric { 15059285Seric /* try old SMTP instead */ 15159285Seric mci->mci_flags &= ~MCIF_ESMTP; 15259285Seric goto tryhelo; 15359285Seric } 15414913Seric goto unavailable; 15559285Seric } 1567963Seric else if (REPLYTYPE(r) != 2) 15752104Seric goto tempfail1; 1584976Seric 1594976Seric /* 16058957Seric ** Check to see if we actually ended up talking to ourself. 16158957Seric ** This means we didn't know about an alias or MX, or we managed 16258957Seric ** to connect to an echo server. 16358957Seric */ 16458957Seric 16559026Seric p = strchr(&SmtpReplyBuffer[4], ' '); 16658957Seric if (p != NULL) 16761707Seric *p = '\0'; 16867472Seric if (!bitnset(M_NOLOOPCHECK, m->m_flags) && 16967472Seric strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 17058957Seric { 17158957Seric syserr("553 %s config error: mail loops back to myself", 17258957Seric MyHostName); 17358957Seric mci->mci_exitstat = EX_CONFIG; 17458957Seric mci->mci_errno = 0; 17558957Seric smtpquit(m, mci, e); 17658957Seric return; 17758957Seric } 17858957Seric 17958957Seric /* 1809315Seric ** If this is expected to be another sendmail, send some internal 1819315Seric ** commands. 1829315Seric */ 1839315Seric 18410688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1859315Seric { 1869315Seric /* tell it to be verbose */ 18753751Seric smtpmessage("VERB", m, mci); 18859285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 1899315Seric if (r < 0) 19052104Seric goto tempfail2; 1919315Seric } 1929315Seric 19365057Seric if (mci->mci_state != MCIS_CLOSED) 19465057Seric { 19565057Seric mci->mci_state = MCIS_OPEN; 19665057Seric return; 19765057Seric } 19853751Seric 19965057Seric /* got a 421 error code during startup */ 20065057Seric 20153751Seric tempfail1: 20253751Seric tempfail2: 20353751Seric mci->mci_exitstat = EX_TEMPFAIL; 20457379Seric if (mci->mci_errno == 0) 20557379Seric mci->mci_errno = errno; 20657379Seric if (mci->mci_state != MCIS_CLOSED) 20757379Seric smtpquit(m, mci, e); 20854967Seric return; 20953751Seric 21053751Seric unavailable: 21153751Seric mci->mci_exitstat = EX_UNAVAILABLE; 21253751Seric mci->mci_errno = errno; 21353751Seric smtpquit(m, mci, e); 21454967Seric return; 21553751Seric } 21659285Seric /* 21760210Seric ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 21860210Seric ** 21960210Seric ** 22060210Seric ** Parameters: 22160210Seric ** line -- the response line. 22260210Seric ** m -- the mailer. 22360210Seric ** mci -- the mailer connection info. 22460210Seric ** e -- the envelope. 22560210Seric ** 22660210Seric ** Returns: 22760210Seric ** none. 22860210Seric */ 22960210Seric 23060210Seric void 23160210Seric esmtp_check(line, m, mci, e) 23260210Seric char *line; 23360210Seric MAILER *m; 23460210Seric register MCI *mci; 23560210Seric ENVELOPE *e; 23660210Seric { 23760210Seric if (strlen(line) < 5) 23860210Seric return; 23960210Seric line += 4; 24060210Seric if (strncmp(line, "ESMTP ", 6) == 0) 24160210Seric mci->mci_flags |= MCIF_ESMTP; 24260210Seric } 24360210Seric /* 24459285Seric ** HELO_OPTIONS -- process the options on a HELO line. 24559285Seric ** 24659285Seric ** Parameters: 24759285Seric ** line -- the response line. 24859285Seric ** m -- the mailer. 24959285Seric ** mci -- the mailer connection info. 25059285Seric ** e -- the envelope. 25159285Seric ** 25259285Seric ** Returns: 25359285Seric ** none. 25459285Seric */ 25553751Seric 25659285Seric void 25759285Seric helo_options(line, m, mci, e) 25859285Seric char *line; 25959285Seric MAILER *m; 26059285Seric register MCI *mci; 26159285Seric ENVELOPE *e; 26259285Seric { 26359285Seric register char *p; 26459285Seric 26559285Seric if (strlen(line) < 5) 26659285Seric return; 26759285Seric line += 4; 26859285Seric p = strchr(line, ' '); 26959285Seric if (p != NULL) 27059285Seric *p++ = '\0'; 27159285Seric if (strcasecmp(line, "size") == 0) 27259285Seric { 27359285Seric mci->mci_flags |= MCIF_SIZE; 27459285Seric if (p != NULL) 27559285Seric mci->mci_maxsize = atol(p); 27659285Seric } 27759285Seric else if (strcasecmp(line, "8bitmime") == 0) 27865870Seric { 27959285Seric mci->mci_flags |= MCIF_8BITMIME; 28065870Seric mci->mci_flags &= ~MCIF_7BIT; 28165870Seric } 28259285Seric else if (strcasecmp(line, "expn") == 0) 28359285Seric mci->mci_flags |= MCIF_EXPN; 284*67880Seric else if (strcasecmp(line, "dsn") == 0) 285*67880Seric mci->mci_flags |= MCIF_DSN; 28659285Seric } 28759285Seric /* 28859285Seric ** SMTPMAILFROM -- send MAIL command 28959285Seric ** 29059285Seric ** Parameters: 29159285Seric ** m -- the mailer. 29259285Seric ** mci -- the mailer connection structure. 29359285Seric ** e -- the envelope (including the sender to specify). 29459285Seric */ 29559285Seric 29653751Seric smtpmailfrom(m, mci, e) 29753751Seric struct mailer *m; 29854967Seric MCI *mci; 29953751Seric ENVELOPE *e; 30053751Seric { 30153751Seric int r; 30265494Seric char *bufp; 30353751Seric char buf[MAXNAME]; 30459285Seric char optbuf[MAXLINE]; 30553751Seric 30663753Seric if (tTd(18, 2)) 30757943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 30857943Seric 30959285Seric /* set up appropriate options to include */ 31064254Seric if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 31159285Seric sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 31259285Seric else 31359285Seric strcpy(optbuf, ""); 31459285Seric 31567417Seric if (e->e_bodytype != NULL) 31667417Seric { 31767417Seric if (bitset(MCIF_8BITMIME, mci->mci_flags)) 31867417Seric { 31967417Seric strcat(optbuf, " BODY="); 32067417Seric strcat(optbuf, e->e_bodytype); 32167417Seric } 32267546Seric else if (!bitset(MM_CVTMIME, MimeMode) && 32367546Seric strcasecmp(e->e_bodytype, "7bit") != 0) 32467417Seric { 32567417Seric /* cannot just send a 7-bit version */ 32667417Seric usrerr("%s does not support 8BITMIME", mci->mci_host); 32767417Seric return EX_DATAERR; 32867417Seric } 32967417Seric } 33067417Seric 331*67880Seric if (e->e_envid != NULL && bitset(MCIF_DSN, mci->mci_flags)) 332*67880Seric { 333*67880Seric strcat(optbuf, " ENVID="); 334*67880Seric strcat(optbuf, e->e_envid); 335*67880Seric } 336*67880Seric 3379315Seric /* 3384865Seric ** Send the MAIL command. 3394865Seric ** Designates the sender. 3404865Seric */ 3414796Seric 34253751Seric mci->mci_state = MCIS_ACTIVE; 34353751Seric 34459540Seric if (bitset(EF_RESPONSE, e->e_flags) && 34559540Seric !bitnset(M_NO_NULL_FROM, m->m_flags)) 34658680Seric (void) strcpy(buf, ""); 34758680Seric else 34858680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 34965494Seric if (buf[0] == '<') 35065494Seric { 35165494Seric /* strip off <angle brackets> (put back on below) */ 35265494Seric bufp = &buf[strlen(buf) - 1]; 35365494Seric if (*bufp == '>') 35465494Seric *bufp = '\0'; 35565494Seric bufp = &buf[1]; 35665494Seric } 35765494Seric else 35865494Seric bufp = buf; 35967472Seric if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 36010688Seric !bitnset(M_FROMPATH, m->m_flags)) 3618436Seric { 36265494Seric smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 3638436Seric } 3648436Seric else 3658436Seric { 36659285Seric smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 36765494Seric *bufp == '@' ? ',' : ':', bufp, optbuf); 3688436Seric } 36961093Seric SmtpPhase = mci->mci_phase = "client MAIL"; 37053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 37159285Seric r = reply(m, mci, e, TimeOuts.to_mail, NULL); 3728005Seric if (r < 0 || REPLYTYPE(r) == 4) 37353751Seric { 37453751Seric mci->mci_exitstat = EX_TEMPFAIL; 37553751Seric mci->mci_errno = errno; 37653751Seric smtpquit(m, mci, e); 37753751Seric return EX_TEMPFAIL; 37853751Seric } 3797963Seric else if (r == 250) 38053751Seric { 38153751Seric mci->mci_exitstat = EX_OK; 38253751Seric return EX_OK; 38353751Seric } 3847963Seric else if (r == 552) 38553751Seric { 38653751Seric /* signal service unavailable */ 38753751Seric mci->mci_exitstat = EX_UNAVAILABLE; 38853751Seric smtpquit(m, mci, e); 38953751Seric return EX_UNAVAILABLE; 39053751Seric } 39114913Seric 39258008Seric #ifdef LOG 39358020Seric if (LogLevel > 1) 39458008Seric { 39567860Seric syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s", 39667860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 39758008Seric } 39858008Seric #endif 39958008Seric 40014913Seric /* protocol error -- close up */ 40153751Seric smtpquit(m, mci, e); 40253751Seric mci->mci_exitstat = EX_PROTOCOL; 40353751Seric return EX_PROTOCOL; 4044684Seric } 4054684Seric /* 4064976Seric ** SMTPRCPT -- designate recipient. 4074797Seric ** 4084797Seric ** Parameters: 4094865Seric ** to -- address of recipient. 41010175Seric ** m -- the mailer we are sending to. 41157379Seric ** mci -- the connection info for this transaction. 41257379Seric ** e -- the envelope for this transaction. 4134797Seric ** 4144797Seric ** Returns: 4154865Seric ** exit status corresponding to recipient status. 4164797Seric ** 4174797Seric ** Side Effects: 4184865Seric ** Sends the mail via SMTP. 4194797Seric */ 4204797Seric 42153751Seric smtprcpt(to, m, mci, e) 4224865Seric ADDRESS *to; 42310175Seric register MAILER *m; 42454967Seric MCI *mci; 42553751Seric ENVELOPE *e; 4264797Seric { 4274797Seric register int r; 428*67880Seric char optbuf[MAXLINE]; 4294797Seric 430*67880Seric strcpy(optbuf, ""); 431*67880Seric if (bitset(MCIF_DSN, mci->mci_flags)) 432*67880Seric { 433*67880Seric strcat(optbuf, " NOTIFY="); 434*67880Seric if (bitset(QPINGONFAILURE, to->q_flags)) 435*67880Seric { 436*67880Seric if (bitset(QPINGONSUCCESS, to->q_flags)) 437*67880Seric strcat(optbuf, "ALWAYS"); 438*67880Seric else 439*67880Seric strcat(optbuf, "FAILURE"); 440*67880Seric } 441*67880Seric else 442*67880Seric { 443*67880Seric if (bitset(QPINGONSUCCESS, to->q_flags)) 444*67880Seric strcat(optbuf, "SUCCESS"); 445*67880Seric else 446*67880Seric strcat(optbuf, "NEVER"); 447*67880Seric } 448*67880Seric if (bitset(QHASRETPARAM, to->q_flags)) 449*67880Seric { 450*67880Seric strcat(optbuf, " RET="); 451*67880Seric if (bitset(QNOBODYRETURN, to->q_flags)) 452*67880Seric strcat(optbuf, "NO"); 453*67880Seric else 454*67880Seric strcat(optbuf, "YES"); 455*67880Seric } 456*67880Seric } 457*67880Seric else if (bitset(QPINGONSUCCESS, to->q_flags)) 458*67880Seric { 459*67880Seric to->q_flags |= QRELAYED; 460*67880Seric fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 461*67880Seric to->q_paddr); 462*67880Seric } 4634865Seric 464*67880Seric smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 465*67880Seric 46661093Seric SmtpPhase = mci->mci_phase = "client RCPT"; 46753751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 46859285Seric r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 469*67880Seric setstatus(to, SmtpReplyBuffer); 4708005Seric if (r < 0 || REPLYTYPE(r) == 4) 4714865Seric return (EX_TEMPFAIL); 4727963Seric else if (REPLYTYPE(r) == 2) 4737963Seric return (EX_OK); 4747964Seric else if (r == 550 || r == 551 || r == 553) 4757964Seric return (EX_NOUSER); 4767964Seric else if (r == 552 || r == 554) 4777964Seric return (EX_UNAVAILABLE); 47858008Seric 47958008Seric #ifdef LOG 48058020Seric if (LogLevel > 1) 48158008Seric { 48267860Seric syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s", 48367860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 48458008Seric } 48558008Seric #endif 48658008Seric 4877964Seric return (EX_PROTOCOL); 4884797Seric } 4894797Seric /* 49010175Seric ** SMTPDATA -- send the data and clean up the transaction. 4914684Seric ** 4924684Seric ** Parameters: 4934865Seric ** m -- mailer being sent to. 4946980Seric ** e -- the envelope for this message. 4954684Seric ** 4964684Seric ** Returns: 4974976Seric ** exit status corresponding to DATA command. 4984684Seric ** 4994684Seric ** Side Effects: 5004865Seric ** none. 5014684Seric */ 5024684Seric 50363753Seric static jmp_buf CtxDataTimeout; 50463937Seric static int datatimeout(); 50563753Seric 50653740Seric smtpdata(m, mci, e) 5074865Seric struct mailer *m; 50854967Seric register MCI *mci; 5096980Seric register ENVELOPE *e; 5104684Seric { 5114684Seric register int r; 51263753Seric register EVENT *ev; 51363753Seric time_t timeout; 5144684Seric 5154797Seric /* 5164797Seric ** Send the data. 51710175Seric ** First send the command and check that it is ok. 51810175Seric ** Then send the data. 51910175Seric ** Follow it up with a dot to terminate. 52010175Seric ** Finally get the results of the transaction. 5214797Seric */ 5224797Seric 52310175Seric /* send the command and check ok to proceed */ 52453751Seric smtpmessage("DATA", m, mci); 52561093Seric SmtpPhase = mci->mci_phase = "client DATA 354"; 52653751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 52759285Seric r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 5288005Seric if (r < 0 || REPLYTYPE(r) == 4) 52957990Seric { 53057990Seric smtpquit(m, mci, e); 5314797Seric return (EX_TEMPFAIL); 53257990Seric } 5337963Seric else if (r == 554) 53457990Seric { 53557990Seric smtprset(m, mci, e); 5367963Seric return (EX_UNAVAILABLE); 53757990Seric } 5387963Seric else if (r != 354) 53957990Seric { 54058008Seric #ifdef LOG 54158020Seric if (LogLevel > 1) 54258008Seric { 54367860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s", 54467860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 54558008Seric } 54658008Seric #endif 54757990Seric smtprset(m, mci, e); 5487964Seric return (EX_PROTOCOL); 54957990Seric } 55010175Seric 55163757Seric /* 55263757Seric ** Set timeout around data writes. Make it at least large 55363757Seric ** enough for DNS timeouts on all recipients plus some fudge 55463757Seric ** factor. The main thing is that it should not be infinite. 55563757Seric */ 55663757Seric 55763753Seric if (setjmp(CtxDataTimeout) != 0) 55863753Seric { 55963753Seric mci->mci_errno = errno; 56063753Seric mci->mci_exitstat = EX_TEMPFAIL; 56163753Seric mci->mci_state = MCIS_ERROR; 56263753Seric syserr("451 timeout writing message to %s", mci->mci_host); 56363753Seric smtpquit(m, mci, e); 56463753Seric return EX_TEMPFAIL; 56563753Seric } 56663753Seric 56763787Seric timeout = e->e_msgsize / 16; 56863787Seric if (timeout < (time_t) 60) 56963787Seric timeout = (time_t) 60; 57063787Seric timeout += e->e_nrcpts * 90; 57163753Seric ev = setevent(timeout, datatimeout, 0); 57263753Seric 57367546Seric /* 57467546Seric ** Output the actual message. 57567546Seric */ 57667546Seric 57767546Seric if (!bitset(MCIF_8BITMIME, mci->mci_flags) && 57867546Seric e->e_bodytype != NULL && 57967546Seric strcasecmp(e->e_bodytype, "7bit") != 0) 58067546Seric { 58167546Seric /* must convert from 8bit MIME format to 7bit encoded */ 58267546Seric mci->mci_flags |= MCIF_CVT8TO7; 58367546Seric } 58467546Seric 58567546Seric (*e->e_puthdr)(mci, e->e_header, e); 58665870Seric (*e->e_putbody)(mci, e, NULL); 58710175Seric 58867546Seric /* 58967546Seric ** Cleanup after sending message. 59067546Seric */ 59167546Seric 59263753Seric clrevent(ev); 59363753Seric 59464718Seric if (ferror(mci->mci_out)) 59564718Seric { 59664718Seric /* error during processing -- don't send the dot */ 59764718Seric mci->mci_errno = EIO; 59864718Seric mci->mci_exitstat = EX_IOERR; 59964718Seric mci->mci_state = MCIS_ERROR; 60064718Seric smtpquit(m, mci, e); 60164718Seric return EX_IOERR; 60264718Seric } 60364718Seric 60410175Seric /* terminate the message */ 60553740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 60663753Seric if (TrafficLogFile != NULL) 60763753Seric fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); 60858120Seric if (Verbose) 60958151Seric nmessage(">>> ."); 61010175Seric 61110175Seric /* check for the results of the transaction */ 61261093Seric SmtpPhase = mci->mci_phase = "client DATA 250"; 61353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 61459285Seric r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 61553751Seric if (r < 0) 61657990Seric { 61757990Seric smtpquit(m, mci, e); 6184797Seric return (EX_TEMPFAIL); 61957990Seric } 62053751Seric mci->mci_state = MCIS_OPEN; 62158917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 62253751Seric if (REPLYTYPE(r) == 4) 62353751Seric return (EX_TEMPFAIL); 6247963Seric else if (r == 250) 6257963Seric return (EX_OK); 6267963Seric else if (r == 552 || r == 554) 6277963Seric return (EX_UNAVAILABLE); 62858008Seric #ifdef LOG 62958020Seric if (LogLevel > 1) 63058008Seric { 63167860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s", 63267860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 63358008Seric } 63458008Seric #endif 6357964Seric return (EX_PROTOCOL); 6364684Seric } 63763753Seric 63863753Seric 63963753Seric static int 64063753Seric datatimeout() 64163753Seric { 64263753Seric longjmp(CtxDataTimeout, 1); 64363753Seric } 6444684Seric /* 6454865Seric ** SMTPQUIT -- close the SMTP connection. 6464865Seric ** 6474865Seric ** Parameters: 64815535Seric ** m -- a pointer to the mailer. 6494865Seric ** 6504865Seric ** Returns: 6514865Seric ** none. 6524865Seric ** 6534865Seric ** Side Effects: 6544865Seric ** sends the final protocol and closes the connection. 6554865Seric */ 6564865Seric 65753751Seric smtpquit(m, mci, e) 65853751Seric register MAILER *m; 65954967Seric register MCI *mci; 66053751Seric ENVELOPE *e; 6614865Seric { 66264822Seric bool oldSuprErrs = SuprErrs; 6634865Seric 66464822Seric /* 66564822Seric ** Suppress errors here -- we may be processing a different 66664822Seric ** job when we do the quit connection, and we don't want the 66764822Seric ** new job to be penalized for something that isn't it's 66864822Seric ** problem. 66964822Seric */ 67064822Seric 67164822Seric SuprErrs = TRUE; 67264822Seric 67354967Seric /* send the quit message if we haven't gotten I/O error */ 67453751Seric if (mci->mci_state != MCIS_ERROR) 6759391Seric { 67661093Seric SmtpPhase = "client QUIT"; 67753751Seric smtpmessage("QUIT", m, mci); 67859285Seric (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 67964822Seric SuprErrs = oldSuprErrs; 68053740Seric if (mci->mci_state == MCIS_CLOSED) 68164822Seric { 68264822Seric SuprErrs = oldSuprErrs; 68310159Seric return; 68464822Seric } 6859391Seric } 6869391Seric 68752676Seric /* now actually close the connection and pick up the zombie */ 68865194Seric (void) endmailer(mci, e, NULL); 68964822Seric 69064822Seric SuprErrs = oldSuprErrs; 6914865Seric } 6924865Seric /* 69354967Seric ** SMTPRSET -- send a RSET (reset) command 69454967Seric */ 69554967Seric 69654967Seric smtprset(m, mci, e) 69754967Seric register MAILER *m; 69854967Seric register MCI *mci; 69954967Seric ENVELOPE *e; 70054967Seric { 70154967Seric int r; 70254967Seric 70361093Seric SmtpPhase = "client RSET"; 70454967Seric smtpmessage("RSET", m, mci); 70559285Seric r = reply(m, mci, e, TimeOuts.to_rset, NULL); 70657734Seric if (r < 0) 70757734Seric mci->mci_state = MCIS_ERROR; 70854967Seric else if (REPLYTYPE(r) == 2) 70957734Seric { 71057734Seric mci->mci_state = MCIS_OPEN; 71157734Seric return; 71257734Seric } 71357734Seric smtpquit(m, mci, e); 71454967Seric } 71554967Seric /* 71658867Seric ** SMTPPROBE -- check the connection state 71754967Seric */ 71854967Seric 71958867Seric smtpprobe(mci) 72054967Seric register MCI *mci; 72154967Seric { 72254967Seric int r; 72354967Seric MAILER *m = mci->mci_mailer; 72454967Seric extern ENVELOPE BlankEnvelope; 72554967Seric ENVELOPE *e = &BlankEnvelope; 72654967Seric 72761093Seric SmtpPhase = "client probe"; 72858867Seric smtpmessage("RSET", m, mci); 72959285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 73058061Seric if (r < 0 || REPLYTYPE(r) != 2) 73154967Seric smtpquit(m, mci, e); 73254967Seric return r; 73354967Seric } 73454967Seric /* 7354684Seric ** REPLY -- read arpanet reply 7364684Seric ** 7374684Seric ** Parameters: 73810175Seric ** m -- the mailer we are reading the reply from. 73957379Seric ** mci -- the mailer connection info structure. 74057379Seric ** e -- the current envelope. 74157379Seric ** timeout -- the timeout for reads. 74259285Seric ** pfunc -- processing function for second and subsequent 74359285Seric ** lines of response -- if null, no special 74459285Seric ** processing is done. 7454684Seric ** 7464684Seric ** Returns: 7474684Seric ** reply code it reads. 7484684Seric ** 7494684Seric ** Side Effects: 7504684Seric ** flushes the mail file. 7514684Seric */ 7524684Seric 75359285Seric reply(m, mci, e, timeout, pfunc) 75453751Seric MAILER *m; 75554967Seric MCI *mci; 75653751Seric ENVELOPE *e; 75759285Seric time_t timeout; 75859285Seric void (*pfunc)(); 7594684Seric { 76059014Seric register char *bufp; 76159014Seric register int r; 76259285Seric bool firstline = TRUE; 76358957Seric char junkbuf[MAXLINE]; 76458957Seric 76557379Seric if (mci->mci_out != NULL) 76657379Seric (void) fflush(mci->mci_out); 7674684Seric 7687677Seric if (tTd(18, 1)) 7694796Seric printf("reply\n"); 7704796Seric 7717356Seric /* 7727356Seric ** Read the input line, being careful not to hang. 7737356Seric */ 7747356Seric 77559014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 7764684Seric { 7777356Seric register char *p; 77853751Seric extern time_t curtime(); 7794684Seric 7807685Seric /* actually do the read */ 78153751Seric if (e->e_xfp != NULL) 78253751Seric (void) fflush(e->e_xfp); /* for debugging */ 7837356Seric 78410054Seric /* if we are in the process of closing just give the code */ 78553740Seric if (mci->mci_state == MCIS_CLOSED) 78610054Seric return (SMTPCLOSING); 78710054Seric 78858680Seric if (mci->mci_out != NULL) 78958680Seric fflush(mci->mci_out); 79058680Seric 79110054Seric /* get the line from the other side */ 79261093Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 79353751Seric mci->mci_lastuse = curtime(); 79453751Seric 79510054Seric if (p == NULL) 79610131Seric { 79763753Seric bool oldholderrs; 79810148Seric extern char MsgBuf[]; /* err.c */ 79910148Seric 80021065Seric /* if the remote end closed early, fake an error */ 80121065Seric if (errno == 0) 80221065Seric # ifdef ECONNRESET 80321065Seric errno = ECONNRESET; 80456795Seric # else /* ECONNRESET */ 80521065Seric errno = EPIPE; 80656795Seric # endif /* ECONNRESET */ 80721065Seric 80857379Seric mci->mci_errno = errno; 80957642Seric mci->mci_exitstat = EX_TEMPFAIL; 81063753Seric oldholderrs = HoldErrs; 81163753Seric HoldErrs = TRUE; 81263753Seric usrerr("451 reply: read error from %s", mci->mci_host); 81363753Seric 81410420Seric /* if debugging, pause so we can see state */ 81510420Seric if (tTd(18, 100)) 81610420Seric pause(); 81754967Seric mci->mci_state = MCIS_ERROR; 81853751Seric smtpquit(m, mci, e); 81963753Seric #ifdef XDEBUG 82063753Seric { 82163753Seric char wbuf[MAXLINE]; 82264082Seric char *p = wbuf; 82364082Seric if (e->e_to != NULL) 82464082Seric { 82564082Seric sprintf(p, "%s... ", e->e_to); 82664082Seric p += strlen(p); 82764082Seric } 82864082Seric sprintf(p, "reply(%s) during %s", 82964082Seric mci->mci_host, SmtpPhase); 83063753Seric checkfd012(wbuf); 83163753Seric } 83263753Seric #endif 83363753Seric HoldErrs = oldholderrs; 83410054Seric return (-1); 83510131Seric } 83658957Seric fixcrlf(bufp, TRUE); 83710054Seric 83863753Seric /* EHLO failure is not a real error */ 83963753Seric if (e->e_xfp != NULL && (bufp[0] == '4' || 84063753Seric (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 84114900Seric { 84214900Seric /* serious error -- log the previous command */ 84364071Seric if (SmtpNeedIntro) 84464071Seric { 84564071Seric /* inform user who we are chatting with */ 84664071Seric fprintf(CurEnv->e_xfp, 84764071Seric "... while talking to %s:\n", 84864071Seric CurHostName); 84964071Seric SmtpNeedIntro = FALSE; 85064071Seric } 85159014Seric if (SmtpMsgBuffer[0] != '\0') 85259014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 85359014Seric SmtpMsgBuffer[0] = '\0'; 85414900Seric 85514900Seric /* now log the message as from the other side */ 85658957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 85714900Seric } 85814900Seric 85914900Seric /* display the input for verbose mode */ 86058120Seric if (Verbose) 86159956Seric nmessage("050 %s", bufp); 8627356Seric 86359285Seric /* process the line */ 86459285Seric if (pfunc != NULL && !firstline) 86559285Seric (*pfunc)(bufp, m, mci, e); 86659285Seric 86759285Seric firstline = FALSE; 86859285Seric 8697356Seric /* if continuation is required, we can go on */ 87059014Seric if (bufp[3] == '-') 8714684Seric continue; 8727356Seric 87359014Seric /* ignore improperly formated input */ 87459014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 87559014Seric continue; 87659014Seric 8777356Seric /* decode the reply code */ 87859014Seric r = atoi(bufp); 8797356Seric 8807356Seric /* extra semantics: 0xx codes are "informational" */ 88159014Seric if (r >= 100) 88259014Seric break; 88359014Seric } 8847356Seric 88559014Seric /* 88659014Seric ** Now look at SmtpReplyBuffer -- only care about the first 88759014Seric ** line of the response from here on out. 88859014Seric */ 88958061Seric 89059014Seric /* save temporary failure messages for posterity */ 89159014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 89259014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 8939391Seric 89459014Seric /* reply code 421 is "Service Shutting Down" */ 89559014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 89659014Seric { 89759014Seric /* send the quit protocol */ 89859014Seric mci->mci_state = MCIS_SSD; 89959014Seric smtpquit(m, mci, e); 9004684Seric } 90159014Seric 90259014Seric return (r); 9034684Seric } 9044796Seric /* 9054865Seric ** SMTPMESSAGE -- send message to server 9064796Seric ** 9074796Seric ** Parameters: 9084796Seric ** f -- format 90910175Seric ** m -- the mailer to control formatting. 9104796Seric ** a, b, c -- parameters 9114796Seric ** 9124796Seric ** Returns: 9134796Seric ** none. 9144796Seric ** 9154796Seric ** Side Effects: 91653740Seric ** writes message to mci->mci_out. 9174796Seric */ 9184796Seric 9194865Seric /*VARARGS1*/ 92057642Seric #ifdef __STDC__ 92157642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 92257642Seric #else 92357642Seric smtpmessage(f, m, mci, va_alist) 9244796Seric char *f; 92510175Seric MAILER *m; 92654967Seric MCI *mci; 92757642Seric va_dcl 92857642Seric #endif 9294796Seric { 93056852Seric VA_LOCAL_DECL 93156852Seric 93257135Seric VA_START(mci); 93356852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 93456852Seric VA_END; 93558680Seric 93658120Seric if (tTd(18, 1) || Verbose) 93758151Seric nmessage(">>> %s", SmtpMsgBuffer); 93863753Seric if (TrafficLogFile != NULL) 93963753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); 94053740Seric if (mci->mci_out != NULL) 94158680Seric { 94253740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 94354967Seric m == NULL ? "\r\n" : m->m_eol); 94458680Seric } 94559149Seric else if (tTd(18, 1)) 94658725Seric { 94759149Seric printf("smtpmessage: NULL mci_out\n"); 94858725Seric } 9494796Seric } 9505182Seric 95156795Seric # endif /* SMTP */ 952