diff options
Diffstat (limited to 'src/usersmtp.c')
-rw-r--r-- | src/usersmtp.c | 1172 |
1 files changed, 0 insertions, 1172 deletions
diff --git a/src/usersmtp.c b/src/usersmtp.c deleted file mode 100644 index c82942b..0000000 --- a/src/usersmtp.c +++ /dev/null @@ -1,1172 +0,0 @@ -/* - * Copyright (c) 1998 Sendmail, Inc. All rights reserved. - * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -# include "sendmail.h" - -#ifndef lint -#if SMTP -static char sccsid[] = "@(#)usersmtp.c 8.111 (Berkeley) 2/3/1999 (with SMTP)"; -#else -static char sccsid[] = "@(#)usersmtp.c 8.111 (Berkeley) 2/3/1999 (without SMTP)"; -#endif -#endif /* not lint */ - -# include <sysexits.h> -# include <errno.h> - -# if SMTP - -/* -** USERSMTP -- run SMTP protocol from the user end. -** -** This protocol is described in RFC821. -*/ - -#define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ -#define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ -#define SMTPCLOSING 421 /* "Service Shutting Down" */ - -char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ -char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ -char SmtpError[MAXLINE] = ""; /* save failure error messages */ -bool SmtpNeedIntro; /* need "while talking" in transcript */ - -extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); -extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)())); -/* -** SMTPINIT -- initialize SMTP. -** -** Opens the connection and sends the initial protocol. -** -** Parameters: -** m -- mailer to create connection to. -** pvp -- pointer to parameter vector to pass to -** the mailer. -** -** Returns: -** none. -** -** Side Effects: -** creates connection and sends initial protocol. -*/ - -void -smtpinit(m, mci, e) - MAILER *m; - register MCI *mci; - ENVELOPE *e; -{ - register int r; - register char *p; - extern void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); - extern void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); - - if (tTd(18, 1)) - { - printf("smtpinit "); - mci_dump(mci, FALSE); - } - - /* - ** Open the connection to the mailer. - */ - - SmtpError[0] = '\0'; - CurHostName = mci->mci_host; /* XXX UGLY XXX */ - if (CurHostName == NULL) - CurHostName = MyHostName; - SmtpNeedIntro = TRUE; - switch (mci->mci_state) - { - case MCIS_ACTIVE: - /* need to clear old information */ - smtprset(m, mci, e); - /* fall through */ - - case MCIS_OPEN: - return; - - case MCIS_ERROR: - case MCIS_SSD: - /* shouldn't happen */ - smtpquit(m, mci, e); - /* fall through */ - - case MCIS_CLOSED: - syserr("451 smtpinit: state CLOSED"); - return; - - case MCIS_OPENING: - break; - } - - mci->mci_state = MCIS_OPENING; - - /* - ** Get the greeting message. - ** This should appear spontaneously. Give it five minutes to - ** happen. - */ - - SmtpPhase = mci->mci_phase = "client greeting"; - sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check); - if (r < 0) - goto tempfail1; - if (REPLYTYPE(r) == 4) - goto tempfail2; - if (REPLYTYPE(r) != 2) - goto unavailable; - - /* - ** Send the HELO command. - ** My mother taught me to always introduce myself. - */ - - if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags)) - mci->mci_flags |= MCIF_ESMTP; - -tryhelo: - if (bitnset(M_LMTP, m->m_flags)) - { - smtpmessage("LHLO %s", m, mci, MyHostName); - SmtpPhase = mci->mci_phase = "client LHLO"; - } - else if (bitset(MCIF_ESMTP, mci->mci_flags)) - { - smtpmessage("EHLO %s", m, mci, MyHostName); - SmtpPhase = mci->mci_phase = "client EHLO"; - } - else - { - smtpmessage("HELO %s", m, mci, MyHostName); - SmtpPhase = mci->mci_phase = "client HELO"; - } - sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_helo, helo_options); - if (r < 0) - goto tempfail1; - else if (REPLYTYPE(r) == 5) - { - if (bitset(MCIF_ESMTP, mci->mci_flags) && - !bitnset(M_LMTP, m->m_flags)) - { - /* try old SMTP instead */ - mci->mci_flags &= ~MCIF_ESMTP; - goto tryhelo; - } - goto unavailable; - } - else if (REPLYTYPE(r) != 2) - goto tempfail2; - - /* - ** Check to see if we actually ended up talking to ourself. - ** This means we didn't know about an alias or MX, or we managed - ** to connect to an echo server. - */ - - p = strchr(&SmtpReplyBuffer[4], ' '); - if (p != NULL) - *p = '\0'; - if (!bitnset(M_NOLOOPCHECK, m->m_flags) && - !bitnset(M_LMTP, m->m_flags) && - strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) - { - syserr("553 %s config error: mail loops back to me (MX problem?)", - CurHostName); - mci_setstat(mci, EX_CONFIG, NULL, NULL); - mci->mci_errno = 0; - smtpquit(m, mci, e); - return; - } - - /* - ** If this is expected to be another sendmail, send some internal - ** commands. - */ - - if (bitnset(M_INTERNAL, m->m_flags)) - { - /* tell it to be verbose */ - smtpmessage("VERB", m, mci); - r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); - if (r < 0) - goto tempfail1; - } - - if (mci->mci_state != MCIS_CLOSED) - { - mci->mci_state = MCIS_OPEN; - return; - } - - /* got a 421 error code during startup */ - - tempfail1: - if (mci->mci_errno == 0) - mci->mci_errno = errno; - mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); - if (mci->mci_state != MCIS_CLOSED) - smtpquit(m, mci, e); - return; - - tempfail2: - if (mci->mci_errno == 0) - mci->mci_errno = errno; - /* XXX should use code from other end iff ENHANCEDSTATUSCODES */ - mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer); - if (mci->mci_state != MCIS_CLOSED) - smtpquit(m, mci, e); - return; - - unavailable: - mci->mci_errno = errno; - mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer); - smtpquit(m, mci, e); - return; -} -/* -** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol -** -** Parameters: -** line -- the response line. -** firstline -- set if this is the first line of the reply. -** m -- the mailer. -** mci -- the mailer connection info. -** e -- the envelope. -** -** Returns: -** none. -*/ - -void -esmtp_check(line, firstline, m, mci, e) - char *line; - bool firstline; - MAILER *m; - register MCI *mci; - ENVELOPE *e; -{ - if (strstr(line, "ESMTP") != NULL) - mci->mci_flags |= MCIF_ESMTP; - if (strstr(line, "8BIT-OK") != NULL) - mci->mci_flags |= MCIF_8BITOK; -} -/* -** HELO_OPTIONS -- process the options on a HELO line. -** -** Parameters: -** line -- the response line. -** firstline -- set if this is the first line of the reply. -** m -- the mailer. -** mci -- the mailer connection info. -** e -- the envelope. -** -** Returns: -** none. -*/ - -void -helo_options(line, firstline, m, mci, e) - char *line; - bool firstline; - MAILER *m; - register MCI *mci; - ENVELOPE *e; -{ - register char *p; - - if (firstline) - return; - - if (strlen(line) < (SIZE_T) 5) - return; - line += 4; - p = strchr(line, ' '); - if (p != NULL) - *p++ = '\0'; - if (strcasecmp(line, "size") == 0) - { - mci->mci_flags |= MCIF_SIZE; - if (p != NULL) - mci->mci_maxsize = atol(p); - } - else if (strcasecmp(line, "8bitmime") == 0) - { - mci->mci_flags |= MCIF_8BITMIME; - mci->mci_flags &= ~MCIF_7BIT; - } - else if (strcasecmp(line, "expn") == 0) - mci->mci_flags |= MCIF_EXPN; - else if (strcasecmp(line, "dsn") == 0) - mci->mci_flags |= MCIF_DSN; -} -/* -** SMTPMAILFROM -- send MAIL command -** -** Parameters: -** m -- the mailer. -** mci -- the mailer connection structure. -** e -- the envelope (including the sender to specify). -*/ - -int -smtpmailfrom(m, mci, e) - MAILER *m; - MCI *mci; - ENVELOPE *e; -{ - int r; - char *bufp; - char *bodytype; - char buf[MAXNAME + 1]; - char optbuf[MAXLINE]; - - if (tTd(18, 2)) - printf("smtpmailfrom: CurHost=%s\n", CurHostName); - - /* set up appropriate options to include */ - bufp = optbuf; - if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) - snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize); - else - strcpy(optbuf, ""); - bufp = &optbuf[strlen(optbuf)]; - - bodytype = e->e_bodytype; - if (bitset(MCIF_8BITMIME, mci->mci_flags)) - { - if (bodytype == NULL && - bitset(MM_MIME8BIT, MimeMode) && - bitset(EF_HAS8BIT, e->e_flags) && - !bitset(EF_DONT_MIME, e->e_flags) && - !bitnset(M_8BITS, m->m_flags)) - bodytype = "8BITMIME"; - if (bodytype != NULL && - SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7) - { - snprintf(bufp, SPACELEFT(optbuf, bufp), - " BODY=%s", bodytype); - bufp += strlen(bufp); - } - } - else if (bitnset(M_8BITS, m->m_flags) || - !bitset(EF_HAS8BIT, e->e_flags) || - bitset(MCIF_8BITOK, mci->mci_flags)) - { - /* just pass it through */ - } -#if MIME8TO7 - else if (bitset(MM_CVTMIME, MimeMode) && - !bitset(EF_DONT_MIME, e->e_flags) && - (!bitset(MM_PASS8BIT, MimeMode) || - bitset(EF_IS_MIME, e->e_flags))) - { - /* must convert from 8bit MIME format to 7bit encoded */ - mci->mci_flags |= MCIF_CVT8TO7; - } -#endif - else if (!bitset(MM_PASS8BIT, MimeMode)) - { - /* cannot just send a 8-bit version */ - extern char MsgBuf[]; - - usrerr("%s does not support 8BITMIME", CurHostName); - mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf); - return EX_DATAERR; - } - - if (bitset(MCIF_DSN, mci->mci_flags)) - { - if (e->e_envid != NULL && - SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7) - { - snprintf(bufp, SPACELEFT(optbuf, bufp), - " ENVID=%s", e->e_envid); - bufp += strlen(bufp); - } - - /* RET= parameter */ - if (bitset(EF_RET_PARAM, e->e_flags) && - SPACELEFT(optbuf, bufp) > 9) - { - snprintf(bufp, SPACELEFT(optbuf, bufp), - " RET=%s", - bitset(EF_NO_BODY_RETN, e->e_flags) ? - "HDRS" : "FULL"); - bufp += strlen(bufp); - } - } - - /* - ** Send the MAIL command. - ** Designates the sender. - */ - - mci->mci_state = MCIS_ACTIVE; - - if (bitset(EF_RESPONSE, e->e_flags) && - !bitnset(M_NO_NULL_FROM, m->m_flags)) - (void) strcpy(buf, ""); - else - expand("\201g", buf, sizeof buf, e); - if (buf[0] == '<') - { - /* strip off <angle brackets> (put back on below) */ - bufp = &buf[strlen(buf) - 1]; - if (*bufp == '>') - *bufp = '\0'; - bufp = &buf[1]; - } - else - bufp = buf; - if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || - !bitnset(M_FROMPATH, m->m_flags)) - { - smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); - } - else - { - smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, - *bufp == '@' ? ',' : ':', bufp, optbuf); - } - SmtpPhase = mci->mci_phase = "client MAIL"; - sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_mail, NULL); - if (r < 0) - { - /* communications failure */ - mci->mci_errno = errno; - mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); - smtpquit(m, mci, e); - return EX_TEMPFAIL; - } - else if (r == 421) - { - /* service shutting down */ - mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer); - smtpquit(m, mci, e); - return EX_TEMPFAIL; - } - else if (REPLYTYPE(r) == 4) - { - mci_setstat(mci, EX_NOTSTICKY, smtptodsn(r), SmtpReplyBuffer); - return EX_TEMPFAIL; - } - else if (REPLYTYPE(r) == 2) - { - return EX_OK; - } - else if (r == 501) - { - /* syntax error in arguments */ - mci_setstat(mci, EX_NOTSTICKY, "5.5.2", SmtpReplyBuffer); - return EX_DATAERR; - } - else if (r == 553) - { - /* mailbox name not allowed */ - mci_setstat(mci, EX_NOTSTICKY, "5.1.3", SmtpReplyBuffer); - return EX_DATAERR; - } - else if (r == 552) - { - /* exceeded storage allocation */ - mci_setstat(mci, EX_NOTSTICKY, "5.3.4", SmtpReplyBuffer); - if (bitset(MCIF_SIZE, mci->mci_flags)) - e->e_flags |= EF_NO_BODY_RETN; - return EX_UNAVAILABLE; - } - else if (REPLYTYPE(r) == 5) - { - /* unknown error */ - mci_setstat(mci, EX_NOTSTICKY, "5.0.0", SmtpReplyBuffer); - return EX_UNAVAILABLE; - } - - if (LogLevel > 1) - { - sm_syslog(LOG_CRIT, e->e_id, - "%.100s: SMTP MAIL protocol error: %s", - CurHostName, - shortenstring(SmtpReplyBuffer, 403)); - } - - /* protocol error -- close up */ - mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); - smtpquit(m, mci, e); - return EX_PROTOCOL; -} -/* -** SMTPRCPT -- designate recipient. -** -** Parameters: -** to -- address of recipient. -** m -- the mailer we are sending to. -** mci -- the connection info for this transaction. -** e -- the envelope for this transaction. -** -** Returns: -** exit status corresponding to recipient status. -** -** Side Effects: -** Sends the mail via SMTP. -*/ - -int -smtprcpt(to, m, mci, e) - ADDRESS *to; - register MAILER *m; - MCI *mci; - ENVELOPE *e; -{ - register int r; - char *bufp; - char optbuf[MAXLINE]; - - strcpy(optbuf, ""); - bufp = &optbuf[strlen(optbuf)]; - if (bitset(MCIF_DSN, mci->mci_flags)) - { - /* NOTIFY= parameter */ - if (bitset(QHASNOTIFY, to->q_flags) && - bitset(QPRIMARY, to->q_flags) && - !bitnset(M_LOCALMAILER, m->m_flags)) - { - bool firstone = TRUE; - - strcat(bufp, " NOTIFY="); - if (bitset(QPINGONSUCCESS, to->q_flags)) - { - strcat(bufp, "SUCCESS"); - firstone = FALSE; - } - if (bitset(QPINGONFAILURE, to->q_flags)) - { - if (!firstone) - strcat(bufp, ","); - strcat(bufp, "FAILURE"); - firstone = FALSE; - } - if (bitset(QPINGONDELAY, to->q_flags)) - { - if (!firstone) - strcat(bufp, ","); - strcat(bufp, "DELAY"); - firstone = FALSE; - } - if (firstone) - strcat(bufp, "NEVER"); - bufp += strlen(bufp); - } - - /* ORCPT= parameter */ - if (to->q_orcpt != NULL && - SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7) - { - snprintf(bufp, SPACELEFT(optbuf, bufp), - " ORCPT=%s", to->q_orcpt); - bufp += strlen(bufp); - } - } - - smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); - - SmtpPhase = mci->mci_phase = "client RCPT"; - sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_rcpt, NULL); - to->q_rstatus = newstr(SmtpReplyBuffer); - to->q_status = smtptodsn(r); - to->q_statmta = mci->mci_host; - if (r < 0 || REPLYTYPE(r) == 4) - return EX_TEMPFAIL; - else if (REPLYTYPE(r) == 2) - return EX_OK; - else if (r == 550) - { - to->q_status = "5.1.1"; - return EX_NOUSER; - } - else if (r == 551) - { - to->q_status = "5.1.6"; - return EX_NOUSER; - } - else if (r == 553) - { - to->q_status = "5.1.3"; - return EX_NOUSER; - } - else if (REPLYTYPE(r) == 5) - { - return EX_UNAVAILABLE; - } - - if (LogLevel > 1) - { - sm_syslog(LOG_CRIT, e->e_id, - "%.100s: SMTP RCPT protocol error: %s", - CurHostName, - shortenstring(SmtpReplyBuffer, 403)); - } - - mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); - return EX_PROTOCOL; -} -/* -** SMTPDATA -- send the data and clean up the transaction. -** -** Parameters: -** m -- mailer being sent to. -** mci -- the mailer connection information. -** e -- the envelope for this message. -** -** Returns: -** exit status corresponding to DATA command. -** -** Side Effects: -** none. -*/ - -static jmp_buf CtxDataTimeout; -static void datatimeout __P((void)); - -int -smtpdata(m, mci, e) - MAILER *m; - register MCI *mci; - register ENVELOPE *e; -{ - register int r; - register EVENT *ev; - int rstat; - int xstat; - time_t timeout; - - /* - ** Send the data. - ** First send the command and check that it is ok. - ** Then send the data. - ** Follow it up with a dot to terminate. - ** Finally get the results of the transaction. - */ - - /* send the command and check ok to proceed */ - smtpmessage("DATA", m, mci); - SmtpPhase = mci->mci_phase = "client DATA 354"; - sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_datainit, NULL); - if (r < 0 || REPLYTYPE(r) == 4) - { - smtpquit(m, mci, e); - return EX_TEMPFAIL; - } - else if (REPLYTYPE(r) == 5) - { - smtprset(m, mci, e); - return EX_UNAVAILABLE; - } - else if (REPLYTYPE(r) != 3) - { - if (LogLevel > 1) - { - sm_syslog(LOG_CRIT, e->e_id, - "%.100s: SMTP DATA-1 protocol error: %s", - CurHostName, - shortenstring(SmtpReplyBuffer, 403)); - } - smtprset(m, mci, e); - mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer); - return (EX_PROTOCOL); - } - - /* - ** Set timeout around data writes. Make it at least large - ** enough for DNS timeouts on all recipients plus some fudge - ** factor. The main thing is that it should not be infinite. - */ - - if (setjmp(CtxDataTimeout) != 0) - { - mci->mci_errno = errno; - mci->mci_state = MCIS_ERROR; - mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); - syserr("451 timeout writing message to %s", CurHostName); - smtpquit(m, mci, e); - return EX_TEMPFAIL; - } - - timeout = e->e_msgsize / 16; - if (timeout < (time_t) 600) - timeout = (time_t) 600; - timeout += e->e_nrcpts * 300; - ev = setevent(timeout, datatimeout, 0); - - /* - ** Output the actual message. - */ - - (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); - (*e->e_putbody)(mci, e, NULL); - - /* - ** Cleanup after sending message. - */ - - clrevent(ev); - - if (ferror(mci->mci_out)) - { - /* error during processing -- don't send the dot */ - mci->mci_errno = EIO; - mci->mci_state = MCIS_ERROR; - mci_setstat(mci, EX_IOERR, "4.4.2", NULL); - smtpquit(m, mci, e); - return EX_IOERR; - } - - /* terminate the message */ - fprintf(mci->mci_out, ".%s", m->m_eol); - if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid()); - if (Verbose) - nmessage(">>> ."); - - /* check for the results of the transaction */ - SmtpPhase = mci->mci_phase = "client DATA status"; - sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase); - if (bitnset(M_LMTP, m->m_flags)) - return EX_OK; - r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); - if (r < 0) - { - smtpquit(m, mci, e); - return EX_TEMPFAIL; - } - mci->mci_state = MCIS_OPEN; - xstat = EX_NOTSTICKY; - if (r == 452) - rstat = EX_TEMPFAIL; - else if (REPLYTYPE(r) == 4) - rstat = xstat = EX_TEMPFAIL; - else if (REPLYCLASS(r) != 5) - rstat = xstat = EX_PROTOCOL; - else if (REPLYTYPE(r) == 2) - rstat = xstat = EX_OK; - else if (REPLYTYPE(r) == 5) - rstat = EX_UNAVAILABLE; - else - rstat = EX_PROTOCOL; - mci_setstat(mci, xstat, smtptodsn(r), SmtpReplyBuffer); - if (e->e_statmsg != NULL) - free(e->e_statmsg); - e->e_statmsg = newstr(&SmtpReplyBuffer[4]); - if (rstat != EX_PROTOCOL) - return rstat; - if (LogLevel > 1) - { - sm_syslog(LOG_CRIT, e->e_id, - "%.100s: SMTP DATA-2 protocol error: %s", - CurHostName, - shortenstring(SmtpReplyBuffer, 403)); - } - return rstat; -} - - -static void -datatimeout() -{ - longjmp(CtxDataTimeout, 1); -} -/* -** SMTPGETSTAT -- get status code from DATA in LMTP -** -** Parameters: -** m -- the mailer to which we are sending the message. -** mci -- the mailer connection structure. -** e -- the current envelope. -** -** Returns: -** The exit status corresponding to the reply code. -*/ - -int -smtpgetstat(m, mci, e) - MAILER *m; - MCI *mci; - ENVELOPE *e; -{ - int r; - int stat; - - /* check for the results of the transaction */ - r = reply(m, mci, e, TimeOuts.to_datafinal, NULL); - if (r < 0) - { - smtpquit(m, mci, e); - return EX_TEMPFAIL; - } - if (e->e_statmsg != NULL) - free(e->e_statmsg); - e->e_statmsg = newstr(&SmtpReplyBuffer[4]); - if (REPLYTYPE(r) == 4) - stat = EX_TEMPFAIL; - else if (REPLYCLASS(r) != 5) - stat = EX_PROTOCOL; - else if (REPLYTYPE(r) == 2) - stat = EX_OK; - else if (REPLYTYPE(r) == 5) - stat = EX_UNAVAILABLE; - else - stat = EX_PROTOCOL; - mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer); - if (LogLevel > 1 && stat == EX_PROTOCOL) - { - sm_syslog(LOG_CRIT, e->e_id, - "%.100s: SMTP DATA-3 protocol error: %s", - CurHostName, - shortenstring(SmtpReplyBuffer, 403)); - } - return stat; -} -/* -** SMTPQUIT -- close the SMTP connection. -** -** Parameters: -** m -- a pointer to the mailer. -** mci -- the mailer connection information. -** e -- the current envelope. -** -** Returns: -** none. -** -** Side Effects: -** sends the final protocol and closes the connection. -*/ - -void -smtpquit(m, mci, e) - register MAILER *m; - register MCI *mci; - ENVELOPE *e; -{ - bool oldSuprErrs = SuprErrs; - - /* - ** Suppress errors here -- we may be processing a different - ** job when we do the quit connection, and we don't want the - ** new job to be penalized for something that isn't it's - ** problem. - */ - - SuprErrs = TRUE; - - /* send the quit message if we haven't gotten I/O error */ - if (mci->mci_state != MCIS_ERROR) - { - SmtpPhase = "client QUIT"; - smtpmessage("QUIT", m, mci); - (void) reply(m, mci, e, TimeOuts.to_quit, NULL); - SuprErrs = oldSuprErrs; - if (mci->mci_state == MCIS_CLOSED) - return; - } - - /* now actually close the connection and pick up the zombie */ - (void) endmailer(mci, e, NULL); - - SuprErrs = oldSuprErrs; -} -/* -** SMTPRSET -- send a RSET (reset) command -*/ - -void -smtprset(m, mci, e) - register MAILER *m; - register MCI *mci; - ENVELOPE *e; -{ - int r; - - SmtpPhase = "client RSET"; - smtpmessage("RSET", m, mci); - r = reply(m, mci, e, TimeOuts.to_rset, NULL); - if (r < 0) - mci->mci_state = MCIS_ERROR; - else if (REPLYTYPE(r) == 2) - { - mci->mci_state = MCIS_OPEN; - return; - } - smtpquit(m, mci, e); -} -/* -** SMTPPROBE -- check the connection state -*/ - -int -smtpprobe(mci) - register MCI *mci; -{ - int r; - MAILER *m = mci->mci_mailer; - extern ENVELOPE BlankEnvelope; - ENVELOPE *e = &BlankEnvelope; - - SmtpPhase = "client probe"; - smtpmessage("RSET", m, mci); - r = reply(m, mci, e, TimeOuts.to_miscshort, NULL); - if (r < 0 || REPLYTYPE(r) != 2) - smtpquit(m, mci, e); - return r; -} -/* -** REPLY -- read arpanet reply -** -** Parameters: -** m -- the mailer we are reading the reply from. -** mci -- the mailer connection info structure. -** e -- the current envelope. -** timeout -- the timeout for reads. -** pfunc -- processing function called on each line of response. -** If null, no special processing is done. -** -** Returns: -** reply code it reads. -** -** Side Effects: -** flushes the mail file. -*/ - -int -reply(m, mci, e, timeout, pfunc) - MAILER *m; - MCI *mci; - ENVELOPE *e; - time_t timeout; - void (*pfunc)(); -{ - register char *bufp; - register int r; - bool firstline = TRUE; - char junkbuf[MAXLINE]; - - if (mci->mci_out != NULL) - (void) fflush(mci->mci_out); - - if (tTd(18, 1)) - printf("reply\n"); - - /* - ** Read the input line, being careful not to hang. - */ - - bufp = SmtpReplyBuffer; - for (;;) - { - register char *p; - - /* actually do the read */ - if (e->e_xfp != NULL) - (void) fflush(e->e_xfp); /* for debugging */ - - /* if we are in the process of closing just give the code */ - if (mci->mci_state == MCIS_CLOSED) - return (SMTPCLOSING); - - if (mci->mci_out != NULL) - fflush(mci->mci_out); - - /* get the line from the other side */ - p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); - mci->mci_lastuse = curtime(); - - if (p == NULL) - { - bool oldholderrs; - extern char MsgBuf[]; - - /* if the remote end closed early, fake an error */ - if (errno == 0) -# ifdef ECONNRESET - errno = ECONNRESET; -# else /* ECONNRESET */ - errno = EPIPE; -# endif /* ECONNRESET */ - - mci->mci_errno = errno; - oldholderrs = HoldErrs; - HoldErrs = TRUE; - usrerr("451 reply: read error from %s", CurHostName); - - /* errors on QUIT should not be persistent */ - if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0) - mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); - - /* if debugging, pause so we can see state */ - if (tTd(18, 100)) - pause(); - mci->mci_state = MCIS_ERROR; - smtpquit(m, mci, e); -#if XDEBUG - { - char wbuf[MAXLINE]; - char *p = wbuf; - int wbufleft = sizeof wbuf; - - if (e->e_to != NULL) - { - int plen; - - snprintf(p, wbufleft, "%s... ", - shortenstring(e->e_to, MAXSHORTSTR)); - plen = strlen(p); - p += plen; - wbufleft -= plen; - } - snprintf(p, wbufleft, "reply(%.100s) during %s", - CurHostName == NULL ? "NO_HOST" : CurHostName, - SmtpPhase); - checkfd012(wbuf); - } -#endif - HoldErrs = oldholderrs; - return (-1); - } - fixcrlf(bufp, TRUE); - - /* EHLO failure is not a real error */ - if (e->e_xfp != NULL && (bufp[0] == '4' || - (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) - { - /* serious error -- log the previous command */ - if (SmtpNeedIntro) - { - /* inform user who we are chatting with */ - fprintf(CurEnv->e_xfp, - "... while talking to %s:\n", - CurHostName); - SmtpNeedIntro = FALSE; - } - if (SmtpMsgBuffer[0] != '\0') - fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); - SmtpMsgBuffer[0] = '\0'; - - /* now log the message as from the other side */ - fprintf(e->e_xfp, "<<< %s\n", bufp); - } - - /* display the input for verbose mode */ - if (Verbose) - nmessage("050 %s", bufp); - - /* ignore improperly formated input */ - if (!(isascii(bufp[0]) && isdigit(bufp[0])) || - !(isascii(bufp[1]) && isdigit(bufp[1])) || - !(isascii(bufp[2]) && isdigit(bufp[2])) || - !(bufp[3] == ' ' || bufp[3] == '-' || bufp[3] == '\0')) - continue; - - /* process the line */ - if (pfunc != NULL) - (*pfunc)(bufp, firstline, m, mci, e); - - firstline = FALSE; - - /* decode the reply code */ - r = atoi(bufp); - - /* extra semantics: 0xx codes are "informational" */ - if (r < 100) - continue; - - /* if no continuation lines, return this line */ - if (bufp[3] != '-') - break; - - /* first line of real reply -- ignore rest */ - bufp = junkbuf; - } - - /* - ** Now look at SmtpReplyBuffer -- only care about the first - ** line of the response from here on out. - */ - - /* save temporary failure messages for posterity */ - if (SmtpReplyBuffer[0] == '4' && - (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0')) - snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer); - - /* reply code 421 is "Service Shutting Down" */ - if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) - { - /* send the quit protocol */ - mci->mci_state = MCIS_SSD; - smtpquit(m, mci, e); - } - - return (r); -} -/* -** SMTPMESSAGE -- send message to server -** -** Parameters: -** f -- format -** m -- the mailer to control formatting. -** a, b, c -- parameters -** -** Returns: -** none. -** -** Side Effects: -** writes message to mci->mci_out. -*/ - -/*VARARGS1*/ -void -#ifdef __STDC__ -smtpmessage(char *f, MAILER *m, MCI *mci, ...) -#else -smtpmessage(f, m, mci, va_alist) - char *f; - MAILER *m; - MCI *mci; - va_dcl -#endif -{ - VA_LOCAL_DECL - - VA_START(mci); - (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap); - VA_END; - - if (tTd(18, 1) || Verbose) - nmessage(">>> %s", SmtpMsgBuffer); - if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d >>> %s\n", - (int) getpid(), SmtpMsgBuffer); - if (mci->mci_out != NULL) - { - fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, - m == NULL ? "\r\n" : m->m_eol); - } - else if (tTd(18, 1)) - { - printf("smtpmessage: NULL mci_out\n"); - } -} - -# endif /* SMTP */ |