122716Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642831Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822716Sdist 933731Sbostic # include "sendmail.h" 1022716Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef SMTP 13*57943Seric static char sccsid[] = "@(#)usersmtp.c 6.5 (Berkeley) 02/12/93 (with SMTP)"; 1433731Sbostic #else 15*57943Seric static char sccsid[] = "@(#)usersmtp.c 6.5 (Berkeley) 02/12/93 (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 */ 389391Seric /* 394865Seric ** SMTPINIT -- initialize SMTP. 404684Seric ** 414865Seric ** Opens the connection and sends the initial protocol. 424684Seric ** 434684Seric ** Parameters: 444865Seric ** m -- mailer to create connection to. 454865Seric ** pvp -- pointer to parameter vector to pass to 464865Seric ** the mailer. 474684Seric ** 484684Seric ** Returns: 4954967Seric ** none. 504684Seric ** 514684Seric ** Side Effects: 524865Seric ** creates connection and sends initial protocol. 534684Seric */ 544684Seric 5554967Seric smtpinit(m, mci, e) 564865Seric struct mailer *m; 5754967Seric register MCI *mci; 5853751Seric ENVELOPE *e; 594684Seric { 604865Seric register int r; 6114886Seric EVENT *gte; 6252107Seric extern STAB *stab(); 634684Seric 6457379Seric if (tTd(17, 1)) 6557379Seric { 6657379Seric printf("smtpinit "); 6757379Seric mci_dump(mci); 6857379Seric } 6957379Seric 704865Seric /* 714865Seric ** Open the connection to the mailer. 724865Seric */ 734684Seric 7421065Seric SmtpError[0] = '\0'; 7557379Seric CurHostName = mci->mci_host; /* XXX UGLY XXX */ 7654967Seric switch (mci->mci_state) 776051Seric { 7854967Seric case MCIS_ACTIVE: 7954967Seric /* need to clear old information */ 8054967Seric smtprset(m, mci, e); 8157734Seric /* fall through */ 8215139Seric 8354967Seric case MCIS_OPEN: 8454967Seric return; 8554967Seric 8654967Seric case MCIS_ERROR: 8754967Seric case MCIS_SSD: 8854967Seric /* shouldn't happen */ 8954967Seric smtpquit(m, mci, e); 9057734Seric /* fall through */ 9154967Seric 9254967Seric case MCIS_CLOSED: 9354967Seric syserr("smtpinit: state CLOSED"); 9454967Seric return; 9554967Seric 9654967Seric case MCIS_OPENING: 9754967Seric break; 986051Seric } 994796Seric 10057379Seric SmtpPhase = mci->mci_phase = "user open"; 10154967Seric mci->mci_state = MCIS_OPENING; 10254967Seric 1034865Seric /* 1044865Seric ** Get the greeting message. 10514913Seric ** This should appear spontaneously. Give it five minutes to 10614886Seric ** happen. 1074865Seric */ 1084797Seric 10957379Seric SmtpPhase = mci->mci_phase = "greeting wait"; 11053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 11157379Seric r = reply(m, mci, e, (time_t) 300); 1128005Seric if (r < 0 || REPLYTYPE(r) != 2) 11352104Seric goto tempfail1; 1144684Seric 1154865Seric /* 1164976Seric ** Send the HELO command. 1177963Seric ** My mother taught me to always introduce myself. 1184976Seric */ 1194976Seric 12053751Seric smtpmessage("HELO %s", m, mci, MyHostName); 12157379Seric SmtpPhase = mci->mci_phase = "HELO wait"; 12253751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 12357379Seric r = reply(m, mci, e, ReadTimeout); 1248005Seric if (r < 0) 12552104Seric goto tempfail1; 1268005Seric else if (REPLYTYPE(r) == 5) 12714913Seric goto unavailable; 1287963Seric else if (REPLYTYPE(r) != 2) 12952104Seric goto tempfail1; 1304976Seric 1314976Seric /* 1329315Seric ** If this is expected to be another sendmail, send some internal 1339315Seric ** commands. 1349315Seric */ 1359315Seric 13610688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1379315Seric { 1389315Seric /* tell it to be verbose */ 13953751Seric smtpmessage("VERB", m, mci); 14057379Seric r = reply(m, mci, e, ReadTimeout); 1419315Seric if (r < 0) 14252104Seric goto tempfail2; 1439315Seric } 1449315Seric 14553751Seric mci->mci_state = MCIS_OPEN; 14654967Seric return; 14753751Seric 14853751Seric tempfail1: 14953751Seric tempfail2: 15053751Seric mci->mci_exitstat = EX_TEMPFAIL; 15157379Seric if (mci->mci_errno == 0) 15257379Seric mci->mci_errno = errno; 15357379Seric if (mci->mci_state != MCIS_CLOSED) 15457379Seric smtpquit(m, mci, e); 15554967Seric return; 15653751Seric 15753751Seric unavailable: 15853751Seric mci->mci_exitstat = EX_UNAVAILABLE; 15953751Seric mci->mci_errno = errno; 16053751Seric smtpquit(m, mci, e); 16154967Seric return; 16253751Seric } 16353751Seric 16453751Seric smtpmailfrom(m, mci, e) 16553751Seric struct mailer *m; 16654967Seric MCI *mci; 16753751Seric ENVELOPE *e; 16853751Seric { 16953751Seric int r; 17053751Seric char buf[MAXNAME]; 17153751Seric 172*57943Seric if (tTd(17, 2)) 173*57943Seric printf("smtpmailfrom: CurHost=%s\n", CurHostName); 174*57943Seric 1759315Seric /* 1764865Seric ** Send the MAIL command. 1774865Seric ** Designates the sender. 1784865Seric */ 1794796Seric 18053751Seric mci->mci_state = MCIS_ACTIVE; 18153751Seric 18253751Seric expand("\001<", buf, &buf[sizeof buf - 1], e); 18353751Seric if (e->e_from.q_mailer == LocalMailer || 18410688Seric !bitnset(M_FROMPATH, m->m_flags)) 1858436Seric { 18653751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 1878436Seric } 1888436Seric else 1898436Seric { 19053751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 19110308Seric buf[0] == '@' ? ',' : ':', buf); 1928436Seric } 19357379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 19453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 19557379Seric r = reply(m, mci, e, ReadTimeout); 1968005Seric if (r < 0 || REPLYTYPE(r) == 4) 19753751Seric { 19853751Seric mci->mci_exitstat = EX_TEMPFAIL; 19953751Seric mci->mci_errno = errno; 20053751Seric smtpquit(m, mci, e); 20153751Seric return EX_TEMPFAIL; 20253751Seric } 2037963Seric else if (r == 250) 20453751Seric { 20553751Seric mci->mci_exitstat = EX_OK; 20653751Seric return EX_OK; 20753751Seric } 2087963Seric else if (r == 552) 20953751Seric { 21053751Seric /* signal service unavailable */ 21153751Seric mci->mci_exitstat = EX_UNAVAILABLE; 21253751Seric smtpquit(m, mci, e); 21353751Seric return EX_UNAVAILABLE; 21453751Seric } 21514913Seric 21614913Seric /* protocol error -- close up */ 21753751Seric smtpquit(m, mci, e); 21853751Seric mci->mci_exitstat = EX_PROTOCOL; 21953751Seric return EX_PROTOCOL; 2204684Seric } 2214684Seric /* 2224976Seric ** SMTPRCPT -- designate recipient. 2234797Seric ** 2244797Seric ** Parameters: 2254865Seric ** to -- address of recipient. 22610175Seric ** m -- the mailer we are sending to. 22757379Seric ** mci -- the connection info for this transaction. 22857379Seric ** e -- the envelope for this transaction. 2294797Seric ** 2304797Seric ** Returns: 2314865Seric ** exit status corresponding to recipient status. 2324797Seric ** 2334797Seric ** Side Effects: 2344865Seric ** Sends the mail via SMTP. 2354797Seric */ 2364797Seric 23753751Seric smtprcpt(to, m, mci, e) 2384865Seric ADDRESS *to; 23910175Seric register MAILER *m; 24054967Seric MCI *mci; 24153751Seric ENVELOPE *e; 2424797Seric { 2434797Seric register int r; 2444797Seric 24553751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2464865Seric 24757379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 24853751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 24957379Seric r = reply(m, mci, e, ReadTimeout); 2508005Seric if (r < 0 || REPLYTYPE(r) == 4) 2514865Seric return (EX_TEMPFAIL); 2527963Seric else if (REPLYTYPE(r) == 2) 2537963Seric return (EX_OK); 2547964Seric else if (r == 550 || r == 551 || r == 553) 2557964Seric return (EX_NOUSER); 2567964Seric else if (r == 552 || r == 554) 2577964Seric return (EX_UNAVAILABLE); 2587964Seric return (EX_PROTOCOL); 2594797Seric } 2604797Seric /* 26110175Seric ** SMTPDATA -- send the data and clean up the transaction. 2624684Seric ** 2634684Seric ** Parameters: 2644865Seric ** m -- mailer being sent to. 2656980Seric ** e -- the envelope for this message. 2664684Seric ** 2674684Seric ** Returns: 2684976Seric ** exit status corresponding to DATA command. 2694684Seric ** 2704684Seric ** Side Effects: 2714865Seric ** none. 2724684Seric */ 2734684Seric 27453740Seric smtpdata(m, mci, e) 2754865Seric struct mailer *m; 27654967Seric register MCI *mci; 2776980Seric register ENVELOPE *e; 2784684Seric { 2794684Seric register int r; 2804684Seric 2814797Seric /* 2824797Seric ** Send the data. 28310175Seric ** First send the command and check that it is ok. 28410175Seric ** Then send the data. 28510175Seric ** Follow it up with a dot to terminate. 28610175Seric ** Finally get the results of the transaction. 2874797Seric */ 2884797Seric 28910175Seric /* send the command and check ok to proceed */ 29053751Seric smtpmessage("DATA", m, mci); 29157379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 29253751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 29357379Seric r = reply(m, mci, e, ReadTimeout); 2948005Seric if (r < 0 || REPLYTYPE(r) == 4) 2954797Seric return (EX_TEMPFAIL); 2967963Seric else if (r == 554) 2977963Seric return (EX_UNAVAILABLE); 2987963Seric else if (r != 354) 2997964Seric return (EX_PROTOCOL); 30010175Seric 30110175Seric /* now output the actual message */ 30253751Seric (*e->e_puthdr)(mci->mci_out, m, e); 30353740Seric putline("\n", mci->mci_out, m); 30453751Seric (*e->e_putbody)(mci->mci_out, m, e); 30510175Seric 30610175Seric /* terminate the message */ 30753740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 30810215Seric if (Verbose && !HoldErrs) 30910215Seric nmessage(Arpa_Info, ">>> ."); 31010175Seric 31110175Seric /* check for the results of the transaction */ 31257379Seric SmtpPhase = mci->mci_phase = "result wait"; 31353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 31457379Seric r = reply(m, mci, e, ReadTimeout); 31553751Seric if (r < 0) 3164797Seric return (EX_TEMPFAIL); 31753751Seric mci->mci_state = MCIS_OPEN; 31853751Seric if (REPLYTYPE(r) == 4) 31953751Seric return (EX_TEMPFAIL); 3207963Seric else if (r == 250) 3217963Seric return (EX_OK); 3227963Seric else if (r == 552 || r == 554) 3237963Seric return (EX_UNAVAILABLE); 3247964Seric return (EX_PROTOCOL); 3254684Seric } 3264684Seric /* 3274865Seric ** SMTPQUIT -- close the SMTP connection. 3284865Seric ** 3294865Seric ** Parameters: 33015535Seric ** m -- a pointer to the mailer. 3314865Seric ** 3324865Seric ** Returns: 3334865Seric ** none. 3344865Seric ** 3354865Seric ** Side Effects: 3364865Seric ** sends the final protocol and closes the connection. 3374865Seric */ 3384865Seric 33953751Seric smtpquit(m, mci, e) 34053751Seric register MAILER *m; 34154967Seric register MCI *mci; 34253751Seric ENVELOPE *e; 3434865Seric { 3449391Seric int i; 3454865Seric 34654967Seric /* send the quit message if we haven't gotten I/O error */ 34753751Seric if (mci->mci_state != MCIS_ERROR) 3489391Seric { 34953751Seric smtpmessage("QUIT", m, mci); 35057379Seric (void) reply(m, mci, e, ReadTimeout); 35153740Seric if (mci->mci_state == MCIS_CLOSED) 35210159Seric return; 3539391Seric } 3549391Seric 35552676Seric /* now actually close the connection and pick up the zombie */ 35652676Seric i = endmailer(mci, m->m_argv[0]); 3579391Seric if (i != EX_OK) 35815535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3594865Seric } 3604865Seric /* 36154967Seric ** SMTPRSET -- send a RSET (reset) command 36254967Seric */ 36354967Seric 36454967Seric smtprset(m, mci, e) 36554967Seric register MAILER *m; 36654967Seric register MCI *mci; 36754967Seric ENVELOPE *e; 36854967Seric { 36954967Seric int r; 37054967Seric 37154967Seric smtpmessage("RSET", m, mci); 37257734Seric r = reply(m, mci, e, (time_t) 300); 37357734Seric if (r < 0) 37457734Seric mci->mci_state = MCIS_ERROR; 37554967Seric else if (REPLYTYPE(r) == 2) 37657734Seric { 37757734Seric mci->mci_state = MCIS_OPEN; 37857734Seric return; 37957734Seric } 38057734Seric smtpquit(m, mci, e); 38154967Seric } 38254967Seric /* 38354967Seric ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 38454967Seric */ 38554967Seric 38654967Seric smtpnoop(mci) 38754967Seric register MCI *mci; 38854967Seric { 38954967Seric int r; 39054967Seric MAILER *m = mci->mci_mailer; 39154967Seric extern ENVELOPE BlankEnvelope; 39254967Seric ENVELOPE *e = &BlankEnvelope; 39354967Seric 39454967Seric smtpmessage("NOOP", m, mci); 39557379Seric r = reply(m, mci, e, ReadTimeout); 39654967Seric if (REPLYTYPE(r) != 2) 39754967Seric smtpquit(m, mci, e); 39854967Seric return r; 39954967Seric } 40054967Seric /* 4014684Seric ** REPLY -- read arpanet reply 4024684Seric ** 4034684Seric ** Parameters: 40410175Seric ** m -- the mailer we are reading the reply from. 40557379Seric ** mci -- the mailer connection info structure. 40657379Seric ** e -- the current envelope. 40757379Seric ** timeout -- the timeout for reads. 4084684Seric ** 4094684Seric ** Returns: 4104684Seric ** reply code it reads. 4114684Seric ** 4124684Seric ** Side Effects: 4134684Seric ** flushes the mail file. 4144684Seric */ 4154684Seric 41657379Seric reply(m, mci, e, timeout) 41753751Seric MAILER *m; 41854967Seric MCI *mci; 41953751Seric ENVELOPE *e; 4204684Seric { 42157379Seric if (mci->mci_out != NULL) 42257379Seric (void) fflush(mci->mci_out); 4234684Seric 4247677Seric if (tTd(18, 1)) 4254796Seric printf("reply\n"); 4264796Seric 4277356Seric /* 4287356Seric ** Read the input line, being careful not to hang. 4297356Seric */ 4307356Seric 4314684Seric for (;;) 4324684Seric { 4334684Seric register int r; 4347356Seric register char *p; 43553751Seric extern time_t curtime(); 4364684Seric 4377685Seric /* actually do the read */ 43853751Seric if (e->e_xfp != NULL) 43953751Seric (void) fflush(e->e_xfp); /* for debugging */ 4407356Seric 44110054Seric /* if we are in the process of closing just give the code */ 44253740Seric if (mci->mci_state == MCIS_CLOSED) 44310054Seric return (SMTPCLOSING); 44410054Seric 44510054Seric /* get the line from the other side */ 44657379Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in, 44757379Seric timeout); 44853751Seric mci->mci_lastuse = curtime(); 44953751Seric 45010054Seric if (p == NULL) 45110131Seric { 45210148Seric extern char MsgBuf[]; /* err.c */ 45310148Seric extern char Arpa_TSyserr[]; /* conf.c */ 45410148Seric 45521065Seric /* if the remote end closed early, fake an error */ 45621065Seric if (errno == 0) 45721065Seric # ifdef ECONNRESET 45821065Seric errno = ECONNRESET; 45956795Seric # else /* ECONNRESET */ 46021065Seric errno = EPIPE; 46156795Seric # endif /* ECONNRESET */ 46221065Seric 46357379Seric mci->mci_errno = errno; 46457642Seric mci->mci_exitstat = EX_TEMPFAIL; 46557642Seric message(Arpa_TSyserr, "%s: reply: read error from %s", 46657642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 46757203Seric mci->mci_host); 46810420Seric /* if debugging, pause so we can see state */ 46910420Seric if (tTd(18, 100)) 47010420Seric pause(); 47110148Seric # ifdef LOG 47257203Seric if (LogLevel > 0) 47357203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 47456795Seric # endif /* LOG */ 47554967Seric mci->mci_state = MCIS_ERROR; 47653751Seric smtpquit(m, mci, e); 47710054Seric return (-1); 47810131Seric } 47910054Seric fixcrlf(SmtpReplyBuffer, TRUE); 48010054Seric 48156795Seric if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) 48214900Seric { 48314900Seric /* serious error -- log the previous command */ 48414900Seric if (SmtpMsgBuffer[0] != '\0') 48553751Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 48614900Seric SmtpMsgBuffer[0] = '\0'; 48714900Seric 48814900Seric /* now log the message as from the other side */ 48953751Seric fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 49014900Seric } 49114900Seric 49214900Seric /* display the input for verbose mode */ 4937229Seric if (Verbose && !HoldErrs) 4949391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4957356Seric 4967356Seric /* if continuation is required, we can go on */ 4979391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4984684Seric continue; 4997356Seric 5007356Seric /* decode the reply code */ 5019391Seric r = atoi(SmtpReplyBuffer); 5027356Seric 5037356Seric /* extra semantics: 0xx codes are "informational" */ 5044684Seric if (r < 100) 5054684Seric continue; 5067356Seric 5079391Seric /* reply code 421 is "Service Shutting Down" */ 50853740Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 5099391Seric { 51010054Seric /* send the quit protocol */ 51153740Seric mci->mci_state = MCIS_SSD; 51253751Seric smtpquit(m, mci, e); 5139391Seric } 5149391Seric 51521065Seric /* save temporary failure messages for posterity */ 51621065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 51721065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 51821065Seric 5194684Seric return (r); 5204684Seric } 5214684Seric } 5224796Seric /* 5234865Seric ** SMTPMESSAGE -- send message to server 5244796Seric ** 5254796Seric ** Parameters: 5264796Seric ** f -- format 52710175Seric ** m -- the mailer to control formatting. 5284796Seric ** a, b, c -- parameters 5294796Seric ** 5304796Seric ** Returns: 5314796Seric ** none. 5324796Seric ** 5334796Seric ** Side Effects: 53453740Seric ** writes message to mci->mci_out. 5354796Seric */ 5364796Seric 5374865Seric /*VARARGS1*/ 53857642Seric #ifdef __STDC__ 53957642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 54057642Seric #else 54157642Seric smtpmessage(f, m, mci, va_alist) 5424796Seric char *f; 54310175Seric MAILER *m; 54454967Seric MCI *mci; 54557642Seric va_dcl 54657642Seric #endif 5474796Seric { 54856852Seric VA_LOCAL_DECL 54956852Seric 55057135Seric VA_START(mci); 55156852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 55256852Seric VA_END; 5537677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 55414900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 55553740Seric if (mci->mci_out != NULL) 55653740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 55754967Seric m == NULL ? "\r\n" : m->m_eol); 5584796Seric } 5595182Seric 56056795Seric # endif /* SMTP */ 561