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*57642Seric static char sccsid[] = "@(#)usersmtp.c 6.3 (Berkeley) 01/21/93 (with SMTP)"; 1433731Sbostic #else 15*57642Seric static char sccsid[] = "@(#)usersmtp.c 6.3 (Berkeley) 01/21/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(); 6354967Seric extern MCI *openmailer(); 644684Seric 6557379Seric if (tTd(17, 1)) 6657379Seric { 6757379Seric printf("smtpinit "); 6857379Seric mci_dump(mci); 6957379Seric } 7057379Seric 714865Seric /* 724865Seric ** Open the connection to the mailer. 734865Seric */ 744684Seric 7521065Seric SmtpError[0] = '\0'; 7657379Seric CurHostName = mci->mci_host; /* XXX UGLY XXX */ 7754967Seric switch (mci->mci_state) 786051Seric { 7954967Seric case MCIS_ACTIVE: 8054967Seric /* need to clear old information */ 8154967Seric smtprset(m, mci, e); 8254967Seric mci->mci_state = MCIS_OPEN; 8315139Seric 8454967Seric case MCIS_OPEN: 8554967Seric return; 8654967Seric 8754967Seric case MCIS_ERROR: 8854967Seric case MCIS_SSD: 8954967Seric /* shouldn't happen */ 9054967Seric smtpquit(m, mci, e); 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 1729315Seric /* 1734865Seric ** Send the MAIL command. 1744865Seric ** Designates the sender. 1754865Seric */ 1764796Seric 17753751Seric mci->mci_state = MCIS_ACTIVE; 17853751Seric 17953751Seric expand("\001<", buf, &buf[sizeof buf - 1], e); 18053751Seric if (e->e_from.q_mailer == LocalMailer || 18110688Seric !bitnset(M_FROMPATH, m->m_flags)) 1828436Seric { 18353751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 1848436Seric } 1858436Seric else 1868436Seric { 18753751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 18810308Seric buf[0] == '@' ? ',' : ':', buf); 1898436Seric } 19057379Seric SmtpPhase = mci->mci_phase = "MAIL wait"; 19153751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 19257379Seric r = reply(m, mci, e, ReadTimeout); 1938005Seric if (r < 0 || REPLYTYPE(r) == 4) 19453751Seric { 19553751Seric mci->mci_exitstat = EX_TEMPFAIL; 19653751Seric mci->mci_errno = errno; 19753751Seric smtpquit(m, mci, e); 19853751Seric return EX_TEMPFAIL; 19953751Seric } 2007963Seric else if (r == 250) 20153751Seric { 20253751Seric mci->mci_exitstat = EX_OK; 20353751Seric return EX_OK; 20453751Seric } 2057963Seric else if (r == 552) 20653751Seric { 20753751Seric /* signal service unavailable */ 20853751Seric mci->mci_exitstat = EX_UNAVAILABLE; 20953751Seric smtpquit(m, mci, e); 21053751Seric return EX_UNAVAILABLE; 21153751Seric } 21214913Seric 21314913Seric /* protocol error -- close up */ 21453751Seric smtpquit(m, mci, e); 21553751Seric mci->mci_exitstat = EX_PROTOCOL; 21653751Seric return EX_PROTOCOL; 2174684Seric } 2184684Seric /* 2194976Seric ** SMTPRCPT -- designate recipient. 2204797Seric ** 2214797Seric ** Parameters: 2224865Seric ** to -- address of recipient. 22310175Seric ** m -- the mailer we are sending to. 22457379Seric ** mci -- the connection info for this transaction. 22557379Seric ** e -- the envelope for this transaction. 2264797Seric ** 2274797Seric ** Returns: 2284865Seric ** exit status corresponding to recipient status. 2294797Seric ** 2304797Seric ** Side Effects: 2314865Seric ** Sends the mail via SMTP. 2324797Seric */ 2334797Seric 23453751Seric smtprcpt(to, m, mci, e) 2354865Seric ADDRESS *to; 23610175Seric register MAILER *m; 23754967Seric MCI *mci; 23853751Seric ENVELOPE *e; 2394797Seric { 2404797Seric register int r; 2414797Seric 24253751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2434865Seric 24457379Seric SmtpPhase = mci->mci_phase = "RCPT wait"; 24553751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 24657379Seric r = reply(m, mci, e, ReadTimeout); 2478005Seric if (r < 0 || REPLYTYPE(r) == 4) 2484865Seric return (EX_TEMPFAIL); 2497963Seric else if (REPLYTYPE(r) == 2) 2507963Seric return (EX_OK); 2517964Seric else if (r == 550 || r == 551 || r == 553) 2527964Seric return (EX_NOUSER); 2537964Seric else if (r == 552 || r == 554) 2547964Seric return (EX_UNAVAILABLE); 2557964Seric return (EX_PROTOCOL); 2564797Seric } 2574797Seric /* 25810175Seric ** SMTPDATA -- send the data and clean up the transaction. 2594684Seric ** 2604684Seric ** Parameters: 2614865Seric ** m -- mailer being sent to. 2626980Seric ** e -- the envelope for this message. 2634684Seric ** 2644684Seric ** Returns: 2654976Seric ** exit status corresponding to DATA command. 2664684Seric ** 2674684Seric ** Side Effects: 2684865Seric ** none. 2694684Seric */ 2704684Seric 27153740Seric smtpdata(m, mci, e) 2724865Seric struct mailer *m; 27354967Seric register MCI *mci; 2746980Seric register ENVELOPE *e; 2754684Seric { 2764684Seric register int r; 2774684Seric 2784797Seric /* 2794797Seric ** Send the data. 28010175Seric ** First send the command and check that it is ok. 28110175Seric ** Then send the data. 28210175Seric ** Follow it up with a dot to terminate. 28310175Seric ** Finally get the results of the transaction. 2844797Seric */ 2854797Seric 28610175Seric /* send the command and check ok to proceed */ 28753751Seric smtpmessage("DATA", m, mci); 28857379Seric SmtpPhase = mci->mci_phase = "DATA wait"; 28953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 29057379Seric r = reply(m, mci, e, ReadTimeout); 2918005Seric if (r < 0 || REPLYTYPE(r) == 4) 2924797Seric return (EX_TEMPFAIL); 2937963Seric else if (r == 554) 2947963Seric return (EX_UNAVAILABLE); 2957963Seric else if (r != 354) 2967964Seric return (EX_PROTOCOL); 29710175Seric 29810175Seric /* now output the actual message */ 29953751Seric (*e->e_puthdr)(mci->mci_out, m, e); 30053740Seric putline("\n", mci->mci_out, m); 30153751Seric (*e->e_putbody)(mci->mci_out, m, e); 30210175Seric 30310175Seric /* terminate the message */ 30453740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 30510215Seric if (Verbose && !HoldErrs) 30610215Seric nmessage(Arpa_Info, ">>> ."); 30710175Seric 30810175Seric /* check for the results of the transaction */ 30957379Seric SmtpPhase = mci->mci_phase = "result wait"; 31053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 31157379Seric r = reply(m, mci, e, ReadTimeout); 31253751Seric if (r < 0) 3134797Seric return (EX_TEMPFAIL); 31453751Seric mci->mci_state = MCIS_OPEN; 31553751Seric if (REPLYTYPE(r) == 4) 31653751Seric return (EX_TEMPFAIL); 3177963Seric else if (r == 250) 3187963Seric return (EX_OK); 3197963Seric else if (r == 552 || r == 554) 3207963Seric return (EX_UNAVAILABLE); 3217964Seric return (EX_PROTOCOL); 3224684Seric } 3234684Seric /* 3244865Seric ** SMTPQUIT -- close the SMTP connection. 3254865Seric ** 3264865Seric ** Parameters: 32715535Seric ** m -- a pointer to the mailer. 3284865Seric ** 3294865Seric ** Returns: 3304865Seric ** none. 3314865Seric ** 3324865Seric ** Side Effects: 3334865Seric ** sends the final protocol and closes the connection. 3344865Seric */ 3354865Seric 33653751Seric smtpquit(m, mci, e) 33753751Seric register MAILER *m; 33854967Seric register MCI *mci; 33953751Seric ENVELOPE *e; 3404865Seric { 3419391Seric int i; 3424865Seric 34354967Seric /* send the quit message if we haven't gotten I/O error */ 34453751Seric if (mci->mci_state != MCIS_ERROR) 3459391Seric { 34653751Seric smtpmessage("QUIT", m, mci); 34757379Seric (void) reply(m, mci, e, ReadTimeout); 34853740Seric if (mci->mci_state == MCIS_CLOSED) 34910159Seric return; 3509391Seric } 3519391Seric 35252676Seric /* now actually close the connection and pick up the zombie */ 35352676Seric i = endmailer(mci, m->m_argv[0]); 3549391Seric if (i != EX_OK) 35515535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3564865Seric } 3574865Seric /* 35854967Seric ** SMTPRSET -- send a RSET (reset) command 35954967Seric */ 36054967Seric 36154967Seric smtprset(m, mci, e) 36254967Seric register MAILER *m; 36354967Seric register MCI *mci; 36454967Seric ENVELOPE *e; 36554967Seric { 36654967Seric int r; 36754967Seric 36854967Seric smtpmessage("RSET", m, mci); 36957379Seric r = reply(m, mci, e, ReadTimeout); 37054967Seric if (r < 0 || REPLYTYPE(r) == 4) 37154967Seric return EX_TEMPFAIL; 37254967Seric else if (REPLYTYPE(r) == 2) 37354967Seric return EX_OK; 37454967Seric else 37554967Seric return EX_PROTOCOL; 37654967Seric } 37754967Seric /* 37854967Seric ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 37954967Seric */ 38054967Seric 38154967Seric smtpnoop(mci) 38254967Seric register MCI *mci; 38354967Seric { 38454967Seric int r; 38554967Seric MAILER *m = mci->mci_mailer; 38654967Seric extern ENVELOPE BlankEnvelope; 38754967Seric ENVELOPE *e = &BlankEnvelope; 38854967Seric 38954967Seric smtpmessage("NOOP", m, mci); 39057379Seric r = reply(m, mci, e, ReadTimeout); 39154967Seric if (REPLYTYPE(r) != 2) 39254967Seric smtpquit(m, mci, e); 39354967Seric return r; 39454967Seric } 39554967Seric /* 3964684Seric ** REPLY -- read arpanet reply 3974684Seric ** 3984684Seric ** Parameters: 39910175Seric ** m -- the mailer we are reading the reply from. 40057379Seric ** mci -- the mailer connection info structure. 40157379Seric ** e -- the current envelope. 40257379Seric ** timeout -- the timeout for reads. 4034684Seric ** 4044684Seric ** Returns: 4054684Seric ** reply code it reads. 4064684Seric ** 4074684Seric ** Side Effects: 4084684Seric ** flushes the mail file. 4094684Seric */ 4104684Seric 41157379Seric reply(m, mci, e, timeout) 41253751Seric MAILER *m; 41354967Seric MCI *mci; 41453751Seric ENVELOPE *e; 4154684Seric { 41657379Seric if (mci->mci_out != NULL) 41757379Seric (void) fflush(mci->mci_out); 4184684Seric 4197677Seric if (tTd(18, 1)) 4204796Seric printf("reply\n"); 4214796Seric 4227356Seric /* 4237356Seric ** Read the input line, being careful not to hang. 4247356Seric */ 4257356Seric 4264684Seric for (;;) 4274684Seric { 4284684Seric register int r; 4297356Seric register char *p; 43053751Seric extern time_t curtime(); 4314684Seric 4327685Seric /* actually do the read */ 43353751Seric if (e->e_xfp != NULL) 43453751Seric (void) fflush(e->e_xfp); /* for debugging */ 4357356Seric 43610054Seric /* if we are in the process of closing just give the code */ 43753740Seric if (mci->mci_state == MCIS_CLOSED) 43810054Seric return (SMTPCLOSING); 43910054Seric 44010054Seric /* get the line from the other side */ 44157379Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in, 44257379Seric timeout); 44353751Seric mci->mci_lastuse = curtime(); 44453751Seric 44510054Seric if (p == NULL) 44610131Seric { 44710148Seric extern char MsgBuf[]; /* err.c */ 44810148Seric extern char Arpa_TSyserr[]; /* conf.c */ 44910148Seric 45021065Seric /* if the remote end closed early, fake an error */ 45121065Seric if (errno == 0) 45221065Seric # ifdef ECONNRESET 45321065Seric errno = ECONNRESET; 45456795Seric # else /* ECONNRESET */ 45521065Seric errno = EPIPE; 45656795Seric # endif /* ECONNRESET */ 45721065Seric 45857379Seric mci->mci_errno = errno; 459*57642Seric mci->mci_exitstat = EX_TEMPFAIL; 460*57642Seric message(Arpa_TSyserr, "%s: reply: read error from %s", 461*57642Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 46257203Seric mci->mci_host); 46310420Seric /* if debugging, pause so we can see state */ 46410420Seric if (tTd(18, 100)) 46510420Seric pause(); 46610148Seric # ifdef LOG 46757203Seric if (LogLevel > 0) 46857203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 46956795Seric # endif /* LOG */ 47054967Seric mci->mci_state = MCIS_ERROR; 47153751Seric smtpquit(m, mci, e); 47210054Seric return (-1); 47310131Seric } 47410054Seric fixcrlf(SmtpReplyBuffer, TRUE); 47510054Seric 47656795Seric if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) 47714900Seric { 47814900Seric /* serious error -- log the previous command */ 47914900Seric if (SmtpMsgBuffer[0] != '\0') 48053751Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 48114900Seric SmtpMsgBuffer[0] = '\0'; 48214900Seric 48314900Seric /* now log the message as from the other side */ 48453751Seric fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 48514900Seric } 48614900Seric 48714900Seric /* display the input for verbose mode */ 4887229Seric if (Verbose && !HoldErrs) 4899391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4907356Seric 4917356Seric /* if continuation is required, we can go on */ 4929391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4934684Seric continue; 4947356Seric 4957356Seric /* decode the reply code */ 4969391Seric r = atoi(SmtpReplyBuffer); 4977356Seric 4987356Seric /* extra semantics: 0xx codes are "informational" */ 4994684Seric if (r < 100) 5004684Seric continue; 5017356Seric 5029391Seric /* reply code 421 is "Service Shutting Down" */ 50353740Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 5049391Seric { 50510054Seric /* send the quit protocol */ 50653740Seric mci->mci_state = MCIS_SSD; 50753751Seric smtpquit(m, mci, e); 5089391Seric } 5099391Seric 51021065Seric /* save temporary failure messages for posterity */ 51121065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 51221065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 51321065Seric 5144684Seric return (r); 5154684Seric } 5164684Seric } 5174796Seric /* 5184865Seric ** SMTPMESSAGE -- send message to server 5194796Seric ** 5204796Seric ** Parameters: 5214796Seric ** f -- format 52210175Seric ** m -- the mailer to control formatting. 5234796Seric ** a, b, c -- parameters 5244796Seric ** 5254796Seric ** Returns: 5264796Seric ** none. 5274796Seric ** 5284796Seric ** Side Effects: 52953740Seric ** writes message to mci->mci_out. 5304796Seric */ 5314796Seric 5324865Seric /*VARARGS1*/ 533*57642Seric #ifdef __STDC__ 534*57642Seric smtpmessage(char *f, MAILER *m, MCI *mci, ...) 535*57642Seric #else 536*57642Seric smtpmessage(f, m, mci, va_alist) 5374796Seric char *f; 53810175Seric MAILER *m; 53954967Seric MCI *mci; 540*57642Seric va_dcl 541*57642Seric #endif 5424796Seric { 54356852Seric VA_LOCAL_DECL 54456852Seric 54557135Seric VA_START(mci); 54656852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 54756852Seric VA_END; 5487677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 54914900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 55053740Seric if (mci->mci_out != NULL) 55153740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 55254967Seric m == NULL ? "\r\n" : m->m_eol); 5534796Seric } 5545182Seric 55556795Seric # endif /* SMTP */ 556