122716Sdist /* 2*33731Sbostic * Copyright (c) 1988 Regents of the University of California. 3*33731Sbostic * All rights reserved. 4*33731Sbostic * 5*33731Sbostic * Redistribution and use in source and binary forms are permitted 6*33731Sbostic * provided that this notice is preserved and that due credit is given 7*33731Sbostic * to the University of California at Berkeley. The name of the University 8*33731Sbostic * may not be used to endorse or promote products derived from this 9*33731Sbostic * software without specific prior written permission. This software 10*33731Sbostic * is provided ``as is'' without express or implied warranty. 11*33731Sbostic * 12*33731Sbostic * Sendmail 13*33731Sbostic * Copyright (c) 1983 Eric P. Allman 14*33731Sbostic * Berkeley, California 15*33731Sbostic */ 1622716Sdist 17*33731Sbostic # include "sendmail.h" 1822716Sdist 19*33731Sbostic #ifndef lint 20*33731Sbostic #ifdef SMTP 21*33731Sbostic static char sccsid[] = "@(#)usersmtp.c 5.9 (Berkeley) 03/13/88 (with SMTP)"; 22*33731Sbostic #else 23*33731Sbostic static char sccsid[] = "@(#)usersmtp.c 5.9 (Berkeley) 03/13/88 (without SMTP)"; 24*33731Sbostic #endif 25*33731Sbostic #endif /* not lint */ 26*33731Sbostic 274684Seric # include <sysexits.h> 2821065Seric # include <errno.h> 294684Seric 30*33731Sbostic # ifdef SMTP 314684Seric 324684Seric /* 339391Seric ** USERSMTP -- run SMTP protocol from the user end. 349391Seric ** 359391Seric ** This protocol is described in RFC821. 369391Seric */ 379391Seric 389391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 399391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 409391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 419391Seric 4214900Seric char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 4310054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 4421065Seric char SmtpError[MAXLINE] = ""; /* save failure error messages */ 4510054Seric FILE *SmtpOut; /* output file */ 4610054Seric FILE *SmtpIn; /* input file */ 4710054Seric int SmtpPid; /* pid of mailer */ 4811159Seric 4911159Seric /* following represents the state of the SMTP connection */ 5011159Seric int SmtpState; /* connection state, see below */ 5111159Seric 5211159Seric #define SMTP_CLOSED 0 /* connection is closed */ 5311159Seric #define SMTP_OPEN 1 /* connection is open for business */ 5411159Seric #define SMTP_SSD 2 /* service shutting down */ 559391Seric /* 564865Seric ** SMTPINIT -- initialize SMTP. 574684Seric ** 584865Seric ** Opens the connection and sends the initial protocol. 594684Seric ** 604684Seric ** Parameters: 614865Seric ** m -- mailer to create connection to. 624865Seric ** pvp -- pointer to parameter vector to pass to 634865Seric ** the mailer. 644684Seric ** 654684Seric ** Returns: 664865Seric ** appropriate exit status -- EX_OK on success. 6714913Seric ** If not EX_OK, it should close the connection. 684684Seric ** 694684Seric ** Side Effects: 704865Seric ** creates connection and sends initial protocol. 714684Seric */ 724684Seric 7314886Seric jmp_buf CtxGreeting; 7414886Seric 7510175Seric smtpinit(m, pvp) 764865Seric struct mailer *m; 774865Seric char **pvp; 784684Seric { 794865Seric register int r; 8014886Seric EVENT *gte; 814865Seric char buf[MAXNAME]; 8214886Seric extern greettimeout(); 834684Seric 844865Seric /* 854865Seric ** Open the connection to the mailer. 864865Seric */ 874684Seric 8811159Seric #ifdef DEBUG 8911159Seric if (SmtpState == SMTP_OPEN) 9011159Seric syserr("smtpinit: already open"); 9111159Seric #endif DEBUG 9211159Seric 936051Seric SmtpIn = SmtpOut = NULL; 9411159Seric SmtpState = SMTP_CLOSED; 9521065Seric SmtpError[0] = '\0'; 9624944Seric SmtpPhase = "user open"; 9710175Seric SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 986051Seric if (SmtpPid < 0) 996051Seric { 1006051Seric # ifdef DEBUG 1017677Seric if (tTd(18, 1)) 1029391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 1039391Seric pvp[0], ExitStat, errno); 1046051Seric # endif DEBUG 10515139Seric if (CurEnv->e_xfp != NULL) 10615139Seric { 10721065Seric register char *p; 10815139Seric extern char *errstring(); 10921065Seric extern char *statstring(); 11015139Seric 11121065Seric if (errno == 0) 11221065Seric { 11321065Seric p = statstring(ExitStat); 11421065Seric fprintf(CurEnv->e_xfp, 11521065Seric "%.3s %s.%s... %s\n", 11621065Seric p, pvp[1], m->m_name, p); 11721065Seric } 11821065Seric else 11921065Seric { 12021065Seric fprintf(CurEnv->e_xfp, 12121065Seric "421 %s.%s... Deferred: %s\n", 12221065Seric pvp[1], m->m_name, errstring(errno)); 12321065Seric } 12415139Seric } 1256051Seric return (ExitStat); 1266051Seric } 12711159Seric SmtpState = SMTP_OPEN; 1284796Seric 1294865Seric /* 1304865Seric ** Get the greeting message. 13114913Seric ** This should appear spontaneously. Give it five minutes to 13214886Seric ** happen. 1334865Seric */ 1344797Seric 13514886Seric if (setjmp(CtxGreeting) != 0) 13614913Seric goto tempfail; 13716141Seric gte = setevent((time_t) 300, greettimeout, 0); 13824944Seric SmtpPhase = "greeting wait"; 13910175Seric r = reply(m); 14014886Seric clrevent(gte); 1418005Seric if (r < 0 || REPLYTYPE(r) != 2) 14214913Seric goto tempfail; 1434684Seric 1444865Seric /* 1454976Seric ** Send the HELO command. 1467963Seric ** My mother taught me to always introduce myself. 1474976Seric */ 1484976Seric 14925050Seric smtpmessage("HELO %s", m, MyHostName); 15024944Seric SmtpPhase = "HELO wait"; 15110175Seric r = reply(m); 1528005Seric if (r < 0) 15314913Seric goto tempfail; 1548005Seric else if (REPLYTYPE(r) == 5) 15514913Seric goto unavailable; 1567963Seric else if (REPLYTYPE(r) != 2) 15714913Seric goto tempfail; 1584976Seric 1594976Seric /* 1609315Seric ** If this is expected to be another sendmail, send some internal 1619315Seric ** commands. 1629315Seric */ 1639315Seric 16410688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1659315Seric { 1669315Seric /* tell it to be verbose */ 16710175Seric smtpmessage("VERB", m); 16810175Seric r = reply(m); 1699315Seric if (r < 0) 17014913Seric goto tempfail; 1719315Seric 1729315Seric /* tell it we will be sending one transaction only */ 17310175Seric smtpmessage("ONEX", m); 17410175Seric r = reply(m); 1759315Seric if (r < 0) 17614913Seric goto tempfail; 1779315Seric } 1789315Seric 1799315Seric /* 1804865Seric ** Send the MAIL command. 1814865Seric ** Designates the sender. 1824865Seric */ 1834796Seric 18416156Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 1858436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 18610688Seric !bitnset(M_FROMPATH, m->m_flags)) 1878436Seric { 18810308Seric smtpmessage("MAIL From:<%s>", m, buf); 1898436Seric } 1908436Seric else 1918436Seric { 19225050Seric smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName, 19310308Seric buf[0] == '@' ? ',' : ':', buf); 1948436Seric } 19524944Seric SmtpPhase = "MAIL wait"; 19610175Seric r = reply(m); 1978005Seric if (r < 0 || REPLYTYPE(r) == 4) 19814913Seric goto tempfail; 1997963Seric else if (r == 250) 2007963Seric return (EX_OK); 2017963Seric else if (r == 552) 20214913Seric goto unavailable; 20314913Seric 20414913Seric /* protocol error -- close up */ 20514913Seric smtpquit(m); 2067964Seric return (EX_PROTOCOL); 20714913Seric 20814913Seric /* signal a temporary failure */ 20914913Seric tempfail: 21014913Seric smtpquit(m); 21114913Seric return (EX_TEMPFAIL); 21214913Seric 21314913Seric /* signal service unavailable */ 21414913Seric unavailable: 21514913Seric smtpquit(m); 21614913Seric return (EX_UNAVAILABLE); 2174684Seric } 21814886Seric 21914886Seric 22014886Seric static 22114886Seric greettimeout() 22214886Seric { 22314886Seric /* timeout reading the greeting message */ 22414886Seric longjmp(CtxGreeting, 1); 22514886Seric } 2264684Seric /* 2274976Seric ** SMTPRCPT -- designate recipient. 2284797Seric ** 2294797Seric ** Parameters: 2304865Seric ** to -- address of recipient. 23110175Seric ** m -- the mailer we are sending to. 2324797Seric ** 2334797Seric ** Returns: 2344865Seric ** exit status corresponding to recipient status. 2354797Seric ** 2364797Seric ** Side Effects: 2374865Seric ** Sends the mail via SMTP. 2384797Seric */ 2394797Seric 24010175Seric smtprcpt(to, m) 2414865Seric ADDRESS *to; 24210175Seric register MAILER *m; 2434797Seric { 2444797Seric register int r; 24510308Seric extern char *remotename(); 2464797Seric 24710308Seric smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 2484865Seric 24924944Seric SmtpPhase = "RCPT wait"; 25010175Seric r = reply(m); 2518005Seric if (r < 0 || REPLYTYPE(r) == 4) 2524865Seric return (EX_TEMPFAIL); 2537963Seric else if (REPLYTYPE(r) == 2) 2547963Seric return (EX_OK); 2557964Seric else if (r == 550 || r == 551 || r == 553) 2567964Seric return (EX_NOUSER); 2577964Seric else if (r == 552 || r == 554) 2587964Seric return (EX_UNAVAILABLE); 2597964Seric return (EX_PROTOCOL); 2604797Seric } 2614797Seric /* 26210175Seric ** SMTPDATA -- send the data and clean up the transaction. 2634684Seric ** 2644684Seric ** Parameters: 2654865Seric ** m -- mailer being sent to. 2666980Seric ** e -- the envelope for this message. 2674684Seric ** 2684684Seric ** Returns: 2694976Seric ** exit status corresponding to DATA command. 2704684Seric ** 2714684Seric ** Side Effects: 2724865Seric ** none. 2734684Seric */ 2744684Seric 27510175Seric smtpdata(m, e) 2764865Seric struct mailer *m; 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 */ 29010175Seric smtpmessage("DATA", m); 29124944Seric SmtpPhase = "DATA wait"; 29210175Seric r = reply(m); 2938005Seric if (r < 0 || REPLYTYPE(r) == 4) 2944797Seric return (EX_TEMPFAIL); 2957963Seric else if (r == 554) 2967963Seric return (EX_UNAVAILABLE); 2977963Seric else if (r != 354) 2987964Seric return (EX_PROTOCOL); 29910175Seric 30010175Seric /* now output the actual message */ 30110175Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 30210175Seric putline("\n", SmtpOut, m); 30310175Seric (*e->e_putbody)(SmtpOut, m, CurEnv); 30410175Seric 30510175Seric /* terminate the message */ 30610328Seric fprintf(SmtpOut, ".%s", m->m_eol); 30710215Seric if (Verbose && !HoldErrs) 30810215Seric nmessage(Arpa_Info, ">>> ."); 30910175Seric 31010175Seric /* check for the results of the transaction */ 31124944Seric SmtpPhase = "result wait"; 31210175Seric r = reply(m); 3138005Seric if (r < 0 || REPLYTYPE(r) == 4) 3144797Seric return (EX_TEMPFAIL); 3157963Seric else if (r == 250) 3167963Seric return (EX_OK); 3177963Seric else if (r == 552 || r == 554) 3187963Seric return (EX_UNAVAILABLE); 3197964Seric return (EX_PROTOCOL); 3204684Seric } 3214684Seric /* 3224865Seric ** SMTPQUIT -- close the SMTP connection. 3234865Seric ** 3244865Seric ** Parameters: 32515535Seric ** m -- a pointer to the mailer. 3264865Seric ** 3274865Seric ** Returns: 3284865Seric ** none. 3294865Seric ** 3304865Seric ** Side Effects: 3314865Seric ** sends the final protocol and closes the connection. 3324865Seric */ 3334865Seric 33415535Seric smtpquit(m) 33510175Seric register MAILER *m; 3364865Seric { 3379391Seric int i; 3384865Seric 33910148Seric /* if the connection is already closed, don't bother */ 34010148Seric if (SmtpIn == NULL) 34110148Seric return; 34210148Seric 34310148Seric /* send the quit message if not a forced quit */ 34411159Seric if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD) 3459391Seric { 34610175Seric smtpmessage("QUIT", m); 34710175Seric (void) reply(m); 34811159Seric if (SmtpState == SMTP_CLOSED) 34910159Seric return; 3509391Seric } 3519391Seric 35210148Seric /* now actually close the connection */ 3537229Seric (void) fclose(SmtpIn); 3547229Seric (void) fclose(SmtpOut); 35510148Seric SmtpIn = SmtpOut = NULL; 35611159Seric SmtpState = SMTP_CLOSED; 35710148Seric 35810148Seric /* and pick up the zombie */ 35915535Seric i = endmailer(SmtpPid, m->m_argv[0]); 3609391Seric if (i != EX_OK) 36115535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3624865Seric } 3634865Seric /* 3644684Seric ** REPLY -- read arpanet reply 3654684Seric ** 3664684Seric ** Parameters: 36710175Seric ** m -- the mailer we are reading the reply from. 3684684Seric ** 3694684Seric ** Returns: 3704684Seric ** reply code it reads. 3714684Seric ** 3724684Seric ** Side Effects: 3734684Seric ** flushes the mail file. 3744684Seric */ 3754684Seric 37610175Seric reply(m) 37710688Seric MAILER *m; 3784684Seric { 3794865Seric (void) fflush(SmtpOut); 3804684Seric 3817677Seric if (tTd(18, 1)) 3824796Seric printf("reply\n"); 3834796Seric 3847356Seric /* 3857356Seric ** Read the input line, being careful not to hang. 3867356Seric */ 3877356Seric 3884684Seric for (;;) 3894684Seric { 3904684Seric register int r; 3917356Seric register char *p; 3924684Seric 3937685Seric /* actually do the read */ 3949547Seric if (CurEnv->e_xfp != NULL) 3959547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 3967356Seric 39710054Seric /* if we are in the process of closing just give the code */ 39811159Seric if (SmtpState == SMTP_CLOSED) 39910054Seric return (SMTPCLOSING); 40010054Seric 40110054Seric /* get the line from the other side */ 40210054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 40310054Seric if (p == NULL) 40410131Seric { 40510148Seric extern char MsgBuf[]; /* err.c */ 40610148Seric extern char Arpa_TSyserr[]; /* conf.c */ 40710148Seric 40821065Seric /* if the remote end closed early, fake an error */ 40921065Seric if (errno == 0) 41021065Seric # ifdef ECONNRESET 41121065Seric errno = ECONNRESET; 41221065Seric # else ECONNRESET 41321065Seric errno = EPIPE; 41421065Seric # endif ECONNRESET 41521065Seric 41610148Seric message(Arpa_TSyserr, "reply: read error"); 41710420Seric # ifdef DEBUG 41810420Seric /* if debugging, pause so we can see state */ 41910420Seric if (tTd(18, 100)) 42010420Seric pause(); 42110420Seric # endif DEBUG 42210148Seric # ifdef LOG 42324945Seric syslog(LOG_ERR, "%s", &MsgBuf[4]); 42410148Seric # endif LOG 42511159Seric SmtpState = SMTP_CLOSED; 42615535Seric smtpquit(m); 42710054Seric return (-1); 42810131Seric } 42910054Seric fixcrlf(SmtpReplyBuffer, TRUE); 43010054Seric 43114900Seric if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 43214900Seric { 43314900Seric /* serious error -- log the previous command */ 43414900Seric if (SmtpMsgBuffer[0] != '\0') 43514900Seric fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer); 43614900Seric SmtpMsgBuffer[0] = '\0'; 43714900Seric 43814900Seric /* now log the message as from the other side */ 43914900Seric fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer); 44014900Seric } 44114900Seric 44214900Seric /* display the input for verbose mode */ 4437229Seric if (Verbose && !HoldErrs) 4449391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4457356Seric 4467356Seric /* if continuation is required, we can go on */ 4479391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4484684Seric continue; 4497356Seric 4507356Seric /* decode the reply code */ 4519391Seric r = atoi(SmtpReplyBuffer); 4527356Seric 4537356Seric /* extra semantics: 0xx codes are "informational" */ 4544684Seric if (r < 100) 4554684Seric continue; 4567356Seric 4579391Seric /* reply code 421 is "Service Shutting Down" */ 45811159Seric if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 4599391Seric { 46010054Seric /* send the quit protocol */ 46111159Seric SmtpState = SMTP_SSD; 46215535Seric smtpquit(m); 4639391Seric } 4649391Seric 46521065Seric /* save temporary failure messages for posterity */ 46621065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 46721065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 46821065Seric 4694684Seric return (r); 4704684Seric } 4714684Seric } 4724796Seric /* 4734865Seric ** SMTPMESSAGE -- send message to server 4744796Seric ** 4754796Seric ** Parameters: 4764796Seric ** f -- format 47710175Seric ** m -- the mailer to control formatting. 4784796Seric ** a, b, c -- parameters 4794796Seric ** 4804796Seric ** Returns: 4814796Seric ** none. 4824796Seric ** 4834796Seric ** Side Effects: 4844865Seric ** writes message to SmtpOut. 4854796Seric */ 4864796Seric 4874865Seric /*VARARGS1*/ 48810175Seric smtpmessage(f, m, a, b, c) 4894796Seric char *f; 49010175Seric MAILER *m; 4914796Seric { 49214900Seric (void) sprintf(SmtpMsgBuffer, f, a, b, c); 4937677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 49414900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 49511159Seric if (SmtpOut != NULL) 49614900Seric fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol); 4974796Seric } 4985182Seric 4995182Seric # endif SMTP 500