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*69922Seric static char sccsid[] = "@(#)usersmtp.c 8.56 (Berkeley) 06/18/95 (with SMTP)"; 1433731Sbostic #else 15*69922Seric static char sccsid[] = "@(#)usersmtp.c 8.56 (Berkeley) 06/18/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 4069748Seric extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); 419391Seric /* 424865Seric ** SMTPINIT -- initialize SMTP. 434684Seric ** 444865Seric ** Opens the connection and sends the initial protocol. 454684Seric ** 464684Seric ** Parameters: 474865Seric ** m -- mailer to create connection to. 484865Seric ** pvp -- pointer to parameter vector to pass to 494865Seric ** the mailer. 504684Seric ** 514684Seric ** Returns: 5254967Seric ** none. 534684Seric ** 544684Seric ** Side Effects: 554865Seric ** creates connection and sends initial protocol. 564684Seric */ 574684Seric 5869748Seric void 5954967Seric smtpinit(m, mci, e) 604865Seric struct mailer *m; 6154967Seric register MCI *mci; 6253751Seric ENVELOPE *e; 634684Seric { 644865Seric register int r; 6558957Seric register char *p; 6660210Seric extern void esmtp_check(); 6759285Seric extern void helo_options(); 684684Seric 6963753Seric if (tTd(18, 1)) 7057379Seric { 7157379Seric printf("smtpinit "); 7264731Seric mci_dump(mci, FALSE); 7357379Seric } 7457379Seric 754865Seric /* 764865Seric ** Open the connection to the mailer. 774865Seric */ 784684Seric 7921065Seric SmtpError[0] = '\0'; 8057379Seric CurHostName = mci->mci_host; /* XXX UGLY XXX */ 8168100Seric if (CurHostName == NULL) 8268100Seric CurHostName = MyHostName; 8364071Seric SmtpNeedIntro = TRUE; 8454967Seric switch (mci->mci_state) 856051Seric { 8654967Seric case MCIS_ACTIVE: 8754967Seric /* need to clear old information */ 8854967Seric smtprset(m, mci, e); 8957734Seric /* fall through */ 9015139Seric 9154967Seric case MCIS_OPEN: 9254967Seric return; 9354967Seric 9454967Seric case MCIS_ERROR: 9554967Seric case MCIS_SSD: 9654967Seric /* shouldn't happen */ 9754967Seric smtpquit(m, mci, e); 9857734Seric /* fall through */ 9954967Seric 10054967Seric case MCIS_CLOSED: 10158151Seric syserr("451 smtpinit: state CLOSED"); 10254967Seric return; 10354967Seric 10454967Seric case MCIS_OPENING: 10554967Seric break; 1066051Seric } 1074796Seric 10854967Seric mci->mci_state = MCIS_OPENING; 10954967Seric 1104865Seric /* 1114865Seric ** Get the greeting message. 11214913Seric ** This should appear spontaneously. Give it five minutes to 11314886Seric ** happen. 1144865Seric */ 1154797Seric 11661093Seric SmtpPhase = mci->mci_phase = "client greeting"; 11753751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 11860210Seric r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); 11964750Seric if (r < 0 || REPLYTYPE(r) == 4) 12052104Seric goto tempfail1; 12164750Seric if (REPLYTYPE(r) != 2) 12264750Seric goto unavailable; 1234684Seric 1244865Seric /* 1254976Seric ** Send the HELO command. 1267963Seric ** My mother taught me to always introduce myself. 1274976Seric */ 1284976Seric 12959285Seric if (bitnset(M_ESMTP, m->m_flags)) 13059285Seric mci->mci_flags |= MCIF_ESMTP; 13159285Seric 13259285Seric tryhelo: 13359285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 13459285Seric { 13559285Seric smtpmessage("EHLO %s", m, mci, MyHostName); 13661093Seric SmtpPhase = mci->mci_phase = "client EHLO"; 13759285Seric } 13859285Seric else 13959285Seric { 14059285Seric smtpmessage("HELO %s", m, mci, MyHostName); 14161093Seric SmtpPhase = mci->mci_phase = "client HELO"; 14259285Seric } 14353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 14459285Seric r = reply(m, mci, e, TimeOuts.to_helo, helo_options); 1458005Seric if (r < 0) 14652104Seric goto tempfail1; 1478005Seric else if (REPLYTYPE(r) == 5) 14859285Seric { 14959285Seric if (bitset(MCIF_ESMTP, mci->mci_flags)) 15059285Seric { 15159285Seric /* try old SMTP instead */ 15259285Seric mci->mci_flags &= ~MCIF_ESMTP; 15359285Seric goto tryhelo; 15459285Seric } 15514913Seric goto unavailable; 15659285Seric } 1577963Seric else if (REPLYTYPE(r) != 2) 15852104Seric goto tempfail1; 1594976Seric 1604976Seric /* 16158957Seric ** Check to see if we actually ended up talking to ourself. 16258957Seric ** This means we didn't know about an alias or MX, or we managed 16358957Seric ** to connect to an echo server. 16458957Seric */ 16558957Seric 16659026Seric p = strchr(&SmtpReplyBuffer[4], ' '); 16758957Seric if (p != NULL) 16861707Seric *p = '\0'; 16967472Seric if (!bitnset(M_NOLOOPCHECK, m->m_flags) && 17067472Seric strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 17158957Seric { 17258957Seric syserr("553 %s config error: mail loops back to myself", 17358957Seric MyHostName); 17458957Seric mci->mci_exitstat = EX_CONFIG; 17558957Seric mci->mci_errno = 0; 17658957Seric smtpquit(m, mci, e); 17758957Seric return; 17858957Seric } 17958957Seric 18058957Seric /* 1819315Seric ** If this is expected to be another sendmail, send some internal 1829315Seric ** commands. 1839315Seric */ 1849315Seric 18510688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1869315Seric { 1879315Seric /* tell it to be verbose */ 18853751Seric smtpmessage("VERB", m, mci); 18959285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 1909315Seric if (r < 0) 19152104Seric goto tempfail2; 1929315Seric } 1939315Seric 19465057Seric if (mci->mci_state != MCIS_CLOSED) 19565057Seric { 19665057Seric mci->mci_state = MCIS_OPEN; 19765057Seric return; 19865057Seric } 19953751Seric 20065057Seric /* got a 421 error code during startup */ 20165057Seric 20253751Seric tempfail1: 20353751Seric tempfail2: 20453751Seric mci->mci_exitstat = EX_TEMPFAIL; 20557379Seric if (mci->mci_errno == 0) 20657379Seric mci->mci_errno = errno; 20757379Seric if (mci->mci_state != MCIS_CLOSED) 20857379Seric smtpquit(m, mci, e); 20954967Seric return; 21053751Seric 21153751Seric unavailable: 21253751Seric mci->mci_exitstat = EX_UNAVAILABLE; 21353751Seric mci->mci_errno = errno; 21453751Seric smtpquit(m, mci, e); 21554967Seric return; 21653751Seric } 21759285Seric /* 21860210Seric ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 21960210Seric ** 22060210Seric ** Parameters: 22160210Seric ** line -- the response line. 22267893Seric ** firstline -- set if this is the first line of the reply. 22360210Seric ** m -- the mailer. 22460210Seric ** mci -- the mailer connection info. 22560210Seric ** e -- the envelope. 22660210Seric ** 22760210Seric ** Returns: 22860210Seric ** none. 22960210Seric */ 23060210Seric 23160210Seric void 23267893Seric esmtp_check(line, firstline, m, mci, e) 23360210Seric char *line; 23467893Seric bool firstline; 23560210Seric MAILER *m; 23660210Seric register MCI *mci; 23760210Seric ENVELOPE *e; 23860210Seric { 23969650Seric if (strstr(line, "ESMTP ") != NULL) 24069650Seric mci->mci_flags |= MCIF_ESMTP; 24169650Seric if (strstr(line, "8BIT OK") != NULL) 24269650Seric mci->mci_flags |= MCIF_8BITOK; 24360210Seric } 24460210Seric /* 24559285Seric ** HELO_OPTIONS -- process the options on a HELO line. 24659285Seric ** 24759285Seric ** Parameters: 24859285Seric ** line -- the response line. 24967893Seric ** firstline -- set if this is the first line of the reply. 25059285Seric ** m -- the mailer. 25159285Seric ** mci -- the mailer connection info. 25259285Seric ** e -- the envelope. 25359285Seric ** 25459285Seric ** Returns: 25559285Seric ** none. 25659285Seric */ 25753751Seric 25859285Seric void 25967893Seric helo_options(line, firstline, m, mci, e) 26059285Seric char *line; 26167893Seric bool firstline; 26259285Seric MAILER *m; 26359285Seric register MCI *mci; 26459285Seric ENVELOPE *e; 26559285Seric { 26659285Seric register char *p; 26759285Seric 26867971Seric if (firstline) 26967893Seric return; 27067893Seric 27168706Seric if (strlen(line) < (SIZE_T) 5) 27259285Seric return; 27359285Seric line += 4; 27459285Seric p = strchr(line, ' '); 27559285Seric if (p != NULL) 27659285Seric *p++ = '\0'; 27759285Seric if (strcasecmp(line, "size") == 0) 27859285Seric { 27959285Seric mci->mci_flags |= MCIF_SIZE; 28059285Seric if (p != NULL) 28159285Seric mci->mci_maxsize = atol(p); 28259285Seric } 28359285Seric else if (strcasecmp(line, "8bitmime") == 0) 28465870Seric { 28559285Seric mci->mci_flags |= MCIF_8BITMIME; 28665870Seric mci->mci_flags &= ~MCIF_7BIT; 28765870Seric } 28859285Seric else if (strcasecmp(line, "expn") == 0) 28959285Seric mci->mci_flags |= MCIF_EXPN; 29068606Seric else if (strcasecmp(line, "x-dsn-03") == 0) 29167880Seric mci->mci_flags |= MCIF_DSN; 29259285Seric } 29359285Seric /* 29459285Seric ** SMTPMAILFROM -- send MAIL command 29559285Seric ** 29659285Seric ** Parameters: 29759285Seric ** m -- the mailer. 29859285Seric ** mci -- the mailer connection structure. 29959285Seric ** e -- the envelope (including the sender to specify). 30059285Seric */ 30159285Seric 30269748Seric int 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) && 329*69922Seric !bitset(EF_DONT_MIME, e->e_flags) && 33067887Seric !bitnset(M_8BITS, m->m_flags)) 33167887Seric bodytype = "8BITMIME"; 33267887Seric if (bodytype != NULL) 33367417Seric { 33467417Seric strcat(optbuf, " BODY="); 33567887Seric strcat(optbuf, bodytype); 33667417Seric } 33767417Seric } 33867995Seric else if (bitnset(M_8BITS, m->m_flags) || 33969104Seric !bitset(EF_HAS8BIT, e->e_flags)) 34067887Seric { 34167887Seric /* just pass it through */ 34267887Seric } 34369480Seric #if MIME8TO7 34467887Seric else if (bitset(MM_CVTMIME, MimeMode) && 345*69922Seric !bitset(EF_DONT_MIME, e->e_flags) && 34668884Seric (!bitset(MM_PASS8BIT, MimeMode) || 34768884Seric bitset(EF_IS_MIME, e->e_flags))) 34867887Seric { 34967887Seric /* must convert from 8bit MIME format to 7bit encoded */ 35067887Seric mci->mci_flags |= MCIF_CVT8TO7; 35167887Seric } 35269480Seric #endif 35367887Seric else if (!bitset(MM_PASS8BIT, MimeMode)) 35467887Seric { 35567887Seric /* cannot just send a 8-bit version */ 35667887Seric usrerr("%s does not support 8BITMIME", mci->mci_host); 35768857Seric mci->mci_status = "5.6.3"; 35867887Seric return EX_DATAERR; 35967887Seric } 36067417Seric 36167963Seric if (bitset(MCIF_DSN, mci->mci_flags)) 36267880Seric { 36367963Seric if (e->e_envid != NULL) 36467963Seric { 36567963Seric strcat(optbuf, " ENVID="); 36667963Seric strcat(optbuf, e->e_envid); 36767963Seric } 36868559Seric 36968559Seric /* RET= parameter */ 37068559Seric if (bitset(EF_RET_PARAM, e->e_flags)) 37168559Seric { 37268559Seric strcat(optbuf, " RET="); 37368559Seric if (bitset(EF_NO_BODY_RETN, e->e_flags)) 37468559Seric strcat(optbuf, "HDRS"); 37568559Seric else 37668559Seric strcat(optbuf, "FULL"); 37768559Seric } 37867880Seric } 37967880Seric 3809315Seric /* 3814865Seric ** Send the MAIL command. 3824865Seric ** Designates the sender. 3834865Seric */ 3844796Seric 38553751Seric mci->mci_state = MCIS_ACTIVE; 38653751Seric 38759540Seric if (bitset(EF_RESPONSE, e->e_flags) && 38859540Seric !bitnset(M_NO_NULL_FROM, m->m_flags)) 38958680Seric (void) strcpy(buf, ""); 39058680Seric else 39168529Seric expand("\201g", buf, sizeof buf, e); 39265494Seric if (buf[0] == '<') 39365494Seric { 39465494Seric /* strip off <angle brackets> (put back on below) */ 39565494Seric bufp = &buf[strlen(buf) - 1]; 39665494Seric if (*bufp == '>') 39765494Seric *bufp = '\0'; 39865494Seric bufp = &buf[1]; 39965494Seric } 40065494Seric else 40165494Seric bufp = buf; 40267472Seric if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 40310688Seric !bitnset(M_FROMPATH, m->m_flags)) 4048436Seric { 40565494Seric smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 4068436Seric } 4078436Seric else 4088436Seric { 40959285Seric smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 41065494Seric *bufp == '@' ? ',' : ':', bufp, optbuf); 4118436Seric } 41261093Seric SmtpPhase = mci->mci_phase = "client MAIL"; 41353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 41459285Seric r = reply(m, mci, e, TimeOuts.to_mail, NULL); 41568811Seric if (r < 0 || r == 421) 41653751Seric { 41768811Seric /* communications failure/service shutting down */ 41853751Seric mci->mci_exitstat = EX_TEMPFAIL; 41953751Seric mci->mci_errno = errno; 42053751Seric smtpquit(m, mci, e); 42153751Seric return EX_TEMPFAIL; 42253751Seric } 42368811Seric else if (REPLYTYPE(r) == 4) 42468811Seric { 42568811Seric return EX_TEMPFAIL; 42668811Seric } 4277963Seric else if (r == 250) 42853751Seric { 42953751Seric return EX_OK; 43053751Seric } 43168857Seric else if (r == 501) 43268075Seric { 43368857Seric /* syntax error in arguments */ 43468857Seric mci->mci_status = "5.5.2"; 43568075Seric return EX_DATAERR; 43668075Seric } 43768857Seric else if (r == 553) 43868857Seric { 43968857Seric /* mailbox name not allowed */ 44068857Seric mci->mci_status = "5.1.3"; 44168857Seric return EX_DATAERR; 44268857Seric } 4437963Seric else if (r == 552) 44453751Seric { 44568811Seric /* exceeded storage allocation */ 44668857Seric mci->mci_status = "5.2.2"; 44753751Seric return EX_UNAVAILABLE; 44853751Seric } 44914913Seric 45058008Seric #ifdef LOG 45158020Seric if (LogLevel > 1) 45258008Seric { 45367860Seric syslog(LOG_CRIT, "%s: %s: SMTP MAIL protocol error: %s", 45467860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 45558008Seric } 45658008Seric #endif 45758008Seric 45814913Seric /* protocol error -- close up */ 45953751Seric smtpquit(m, mci, e); 46053751Seric return EX_PROTOCOL; 4614684Seric } 4624684Seric /* 4634976Seric ** SMTPRCPT -- designate recipient. 4644797Seric ** 4654797Seric ** Parameters: 4664865Seric ** to -- address of recipient. 46710175Seric ** m -- the mailer we are sending to. 46857379Seric ** mci -- the connection info for this transaction. 46957379Seric ** e -- the envelope for this transaction. 4704797Seric ** 4714797Seric ** Returns: 4724865Seric ** exit status corresponding to recipient status. 4734797Seric ** 4744797Seric ** Side Effects: 4754865Seric ** Sends the mail via SMTP. 4764797Seric */ 4774797Seric 47869748Seric int 47953751Seric smtprcpt(to, m, mci, e) 4804865Seric ADDRESS *to; 48110175Seric register MAILER *m; 48254967Seric MCI *mci; 48353751Seric ENVELOPE *e; 4844797Seric { 4854797Seric register int r; 48667880Seric char optbuf[MAXLINE]; 48768857Seric extern char *smtptodsn(); 4884797Seric 48967880Seric strcpy(optbuf, ""); 49067880Seric if (bitset(MCIF_DSN, mci->mci_flags)) 49167880Seric { 49267987Seric /* NOTIFY= parameter */ 49368603Seric if (bitset(QHASNOTIFY, to->q_flags) && 49468603Seric bitset(QPRIMARY, to->q_flags)) 49567880Seric { 49668595Seric bool firstone = TRUE; 49768595Seric 49868595Seric strcat(optbuf, " NOTIFY="); 49968595Seric if (bitset(QPINGONSUCCESS, to->q_flags)) 50068595Seric { 50168595Seric strcat(optbuf, "SUCCESS"); 50268595Seric firstone = FALSE; 50368595Seric } 50468595Seric if (bitset(QPINGONFAILURE, to->q_flags)) 50568595Seric { 50668595Seric if (!firstone) 50768595Seric strcat(optbuf, ","); 50868595Seric strcat(optbuf, "FAILURE"); 50968595Seric firstone = FALSE; 51068595Seric } 51168595Seric if (bitset(QPINGONDELAY, to->q_flags)) 51268595Seric { 51368595Seric if (!firstone) 51468595Seric strcat(optbuf, ","); 51568595Seric strcat(optbuf, "DELAY"); 51668595Seric firstone = FALSE; 51768595Seric } 51868595Seric if (firstone) 51968595Seric strcat(optbuf, "NEVER"); 52067880Seric } 52167963Seric 52267987Seric /* ORCPT= parameter */ 52367987Seric if (to->q_orcpt != NULL) 52467987Seric { 52567987Seric strcat(optbuf, " ORCPT="); 52667987Seric strcat(optbuf, to->q_orcpt); 52767987Seric } 52867880Seric } 5294865Seric 53067880Seric smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 53167880Seric 53261093Seric SmtpPhase = mci->mci_phase = "client RCPT"; 53353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 53459285Seric r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); 53568867Seric to->q_rstatus = newstr(SmtpReplyBuffer); 53668857Seric to->q_status = smtptodsn(r); 5378005Seric if (r < 0 || REPLYTYPE(r) == 4) 53868857Seric return EX_TEMPFAIL; 5397963Seric else if (REPLYTYPE(r) == 2) 54068857Seric return EX_OK; 5417964Seric else if (r == 550 || r == 551 || r == 553) 54268857Seric return EX_NOUSER; 5437964Seric else if (r == 552 || r == 554) 54468857Seric return EX_UNAVAILABLE; 54558008Seric 54658008Seric #ifdef LOG 54758020Seric if (LogLevel > 1) 54858008Seric { 54967860Seric syslog(LOG_CRIT, "%s: %s: SMTP RCPT protocol error: %s", 55067860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 55158008Seric } 55258008Seric #endif 55358008Seric 5547964Seric return (EX_PROTOCOL); 5554797Seric } 5564797Seric /* 55710175Seric ** SMTPDATA -- send the data and clean up the transaction. 5584684Seric ** 5594684Seric ** Parameters: 5604865Seric ** m -- mailer being sent to. 5616980Seric ** e -- the envelope for this message. 5624684Seric ** 5634684Seric ** Returns: 5644976Seric ** exit status corresponding to DATA command. 5654684Seric ** 5664684Seric ** Side Effects: 5674865Seric ** none. 5684684Seric */ 5694684Seric 57063753Seric static jmp_buf CtxDataTimeout; 57168433Seric static void datatimeout(); 57263753Seric 57369748Seric int 57453740Seric smtpdata(m, mci, e) 5754865Seric struct mailer *m; 57654967Seric register MCI *mci; 5776980Seric register ENVELOPE *e; 5784684Seric { 5794684Seric register int r; 58063753Seric register EVENT *ev; 58163753Seric time_t timeout; 5824684Seric 5834797Seric /* 5844797Seric ** Send the data. 58510175Seric ** First send the command and check that it is ok. 58610175Seric ** Then send the data. 58710175Seric ** Follow it up with a dot to terminate. 58810175Seric ** Finally get the results of the transaction. 5894797Seric */ 5904797Seric 59110175Seric /* send the command and check ok to proceed */ 59253751Seric smtpmessage("DATA", m, mci); 59361093Seric SmtpPhase = mci->mci_phase = "client DATA 354"; 59453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 59559285Seric r = reply(m, mci, e, TimeOuts.to_datainit, NULL); 5968005Seric if (r < 0 || REPLYTYPE(r) == 4) 59757990Seric { 59857990Seric smtpquit(m, mci, e); 5994797Seric return (EX_TEMPFAIL); 60057990Seric } 6017963Seric else if (r == 554) 60257990Seric { 60357990Seric smtprset(m, mci, e); 6047963Seric return (EX_UNAVAILABLE); 60557990Seric } 6067963Seric else if (r != 354) 60757990Seric { 60858008Seric #ifdef LOG 60958020Seric if (LogLevel > 1) 61058008Seric { 61167860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-1 protocol error: %s", 61267860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 61358008Seric } 61458008Seric #endif 61557990Seric smtprset(m, mci, e); 6167964Seric return (EX_PROTOCOL); 61757990Seric } 61810175Seric 61963757Seric /* 62063757Seric ** Set timeout around data writes. Make it at least large 62163757Seric ** enough for DNS timeouts on all recipients plus some fudge 62263757Seric ** factor. The main thing is that it should not be infinite. 62363757Seric */ 62463757Seric 62563753Seric if (setjmp(CtxDataTimeout) != 0) 62663753Seric { 62763753Seric mci->mci_errno = errno; 62863753Seric mci->mci_exitstat = EX_TEMPFAIL; 62963753Seric mci->mci_state = MCIS_ERROR; 63063753Seric syserr("451 timeout writing message to %s", mci->mci_host); 63163753Seric smtpquit(m, mci, e); 63263753Seric return EX_TEMPFAIL; 63363753Seric } 63463753Seric 63563787Seric timeout = e->e_msgsize / 16; 63668740Seric if (timeout < (time_t) 600) 63768740Seric timeout = (time_t) 600; 63868740Seric timeout += e->e_nrcpts * 300; 63963753Seric ev = setevent(timeout, datatimeout, 0); 64063753Seric 64167546Seric /* 64267546Seric ** Output the actual message. 64367546Seric */ 64467546Seric 64568228Seric (*e->e_puthdr)(mci, e->e_header, e); 64668228Seric (*e->e_putbody)(mci, e, NULL); 64710175Seric 64867546Seric /* 64967546Seric ** Cleanup after sending message. 65067546Seric */ 65167546Seric 65263753Seric clrevent(ev); 65363753Seric 65464718Seric if (ferror(mci->mci_out)) 65564718Seric { 65664718Seric /* error during processing -- don't send the dot */ 65764718Seric mci->mci_errno = EIO; 65864718Seric mci->mci_exitstat = EX_IOERR; 65964718Seric mci->mci_state = MCIS_ERROR; 66064718Seric smtpquit(m, mci, e); 66164718Seric return EX_IOERR; 66264718Seric } 66364718Seric 66410175Seric /* terminate the message */ 66553740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 66663753Seric if (TrafficLogFile != NULL) 66763753Seric fprintf(TrafficLogFile, "%05d >>> .\n", getpid()); 66858120Seric if (Verbose) 66958151Seric nmessage(">>> ."); 67010175Seric 67110175Seric /* check for the results of the transaction */ 67261093Seric SmtpPhase = mci->mci_phase = "client DATA 250"; 67353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 67459285Seric r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); 67553751Seric if (r < 0) 67657990Seric { 67757990Seric smtpquit(m, mci, e); 6784797Seric return (EX_TEMPFAIL); 67957990Seric } 68053751Seric mci->mci_state = MCIS_OPEN; 68158917Seric e->e_statmsg = newstr(&SmtpReplyBuffer[4]); 68253751Seric if (REPLYTYPE(r) == 4) 68353751Seric return (EX_TEMPFAIL); 6847963Seric else if (r == 250) 6857963Seric return (EX_OK); 6867963Seric else if (r == 552 || r == 554) 6877963Seric return (EX_UNAVAILABLE); 68858008Seric #ifdef LOG 68958020Seric if (LogLevel > 1) 69058008Seric { 69167860Seric syslog(LOG_CRIT, "%s: %s: SMTP DATA-2 protocol error: %s", 69267860Seric e->e_id, mci->mci_host, SmtpReplyBuffer); 69358008Seric } 69458008Seric #endif 6957964Seric return (EX_PROTOCOL); 6964684Seric } 69763753Seric 69863753Seric 69968433Seric static void 70063753Seric datatimeout() 70163753Seric { 70263753Seric longjmp(CtxDataTimeout, 1); 70363753Seric } 7044684Seric /* 7054865Seric ** SMTPQUIT -- close the SMTP connection. 7064865Seric ** 7074865Seric ** Parameters: 70815535Seric ** m -- a pointer to the mailer. 7094865Seric ** 7104865Seric ** Returns: 7114865Seric ** none. 7124865Seric ** 7134865Seric ** Side Effects: 7144865Seric ** sends the final protocol and closes the connection. 7154865Seric */ 7164865Seric 71769748Seric void 71853751Seric smtpquit(m, mci, e) 71953751Seric register MAILER *m; 72054967Seric register MCI *mci; 72153751Seric ENVELOPE *e; 7224865Seric { 72364822Seric bool oldSuprErrs = SuprErrs; 7244865Seric 72564822Seric /* 72664822Seric ** Suppress errors here -- we may be processing a different 72764822Seric ** job when we do the quit connection, and we don't want the 72864822Seric ** new job to be penalized for something that isn't it's 72964822Seric ** problem. 73064822Seric */ 73164822Seric 73264822Seric SuprErrs = TRUE; 73364822Seric 73454967Seric /* send the quit message if we haven't gotten I/O error */ 73553751Seric if (mci->mci_state != MCIS_ERROR) 7369391Seric { 73761093Seric SmtpPhase = "client QUIT"; 73853751Seric smtpmessage("QUIT", m, mci); 73959285Seric (void) reply(m, mci, e, TimeOuts.to_quit, NULL); 74064822Seric SuprErrs = oldSuprErrs; 74153740Seric if (mci->mci_state == MCIS_CLOSED) 74264822Seric { 74364822Seric SuprErrs = oldSuprErrs; 74410159Seric return; 74564822Seric } 7469391Seric } 7479391Seric 74852676Seric /* now actually close the connection and pick up the zombie */ 74965194Seric (void) endmailer(mci, e, NULL); 75064822Seric 75164822Seric SuprErrs = oldSuprErrs; 7524865Seric } 7534865Seric /* 75454967Seric ** SMTPRSET -- send a RSET (reset) command 75554967Seric */ 75654967Seric 75769748Seric void 75854967Seric smtprset(m, mci, e) 75954967Seric register MAILER *m; 76054967Seric register MCI *mci; 76154967Seric ENVELOPE *e; 76254967Seric { 76354967Seric int r; 76454967Seric 76561093Seric SmtpPhase = "client RSET"; 76654967Seric smtpmessage("RSET", m, mci); 76759285Seric r = reply(m, mci, e, TimeOuts.to_rset, NULL); 76857734Seric if (r < 0) 76957734Seric mci->mci_state = MCIS_ERROR; 77054967Seric else if (REPLYTYPE(r) == 2) 77157734Seric { 77257734Seric mci->mci_state = MCIS_OPEN; 77357734Seric return; 77457734Seric } 77557734Seric smtpquit(m, mci, e); 77654967Seric } 77754967Seric /* 77858867Seric ** SMTPPROBE -- check the connection state 77954967Seric */ 78054967Seric 78169748Seric int 78258867Seric smtpprobe(mci) 78354967Seric register MCI *mci; 78454967Seric { 78554967Seric int r; 78654967Seric MAILER *m = mci->mci_mailer; 78754967Seric extern ENVELOPE BlankEnvelope; 78854967Seric ENVELOPE *e = &BlankEnvelope; 78954967Seric 79061093Seric SmtpPhase = "client probe"; 79158867Seric smtpmessage("RSET", m, mci); 79259285Seric r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); 79358061Seric if (r < 0 || REPLYTYPE(r) != 2) 79454967Seric smtpquit(m, mci, e); 79554967Seric return r; 79654967Seric } 79754967Seric /* 7984684Seric ** REPLY -- read arpanet reply 7994684Seric ** 8004684Seric ** Parameters: 80110175Seric ** m -- the mailer we are reading the reply from. 80257379Seric ** mci -- the mailer connection info structure. 80357379Seric ** e -- the current envelope. 80457379Seric ** timeout -- the timeout for reads. 80569107Seric ** pfunc -- processing function called on each line of response. 80669107Seric ** If null, no special processing is done. 8074684Seric ** 8084684Seric ** Returns: 8094684Seric ** reply code it reads. 8104684Seric ** 8114684Seric ** Side Effects: 8124684Seric ** flushes the mail file. 8134684Seric */ 8144684Seric 81569748Seric int 81659285Seric reply(m, mci, e, timeout, pfunc) 81753751Seric MAILER *m; 81854967Seric MCI *mci; 81953751Seric ENVELOPE *e; 82059285Seric time_t timeout; 82159285Seric void (*pfunc)(); 8224684Seric { 82359014Seric register char *bufp; 82459014Seric register int r; 82559285Seric bool firstline = TRUE; 82658957Seric char junkbuf[MAXLINE]; 82758957Seric 82857379Seric if (mci->mci_out != NULL) 82957379Seric (void) fflush(mci->mci_out); 8304684Seric 8317677Seric if (tTd(18, 1)) 8324796Seric printf("reply\n"); 8334796Seric 8347356Seric /* 8357356Seric ** Read the input line, being careful not to hang. 8367356Seric */ 8377356Seric 83859014Seric for (bufp = SmtpReplyBuffer;; bufp = junkbuf) 8394684Seric { 8407356Seric register char *p; 84153751Seric extern time_t curtime(); 8424684Seric 8437685Seric /* actually do the read */ 84453751Seric if (e->e_xfp != NULL) 84553751Seric (void) fflush(e->e_xfp); /* for debugging */ 8467356Seric 84710054Seric /* if we are in the process of closing just give the code */ 84853740Seric if (mci->mci_state == MCIS_CLOSED) 84910054Seric return (SMTPCLOSING); 85010054Seric 85158680Seric if (mci->mci_out != NULL) 85258680Seric fflush(mci->mci_out); 85358680Seric 85410054Seric /* get the line from the other side */ 85561093Seric p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 85653751Seric mci->mci_lastuse = curtime(); 85753751Seric 85810054Seric if (p == NULL) 85910131Seric { 86063753Seric bool oldholderrs; 86110148Seric 86221065Seric /* if the remote end closed early, fake an error */ 86321065Seric if (errno == 0) 86421065Seric # ifdef ECONNRESET 86521065Seric errno = ECONNRESET; 86656795Seric # else /* ECONNRESET */ 86721065Seric errno = EPIPE; 86856795Seric # endif /* ECONNRESET */ 86921065Seric 87057379Seric mci->mci_errno = errno; 87157642Seric mci->mci_exitstat = EX_TEMPFAIL; 87263753Seric oldholderrs = HoldErrs; 87363753Seric HoldErrs = TRUE; 87463753Seric usrerr("451 reply: read error from %s", mci->mci_host); 87563753Seric 87610420Seric /* if debugging, pause so we can see state */ 87710420Seric if (tTd(18, 100)) 87810420Seric pause(); 87954967Seric mci->mci_state = MCIS_ERROR; 88053751Seric smtpquit(m, mci, e); 88169881Seric #if XDEBUG 88263753Seric { 88363753Seric char wbuf[MAXLINE]; 88464082Seric char *p = wbuf; 88564082Seric if (e->e_to != NULL) 88664082Seric { 88764082Seric sprintf(p, "%s... ", e->e_to); 88864082Seric p += strlen(p); 88964082Seric } 89064082Seric sprintf(p, "reply(%s) during %s", 89164082Seric mci->mci_host, SmtpPhase); 89263753Seric checkfd012(wbuf); 89363753Seric } 89463753Seric #endif 89563753Seric HoldErrs = oldholderrs; 89610054Seric return (-1); 89710131Seric } 89858957Seric fixcrlf(bufp, TRUE); 89910054Seric 90063753Seric /* EHLO failure is not a real error */ 90163753Seric if (e->e_xfp != NULL && (bufp[0] == '4' || 90263753Seric (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 90314900Seric { 90414900Seric /* serious error -- log the previous command */ 90564071Seric if (SmtpNeedIntro) 90664071Seric { 90764071Seric /* inform user who we are chatting with */ 90864071Seric fprintf(CurEnv->e_xfp, 90964071Seric "... while talking to %s:\n", 91064071Seric CurHostName); 91164071Seric SmtpNeedIntro = FALSE; 91264071Seric } 91359014Seric if (SmtpMsgBuffer[0] != '\0') 91459014Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 91559014Seric SmtpMsgBuffer[0] = '\0'; 91614900Seric 91714900Seric /* now log the message as from the other side */ 91858957Seric fprintf(e->e_xfp, "<<< %s\n", bufp); 91914900Seric } 92014900Seric 92114900Seric /* display the input for verbose mode */ 92258120Seric if (Verbose) 92359956Seric nmessage("050 %s", bufp); 9247356Seric 92559285Seric /* process the line */ 92667893Seric if (pfunc != NULL) 92767893Seric (*pfunc)(bufp, firstline, m, mci, e); 92859285Seric 92959285Seric firstline = FALSE; 93059285Seric 9317356Seric /* if continuation is required, we can go on */ 93259014Seric if (bufp[3] == '-') 9334684Seric continue; 9347356Seric 93559014Seric /* ignore improperly formated input */ 93659014Seric if (!(isascii(bufp[0]) && isdigit(bufp[0]))) 93759014Seric continue; 93859014Seric 9397356Seric /* decode the reply code */ 94059014Seric r = atoi(bufp); 9417356Seric 9427356Seric /* extra semantics: 0xx codes are "informational" */ 94359014Seric if (r >= 100) 94459014Seric break; 94559014Seric } 9467356Seric 94759014Seric /* 94859014Seric ** Now look at SmtpReplyBuffer -- only care about the first 94959014Seric ** line of the response from here on out. 95059014Seric */ 95158061Seric 95259014Seric /* save temporary failure messages for posterity */ 95359014Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 95459014Seric (void) strcpy(SmtpError, SmtpReplyBuffer); 9559391Seric 95659014Seric /* reply code 421 is "Service Shutting Down" */ 95759014Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 95859014Seric { 95959014Seric /* send the quit protocol */ 96059014Seric mci->mci_state = MCIS_SSD; 96159014Seric smtpquit(m, mci, e); 9624684Seric } 96359014Seric 96459014Seric return (r); 9654684Seric } 9664796Seric /* 9674865Seric ** SMTPMESSAGE -- send message to server 9684796Seric ** 9694796Seric ** Parameters: 9704796Seric ** f -- format 97110175Seric ** m -- the mailer to control formatting. 9724796Seric ** a, b, c -- parameters 9734796Seric ** 9744796Seric ** Returns: 9754796Seric ** none. 9764796Seric ** 9774796Seric ** Side Effects: 97853740Seric ** writes message to mci->mci_out. 9794796Seric */ 9804796Seric 9814865Seric /*VARARGS1*/ 98269748Seric void 98357642Seric #ifdef __STDC__ 98457642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 98557642Seric #else 98657642Seric smtpmessage(f, m, mci, va_alist) 9874796Seric char *f; 98810175Seric MAILER *m; 98954967Seric MCI *mci; 99057642Seric va_dcl 99157642Seric #endif 9924796Seric { 99356852Seric VA_LOCAL_DECL 99456852Seric 99557135Seric VA_START(mci); 99656852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 99756852Seric VA_END; 99858680Seric 99958120Seric if (tTd(18, 1) || Verbose) 100058151Seric nmessage(">>> %s", SmtpMsgBuffer); 100163753Seric if (TrafficLogFile != NULL) 100263753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), SmtpMsgBuffer); 100353740Seric if (mci->mci_out != NULL) 100458680Seric { 100553740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 100654967Seric m == NULL ? "\r\n" : m->m_eol); 100758680Seric } 100859149Seric else if (tTd(18, 1)) 100958725Seric { 101059149Seric printf("smtpmessage: NULL mci_out\n"); 101158725Seric } 10124796Seric } 10135182Seric 101456795Seric # endif /* SMTP */ 1015