122716Sdist /* 2*34921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 633731Sbostic * Redistribution and use in source and binary forms are permitted 7*34921Sbostic * provided that the above copyright notice and this paragraph are 8*34921Sbostic * duplicated in all such forms and that any documentation, 9*34921Sbostic * advertising materials, and other materials related to such 10*34921Sbostic * distribution and use acknowledge that the software was developed 11*34921Sbostic * by the University of California, Berkeley. The name of the 12*34921Sbostic * University may not be used to endorse or promote products derived 13*34921Sbostic * from this software without specific prior written permission. 14*34921Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15*34921Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16*34921Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1733731Sbostic */ 1822716Sdist 1933731Sbostic # include "sendmail.h" 2022716Sdist 2133731Sbostic #ifndef lint 2233731Sbostic #ifdef SMTP 23*34921Sbostic static char sccsid[] = "@(#)usersmtp.c 5.10 (Berkeley) 06/30/88 (with SMTP)"; 2433731Sbostic #else 25*34921Sbostic static char sccsid[] = "@(#)usersmtp.c 5.10 (Berkeley) 06/30/88 (without SMTP)"; 2633731Sbostic #endif 2733731Sbostic #endif /* not lint */ 2833731Sbostic 294684Seric # include <sysexits.h> 3021065Seric # include <errno.h> 314684Seric 3233731Sbostic # ifdef SMTP 334684Seric 344684Seric /* 359391Seric ** USERSMTP -- run SMTP protocol from the user end. 369391Seric ** 379391Seric ** This protocol is described in RFC821. 389391Seric */ 399391Seric 409391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 419391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 429391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 439391Seric 4414900Seric char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 4510054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 4621065Seric char SmtpError[MAXLINE] = ""; /* save failure error messages */ 4710054Seric FILE *SmtpOut; /* output file */ 4810054Seric FILE *SmtpIn; /* input file */ 4910054Seric int SmtpPid; /* pid of mailer */ 5011159Seric 5111159Seric /* following represents the state of the SMTP connection */ 5211159Seric int SmtpState; /* connection state, see below */ 5311159Seric 5411159Seric #define SMTP_CLOSED 0 /* connection is closed */ 5511159Seric #define SMTP_OPEN 1 /* connection is open for business */ 5611159Seric #define SMTP_SSD 2 /* service shutting down */ 579391Seric /* 584865Seric ** SMTPINIT -- initialize SMTP. 594684Seric ** 604865Seric ** Opens the connection and sends the initial protocol. 614684Seric ** 624684Seric ** Parameters: 634865Seric ** m -- mailer to create connection to. 644865Seric ** pvp -- pointer to parameter vector to pass to 654865Seric ** the mailer. 664684Seric ** 674684Seric ** Returns: 684865Seric ** appropriate exit status -- EX_OK on success. 6914913Seric ** If not EX_OK, it should close the connection. 704684Seric ** 714684Seric ** Side Effects: 724865Seric ** creates connection and sends initial protocol. 734684Seric */ 744684Seric 7514886Seric jmp_buf CtxGreeting; 7614886Seric 7710175Seric smtpinit(m, pvp) 784865Seric struct mailer *m; 794865Seric char **pvp; 804684Seric { 814865Seric register int r; 8214886Seric EVENT *gte; 834865Seric char buf[MAXNAME]; 8414886Seric extern greettimeout(); 854684Seric 864865Seric /* 874865Seric ** Open the connection to the mailer. 884865Seric */ 894684Seric 9011159Seric #ifdef DEBUG 9111159Seric if (SmtpState == SMTP_OPEN) 9211159Seric syserr("smtpinit: already open"); 9311159Seric #endif DEBUG 9411159Seric 956051Seric SmtpIn = SmtpOut = NULL; 9611159Seric SmtpState = SMTP_CLOSED; 9721065Seric SmtpError[0] = '\0'; 9824944Seric SmtpPhase = "user open"; 9910175Seric SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 1006051Seric if (SmtpPid < 0) 1016051Seric { 1026051Seric # ifdef DEBUG 1037677Seric if (tTd(18, 1)) 1049391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 1059391Seric pvp[0], ExitStat, errno); 1066051Seric # endif DEBUG 10715139Seric if (CurEnv->e_xfp != NULL) 10815139Seric { 10921065Seric register char *p; 11015139Seric extern char *errstring(); 11121065Seric extern char *statstring(); 11215139Seric 11321065Seric if (errno == 0) 11421065Seric { 11521065Seric p = statstring(ExitStat); 11621065Seric fprintf(CurEnv->e_xfp, 11721065Seric "%.3s %s.%s... %s\n", 11821065Seric p, pvp[1], m->m_name, p); 11921065Seric } 12021065Seric else 12121065Seric { 12221065Seric fprintf(CurEnv->e_xfp, 12321065Seric "421 %s.%s... Deferred: %s\n", 12421065Seric pvp[1], m->m_name, errstring(errno)); 12521065Seric } 12615139Seric } 1276051Seric return (ExitStat); 1286051Seric } 12911159Seric SmtpState = SMTP_OPEN; 1304796Seric 1314865Seric /* 1324865Seric ** Get the greeting message. 13314913Seric ** This should appear spontaneously. Give it five minutes to 13414886Seric ** happen. 1354865Seric */ 1364797Seric 13714886Seric if (setjmp(CtxGreeting) != 0) 13814913Seric goto tempfail; 13916141Seric gte = setevent((time_t) 300, greettimeout, 0); 14024944Seric SmtpPhase = "greeting wait"; 14110175Seric r = reply(m); 14214886Seric clrevent(gte); 1438005Seric if (r < 0 || REPLYTYPE(r) != 2) 14414913Seric goto tempfail; 1454684Seric 1464865Seric /* 1474976Seric ** Send the HELO command. 1487963Seric ** My mother taught me to always introduce myself. 1494976Seric */ 1504976Seric 15125050Seric smtpmessage("HELO %s", m, MyHostName); 15224944Seric SmtpPhase = "HELO wait"; 15310175Seric r = reply(m); 1548005Seric if (r < 0) 15514913Seric goto tempfail; 1568005Seric else if (REPLYTYPE(r) == 5) 15714913Seric goto unavailable; 1587963Seric else if (REPLYTYPE(r) != 2) 15914913Seric goto tempfail; 1604976Seric 1614976Seric /* 1629315Seric ** If this is expected to be another sendmail, send some internal 1639315Seric ** commands. 1649315Seric */ 1659315Seric 16610688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1679315Seric { 1689315Seric /* tell it to be verbose */ 16910175Seric smtpmessage("VERB", m); 17010175Seric r = reply(m); 1719315Seric if (r < 0) 17214913Seric goto tempfail; 1739315Seric 1749315Seric /* tell it we will be sending one transaction only */ 17510175Seric smtpmessage("ONEX", m); 17610175Seric r = reply(m); 1779315Seric if (r < 0) 17814913Seric goto tempfail; 1799315Seric } 1809315Seric 1819315Seric /* 1824865Seric ** Send the MAIL command. 1834865Seric ** Designates the sender. 1844865Seric */ 1854796Seric 18616156Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 1878436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 18810688Seric !bitnset(M_FROMPATH, m->m_flags)) 1898436Seric { 19010308Seric smtpmessage("MAIL From:<%s>", m, buf); 1918436Seric } 1928436Seric else 1938436Seric { 19425050Seric smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName, 19510308Seric buf[0] == '@' ? ',' : ':', buf); 1968436Seric } 19724944Seric SmtpPhase = "MAIL wait"; 19810175Seric r = reply(m); 1998005Seric if (r < 0 || REPLYTYPE(r) == 4) 20014913Seric goto tempfail; 2017963Seric else if (r == 250) 2027963Seric return (EX_OK); 2037963Seric else if (r == 552) 20414913Seric goto unavailable; 20514913Seric 20614913Seric /* protocol error -- close up */ 20714913Seric smtpquit(m); 2087964Seric return (EX_PROTOCOL); 20914913Seric 21014913Seric /* signal a temporary failure */ 21114913Seric tempfail: 21214913Seric smtpquit(m); 21314913Seric return (EX_TEMPFAIL); 21414913Seric 21514913Seric /* signal service unavailable */ 21614913Seric unavailable: 21714913Seric smtpquit(m); 21814913Seric return (EX_UNAVAILABLE); 2194684Seric } 22014886Seric 22114886Seric 22214886Seric static 22314886Seric greettimeout() 22414886Seric { 22514886Seric /* timeout reading the greeting message */ 22614886Seric longjmp(CtxGreeting, 1); 22714886Seric } 2284684Seric /* 2294976Seric ** SMTPRCPT -- designate recipient. 2304797Seric ** 2314797Seric ** Parameters: 2324865Seric ** to -- address of recipient. 23310175Seric ** m -- the mailer we are sending to. 2344797Seric ** 2354797Seric ** Returns: 2364865Seric ** exit status corresponding to recipient status. 2374797Seric ** 2384797Seric ** Side Effects: 2394865Seric ** Sends the mail via SMTP. 2404797Seric */ 2414797Seric 24210175Seric smtprcpt(to, m) 2434865Seric ADDRESS *to; 24410175Seric register MAILER *m; 2454797Seric { 2464797Seric register int r; 24710308Seric extern char *remotename(); 2484797Seric 24910308Seric smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 2504865Seric 25124944Seric SmtpPhase = "RCPT wait"; 25210175Seric r = reply(m); 2538005Seric if (r < 0 || REPLYTYPE(r) == 4) 2544865Seric return (EX_TEMPFAIL); 2557963Seric else if (REPLYTYPE(r) == 2) 2567963Seric return (EX_OK); 2577964Seric else if (r == 550 || r == 551 || r == 553) 2587964Seric return (EX_NOUSER); 2597964Seric else if (r == 552 || r == 554) 2607964Seric return (EX_UNAVAILABLE); 2617964Seric return (EX_PROTOCOL); 2624797Seric } 2634797Seric /* 26410175Seric ** SMTPDATA -- send the data and clean up the transaction. 2654684Seric ** 2664684Seric ** Parameters: 2674865Seric ** m -- mailer being sent to. 2686980Seric ** e -- the envelope for this message. 2694684Seric ** 2704684Seric ** Returns: 2714976Seric ** exit status corresponding to DATA command. 2724684Seric ** 2734684Seric ** Side Effects: 2744865Seric ** none. 2754684Seric */ 2764684Seric 27710175Seric smtpdata(m, e) 2784865Seric struct mailer *m; 2796980Seric register ENVELOPE *e; 2804684Seric { 2814684Seric register int r; 2824684Seric 2834797Seric /* 2844797Seric ** Send the data. 28510175Seric ** First send the command and check that it is ok. 28610175Seric ** Then send the data. 28710175Seric ** Follow it up with a dot to terminate. 28810175Seric ** Finally get the results of the transaction. 2894797Seric */ 2904797Seric 29110175Seric /* send the command and check ok to proceed */ 29210175Seric smtpmessage("DATA", m); 29324944Seric SmtpPhase = "DATA wait"; 29410175Seric r = reply(m); 2958005Seric if (r < 0 || REPLYTYPE(r) == 4) 2964797Seric return (EX_TEMPFAIL); 2977963Seric else if (r == 554) 2987963Seric return (EX_UNAVAILABLE); 2997963Seric else if (r != 354) 3007964Seric return (EX_PROTOCOL); 30110175Seric 30210175Seric /* now output the actual message */ 30310175Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 30410175Seric putline("\n", SmtpOut, m); 30510175Seric (*e->e_putbody)(SmtpOut, m, CurEnv); 30610175Seric 30710175Seric /* terminate the message */ 30810328Seric fprintf(SmtpOut, ".%s", m->m_eol); 30910215Seric if (Verbose && !HoldErrs) 31010215Seric nmessage(Arpa_Info, ">>> ."); 31110175Seric 31210175Seric /* check for the results of the transaction */ 31324944Seric SmtpPhase = "result wait"; 31410175Seric r = reply(m); 3158005Seric if (r < 0 || REPLYTYPE(r) == 4) 3164797Seric 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 33615535Seric smtpquit(m) 33710175Seric register MAILER *m; 3384865Seric { 3399391Seric int i; 3404865Seric 34110148Seric /* if the connection is already closed, don't bother */ 34210148Seric if (SmtpIn == NULL) 34310148Seric return; 34410148Seric 34510148Seric /* send the quit message if not a forced quit */ 34611159Seric if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD) 3479391Seric { 34810175Seric smtpmessage("QUIT", m); 34910175Seric (void) reply(m); 35011159Seric if (SmtpState == SMTP_CLOSED) 35110159Seric return; 3529391Seric } 3539391Seric 35410148Seric /* now actually close the connection */ 3557229Seric (void) fclose(SmtpIn); 3567229Seric (void) fclose(SmtpOut); 35710148Seric SmtpIn = SmtpOut = NULL; 35811159Seric SmtpState = SMTP_CLOSED; 35910148Seric 36010148Seric /* and pick up the zombie */ 36115535Seric i = endmailer(SmtpPid, m->m_argv[0]); 3629391Seric if (i != EX_OK) 36315535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3644865Seric } 3654865Seric /* 3664684Seric ** REPLY -- read arpanet reply 3674684Seric ** 3684684Seric ** Parameters: 36910175Seric ** m -- the mailer we are reading the reply from. 3704684Seric ** 3714684Seric ** Returns: 3724684Seric ** reply code it reads. 3734684Seric ** 3744684Seric ** Side Effects: 3754684Seric ** flushes the mail file. 3764684Seric */ 3774684Seric 37810175Seric reply(m) 37910688Seric MAILER *m; 3804684Seric { 3814865Seric (void) fflush(SmtpOut); 3824684Seric 3837677Seric if (tTd(18, 1)) 3844796Seric printf("reply\n"); 3854796Seric 3867356Seric /* 3877356Seric ** Read the input line, being careful not to hang. 3887356Seric */ 3897356Seric 3904684Seric for (;;) 3914684Seric { 3924684Seric register int r; 3937356Seric register char *p; 3944684Seric 3957685Seric /* actually do the read */ 3969547Seric if (CurEnv->e_xfp != NULL) 3979547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 3987356Seric 39910054Seric /* if we are in the process of closing just give the code */ 40011159Seric if (SmtpState == SMTP_CLOSED) 40110054Seric return (SMTPCLOSING); 40210054Seric 40310054Seric /* get the line from the other side */ 40410054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 40510054Seric if (p == NULL) 40610131Seric { 40710148Seric extern char MsgBuf[]; /* err.c */ 40810148Seric extern char Arpa_TSyserr[]; /* conf.c */ 40910148Seric 41021065Seric /* if the remote end closed early, fake an error */ 41121065Seric if (errno == 0) 41221065Seric # ifdef ECONNRESET 41321065Seric errno = ECONNRESET; 41421065Seric # else ECONNRESET 41521065Seric errno = EPIPE; 41621065Seric # endif ECONNRESET 41721065Seric 41810148Seric message(Arpa_TSyserr, "reply: read error"); 41910420Seric # ifdef DEBUG 42010420Seric /* if debugging, pause so we can see state */ 42110420Seric if (tTd(18, 100)) 42210420Seric pause(); 42310420Seric # endif DEBUG 42410148Seric # ifdef LOG 42524945Seric syslog(LOG_ERR, "%s", &MsgBuf[4]); 42610148Seric # endif LOG 42711159Seric SmtpState = SMTP_CLOSED; 42815535Seric smtpquit(m); 42910054Seric return (-1); 43010131Seric } 43110054Seric fixcrlf(SmtpReplyBuffer, TRUE); 43210054Seric 43314900Seric if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 43414900Seric { 43514900Seric /* serious error -- log the previous command */ 43614900Seric if (SmtpMsgBuffer[0] != '\0') 43714900Seric fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer); 43814900Seric SmtpMsgBuffer[0] = '\0'; 43914900Seric 44014900Seric /* now log the message as from the other side */ 44114900Seric fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer); 44214900Seric } 44314900Seric 44414900Seric /* display the input for verbose mode */ 4457229Seric if (Verbose && !HoldErrs) 4469391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4477356Seric 4487356Seric /* if continuation is required, we can go on */ 4499391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4504684Seric continue; 4517356Seric 4527356Seric /* decode the reply code */ 4539391Seric r = atoi(SmtpReplyBuffer); 4547356Seric 4557356Seric /* extra semantics: 0xx codes are "informational" */ 4564684Seric if (r < 100) 4574684Seric continue; 4587356Seric 4599391Seric /* reply code 421 is "Service Shutting Down" */ 46011159Seric if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 4619391Seric { 46210054Seric /* send the quit protocol */ 46311159Seric SmtpState = SMTP_SSD; 46415535Seric smtpquit(m); 4659391Seric } 4669391Seric 46721065Seric /* save temporary failure messages for posterity */ 46821065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 46921065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 47021065Seric 4714684Seric return (r); 4724684Seric } 4734684Seric } 4744796Seric /* 4754865Seric ** SMTPMESSAGE -- send message to server 4764796Seric ** 4774796Seric ** Parameters: 4784796Seric ** f -- format 47910175Seric ** m -- the mailer to control formatting. 4804796Seric ** a, b, c -- parameters 4814796Seric ** 4824796Seric ** Returns: 4834796Seric ** none. 4844796Seric ** 4854796Seric ** Side Effects: 4864865Seric ** writes message to SmtpOut. 4874796Seric */ 4884796Seric 4894865Seric /*VARARGS1*/ 49010175Seric smtpmessage(f, m, a, b, c) 4914796Seric char *f; 49210175Seric MAILER *m; 4934796Seric { 49414900Seric (void) sprintf(SmtpMsgBuffer, f, a, b, c); 4957677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 49614900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 49711159Seric if (SmtpOut != NULL) 49814900Seric fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol); 4994796Seric } 5005182Seric 5015182Seric # endif SMTP 502