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*67887Seric static char sccsid[] = "@(#)usersmtp.c 8.25 (Berkeley) 11/05/94 (with SMTP)"; 1433731Sbostic #else 15*67887Seric static char sccsid[] = "@(#)usersmtp.c 8.25 (Berkeley) 11/05/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*67887Seric else if (strcasecmp(line, "x-dsn-0") == 0) 28567880Seric 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; 303*67887Seric char *bodytype; 30453751Seric char buf[MAXNAME]; 30559285Seric char optbuf[MAXLINE]; 30653751Seric 30763753Seric if (tTd(18, 2)) 30857943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 30957943Seric 31059285Seric /* set up appropriate options to include */ 31164254Seric if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 31259285Seric sprintf(optbuf, " SIZE=%ld", e->e_msgsize); 31359285Seric else 31459285Seric strcpy(optbuf, ""); 31559285Seric 316*67887Seric bodytype = e->e_bodytype; 317*67887Seric if (bitset(MCIF_8BITMIME, mci->mci_flags)) 31867417Seric { 319*67887Seric if (bodytype == NULL && 320*67887Seric bitset(MM_MIME8BIT, MimeMode) && 321*67887Seric bitset(EF_HAS8BIT, e->e_flags) && 322*67887Seric !bitnset(M_8BITS, m->m_flags)) 323*67887Seric bodytype = "8BITMIME"; 324*67887Seric if (bodytype != NULL) 32567417Seric { 32667417Seric strcat(optbuf, " BODY="); 327*67887Seric strcat(optbuf, bodytype); 32867417Seric } 32967417Seric } 330*67887Seric else if (bitnset(M_8BITS, m->m_flags)) 331*67887Seric { 332*67887Seric /* just pass it through */ 333*67887Seric } 334*67887Seric else if (bitset(MM_CVTMIME, MimeMode) && 335*67887Seric (e->e_bodytype == NULL ? !bitset(MM_PASS8BIT, MimeMode) 336*67887Seric : strcasecmp(e->e_bodytype, "7bit") != 0)) 337*67887Seric { 338*67887Seric /* must convert from 8bit MIME format to 7bit encoded */ 339*67887Seric mci->mci_flags |= MCIF_CVT8TO7; 340*67887Seric } 341*67887Seric else if (!bitset(MM_PASS8BIT, MimeMode)) 342*67887Seric { 343*67887Seric /* cannot just send a 8-bit version */ 344*67887Seric usrerr("%s does not support 8BITMIME", mci->mci_host); 345*67887Seric return EX_DATAERR; 346*67887Seric } 34767417Seric 34867880Seric if (e->e_envid != NULL && bitset(MCIF_DSN, mci->mci_flags)) 34967880Seric { 35067880Seric strcat(optbuf, " ENVID="); 35167880Seric strcat(optbuf, e->e_envid); 35267880Seric } 35367880Seric 3549315Seric /* 3554865Seric ** Send the MAIL command. 3564865Seric ** Designates the sender. 3574865Seric */ 3584796Seric 35953751Seric mci->mci_state = MCIS_ACTIVE; 36053751Seric 36159540Seric if (bitset(EF_RESPONSE, e->e_flags) && 36259540Seric !bitnset(M_NO_NULL_FROM, m->m_flags)) 36358680Seric (void) strcpy(buf, ""); 36458680Seric else 36558680Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 36665494Seric if (buf[0] == '<') 36765494Seric { 36865494Seric /* strip off <angle brackets> (put back on below) */ 36965494Seric bufp = &buf[strlen(buf) - 1]; 37065494Seric if (*bufp == '>') 37165494Seric *bufp = '\0'; 37265494Seric bufp = &buf[1]; 37365494Seric } 37465494Seric else 37565494Seric bufp = buf; 37667472Seric if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 37710688Seric !bitnset(M_FROMPATH, m->m_flags)) 3788436Seric { 37965494Seric smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 3808436Seric } 3818436Seric else 3828436Seric { 38359285Seric smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 38465494Seric *bufp == '@' ? ',' : ':', bufp, optbuf); 3858436Seric } 38661093Seric SmtpPhase = mci->mci_phase = "client MAIL"; 38753751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 38859285Seric r = reply(m, mci, e, TimeOuts.to_mail, NULL); 3898005Seric if (r < 0 || REPLYTYPE(r) == 4) 39053751Seric { 39153751Seric mci->mci_exitstat = EX_TEMPFAIL; 39253751Seric mci->mci_errno = errno; 39353751Seric smtpquit(m, mci, e); 39453751Seric return EX_TEMPFAIL; 39553751Seric } 3967963Seric else if (r == 250) 39753751Seric { 39853751Seric mci->mci_exitstat = EX_OK; 39953751Seric return EX_OK; 40053751Seric } 4017963Seric else if (r == 552) 40253751Seric { 40353751Seric /* signal service unavailable */ 40453751Seric mci->mci_exitstat = EX_UNAVAILABLE; 40553751Seric smtpquit(m, mci, e); 40653751Seric return EX_UNAVAILABLE; 40753751Seric } 40814913Seric 40958008Seric #ifdef LOG 41058020Seric if (LogLevel > 1) 41158008Seric { 41267860Seric syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s", 41367860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 41458008Seric } 41558008Seric #endif 41658008Seric 41714913Seric /* protocol error -- close up */ 41853751Seric smtpquit(m, mci, e); 41953751Seric mci->mci_exitstat = EX_PROTOCOL; 42053751Seric return EX_PROTOCOL; 4214684Seric } 4224684Seric /* 4234976Seric ** SMTPRCPT -- designate recipient. 4244797Seric ** 4254797Seric ** Parameters: 4264865Seric ** to -- address of recipient. 42710175Seric ** m -- the mailer we are sending to. 42857379Seric ** mci -- the connection info for this transaction. 42957379Seric ** e -- the envelope for this transaction. 4304797Seric ** 4314797Seric ** Returns: 4324865Seric ** exit status corresponding to recipient status. 4334797Seric ** 4344797Seric ** Side Effects: 4354865Seric ** Sends the mail via SMTP. 4364797Seric */ 4374797Seric 43853751Seric smtprcpt(to, m, mci, e) 4394865Seric ADDRESS *to; 44010175Seric register MAILER *m; 44154967Seric MCI *mci; 44253751Seric ENVELOPE *e; 4434797Seric { 4444797Seric register int r; 44567880Seric char optbuf[MAXLINE]; 4464797Seric 44767880Seric strcpy(optbuf, ""); 44867880Seric if (bitset(MCIF_DSN, mci->mci_flags)) 44967880Seric { 45067880Seric strcat(optbuf, " NOTIFY="); 45167880Seric if (bitset(QPINGONFAILURE, to->q_flags)) 45267880Seric { 45367880Seric if (bitset(QPINGONSUCCESS, to->q_flags)) 45467880Seric strcat(optbuf, "ALWAYS"); 45567880Seric else 45667880Seric strcat(optbuf, "FAILURE"); 45767880Seric } 45867880Seric else 45967880Seric { 46067880Seric if (bitset(QPINGONSUCCESS, to->q_flags)) 46167880Seric strcat(optbuf, "SUCCESS"); 46267880Seric else 46367880Seric strcat(optbuf, "NEVER"); 46467880Seric } 46567880Seric if (bitset(QHASRETPARAM, to->q_flags)) 46667880Seric { 46767880Seric strcat(optbuf, " RET="); 46867880Seric if (bitset(QNOBODYRETURN, to->q_flags)) 46967880Seric strcat(optbuf, "NO"); 47067880Seric else 47167880Seric strcat(optbuf, "YES"); 47267880Seric } 47367880Seric } 47467880Seric else if (bitset(QPINGONSUCCESS, to->q_flags)) 47567880Seric { 47667880Seric to->q_flags |= QRELAYED; 47767880Seric fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 47867880Seric to->q_paddr); 47967880Seric } 4804865Seric 48167880Seric smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 48267880Seric 48361093Seric SmtpPhase = mci->mci_phase = "client RCPT"; 48453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 48559285Seric r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 48667880Seric setstatus(to, SmtpReplyBuffer); 4878005Seric if (r < 0 || REPLYTYPE(r) == 4) 4884865Seric return (EX_TEMPFAIL); 4897963Seric else if (REPLYTYPE(r) == 2) 4907963Seric return (EX_OK); 4917964Seric else if (r == 550 || r == 551 || r == 553) 4927964Seric return (EX_NOUSER); 4937964Seric else if (r == 552 || r == 554) 4947964Seric return (EX_UNAVAILABLE); 49558008Seric 49658008Seric #ifdef LOG 49758020Seric if (LogLevel > 1) 49858008Seric { 49967860Seric syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s", 50067860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 50158008Seric } 50258008Seric #endif 50358008Seric 5047964Seric return (EX_PROTOCOL); 5054797Seric } 5064797Seric /* 50710175Seric ** SMTPDATA -- send the data and clean up the transaction. 5084684Seric ** 5094684Seric ** Parameters: 5104865Seric ** m -- mailer being sent to. 5116980Seric ** e -- the envelope for this message. 5124684Seric ** 5134684Seric ** Returns: 5144976Seric ** exit status corresponding to DATA command. 5154684Seric ** 5164684Seric ** Side Effects: 5174865Seric ** none. 5184684Seric */ 5194684Seric 52063753Seric static jmp_buf CtxDataTimeout; 52163937Seric static int datatimeout(); 52263753Seric 52353740Seric smtpdata(m, mci, e) 5244865Seric struct mailer *m; 52554967Seric register MCI *mci; 5266980Seric register ENVELOPE *e; 5274684Seric { 5284684Seric register int r; 52963753Seric register EVENT *ev; 53063753Seric time_t timeout; 5314684Seric 5324797Seric /* 5334797Seric ** Send the data. 53410175Seric ** First send the command and check that it is ok. 53510175Seric ** Then send the data. 53610175Seric ** Follow it up with a dot to terminate. 53710175Seric ** Finally get the results of the transaction. 5384797Seric */ 5394797Seric 54010175Seric /* send the command and check ok to proceed */ 54153751Seric smtpmessage("DATA", m, mci); 54261093Seric SmtpPhase = mci->mci_phase = "client DATA 354"; 54353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 54459285Seric r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 5458005Seric if (r < 0 || REPLYTYPE(r) == 4) 54657990Seric { 54757990Seric smtpquit(m, mci, e); 5484797Seric return (EX_TEMPFAIL); 54957990Seric } 5507963Seric else if (r == 554) 55157990Seric { 55257990Seric smtprset(m, mci, e); 5537963Seric return (EX_UNAVAILABLE); 55457990Seric } 5557963Seric else if (r != 354) 55657990Seric { 55758008Seric #ifdef LOG 55858020Seric if (LogLevel > 1) 55958008Seric { 56067860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s", 56167860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 56258008Seric } 56358008Seric #endif 56457990Seric smtprset(m, mci, e); 5657964Seric return (EX_PROTOCOL); 56657990Seric } 56710175Seric 56863757Seric /* 56963757Seric ** Set timeout around data writes. Make it at least large 57063757Seric ** enough for DNS timeouts on all recipients plus some fudge 57163757Seric ** factor. The main thing is that it should not be infinite. 57263757Seric */ 57363757Seric 57463753Seric if (setjmp(CtxDataTimeout) != 0) 57563753Seric { 57663753Seric mci->mci_errno = errno; 57763753Seric mci->mci_exitstat = EX_TEMPFAIL; 57863753Seric mci->mci_state = MCIS_ERROR; 57963753Seric syserr("451 timeout writing message to %s", mci->mci_host); 58063753Seric smtpquit(m, mci, e); 58163753Seric return EX_TEMPFAIL; 58263753Seric } 58363753Seric 58463787Seric timeout = e->e_msgsize / 16; 58563787Seric if (timeout < (time_t) 60) 58663787Seric timeout = (time_t) 60; 58763787Seric timeout += e->e_nrcpts * 90; 58863753Seric ev = setevent(timeout, datatimeout, 0); 58963753Seric 59067546Seric /* 59167546Seric ** Output the actual message. 59267546Seric */ 59367546Seric 59467546Seric (*e->e_puthdr)(mci, e->e_header, e); 59565870Seric (*e->e_putbody)(mci, e, NULL); 59610175Seric 59767546Seric /* 59867546Seric ** Cleanup after sending message. 59967546Seric */ 60067546Seric 60163753Seric clrevent(ev); 60263753Seric 60364718Seric if (ferror(mci->mci_out)) 60464718Seric { 60564718Seric /* error during processing -- don't send the dot */ 60664718Seric mci->mci_errno = EIO; 60764718Seric mci->mci_exitstat = EX_IOERR; 60864718Seric mci->mci_state = MCIS_ERROR; 60964718Seric smtpquit(m, mci, e); 61064718Seric return EX_IOERR; 61164718Seric } 61264718Seric 61310175Seric /* terminate the message */ 61453740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 61563753Seric if (TrafficLogFile != NULL) 61663753Seric fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); 61758120Seric if (Verbose) 61858151Seric nmessage(">>> ."); 61910175Seric 62010175Seric /* check for the results of the transaction */ 62161093Seric SmtpPhase = mci->mci_phase = "client DATA 250"; 62253751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 62359285Seric r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 62453751Seric if (r < 0) 62557990Seric { 62657990Seric smtpquit(m, mci, e); 6274797Seric return (EX_TEMPFAIL); 62857990Seric } 62953751Seric mci->mci_state = MCIS_OPEN; 63058917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 63153751Seric if (REPLYTYPE(r) == 4) 63253751Seric return (EX_TEMPFAIL); 6337963Seric else if (r == 250) 6347963Seric return (EX_OK); 6357963Seric else if (r == 552 || r == 554) 6367963Seric return (EX_UNAVAILABLE); 63758008Seric #ifdef LOG 63858020Seric if (LogLevel > 1) 63958008Seric { 64067860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s", 64167860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 64258008Seric } 64358008Seric #endif 6447964Seric return (EX_PROTOCOL); 6454684Seric } 64663753Seric 64763753Seric 64863753Seric static int 64963753Seric datatimeout() 65063753Seric { 65163753Seric longjmp(CtxDataTimeout, 1); 65263753Seric } 6534684Seric /* 6544865Seric ** SMTPQUIT -- close the SMTP connection. 6554865Seric ** 6564865Seric ** Parameters: 65715535Seric ** m -- a pointer to the mailer. 6584865Seric ** 6594865Seric ** Returns: 6604865Seric ** none. 6614865Seric ** 6624865Seric ** Side Effects: 6634865Seric ** sends the final protocol and closes the connection. 6644865Seric */ 6654865Seric 66653751Seric smtpquit(m, mci, e) 66753751Seric register MAILER *m; 66854967Seric register MCI *mci; 66953751Seric ENVELOPE *e; 6704865Seric { 67164822Seric bool oldSuprErrs = SuprErrs; 6724865Seric 67364822Seric /* 67464822Seric ** Suppress errors here -- we may be processing a different 67564822Seric ** job when we do the quit connection, and we don't want the 67664822Seric ** new job to be penalized for something that isn't it's 67764822Seric ** problem. 67864822Seric */ 67964822Seric 68064822Seric SuprErrs = TRUE; 68164822Seric 68254967Seric /* send the quit message if we haven't gotten I/O error */ 68353751Seric if (mci->mci_state != MCIS_ERROR) 6849391Seric { 68561093Seric SmtpPhase = "client QUIT"; 68653751Seric smtpmessage("QUIT", m, mci); 68759285Seric (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 68864822Seric SuprErrs = oldSuprErrs; 68953740Seric if (mci->mci_state == MCIS_CLOSED) 69064822Seric { 69164822Seric SuprErrs = oldSuprErrs; 69210159Seric return; 69364822Seric } 6949391Seric } 6959391Seric 69652676Seric /* now actually close the connection and pick up the zombie */ 69765194Seric (void) endmailer(mci, e, NULL); 69864822Seric 69964822Seric SuprErrs = oldSuprErrs; 7004865Seric } 7014865Seric /* 70254967Seric ** SMTPRSET -- send a RSET (reset) command 70354967Seric */ 70454967Seric 70554967Seric smtprset(m, mci, e) 70654967Seric register MAILER *m; 70754967Seric register MCI *mci; 70854967Seric ENVELOPE *e; 70954967Seric { 71054967Seric int r; 71154967Seric 71261093Seric SmtpPhase = "client RSET"; 71354967Seric smtpmessage("RSET", m, mci); 71459285Seric r = reply(m, mci, e, TimeOuts.to_rset, NULL); 71557734Seric if (r < 0) 71657734Seric mci->mci_state = MCIS_ERROR; 71754967Seric else if (REPLYTYPE(r) == 2) 71857734Seric { 71957734Seric mci->mci_state = MCIS_OPEN; 72057734Seric return; 72157734Seric } 72257734Seric smtpquit(m, mci, e); 72354967Seric } 72454967Seric /* 72558867Seric ** SMTPPROBE -- check the connection state 72654967Seric */ 72754967Seric 72858867Seric smtpprobe(mci) 72954967Seric register MCI *mci; 73054967Seric { 73154967Seric int r; 73254967Seric MAILER *m = mci->mci_mailer; 73354967Seric extern ENVELOPE BlankEnvelope; 73454967Seric ENVELOPE *e = &BlankEnvelope; 73554967Seric 73661093Seric SmtpPhase = "client probe"; 73758867Seric smtpmessage("RSET", m, mci); 73859285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 73958061Seric if (r < 0 || REPLYTYPE(r) != 2) 74054967Seric smtpquit(m, mci, e); 74154967Seric return r; 74254967Seric } 74354967Seric /* 7444684Seric ** REPLY -- read arpanet reply 7454684Seric ** 7464684Seric ** Parameters: 74710175Seric ** m -- the mailer we are reading the reply from. 74857379Seric ** mci -- the mailer connection info structure. 74957379Seric ** e -- the current envelope. 75057379Seric ** timeout -- the timeout for reads. 75159285Seric ** pfunc -- processing function for second and subsequent 75259285Seric ** lines of response -- if null, no special 75359285Seric ** processing is done. 7544684Seric ** 7554684Seric ** Returns: 7564684Seric ** reply code it reads. 7574684Seric ** 7584684Seric ** Side Effects: 7594684Seric ** flushes the mail file. 7604684Seric */ 7614684Seric 76259285Seric reply(m, mci, e, timeout, pfunc) 76353751Seric MAILER *m; 76454967Seric MCI *mci; 76553751Seric ENVELOPE *e; 76659285Seric time_t timeout; 76759285Seric void (*pfunc)(); 7684684Seric { 76959014Seric register char *bufp; 77059014Seric register int r; 77159285Seric bool firstline = TRUE; 77258957Seric char junkbuf[MAXLINE]; 77358957Seric 77457379Seric if (mci->mci_out != NULL) 77557379Seric (void) fflush(mci->mci_out); 7764684Seric 7777677Seric if (tTd(18, 1)) 7784796Seric printf("reply\n"); 7794796Seric 7807356Seric /* 7817356Seric ** Read the input line, being careful not to hang. 7827356Seric */ 7837356Seric 78459014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 7854684Seric { 7867356Seric register char *p; 78753751Seric extern time_t curtime(); 7884684Seric 7897685Seric /* actually do the read */ 79053751Seric if (e->e_xfp != NULL) 79153751Seric (void) fflush(e->e_xfp); /* for debugging */ 7927356Seric 79310054Seric /* if we are in the process of closing just give the code */ 79453740Seric if (mci->mci_state == MCIS_CLOSED) 79510054Seric return (SMTPCLOSING); 79610054Seric 79758680Seric if (mci->mci_out != NULL) 79858680Seric fflush(mci->mci_out); 79958680Seric 80010054Seric /* get the line from the other side */ 80161093Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 80253751Seric mci->mci_lastuse = curtime(); 80353751Seric 80410054Seric if (p == NULL) 80510131Seric { 80663753Seric bool oldholderrs; 80710148Seric extern char MsgBuf[]; /* err.c */ 80810148Seric 80921065Seric /* if the remote end closed early, fake an error */ 81021065Seric if (errno == 0) 81121065Seric # ifdef ECONNRESET 81221065Seric errno = ECONNRESET; 81356795Seric # else /* ECONNRESET */ 81421065Seric errno = EPIPE; 81556795Seric # endif /* ECONNRESET */ 81621065Seric 81757379Seric mci->mci_errno = errno; 81857642Seric mci->mci_exitstat = EX_TEMPFAIL; 81963753Seric oldholderrs = HoldErrs; 82063753Seric HoldErrs = TRUE; 82163753Seric usrerr("451 reply: read error from %s", mci->mci_host); 82263753Seric 82310420Seric /* if debugging, pause so we can see state */ 82410420Seric if (tTd(18, 100)) 82510420Seric pause(); 82654967Seric mci->mci_state = MCIS_ERROR; 82753751Seric smtpquit(m, mci, e); 82863753Seric #ifdef XDEBUG 82963753Seric { 83063753Seric char wbuf[MAXLINE]; 83164082Seric char *p = wbuf; 83264082Seric if (e->e_to != NULL) 83364082Seric { 83464082Seric sprintf(p, "%s... ", e->e_to); 83564082Seric p += strlen(p); 83664082Seric } 83764082Seric sprintf(p, "reply(%s) during %s", 83864082Seric mci->mci_host, SmtpPhase); 83963753Seric checkfd012(wbuf); 84063753Seric } 84163753Seric #endif 84263753Seric HoldErrs = oldholderrs; 84310054Seric return (-1); 84410131Seric } 84558957Seric fixcrlf(bufp, TRUE); 84610054Seric 84763753Seric /* EHLO failure is not a real error */ 84863753Seric if (e->e_xfp != NULL && (bufp[0] == '4' || 84963753Seric (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 85014900Seric { 85114900Seric /* serious error -- log the previous command */ 85264071Seric if (SmtpNeedIntro) 85364071Seric { 85464071Seric /* inform user who we are chatting with */ 85564071Seric fprintf(CurEnv->e_xfp, 85664071Seric "... while talking to %s:\n", 85764071Seric CurHostName); 85864071Seric SmtpNeedIntro = FALSE; 85964071Seric } 86059014Seric if (SmtpMsgBuffer[0] != '\0') 86159014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 86259014Seric SmtpMsgBuffer[0] = '\0'; 86314900Seric 86414900Seric /* now log the message as from the other side */ 86558957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 86614900Seric } 86714900Seric 86814900Seric /* display the input for verbose mode */ 86958120Seric if (Verbose) 87059956Seric nmessage("050 %s", bufp); 8717356Seric 87259285Seric /* process the line */ 87359285Seric if (pfunc != NULL && !firstline) 87459285Seric (*pfunc)(bufp, m, mci, e); 87559285Seric 87659285Seric firstline = FALSE; 87759285Seric 8787356Seric /* if continuation is required, we can go on */ 87959014Seric if (bufp[3] == '-') 8804684Seric continue; 8817356Seric 88259014Seric /* ignore improperly formated input */ 88359014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 88459014Seric continue; 88559014Seric 8867356Seric /* decode the reply code */ 88759014Seric r = atoi(bufp); 8887356Seric 8897356Seric /* extra semantics: 0xx codes are "informational" */ 89059014Seric if (r >= 100) 89159014Seric break; 89259014Seric } 8937356Seric 89459014Seric /* 89559014Seric ** Now look at SmtpReplyBuffer -- only care about the first 89659014Seric ** line of the response from here on out. 89759014Seric */ 89858061Seric 89959014Seric /* save temporary failure messages for posterity */ 90059014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 90159014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 9029391Seric 90359014Seric /* reply code 421 is "Service Shutting Down" */ 90459014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 90559014Seric { 90659014Seric /* send the quit protocol */ 90759014Seric mci->mci_state = MCIS_SSD; 90859014Seric smtpquit(m, mci, e); 9094684Seric } 91059014Seric 91159014Seric return (r); 9124684Seric } 9134796Seric /* 9144865Seric ** SMTPMESSAGE -- send message to server 9154796Seric ** 9164796Seric ** Parameters: 9174796Seric ** f -- format 91810175Seric ** m -- the mailer to control formatting. 9194796Seric ** a, b, c -- parameters 9204796Seric ** 9214796Seric ** Returns: 9224796Seric ** none. 9234796Seric ** 9244796Seric ** Side Effects: 92553740Seric ** writes message to mci->mci_out. 9264796Seric */ 9274796Seric 9284865Seric /*VARARGS1*/ 92957642Seric #ifdef __STDC__ 93057642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 93157642Seric #else 93257642Seric smtpmessage(f, m, mci, va_alist) 9334796Seric char *f; 93410175Seric MAILER *m; 93554967Seric MCI *mci; 93657642Seric va_dcl 93757642Seric #endif 9384796Seric { 93956852Seric VA_LOCAL_DECL 94056852Seric 94157135Seric VA_START(mci); 94256852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 94356852Seric VA_END; 94458680Seric 94558120Seric if (tTd(18, 1) || Verbose) 94658151Seric nmessage(">>> %s", SmtpMsgBuffer); 94763753Seric if (TrafficLogFile != NULL) 94863753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); 94953740Seric if (mci->mci_out != NULL) 95058680Seric { 95153740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 95254967Seric m == NULL ? "\r\n" : m->m_eol); 95358680Seric } 95459149Seric else if (tTd(18, 1)) 95558725Seric { 95659149Seric printf("smtpmessage: NULL mci_out\n"); 95758725Seric } 9584796Seric } 9595182Seric 96056795Seric # endif /* SMTP */ 961