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*53751Seric static char sccsid[] = "@(#)usersmtp.c 5.21 (Berkeley) 05/31/92 (with SMTP)"; 1433731Sbostic #else 15*53751Seric static char sccsid[] = "@(#)usersmtp.c 5.21 (Berkeley) 05/31/92 (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: 494865Seric ** appropriate exit status -- EX_OK on success. 5014913Seric ** If not EX_OK, it should close the connection. 514684Seric ** 524684Seric ** Side Effects: 534865Seric ** creates connection and sends initial protocol. 544684Seric */ 554684Seric 5614886Seric jmp_buf CtxGreeting; 5714886Seric 58*53751Seric MCONINFO * 59*53751Seric smtpinit(m, pvp, e) 604865Seric struct mailer *m; 614865Seric char **pvp; 62*53751Seric ENVELOPE *e; 634684Seric { 644865Seric register int r; 6514886Seric EVENT *gte; 66*53751Seric MCONINFO *mci; 6746928Sbostic static int greettimeout(); 6852107Seric extern STAB *stab(); 6953740Seric extern MCONINFO *openmailer(); 704684Seric 714865Seric /* 724865Seric ** Open the connection to the mailer. 734865Seric */ 744684Seric 7521065Seric SmtpError[0] = '\0'; 76*53751Seric setproctitle("%s %s: %s", e->e_id, pvp[1], "user open"); 7752676Seric mci = openmailer(m, pvp, (ADDRESS *) NULL, TRUE); 78*53751Seric if (mci == NULL) 79*53751Seric return NULL; 80*53751Seric if (mci->mci_state != MCIS_OPENING && mci->mci_state != MCIS_CLOSED) 81*53751Seric return mci; 82*53751Seric mci->mci_phase = "user open"; 83*53751Seric mci->mci_state = MCIS_OPENING; 84*53751Seric if (mci->mci_pid < 0) 856051Seric { 867677Seric if (tTd(18, 1)) 879391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 889391Seric pvp[0], ExitStat, errno); 89*53751Seric if (e->e_xfp != NULL) 9015139Seric { 9121065Seric register char *p; 9215139Seric extern char *errstring(); 9321065Seric extern char *statstring(); 9415139Seric 9521065Seric if (errno == 0) 9621065Seric { 9721065Seric p = statstring(ExitStat); 98*53751Seric fprintf(e->e_xfp, 9921065Seric "%.3s %s.%s... %s\n", 10021065Seric p, pvp[1], m->m_name, p); 10121065Seric } 10221065Seric else 10321065Seric { 10436584Sbostic r = errno; 105*53751Seric fprintf(e->e_xfp, 10621065Seric "421 %s.%s... Deferred: %s\n", 10721065Seric pvp[1], m->m_name, errstring(errno)); 10836584Sbostic errno = r; 10921065Seric } 11015139Seric } 111*53751Seric mci->mci_exitstat = ExitStat; 112*53751Seric return mci; 1136051Seric } 1144796Seric 1154865Seric /* 1164865Seric ** Get the greeting message. 11714913Seric ** This should appear spontaneously. Give it five minutes to 11814886Seric ** happen. 1194865Seric */ 1204797Seric 12114886Seric if (setjmp(CtxGreeting) != 0) 12252104Seric goto tempfail1; 12316141Seric gte = setevent((time_t) 300, greettimeout, 0); 124*53751Seric mci->mci_phase = "greeting wait"; 125*53751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 126*53751Seric r = reply(m, mci, e); 12714886Seric clrevent(gte); 1288005Seric if (r < 0 || REPLYTYPE(r) != 2) 12952104Seric goto tempfail1; 1304684Seric 1314865Seric /* 1324976Seric ** Send the HELO command. 1337963Seric ** My mother taught me to always introduce myself. 1344976Seric */ 1354976Seric 136*53751Seric smtpmessage("HELO %s", m, mci, MyHostName); 137*53751Seric mci->mci_phase = "HELO wait"; 138*53751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 139*53751Seric r = reply(m, mci, e); 1408005Seric if (r < 0) 14152104Seric goto tempfail1; 1428005Seric else if (REPLYTYPE(r) == 5) 14314913Seric goto unavailable; 1447963Seric else if (REPLYTYPE(r) != 2) 14552104Seric goto tempfail1; 1464976Seric 1474976Seric /* 1489315Seric ** If this is expected to be another sendmail, send some internal 1499315Seric ** commands. 1509315Seric */ 1519315Seric 15210688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1539315Seric { 1549315Seric /* tell it to be verbose */ 155*53751Seric smtpmessage("VERB", m, mci); 156*53751Seric r = reply(m, mci, e); 1579315Seric if (r < 0) 15852104Seric goto tempfail2; 1599315Seric 1609315Seric /* tell it we will be sending one transaction only */ 161*53751Seric smtpmessage("ONEX", m, mci); 162*53751Seric r = reply(m, mci, e); 1639315Seric if (r < 0) 16452104Seric goto tempfail2; 1659315Seric } 1669315Seric 167*53751Seric mci->mci_state = MCIS_OPEN; 168*53751Seric return mci; 169*53751Seric 170*53751Seric tempfail1: 171*53751Seric tempfail2: 172*53751Seric mci->mci_exitstat = EX_TEMPFAIL; 173*53751Seric mci->mci_errno = errno; 174*53751Seric smtpquit(m, mci, e); 175*53751Seric mci->mci_state = MCIS_TEMPFAIL; 176*53751Seric return mci; 177*53751Seric 178*53751Seric unavailable: 179*53751Seric mci->mci_exitstat = EX_UNAVAILABLE; 180*53751Seric mci->mci_errno = errno; 181*53751Seric smtpquit(m, mci, e); 182*53751Seric mci->mci_state = MCIS_ERROR; 183*53751Seric return mci; 184*53751Seric } 185*53751Seric 186*53751Seric smtpmailfrom(m, mci, e) 187*53751Seric struct mailer *m; 188*53751Seric MCONINFO *mci; 189*53751Seric ENVELOPE *e; 190*53751Seric { 191*53751Seric int r; 192*53751Seric char buf[MAXNAME]; 193*53751Seric 1949315Seric /* 1954865Seric ** Send the MAIL command. 1964865Seric ** Designates the sender. 1974865Seric */ 1984796Seric 199*53751Seric mci->mci_state = MCIS_ACTIVE; 200*53751Seric 201*53751Seric expand("\001<", buf, &buf[sizeof buf - 1], e); 202*53751Seric if (e->e_from.q_mailer == LocalMailer || 20310688Seric !bitnset(M_FROMPATH, m->m_flags)) 2048436Seric { 205*53751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 2068436Seric } 2078436Seric else 2088436Seric { 209*53751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 21010308Seric buf[0] == '@' ? ',' : ':', buf); 2118436Seric } 212*53751Seric mci->mci_phase = "MAIL wait"; 213*53751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 214*53751Seric r = reply(m, mci, e); 2158005Seric if (r < 0 || REPLYTYPE(r) == 4) 216*53751Seric { 217*53751Seric mci->mci_exitstat = EX_TEMPFAIL; 218*53751Seric mci->mci_errno = errno; 219*53751Seric smtpquit(m, mci, e); 220*53751Seric mci->mci_state = MCIS_TEMPFAIL; 221*53751Seric return EX_TEMPFAIL; 222*53751Seric } 2237963Seric else if (r == 250) 224*53751Seric { 225*53751Seric mci->mci_exitstat = EX_OK; 226*53751Seric return EX_OK; 227*53751Seric } 2287963Seric else if (r == 552) 229*53751Seric { 230*53751Seric /* signal service unavailable */ 231*53751Seric mci->mci_exitstat = EX_UNAVAILABLE; 232*53751Seric smtpquit(m, mci, e); 233*53751Seric mci->mci_state = MCIS_ERROR; 234*53751Seric return EX_UNAVAILABLE; 235*53751Seric } 23614913Seric 23714913Seric /* protocol error -- close up */ 238*53751Seric smtpquit(m, mci, e); 239*53751Seric mci->mci_exitstat = EX_PROTOCOL; 240*53751Seric mci->mci_state = MCIS_ERROR; 241*53751Seric return EX_PROTOCOL; 2424684Seric } 24314886Seric 24414886Seric 24514886Seric static 24614886Seric greettimeout() 24714886Seric { 24814886Seric /* timeout reading the greeting message */ 24914886Seric longjmp(CtxGreeting, 1); 25014886Seric } 2514684Seric /* 2524976Seric ** SMTPRCPT -- designate recipient. 2534797Seric ** 2544797Seric ** Parameters: 2554865Seric ** to -- address of recipient. 25610175Seric ** m -- the mailer we are sending to. 2574797Seric ** 2584797Seric ** Returns: 2594865Seric ** exit status corresponding to recipient status. 2604797Seric ** 2614797Seric ** Side Effects: 2624865Seric ** Sends the mail via SMTP. 2634797Seric */ 2644797Seric 265*53751Seric smtprcpt(to, m, mci, e) 2664865Seric ADDRESS *to; 26710175Seric register MAILER *m; 26853740Seric MCONINFO *mci; 269*53751Seric ENVELOPE *e; 2704797Seric { 2714797Seric register int r; 27210308Seric extern char *remotename(); 2734797Seric 274*53751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2754865Seric 276*53751Seric mci->mci_phase = "RCPT wait"; 277*53751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 278*53751Seric r = reply(m, mci, e); 2798005Seric if (r < 0 || REPLYTYPE(r) == 4) 2804865Seric return (EX_TEMPFAIL); 2817963Seric else if (REPLYTYPE(r) == 2) 2827963Seric return (EX_OK); 2837964Seric else if (r == 550 || r == 551 || r == 553) 2847964Seric return (EX_NOUSER); 2857964Seric else if (r == 552 || r == 554) 2867964Seric return (EX_UNAVAILABLE); 2877964Seric return (EX_PROTOCOL); 2884797Seric } 2894797Seric /* 29010175Seric ** SMTPDATA -- send the data and clean up the transaction. 2914684Seric ** 2924684Seric ** Parameters: 2934865Seric ** m -- mailer being sent to. 2946980Seric ** e -- the envelope for this message. 2954684Seric ** 2964684Seric ** Returns: 2974976Seric ** exit status corresponding to DATA command. 2984684Seric ** 2994684Seric ** Side Effects: 3004865Seric ** none. 3014684Seric */ 3024684Seric 30353740Seric smtpdata(m, mci, e) 3044865Seric struct mailer *m; 30553740Seric register MCONINFO *mci; 3066980Seric register ENVELOPE *e; 3074684Seric { 3084684Seric register int r; 3094684Seric 3104797Seric /* 3114797Seric ** Send the data. 31210175Seric ** First send the command and check that it is ok. 31310175Seric ** Then send the data. 31410175Seric ** Follow it up with a dot to terminate. 31510175Seric ** Finally get the results of the transaction. 3164797Seric */ 3174797Seric 31810175Seric /* send the command and check ok to proceed */ 319*53751Seric smtpmessage("DATA", m, mci); 320*53751Seric mci->mci_phase = "DATA wait"; 321*53751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 322*53751Seric r = reply(m, mci, e); 3238005Seric if (r < 0 || REPLYTYPE(r) == 4) 3244797Seric return (EX_TEMPFAIL); 3257963Seric else if (r == 554) 3267963Seric return (EX_UNAVAILABLE); 3277963Seric else if (r != 354) 3287964Seric return (EX_PROTOCOL); 32910175Seric 33010175Seric /* now output the actual message */ 331*53751Seric (*e->e_puthdr)(mci->mci_out, m, e); 33253740Seric putline("\n", mci->mci_out, m); 333*53751Seric (*e->e_putbody)(mci->mci_out, m, e); 33410175Seric 33510175Seric /* terminate the message */ 33653740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 33710215Seric if (Verbose && !HoldErrs) 33810215Seric nmessage(Arpa_Info, ">>> ."); 33910175Seric 34010175Seric /* check for the results of the transaction */ 341*53751Seric mci->mci_phase = "result wait"; 342*53751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 343*53751Seric r = reply(m, mci, e); 344*53751Seric if (r < 0) 3454797Seric return (EX_TEMPFAIL); 346*53751Seric mci->mci_state = MCIS_OPEN; 347*53751Seric if (REPLYTYPE(r) == 4) 348*53751Seric return (EX_TEMPFAIL); 3497963Seric else if (r == 250) 3507963Seric return (EX_OK); 3517963Seric else if (r == 552 || r == 554) 3527963Seric return (EX_UNAVAILABLE); 3537964Seric return (EX_PROTOCOL); 3544684Seric } 3554684Seric /* 3564865Seric ** SMTPQUIT -- close the SMTP connection. 3574865Seric ** 3584865Seric ** Parameters: 35915535Seric ** m -- a pointer to the mailer. 3604865Seric ** 3614865Seric ** Returns: 3624865Seric ** none. 3634865Seric ** 3644865Seric ** Side Effects: 3654865Seric ** sends the final protocol and closes the connection. 3664865Seric */ 3674865Seric 368*53751Seric smtpquit(m, mci, e) 369*53751Seric register MAILER *m; 37052676Seric register MCONINFO *mci; 371*53751Seric ENVELOPE *e; 3724865Seric { 3739391Seric int i; 3744865Seric 37510148Seric /* if the connection is already closed, don't bother */ 37653740Seric if (mci->mci_state == MCIS_CLOSED) 37710148Seric return; 37810148Seric 37910148Seric /* send the quit message if not a forced quit */ 380*53751Seric if (mci->mci_state != MCIS_ERROR) 3819391Seric { 382*53751Seric smtpmessage("QUIT", m, mci); 383*53751Seric (void) reply(m, mci, e); 38453740Seric if (mci->mci_state == MCIS_CLOSED) 38510159Seric return; 3869391Seric } 3879391Seric 38852676Seric /* now actually close the connection and pick up the zombie */ 38952676Seric i = endmailer(mci, m->m_argv[0]); 3909391Seric if (i != EX_OK) 39115535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3924865Seric } 3934865Seric /* 3944684Seric ** REPLY -- read arpanet reply 3954684Seric ** 3964684Seric ** Parameters: 39710175Seric ** m -- the mailer we are reading the reply from. 3984684Seric ** 3994684Seric ** Returns: 4004684Seric ** reply code it reads. 4014684Seric ** 4024684Seric ** Side Effects: 4034684Seric ** flushes the mail file. 4044684Seric */ 4054684Seric 406*53751Seric reply(m, mci, e) 407*53751Seric MAILER *m; 40853740Seric MCONINFO *mci; 409*53751Seric ENVELOPE *e; 4104684Seric { 41153740Seric (void) fflush(mci->mci_out); 4124684Seric 4137677Seric if (tTd(18, 1)) 4144796Seric printf("reply\n"); 4154796Seric 4167356Seric /* 4177356Seric ** Read the input line, being careful not to hang. 4187356Seric */ 4197356Seric 4204684Seric for (;;) 4214684Seric { 4224684Seric register int r; 4237356Seric register char *p; 424*53751Seric extern time_t curtime(); 4254684Seric 4267685Seric /* actually do the read */ 427*53751Seric if (e->e_xfp != NULL) 428*53751Seric (void) fflush(e->e_xfp); /* for debugging */ 4297356Seric 43010054Seric /* if we are in the process of closing just give the code */ 43153740Seric if (mci->mci_state == MCIS_CLOSED) 43210054Seric return (SMTPCLOSING); 43310054Seric 43410054Seric /* get the line from the other side */ 43553740Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in); 436*53751Seric mci->mci_lastuse = curtime(); 437*53751Seric 43810054Seric if (p == NULL) 43910131Seric { 44010148Seric extern char MsgBuf[]; /* err.c */ 44110148Seric extern char Arpa_TSyserr[]; /* conf.c */ 44210148Seric 44321065Seric /* if the remote end closed early, fake an error */ 44421065Seric if (errno == 0) 44521065Seric # ifdef ECONNRESET 44621065Seric errno = ECONNRESET; 44721065Seric # else ECONNRESET 44821065Seric errno = EPIPE; 44921065Seric # endif ECONNRESET 45021065Seric 45110148Seric message(Arpa_TSyserr, "reply: read error"); 45210420Seric /* if debugging, pause so we can see state */ 45310420Seric if (tTd(18, 100)) 45410420Seric pause(); 45510148Seric # ifdef LOG 45636234Skarels syslog(LOG_INFO, "%s", &MsgBuf[4]); 45710148Seric # endif LOG 45853740Seric mci->mci_state = MCIS_CLOSED; 459*53751Seric smtpquit(m, mci, e); 46010054Seric return (-1); 46110131Seric } 46210054Seric fixcrlf(SmtpReplyBuffer, TRUE); 46310054Seric 464*53751Seric if (e->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 46514900Seric { 46614900Seric /* serious error -- log the previous command */ 46714900Seric if (SmtpMsgBuffer[0] != '\0') 468*53751Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 46914900Seric SmtpMsgBuffer[0] = '\0'; 47014900Seric 47114900Seric /* now log the message as from the other side */ 472*53751Seric fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 47314900Seric } 47414900Seric 47514900Seric /* display the input for verbose mode */ 4767229Seric if (Verbose && !HoldErrs) 4779391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4787356Seric 4797356Seric /* if continuation is required, we can go on */ 4809391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4814684Seric continue; 4827356Seric 4837356Seric /* decode the reply code */ 4849391Seric r = atoi(SmtpReplyBuffer); 4857356Seric 4867356Seric /* extra semantics: 0xx codes are "informational" */ 4874684Seric if (r < 100) 4884684Seric continue; 4897356Seric 4909391Seric /* reply code 421 is "Service Shutting Down" */ 49153740Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 4929391Seric { 49310054Seric /* send the quit protocol */ 49453740Seric mci->mci_state = MCIS_SSD; 495*53751Seric smtpquit(m, mci, e); 4969391Seric } 4979391Seric 49821065Seric /* save temporary failure messages for posterity */ 49921065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 50021065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 50121065Seric 5024684Seric return (r); 5034684Seric } 5044684Seric } 5054796Seric /* 5064865Seric ** SMTPMESSAGE -- send message to server 5074796Seric ** 5084796Seric ** Parameters: 5094796Seric ** f -- format 51010175Seric ** m -- the mailer to control formatting. 5114796Seric ** a, b, c -- parameters 5124796Seric ** 5134796Seric ** Returns: 5144796Seric ** none. 5154796Seric ** 5164796Seric ** Side Effects: 51753740Seric ** writes message to mci->mci_out. 5184796Seric */ 5194796Seric 5204865Seric /*VARARGS1*/ 52153740Seric smtpmessage(f, m, mci, a, b, c) 5224796Seric char *f; 52310175Seric MAILER *m; 52453740Seric MCONINFO *mci; 5254796Seric { 52614900Seric (void) sprintf(SmtpMsgBuffer, f, a, b, c); 5277677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 52814900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 52953740Seric if (mci->mci_out != NULL) 53053740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 53140997Sbostic m == 0 ? "\r\n" : m->m_eol); 5324796Seric } 5335182Seric 5345182Seric # endif SMTP 535