122716Sdist /* 268839Seric * Copyright (c) 1983, 1995 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*69650Seric static char sccsid[] = "@(#)usersmtp.c 8.53 (Berkeley) 05/24/95 (with SMTP)"; 1433731Sbostic #else 15*69650Seric static char sccsid[] = "@(#)usersmtp.c 8.53 (Berkeley) 05/24/95 (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 */ 8268100Seric if (CurHostName == NULL) 8368100Seric CurHostName = MyHostName; 8464071Seric SmtpNeedIntro = TRUE; 8554967Seric switch (mci->mci_state) 866051Seric { 8754967Seric case MCIS_ACTIVE: 8854967Seric /* need to clear old information */ 8954967Seric smtprset(m, mci, e); 9057734Seric /* fall through */ 9115139Seric 9254967Seric case MCIS_OPEN: 9354967Seric return; 9454967Seric 9554967Seric case MCIS_ERROR: 9654967Seric case MCIS_SSD: 9754967Seric /* shouldn't happen */ 9854967Seric smtpquit(m, mci, e); 9957734Seric /* fall through */ 10054967Seric 10154967Seric case MCIS_CLOSED: 10258151Seric syserr("451 smtpinit: state CLOSED"); 10354967Seric return; 10454967Seric 10554967Seric case MCIS_OPENING: 10654967Seric break; 1076051Seric } 1084796Seric 10954967Seric mci->mci_state = MCIS_OPENING; 11054967Seric 1114865Seric /* 1124865Seric ** Get the greeting message. 11314913Seric ** This should appear spontaneously. Give it five minutes to 11414886Seric ** happen. 1154865Seric */ 1164797Seric 11761093Seric SmtpPhase = mci->mci_phase = "client greeting"; 11853751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 11960210Seric r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); 12064750Seric if (r < 0 || REPLYTYPE(r) == 4) 12152104Seric goto tempfail1; 12264750Seric if (REPLYTYPE(r) != 2) 12364750Seric goto unavailable; 1244684Seric 1254865Seric /* 1264976Seric ** Send the HELO command. 1277963Seric ** My mother taught me to always introduce myself. 1284976Seric */ 1294976Seric 13059285Seric if (bitnset(M_ESMTP, m->m_flags)) 13159285Seric mci->mci_flags |= MCIF_ESMTP; 13259285Seric 13359285Seric tryhelo: 13459285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 13559285Seric { 13659285Seric smtpmessage("EHLO %s", m, mci, MyHostName); 13761093Seric SmtpPhase = mci->mci_phase = "client EHLO"; 13859285Seric } 13959285Seric else 14059285Seric { 14159285Seric smtpmessage("HELO %s", m, mci, MyHostName); 14261093Seric SmtpPhase = mci->mci_phase = "client HELO"; 14359285Seric } 14453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 14559285Seric r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 1468005Seric if (r < 0) 14752104Seric goto tempfail1; 1488005Seric else if (REPLYTYPE(r) == 5) 14959285Seric { 15059285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 15159285Seric { 15259285Seric /* try old SMTP instead */ 15359285Seric mci->mci_flags &= ~MCIF_ESMTP; 15459285Seric goto tryhelo; 15559285Seric } 15614913Seric goto unavailable; 15759285Seric } 1587963Seric else if (REPLYTYPE(r) != 2) 15952104Seric goto tempfail1; 1604976Seric 1614976Seric /* 16258957Seric ** Check to see if we actually ended up talking to ourself. 16358957Seric ** This means we didn't know about an alias or MX, or we managed 16458957Seric ** to connect to an echo server. 16558957Seric */ 16658957Seric 16759026Seric p = strchr(&SmtpReplyBuffer[4], ' '); 16858957Seric if (p != NULL) 16961707Seric *p = '\0'; 17067472Seric if (!bitnset(M_NOLOOPCHECK, m->m_flags) && 17167472Seric strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 17258957Seric { 17358957Seric syserr("553 %s config error: mail loops back to myself", 17458957Seric MyHostName); 17558957Seric mci->mci_exitstat = EX_CONFIG; 17658957Seric mci->mci_errno = 0; 17758957Seric smtpquit(m, mci, e); 17858957Seric return; 17958957Seric } 18058957Seric 18158957Seric /* 1829315Seric ** If this is expected to be another sendmail, send some internal 1839315Seric ** commands. 1849315Seric */ 1859315Seric 18610688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1879315Seric { 1889315Seric /* tell it to be verbose */ 18953751Seric smtpmessage("VERB", m, mci); 19059285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 1919315Seric if (r < 0) 19252104Seric goto tempfail2; 1939315Seric } 1949315Seric 19565057Seric if (mci->mci_state != MCIS_CLOSED) 19665057Seric { 19765057Seric mci->mci_state = MCIS_OPEN; 19865057Seric return; 19965057Seric } 20053751Seric 20165057Seric /* got a 421 error code during startup */ 20265057Seric 20353751Seric tempfail1: 20453751Seric tempfail2: 20553751Seric mci->mci_exitstat = EX_TEMPFAIL; 20657379Seric if (mci->mci_errno == 0) 20757379Seric mci->mci_errno = errno; 20857379Seric if (mci->mci_state != MCIS_CLOSED) 20957379Seric smtpquit(m, mci, e); 21054967Seric return; 21153751Seric 21253751Seric unavailable: 21353751Seric mci->mci_exitstat = EX_UNAVAILABLE; 21453751Seric mci->mci_errno = errno; 21553751Seric smtpquit(m, mci, e); 21654967Seric return; 21753751Seric } 21859285Seric /* 21960210Seric ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 22060210Seric ** 22160210Seric ** Parameters: 22260210Seric ** line -- the response line. 22367893Seric ** firstline -- set if this is the first line of the reply. 22460210Seric ** m -- the mailer. 22560210Seric ** mci -- the mailer connection info. 22660210Seric ** e -- the envelope. 22760210Seric ** 22860210Seric ** Returns: 22960210Seric ** none. 23060210Seric */ 23160210Seric 23260210Seric void 23367893Seric esmtp_check(line, firstline, m, mci, e) 23460210Seric char *line; 23567893Seric bool firstline; 23660210Seric MAILER *m; 23760210Seric register MCI *mci; 23860210Seric ENVELOPE *e; 23960210Seric { 240*69650Seric if (strstr(line, "ESMTP ") != NULL) 241*69650Seric mci->mci_flags |= MCIF_ESMTP; 242*69650Seric if (strstr(line, "8BIT OK") != NULL) 243*69650Seric mci->mci_flags |= MCIF_8BITOK; 24460210Seric } 24560210Seric /* 24659285Seric ** HELO_OPTIONS -- process the options on a HELO line. 24759285Seric ** 24859285Seric ** Parameters: 24959285Seric ** line -- the response line. 25067893Seric ** firstline -- set if this is the first line of the reply. 25159285Seric ** m -- the mailer. 25259285Seric ** mci -- the mailer connection info. 25359285Seric ** e -- the envelope. 25459285Seric ** 25559285Seric ** Returns: 25659285Seric ** none. 25759285Seric */ 25853751Seric 25959285Seric void 26067893Seric helo_options(line, firstline, m, mci, e) 26159285Seric char *line; 26267893Seric bool firstline; 26359285Seric MAILER *m; 26459285Seric register MCI *mci; 26559285Seric ENVELOPE *e; 26659285Seric { 26759285Seric register char *p; 26859285Seric 26967971Seric if (firstline) 27067893Seric return; 27167893Seric 27268706Seric if (strlen(line) < (SIZE_T) 5) 27359285Seric return; 27459285Seric line += 4; 27559285Seric p = strchr(line, ' '); 27659285Seric if (p != NULL) 27759285Seric *p++ = '\0'; 27859285Seric if (strcasecmp(line, "size") == 0) 27959285Seric { 28059285Seric mci->mci_flags |= MCIF_SIZE; 28159285Seric if (p != NULL) 28259285Seric mci->mci_maxsize = atol(p); 28359285Seric } 28459285Seric else if (strcasecmp(line, "8bitmime") == 0) 28565870Seric { 28659285Seric mci->mci_flags |= MCIF_8BITMIME; 28765870Seric mci->mci_flags &= ~MCIF_7BIT; 28865870Seric } 28959285Seric else if (strcasecmp(line, "expn") == 0) 29059285Seric mci->mci_flags |= MCIF_EXPN; 29168606Seric else if (strcasecmp(line, "x-dsn-03") == 0) 29267880Seric mci->mci_flags |= MCIF_DSN; 29359285Seric } 29459285Seric /* 29559285Seric ** SMTPMAILFROM -- send MAIL command 29659285Seric ** 29759285Seric ** Parameters: 29859285Seric ** m -- the mailer. 29959285Seric ** mci -- the mailer connection structure. 30059285Seric ** e -- the envelope (including the sender to specify). 30159285Seric */ 30259285Seric 30353751Seric smtpmailfrom(m, mci, e) 30453751Seric struct mailer *m; 30554967Seric MCI *mci; 30653751Seric ENVELOPE *e; 30753751Seric { 30853751Seric int r; 30965494Seric char *bufp; 31067887Seric char *bodytype; 31168528Seric char buf[MAXNAME + 1]; 31259285Seric char optbuf[MAXLINE]; 31353751Seric 31463753Seric if (tTd(18, 2)) 31557943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 31657943Seric 31759285Seric /* set up appropriate options to include */ 31864254Seric if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 31959285Seric sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 32059285Seric else 32159285Seric strcpy(optbuf, ""); 32259285Seric 32367887Seric bodytype = e->e_bodytype; 32467887Seric if (bitset(MCIF_8BITMIME, mci->mci_flags)) 32567417Seric { 32667887Seric if (bodytype == NULL && 32767887Seric bitset(MM_MIME8BIT, MimeMode) && 32867887Seric bitset(EF_HAS8BIT, e->e_flags) && 32967887Seric !bitnset(M_8BITS, m->m_flags)) 33067887Seric bodytype = "8BITMIME"; 33167887Seric if (bodytype != NULL) 33267417Seric { 33367417Seric strcat(optbuf, " BODY="); 33467887Seric strcat(optbuf, bodytype); 33567417Seric } 33667417Seric } 33767995Seric else if (bitnset(M_8BITS, m->m_flags) || 33869104Seric !bitset(EF_HAS8BIT, e->e_flags)) 33967887Seric { 34067887Seric /* just pass it through */ 34167887Seric } 34269480Seric #if MIME8TO7 34367887Seric else if (bitset(MM_CVTMIME, MimeMode) && 34468884Seric (!bitset(MM_PASS8BIT, MimeMode) || 34568884Seric bitset(EF_IS_MIME, e->e_flags))) 34667887Seric { 34767887Seric /* must convert from 8bit MIME format to 7bit encoded */ 34867887Seric mci->mci_flags |= MCIF_CVT8TO7; 34967887Seric } 35069480Seric #endif 35167887Seric else if (!bitset(MM_PASS8BIT, MimeMode)) 35267887Seric { 35367887Seric /* cannot just send a 8-bit version */ 35467887Seric usrerr("%s does not support 8BITMIME", mci->mci_host); 35568857Seric mci->mci_status = "5.6.3"; 35667887Seric return EX_DATAERR; 35767887Seric } 35867417Seric 35967963Seric if (bitset(MCIF_DSN, mci->mci_flags)) 36067880Seric { 36167963Seric if (e->e_envid != NULL) 36267963Seric { 36367963Seric strcat(optbuf, " ENVID="); 36467963Seric strcat(optbuf, e->e_envid); 36567963Seric } 36668559Seric 36768559Seric /* RET= parameter */ 36868559Seric if (bitset(EF_RET_PARAM, e->e_flags)) 36968559Seric { 37068559Seric strcat(optbuf, " RET="); 37168559Seric if (bitset(EF_NO_BODY_RETN, e->e_flags)) 37268559Seric strcat(optbuf, "HDRS"); 37368559Seric else 37468559Seric strcat(optbuf, "FULL"); 37568559Seric } 37667880Seric } 37767880Seric 3789315Seric /* 3794865Seric ** Send the MAIL command. 3804865Seric ** Designates the sender. 3814865Seric */ 3824796Seric 38353751Seric mci->mci_state = MCIS_ACTIVE; 38453751Seric 38559540Seric if (bitset(EF_RESPONSE, e->e_flags) && 38659540Seric !bitnset(M_NO_NULL_FROM, m->m_flags)) 38758680Seric (void) strcpy(buf, ""); 38858680Seric else 38968529Seric expand("\201g", buf, sizeof buf, e); 39065494Seric if (buf[0] == '<') 39165494Seric { 39265494Seric /* strip off <angle brackets> (put back on below) */ 39365494Seric bufp = &buf[strlen(buf) - 1]; 39465494Seric if (*bufp == '>') 39565494Seric *bufp = '\0'; 39665494Seric bufp = &buf[1]; 39765494Seric } 39865494Seric else 39965494Seric bufp = buf; 40067472Seric if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 40110688Seric !bitnset(M_FROMPATH, m->m_flags)) 4028436Seric { 40365494Seric smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 4048436Seric } 4058436Seric else 4068436Seric { 40759285Seric smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 40865494Seric *bufp == '@' ? ',' : ':', bufp, optbuf); 4098436Seric } 41061093Seric SmtpPhase = mci->mci_phase = "client MAIL"; 41153751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 41259285Seric r = reply(m, mci, e, TimeOuts.to_mail, NULL); 41368811Seric if (r < 0 || r == 421) 41453751Seric { 41568811Seric /* communications failure/service shutting down */ 41653751Seric mci->mci_exitstat = EX_TEMPFAIL; 41753751Seric mci->mci_errno = errno; 41853751Seric smtpquit(m, mci, e); 41953751Seric return EX_TEMPFAIL; 42053751Seric } 42168811Seric else if (REPLYTYPE(r) == 4) 42268811Seric { 42368811Seric return EX_TEMPFAIL; 42468811Seric } 4257963Seric else if (r == 250) 42653751Seric { 42753751Seric return EX_OK; 42853751Seric } 42968857Seric else if (r == 501) 43068075Seric { 43168857Seric /* syntax error in arguments */ 43268857Seric mci->mci_status = "5.5.2"; 43368075Seric return EX_DATAERR; 43468075Seric } 43568857Seric else if (r == 553) 43668857Seric { 43768857Seric /* mailbox name not allowed */ 43868857Seric mci->mci_status = "5.1.3"; 43968857Seric return EX_DATAERR; 44068857Seric } 4417963Seric else if (r == 552) 44253751Seric { 44368811Seric /* exceeded storage allocation */ 44468857Seric mci->mci_status = "5.2.2"; 44553751Seric return EX_UNAVAILABLE; 44653751Seric } 44714913Seric 44858008Seric #ifdef LOG 44958020Seric if (LogLevel > 1) 45058008Seric { 45167860Seric syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s", 45267860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 45358008Seric } 45458008Seric #endif 45558008Seric 45614913Seric /* protocol error -- close up */ 45753751Seric smtpquit(m, mci, e); 45853751Seric return EX_PROTOCOL; 4594684Seric } 4604684Seric /* 4614976Seric ** SMTPRCPT -- designate recipient. 4624797Seric ** 4634797Seric ** Parameters: 4644865Seric ** to -- address of recipient. 46510175Seric ** m -- the mailer we are sending to. 46657379Seric ** mci -- the connection info for this transaction. 46757379Seric ** e -- the envelope for this transaction. 4684797Seric ** 4694797Seric ** Returns: 4704865Seric ** exit status corresponding to recipient status. 4714797Seric ** 4724797Seric ** Side Effects: 4734865Seric ** Sends the mail via SMTP. 4744797Seric */ 4754797Seric 47653751Seric smtprcpt(to, m, mci, e) 4774865Seric ADDRESS *to; 47810175Seric register MAILER *m; 47954967Seric MCI *mci; 48053751Seric ENVELOPE *e; 4814797Seric { 4824797Seric register int r; 48367880Seric char optbuf[MAXLINE]; 48468857Seric extern char *smtptodsn(); 4854797Seric 48667880Seric strcpy(optbuf, ""); 48767880Seric if (bitset(MCIF_DSN, mci->mci_flags)) 48867880Seric { 48967987Seric /* NOTIFY= parameter */ 49068603Seric if (bitset(QHASNOTIFY, to->q_flags) && 49168603Seric bitset(QPRIMARY, to->q_flags)) 49267880Seric { 49368595Seric bool firstone = TRUE; 49468595Seric 49568595Seric strcat(optbuf, " NOTIFY="); 49668595Seric if (bitset(QPINGONSUCCESS, to->q_flags)) 49768595Seric { 49868595Seric strcat(optbuf, "SUCCESS"); 49968595Seric firstone = FALSE; 50068595Seric } 50168595Seric if (bitset(QPINGONFAILURE, to->q_flags)) 50268595Seric { 50368595Seric if (!firstone) 50468595Seric strcat(optbuf, ","); 50568595Seric strcat(optbuf, "FAILURE"); 50668595Seric firstone = FALSE; 50768595Seric } 50868595Seric if (bitset(QPINGONDELAY, to->q_flags)) 50968595Seric { 51068595Seric if (!firstone) 51168595Seric strcat(optbuf, ","); 51268595Seric strcat(optbuf, "DELAY"); 51368595Seric firstone = FALSE; 51468595Seric } 51568595Seric if (firstone) 51668595Seric strcat(optbuf, "NEVER"); 51767880Seric } 51867963Seric 51967987Seric /* ORCPT= parameter */ 52067987Seric if (to->q_orcpt != NULL) 52167987Seric { 52267987Seric strcat(optbuf, " ORCPT="); 52367987Seric strcat(optbuf, to->q_orcpt); 52467987Seric } 52567880Seric } 5264865Seric 52767880Seric smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 52867880Seric 52961093Seric SmtpPhase = mci->mci_phase = "client RCPT"; 53053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 53159285Seric r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 53268867Seric to->q_rstatus = newstr(SmtpReplyBuffer); 53368857Seric to->q_status = smtptodsn(r); 5348005Seric if (r < 0 || REPLYTYPE(r) == 4) 53568857Seric return EX_TEMPFAIL; 5367963Seric else if (REPLYTYPE(r) == 2) 53768857Seric return EX_OK; 5387964Seric else if (r == 550 || r == 551 || r == 553) 53968857Seric return EX_NOUSER; 5407964Seric else if (r == 552 || r == 554) 54168857Seric return EX_UNAVAILABLE; 54258008Seric 54358008Seric #ifdef LOG 54458020Seric if (LogLevel > 1) 54558008Seric { 54667860Seric syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s", 54767860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 54858008Seric } 54958008Seric #endif 55058008Seric 5517964Seric return (EX_PROTOCOL); 5524797Seric } 5534797Seric /* 55410175Seric ** SMTPDATA -- send the data and clean up the transaction. 5554684Seric ** 5564684Seric ** Parameters: 5574865Seric ** m -- mailer being sent to. 5586980Seric ** e -- the envelope for this message. 5594684Seric ** 5604684Seric ** Returns: 5614976Seric ** exit status corresponding to DATA command. 5624684Seric ** 5634684Seric ** Side Effects: 5644865Seric ** none. 5654684Seric */ 5664684Seric 56763753Seric static jmp_buf CtxDataTimeout; 56868433Seric static void datatimeout(); 56963753Seric 57053740Seric smtpdata(m, mci, e) 5714865Seric struct mailer *m; 57254967Seric register MCI *mci; 5736980Seric register ENVELOPE *e; 5744684Seric { 5754684Seric register int r; 57663753Seric register EVENT *ev; 57763753Seric time_t timeout; 5784684Seric 5794797Seric /* 5804797Seric ** Send the data. 58110175Seric ** First send the command and check that it is ok. 58210175Seric ** Then send the data. 58310175Seric ** Follow it up with a dot to terminate. 58410175Seric ** Finally get the results of the transaction. 5854797Seric */ 5864797Seric 58710175Seric /* send the command and check ok to proceed */ 58853751Seric smtpmessage("DATA", m, mci); 58961093Seric SmtpPhase = mci->mci_phase = "client DATA 354"; 59053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 59159285Seric r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 5928005Seric if (r < 0 || REPLYTYPE(r) == 4) 59357990Seric { 59457990Seric smtpquit(m, mci, e); 5954797Seric return (EX_TEMPFAIL); 59657990Seric } 5977963Seric else if (r == 554) 59857990Seric { 59957990Seric smtprset(m, mci, e); 6007963Seric return (EX_UNAVAILABLE); 60157990Seric } 6027963Seric else if (r != 354) 60357990Seric { 60458008Seric #ifdef LOG 60558020Seric if (LogLevel > 1) 60658008Seric { 60767860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s", 60867860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 60958008Seric } 61058008Seric #endif 61157990Seric smtprset(m, mci, e); 6127964Seric return (EX_PROTOCOL); 61357990Seric } 61410175Seric 61563757Seric /* 61663757Seric ** Set timeout around data writes. Make it at least large 61763757Seric ** enough for DNS timeouts on all recipients plus some fudge 61863757Seric ** factor. The main thing is that it should not be infinite. 61963757Seric */ 62063757Seric 62163753Seric if (setjmp(CtxDataTimeout) != 0) 62263753Seric { 62363753Seric mci->mci_errno = errno; 62463753Seric mci->mci_exitstat = EX_TEMPFAIL; 62563753Seric mci->mci_state = MCIS_ERROR; 62663753Seric syserr("451 timeout writing message to %s", mci->mci_host); 62763753Seric smtpquit(m, mci, e); 62863753Seric return EX_TEMPFAIL; 62963753Seric } 63063753Seric 63163787Seric timeout = e->e_msgsize / 16; 63268740Seric if (timeout < (time_t) 600) 63368740Seric timeout = (time_t) 600; 63468740Seric timeout += e->e_nrcpts * 300; 63563753Seric ev = setevent(timeout, datatimeout, 0); 63663753Seric 63767546Seric /* 63867546Seric ** Output the actual message. 63967546Seric */ 64067546Seric 64168228Seric (*e->e_puthdr)(mci, e->e_header, e); 64268228Seric (*e->e_putbody)(mci, e, NULL); 64310175Seric 64467546Seric /* 64567546Seric ** Cleanup after sending message. 64667546Seric */ 64767546Seric 64863753Seric clrevent(ev); 64963753Seric 65064718Seric if (ferror(mci->mci_out)) 65164718Seric { 65264718Seric /* error during processing -- don't send the dot */ 65364718Seric mci->mci_errno = EIO; 65464718Seric mci->mci_exitstat = EX_IOERR; 65564718Seric mci->mci_state = MCIS_ERROR; 65664718Seric smtpquit(m, mci, e); 65764718Seric return EX_IOERR; 65864718Seric } 65964718Seric 66010175Seric /* terminate the message */ 66153740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 66263753Seric if (TrafficLogFile != NULL) 66363753Seric fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); 66458120Seric if (Verbose) 66558151Seric nmessage(">>> ."); 66610175Seric 66710175Seric /* check for the results of the transaction */ 66861093Seric SmtpPhase = mci->mci_phase = "client DATA 250"; 66953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 67059285Seric r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 67153751Seric if (r < 0) 67257990Seric { 67357990Seric smtpquit(m, mci, e); 6744797Seric return (EX_TEMPFAIL); 67557990Seric } 67653751Seric mci->mci_state = MCIS_OPEN; 67758917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 67853751Seric if (REPLYTYPE(r) == 4) 67953751Seric return (EX_TEMPFAIL); 6807963Seric else if (r == 250) 6817963Seric return (EX_OK); 6827963Seric else if (r == 552 || r == 554) 6837963Seric return (EX_UNAVAILABLE); 68458008Seric #ifdef LOG 68558020Seric if (LogLevel > 1) 68658008Seric { 68767860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s", 68867860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 68958008Seric } 69058008Seric #endif 6917964Seric return (EX_PROTOCOL); 6924684Seric } 69363753Seric 69463753Seric 69568433Seric static void 69663753Seric datatimeout() 69763753Seric { 69863753Seric longjmp(CtxDataTimeout, 1); 69963753Seric } 7004684Seric /* 7014865Seric ** SMTPQUIT -- close the SMTP connection. 7024865Seric ** 7034865Seric ** Parameters: 70415535Seric ** m -- a pointer to the mailer. 7054865Seric ** 7064865Seric ** Returns: 7074865Seric ** none. 7084865Seric ** 7094865Seric ** Side Effects: 7104865Seric ** sends the final protocol and closes the connection. 7114865Seric */ 7124865Seric 71353751Seric smtpquit(m, mci, e) 71453751Seric register MAILER *m; 71554967Seric register MCI *mci; 71653751Seric ENVELOPE *e; 7174865Seric { 71864822Seric bool oldSuprErrs = SuprErrs; 7194865Seric 72064822Seric /* 72164822Seric ** Suppress errors here -- we may be processing a different 72264822Seric ** job when we do the quit connection, and we don't want the 72364822Seric ** new job to be penalized for something that isn't it's 72464822Seric ** problem. 72564822Seric */ 72664822Seric 72764822Seric SuprErrs = TRUE; 72864822Seric 72954967Seric /* send the quit message if we haven't gotten I/O error */ 73053751Seric if (mci->mci_state != MCIS_ERROR) 7319391Seric { 73261093Seric SmtpPhase = "client QUIT"; 73353751Seric smtpmessage("QUIT", m, mci); 73459285Seric (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 73564822Seric SuprErrs = oldSuprErrs; 73653740Seric if (mci->mci_state == MCIS_CLOSED) 73764822Seric { 73864822Seric SuprErrs = oldSuprErrs; 73910159Seric return; 74064822Seric } 7419391Seric } 7429391Seric 74352676Seric /* now actually close the connection and pick up the zombie */ 74465194Seric (void) endmailer(mci, e, NULL); 74564822Seric 74664822Seric SuprErrs = oldSuprErrs; 7474865Seric } 7484865Seric /* 74954967Seric ** SMTPRSET -- send a RSET (reset) command 75054967Seric */ 75154967Seric 75254967Seric smtprset(m, mci, e) 75354967Seric register MAILER *m; 75454967Seric register MCI *mci; 75554967Seric ENVELOPE *e; 75654967Seric { 75754967Seric int r; 75854967Seric 75961093Seric SmtpPhase = "client RSET"; 76054967Seric smtpmessage("RSET", m, mci); 76159285Seric r = reply(m, mci, e, TimeOuts.to_rset, NULL); 76257734Seric if (r < 0) 76357734Seric mci->mci_state = MCIS_ERROR; 76454967Seric else if (REPLYTYPE(r) == 2) 76557734Seric { 76657734Seric mci->mci_state = MCIS_OPEN; 76757734Seric return; 76857734Seric } 76957734Seric smtpquit(m, mci, e); 77054967Seric } 77154967Seric /* 77258867Seric ** SMTPPROBE -- check the connection state 77354967Seric */ 77454967Seric 77558867Seric smtpprobe(mci) 77654967Seric register MCI *mci; 77754967Seric { 77854967Seric int r; 77954967Seric MAILER *m = mci->mci_mailer; 78054967Seric extern ENVELOPE BlankEnvelope; 78154967Seric ENVELOPE *e = &BlankEnvelope; 78254967Seric 78361093Seric SmtpPhase = "client probe"; 78458867Seric smtpmessage("RSET", m, mci); 78559285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 78658061Seric if (r < 0 || REPLYTYPE(r) != 2) 78754967Seric smtpquit(m, mci, e); 78854967Seric return r; 78954967Seric } 79054967Seric /* 7914684Seric ** REPLY -- read arpanet reply 7924684Seric ** 7934684Seric ** Parameters: 79410175Seric ** m -- the mailer we are reading the reply from. 79557379Seric ** mci -- the mailer connection info structure. 79657379Seric ** e -- the current envelope. 79757379Seric ** timeout -- the timeout for reads. 79869107Seric ** pfunc -- processing function called on each line of response. 79969107Seric ** If null, no special processing is done. 8004684Seric ** 8014684Seric ** Returns: 8024684Seric ** reply code it reads. 8034684Seric ** 8044684Seric ** Side Effects: 8054684Seric ** flushes the mail file. 8064684Seric */ 8074684Seric 80859285Seric reply(m, mci, e, timeout, pfunc) 80953751Seric MAILER *m; 81054967Seric MCI *mci; 81153751Seric ENVELOPE *e; 81259285Seric time_t timeout; 81359285Seric void (*pfunc)(); 8144684Seric { 81559014Seric register char *bufp; 81659014Seric register int r; 81759285Seric bool firstline = TRUE; 81858957Seric char junkbuf[MAXLINE]; 81958957Seric 82057379Seric if (mci->mci_out != NULL) 82157379Seric (void) fflush(mci->mci_out); 8224684Seric 8237677Seric if (tTd(18, 1)) 8244796Seric printf("reply\n"); 8254796Seric 8267356Seric /* 8277356Seric ** Read the input line, being careful not to hang. 8287356Seric */ 8297356Seric 83059014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 8314684Seric { 8327356Seric register char *p; 83353751Seric extern time_t curtime(); 8344684Seric 8357685Seric /* actually do the read */ 83653751Seric if (e->e_xfp != NULL) 83753751Seric (void) fflush(e->e_xfp); /* for debugging */ 8387356Seric 83910054Seric /* if we are in the process of closing just give the code */ 84053740Seric if (mci->mci_state == MCIS_CLOSED) 84110054Seric return (SMTPCLOSING); 84210054Seric 84358680Seric if (mci->mci_out != NULL) 84458680Seric fflush(mci->mci_out); 84558680Seric 84610054Seric /* get the line from the other side */ 84761093Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 84853751Seric mci->mci_lastuse = curtime(); 84953751Seric 85010054Seric if (p == NULL) 85110131Seric { 85263753Seric bool oldholderrs; 85310148Seric extern char MsgBuf[]; /* err.c */ 85410148Seric 85521065Seric /* if the remote end closed early, fake an error */ 85621065Seric if (errno == 0) 85721065Seric # ifdef ECONNRESET 85821065Seric errno = ECONNRESET; 85956795Seric # else /* ECONNRESET */ 86021065Seric errno = EPIPE; 86156795Seric # endif /* ECONNRESET */ 86221065Seric 86357379Seric mci->mci_errno = errno; 86457642Seric mci->mci_exitstat = EX_TEMPFAIL; 86563753Seric oldholderrs = HoldErrs; 86663753Seric HoldErrs = TRUE; 86763753Seric usrerr("451 reply: read error from %s", mci->mci_host); 86863753Seric 86910420Seric /* if debugging, pause so we can see state */ 87010420Seric if (tTd(18, 100)) 87110420Seric pause(); 87254967Seric mci->mci_state = MCIS_ERROR; 87353751Seric smtpquit(m, mci, e); 87463753Seric #ifdef XDEBUG 87563753Seric { 87663753Seric char wbuf[MAXLINE]; 87764082Seric char *p = wbuf; 87864082Seric if (e->e_to != NULL) 87964082Seric { 88064082Seric sprintf(p, "%s... ", e->e_to); 88164082Seric p += strlen(p); 88264082Seric } 88364082Seric sprintf(p, "reply(%s) during %s", 88464082Seric mci->mci_host, SmtpPhase); 88563753Seric checkfd012(wbuf); 88663753Seric } 88763753Seric #endif 88863753Seric HoldErrs = oldholderrs; 88910054Seric return (-1); 89010131Seric } 89158957Seric fixcrlf(bufp, TRUE); 89210054Seric 89363753Seric /* EHLO failure is not a real error */ 89463753Seric if (e->e_xfp != NULL && (bufp[0] == '4' || 89563753Seric (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 89614900Seric { 89714900Seric /* serious error -- log the previous command */ 89864071Seric if (SmtpNeedIntro) 89964071Seric { 90064071Seric /* inform user who we are chatting with */ 90164071Seric fprintf(CurEnv->e_xfp, 90264071Seric "... while talking to %s:\n", 90364071Seric CurHostName); 90464071Seric SmtpNeedIntro = FALSE; 90564071Seric } 90659014Seric if (SmtpMsgBuffer[0] != '\0') 90759014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 90859014Seric SmtpMsgBuffer[0] = '\0'; 90914900Seric 91014900Seric /* now log the message as from the other side */ 91158957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 91214900Seric } 91314900Seric 91414900Seric /* display the input for verbose mode */ 91558120Seric if (Verbose) 91659956Seric nmessage("050 %s", bufp); 9177356Seric 91859285Seric /* process the line */ 91967893Seric if (pfunc != NULL) 92067893Seric (*pfunc)(bufp, firstline, m, mci, e); 92159285Seric 92259285Seric firstline = FALSE; 92359285Seric 9247356Seric /* if continuation is required, we can go on */ 92559014Seric if (bufp[3] == '-') 9264684Seric continue; 9277356Seric 92859014Seric /* ignore improperly formated input */ 92959014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 93059014Seric continue; 93159014Seric 9327356Seric /* decode the reply code */ 93359014Seric r = atoi(bufp); 9347356Seric 9357356Seric /* extra semantics: 0xx codes are "informational" */ 93659014Seric if (r >= 100) 93759014Seric break; 93859014Seric } 9397356Seric 94059014Seric /* 94159014Seric ** Now look at SmtpReplyBuffer -- only care about the first 94259014Seric ** line of the response from here on out. 94359014Seric */ 94458061Seric 94559014Seric /* save temporary failure messages for posterity */ 94659014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 94759014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 9489391Seric 94959014Seric /* reply code 421 is "Service Shutting Down" */ 95059014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 95159014Seric { 95259014Seric /* send the quit protocol */ 95359014Seric mci->mci_state = MCIS_SSD; 95459014Seric smtpquit(m, mci, e); 9554684Seric } 95659014Seric 95759014Seric return (r); 9584684Seric } 9594796Seric /* 9604865Seric ** SMTPMESSAGE -- send message to server 9614796Seric ** 9624796Seric ** Parameters: 9634796Seric ** f -- format 96410175Seric ** m -- the mailer to control formatting. 9654796Seric ** a, b, c -- parameters 9664796Seric ** 9674796Seric ** Returns: 9684796Seric ** none. 9694796Seric ** 9704796Seric ** Side Effects: 97153740Seric ** writes message to mci->mci_out. 9724796Seric */ 9734796Seric 9744865Seric /*VARARGS1*/ 97557642Seric #ifdef __STDC__ 97657642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 97757642Seric #else 97857642Seric smtpmessage(f, m, mci, va_alist) 9794796Seric char *f; 98010175Seric MAILER *m; 98154967Seric MCI *mci; 98257642Seric va_dcl 98357642Seric #endif 9844796Seric { 98556852Seric VA_LOCAL_DECL 98656852Seric 98757135Seric VA_START(mci); 98856852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 98956852Seric VA_END; 99058680Seric 99158120Seric if (tTd(18, 1) || Verbose) 99258151Seric nmessage(">>> %s", SmtpMsgBuffer); 99363753Seric if (TrafficLogFile != NULL) 99463753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); 99553740Seric if (mci->mci_out != NULL) 99658680Seric { 99753740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 99854967Seric m == NULL ? "\r\n" : m->m_eol); 99958680Seric } 100059149Seric else if (tTd(18, 1)) 100158725Seric { 100259149Seric printf("smtpmessage: NULL mci_out\n"); 100358725Seric } 10044796Seric } 10055182Seric 100656795Seric # endif /* SMTP */ 1007