122716Sdist /* 222716Sdist ** Sendmail 322716Sdist ** Copyright (c) 1983 Eric P. Allman 422716Sdist ** Berkeley, California 522716Sdist ** 622716Sdist ** Copyright (c) 1983 Regents of the University of California. 722716Sdist ** All rights reserved. The Berkeley software License Agreement 822716Sdist ** specifies the terms and conditions for redistribution. 922716Sdist */ 1022716Sdist 1122716Sdist 124796Seric # include <ctype.h> 134684Seric # include <sysexits.h> 1421065Seric # include <errno.h> 154865Seric # include "sendmail.h" 164684Seric 175182Seric # ifndef SMTP 18*23124Seric # ifndef lint 19*23124Seric static char SccsId[] = "@(#)usersmtp.c 5.3 (Berkeley) 06/08/85 (no SMTP)"; 20*23124Seric # endif not lint 215182Seric # else SMTP 224684Seric 23*23124Seric # ifndef lint 24*23124Seric static char SccsId[] = "@(#)usersmtp.c 5.3 (Berkeley) 06/08/85"; 25*23124Seric # endif not lint 265182Seric 279391Seric 289391Seric 294684Seric /* 309391Seric ** USERSMTP -- run SMTP protocol from the user end. 319391Seric ** 329391Seric ** This protocol is described in RFC821. 339391Seric */ 349391Seric 359391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 369391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 379391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 389391Seric 3914900Seric char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 4010054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 4121065Seric char SmtpError[MAXLINE] = ""; /* save failure error messages */ 4210054Seric FILE *SmtpOut; /* output file */ 4310054Seric FILE *SmtpIn; /* input file */ 4410054Seric int SmtpPid; /* pid of mailer */ 4511159Seric 4611159Seric /* following represents the state of the SMTP connection */ 4711159Seric int SmtpState; /* connection state, see below */ 4811159Seric 4911159Seric #define SMTP_CLOSED 0 /* connection is closed */ 5011159Seric #define SMTP_OPEN 1 /* connection is open for business */ 5111159Seric #define SMTP_SSD 2 /* service shutting down */ 529391Seric /* 534865Seric ** SMTPINIT -- initialize SMTP. 544684Seric ** 554865Seric ** Opens the connection and sends the initial protocol. 564684Seric ** 574684Seric ** Parameters: 584865Seric ** m -- mailer to create connection to. 594865Seric ** pvp -- pointer to parameter vector to pass to 604865Seric ** the mailer. 614684Seric ** 624684Seric ** Returns: 634865Seric ** appropriate exit status -- EX_OK on success. 6414913Seric ** If not EX_OK, it should close the connection. 654684Seric ** 664684Seric ** Side Effects: 674865Seric ** creates connection and sends initial protocol. 684684Seric */ 694684Seric 7014886Seric jmp_buf CtxGreeting; 7114886Seric 7210175Seric smtpinit(m, pvp) 734865Seric struct mailer *m; 744865Seric char **pvp; 754684Seric { 764865Seric register int r; 7714886Seric EVENT *gte; 784865Seric char buf[MAXNAME]; 7914886Seric extern greettimeout(); 804684Seric 814865Seric /* 824865Seric ** Open the connection to the mailer. 834865Seric */ 844684Seric 8511159Seric #ifdef DEBUG 8611159Seric if (SmtpState == SMTP_OPEN) 8711159Seric syserr("smtpinit: already open"); 8811159Seric #endif DEBUG 8911159Seric 906051Seric SmtpIn = SmtpOut = NULL; 9111159Seric SmtpState = SMTP_CLOSED; 9221065Seric SmtpError[0] = '\0'; 9310175Seric SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 946051Seric if (SmtpPid < 0) 956051Seric { 966051Seric # ifdef DEBUG 977677Seric if (tTd(18, 1)) 989391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 999391Seric pvp[0], ExitStat, errno); 1006051Seric # endif DEBUG 10115139Seric if (CurEnv->e_xfp != NULL) 10215139Seric { 10321065Seric register char *p; 10415139Seric extern char *errstring(); 10521065Seric extern char *statstring(); 10615139Seric 10721065Seric if (errno == 0) 10821065Seric { 10921065Seric p = statstring(ExitStat); 11021065Seric fprintf(CurEnv->e_xfp, 11121065Seric "%.3s %s.%s... %s\n", 11221065Seric p, pvp[1], m->m_name, p); 11321065Seric } 11421065Seric else 11521065Seric { 11621065Seric fprintf(CurEnv->e_xfp, 11721065Seric "421 %s.%s... Deferred: %s\n", 11821065Seric pvp[1], m->m_name, errstring(errno)); 11921065Seric } 12015139Seric } 1216051Seric return (ExitStat); 1226051Seric } 12311159Seric SmtpState = SMTP_OPEN; 1244796Seric 1254865Seric /* 1264865Seric ** Get the greeting message. 12714913Seric ** This should appear spontaneously. Give it five minutes to 12814886Seric ** happen. 1294865Seric */ 1304797Seric 13114886Seric if (setjmp(CtxGreeting) != 0) 13214913Seric goto tempfail; 13316141Seric gte = setevent((time_t) 300, greettimeout, 0); 13410175Seric r = reply(m); 13514886Seric clrevent(gte); 1368005Seric if (r < 0 || REPLYTYPE(r) != 2) 13714913Seric goto tempfail; 1384684Seric 1394865Seric /* 1404976Seric ** Send the HELO command. 1417963Seric ** My mother taught me to always introduce myself. 1424976Seric */ 1434976Seric 14410175Seric smtpmessage("HELO %s", m, HostName); 14510175Seric r = reply(m); 1468005Seric if (r < 0) 14714913Seric goto tempfail; 1488005Seric else if (REPLYTYPE(r) == 5) 14914913Seric goto unavailable; 1507963Seric else if (REPLYTYPE(r) != 2) 15114913Seric goto tempfail; 1524976Seric 1534976Seric /* 1549315Seric ** If this is expected to be another sendmail, send some internal 1559315Seric ** commands. 1569315Seric */ 1579315Seric 15810688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1599315Seric { 1609315Seric /* tell it to be verbose */ 16110175Seric smtpmessage("VERB", m); 16210175Seric r = reply(m); 1639315Seric if (r < 0) 16414913Seric goto tempfail; 1659315Seric 1669315Seric /* tell it we will be sending one transaction only */ 16710175Seric smtpmessage("ONEX", m); 16810175Seric r = reply(m); 1699315Seric if (r < 0) 17014913Seric goto tempfail; 1719315Seric } 1729315Seric 1739315Seric /* 1744865Seric ** Send the MAIL command. 1754865Seric ** Designates the sender. 1764865Seric */ 1774796Seric 17816156Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 1798436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 18010688Seric !bitnset(M_FROMPATH, m->m_flags)) 1818436Seric { 18210308Seric smtpmessage("MAIL From:<%s>", m, buf); 1838436Seric } 1848436Seric else 1858436Seric { 18610175Seric smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 18710308Seric buf[0] == '@' ? ',' : ':', buf); 1888436Seric } 18910175Seric r = reply(m); 1908005Seric if (r < 0 || REPLYTYPE(r) == 4) 19114913Seric goto tempfail; 1927963Seric else if (r == 250) 1937963Seric return (EX_OK); 1947963Seric else if (r == 552) 19514913Seric goto unavailable; 19614913Seric 19714913Seric /* protocol error -- close up */ 19814913Seric smtpquit(m); 1997964Seric return (EX_PROTOCOL); 20014913Seric 20114913Seric /* signal a temporary failure */ 20214913Seric tempfail: 20314913Seric smtpquit(m); 20416891Seric CurEnv->e_flags &= ~EF_FATALERRS; 20514913Seric return (EX_TEMPFAIL); 20614913Seric 20714913Seric /* signal service unavailable */ 20814913Seric unavailable: 20914913Seric smtpquit(m); 21014913Seric return (EX_UNAVAILABLE); 2114684Seric } 21214886Seric 21314886Seric 21414886Seric static 21514886Seric greettimeout() 21614886Seric { 21714886Seric /* timeout reading the greeting message */ 21814886Seric longjmp(CtxGreeting, 1); 21914886Seric } 2204684Seric /* 2214976Seric ** SMTPRCPT -- designate recipient. 2224797Seric ** 2234797Seric ** Parameters: 2244865Seric ** to -- address of recipient. 22510175Seric ** m -- the mailer we are sending to. 2264797Seric ** 2274797Seric ** Returns: 2284865Seric ** exit status corresponding to recipient status. 2294797Seric ** 2304797Seric ** Side Effects: 2314865Seric ** Sends the mail via SMTP. 2324797Seric */ 2334797Seric 23410175Seric smtprcpt(to, m) 2354865Seric ADDRESS *to; 23610175Seric register MAILER *m; 2374797Seric { 2384797Seric register int r; 23910308Seric extern char *remotename(); 2404797Seric 24110308Seric smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 2424865Seric 24310175Seric r = reply(m); 2448005Seric if (r < 0 || REPLYTYPE(r) == 4) 2454865Seric return (EX_TEMPFAIL); 2467963Seric else if (REPLYTYPE(r) == 2) 2477963Seric return (EX_OK); 2487964Seric else if (r == 550 || r == 551 || r == 553) 2497964Seric return (EX_NOUSER); 2507964Seric else if (r == 552 || r == 554) 2517964Seric return (EX_UNAVAILABLE); 2527964Seric return (EX_PROTOCOL); 2534797Seric } 2544797Seric /* 25510175Seric ** SMTPDATA -- send the data and clean up the transaction. 2564684Seric ** 2574684Seric ** Parameters: 2584865Seric ** m -- mailer being sent to. 2596980Seric ** e -- the envelope for this message. 2604684Seric ** 2614684Seric ** Returns: 2624976Seric ** exit status corresponding to DATA command. 2634684Seric ** 2644684Seric ** Side Effects: 2654865Seric ** none. 2664684Seric */ 2674684Seric 26810175Seric smtpdata(m, e) 2694865Seric struct mailer *m; 2706980Seric register ENVELOPE *e; 2714684Seric { 2724684Seric register int r; 2734684Seric 2744797Seric /* 2754797Seric ** Send the data. 27610175Seric ** First send the command and check that it is ok. 27710175Seric ** Then send the data. 27810175Seric ** Follow it up with a dot to terminate. 27910175Seric ** Finally get the results of the transaction. 2804797Seric */ 2814797Seric 28210175Seric /* send the command and check ok to proceed */ 28310175Seric smtpmessage("DATA", m); 28410175Seric r = reply(m); 2858005Seric if (r < 0 || REPLYTYPE(r) == 4) 2864797Seric return (EX_TEMPFAIL); 2877963Seric else if (r == 554) 2887963Seric return (EX_UNAVAILABLE); 2897963Seric else if (r != 354) 2907964Seric return (EX_PROTOCOL); 29110175Seric 29210175Seric /* now output the actual message */ 29310175Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 29410175Seric putline("\n", SmtpOut, m); 29510175Seric (*e->e_putbody)(SmtpOut, m, CurEnv); 29610175Seric 29710175Seric /* terminate the message */ 29810328Seric fprintf(SmtpOut, ".%s", m->m_eol); 29910215Seric if (Verbose && !HoldErrs) 30010215Seric nmessage(Arpa_Info, ">>> ."); 30110175Seric 30210175Seric /* check for the results of the transaction */ 30310175Seric r = reply(m); 3048005Seric if (r < 0 || REPLYTYPE(r) == 4) 3054797Seric return (EX_TEMPFAIL); 3067963Seric else if (r == 250) 3077963Seric return (EX_OK); 3087963Seric else if (r == 552 || r == 554) 3097963Seric return (EX_UNAVAILABLE); 3107964Seric return (EX_PROTOCOL); 3114684Seric } 3124684Seric /* 3134865Seric ** SMTPQUIT -- close the SMTP connection. 3144865Seric ** 3154865Seric ** Parameters: 31615535Seric ** m -- a pointer to the mailer. 3174865Seric ** 3184865Seric ** Returns: 3194865Seric ** none. 3204865Seric ** 3214865Seric ** Side Effects: 3224865Seric ** sends the final protocol and closes the connection. 3234865Seric */ 3244865Seric 32515535Seric smtpquit(m) 32610175Seric register MAILER *m; 3274865Seric { 3289391Seric int i; 3294865Seric 33010148Seric /* if the connection is already closed, don't bother */ 33110148Seric if (SmtpIn == NULL) 33210148Seric return; 33310148Seric 33410148Seric /* send the quit message if not a forced quit */ 33511159Seric if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD) 3369391Seric { 33710175Seric smtpmessage("QUIT", m); 33810175Seric (void) reply(m); 33911159Seric if (SmtpState == SMTP_CLOSED) 34010159Seric return; 3419391Seric } 3429391Seric 34310148Seric /* now actually close the connection */ 3447229Seric (void) fclose(SmtpIn); 3457229Seric (void) fclose(SmtpOut); 34610148Seric SmtpIn = SmtpOut = NULL; 34711159Seric SmtpState = SMTP_CLOSED; 34810148Seric 34910148Seric /* and pick up the zombie */ 35015535Seric i = endmailer(SmtpPid, m->m_argv[0]); 3519391Seric if (i != EX_OK) 35215535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3534865Seric } 3544865Seric /* 3554684Seric ** REPLY -- read arpanet reply 3564684Seric ** 3574684Seric ** Parameters: 35810175Seric ** m -- the mailer we are reading the reply from. 3594684Seric ** 3604684Seric ** Returns: 3614684Seric ** reply code it reads. 3624684Seric ** 3634684Seric ** Side Effects: 3644684Seric ** flushes the mail file. 3654684Seric */ 3664684Seric 36710175Seric reply(m) 36810688Seric MAILER *m; 3694684Seric { 3704865Seric (void) fflush(SmtpOut); 3714684Seric 3727677Seric if (tTd(18, 1)) 3734796Seric printf("reply\n"); 3744796Seric 3757356Seric /* 3767356Seric ** Read the input line, being careful not to hang. 3777356Seric */ 3787356Seric 3794684Seric for (;;) 3804684Seric { 3814684Seric register int r; 3827356Seric register char *p; 3834684Seric 3847685Seric /* actually do the read */ 3859547Seric if (CurEnv->e_xfp != NULL) 3869547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 3877356Seric 38810054Seric /* if we are in the process of closing just give the code */ 38911159Seric if (SmtpState == SMTP_CLOSED) 39010054Seric return (SMTPCLOSING); 39110054Seric 39210054Seric /* get the line from the other side */ 39310054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 39410054Seric if (p == NULL) 39510131Seric { 39610148Seric extern char MsgBuf[]; /* err.c */ 39710148Seric extern char Arpa_TSyserr[]; /* conf.c */ 39810148Seric 39921065Seric /* if the remote end closed early, fake an error */ 40021065Seric if (errno == 0) 40121065Seric # ifdef ECONNRESET 40221065Seric errno = ECONNRESET; 40321065Seric # else ECONNRESET 40421065Seric errno = EPIPE; 40521065Seric # endif ECONNRESET 40621065Seric 40710148Seric message(Arpa_TSyserr, "reply: read error"); 40810420Seric # ifdef DEBUG 40910420Seric /* if debugging, pause so we can see state */ 41010420Seric if (tTd(18, 100)) 41110420Seric pause(); 41210420Seric # endif DEBUG 41310148Seric # ifdef LOG 41418573Smiriam syslog(LOG_MAIL, "%s", &MsgBuf[4]); 41510148Seric # endif LOG 41611159Seric SmtpState = SMTP_CLOSED; 41715535Seric smtpquit(m); 41810054Seric return (-1); 41910131Seric } 42010054Seric fixcrlf(SmtpReplyBuffer, TRUE); 42110054Seric 42214900Seric if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 42314900Seric { 42414900Seric /* serious error -- log the previous command */ 42514900Seric if (SmtpMsgBuffer[0] != '\0') 42614900Seric fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer); 42714900Seric SmtpMsgBuffer[0] = '\0'; 42814900Seric 42914900Seric /* now log the message as from the other side */ 43014900Seric fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer); 43114900Seric } 43214900Seric 43314900Seric /* display the input for verbose mode */ 4347229Seric if (Verbose && !HoldErrs) 4359391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4367356Seric 4377356Seric /* if continuation is required, we can go on */ 4389391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4394684Seric continue; 4407356Seric 4417356Seric /* decode the reply code */ 4429391Seric r = atoi(SmtpReplyBuffer); 4437356Seric 4447356Seric /* extra semantics: 0xx codes are "informational" */ 4454684Seric if (r < 100) 4464684Seric continue; 4477356Seric 4489391Seric /* reply code 421 is "Service Shutting Down" */ 44911159Seric if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 4509391Seric { 45110054Seric /* send the quit protocol */ 45211159Seric SmtpState = SMTP_SSD; 45315535Seric smtpquit(m); 4549391Seric } 4559391Seric 45621065Seric /* save temporary failure messages for posterity */ 45721065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 45821065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 45921065Seric 4604684Seric return (r); 4614684Seric } 4624684Seric } 4634796Seric /* 4644865Seric ** SMTPMESSAGE -- send message to server 4654796Seric ** 4664796Seric ** Parameters: 4674796Seric ** f -- format 46810175Seric ** m -- the mailer to control formatting. 4694796Seric ** a, b, c -- parameters 4704796Seric ** 4714796Seric ** Returns: 4724796Seric ** none. 4734796Seric ** 4744796Seric ** Side Effects: 4754865Seric ** writes message to SmtpOut. 4764796Seric */ 4774796Seric 4784865Seric /*VARARGS1*/ 47910175Seric smtpmessage(f, m, a, b, c) 4804796Seric char *f; 48110175Seric MAILER *m; 4824796Seric { 48314900Seric (void) sprintf(SmtpMsgBuffer, f, a, b, c); 4847677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 48514900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 48611159Seric if (SmtpOut != NULL) 48714900Seric fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol); 4884796Seric } 4895182Seric 4905182Seric # endif SMTP 491