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*57203Seric static char sccsid[] = "@(#)usersmtp.c 5.27 (Berkeley) 12/18/92 (with SMTP)"; 1433731Sbostic #else 15*57203Seric static char sccsid[] = "@(#)usersmtp.c 5.27 (Berkeley) 12/18/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: 4954967Seric ** none. 504684Seric ** 514684Seric ** Side Effects: 524865Seric ** creates connection and sends initial protocol. 534684Seric */ 544684Seric 5514886Seric jmp_buf CtxGreeting; 5614886Seric 5754967Seric smtpinit(m, mci, e) 584865Seric struct mailer *m; 5954967Seric register MCI *mci; 6053751Seric ENVELOPE *e; 614684Seric { 624865Seric register int r; 6314886Seric EVENT *gte; 6446928Sbostic static int greettimeout(); 6552107Seric extern STAB *stab(); 6654967Seric extern MCI *openmailer(); 674684Seric 684865Seric /* 694865Seric ** Open the connection to the mailer. 704865Seric */ 714684Seric 7221065Seric SmtpError[0] = '\0'; 7354967Seric switch (mci->mci_state) 746051Seric { 7554967Seric case MCIS_ACTIVE: 7654967Seric /* need to clear old information */ 7754967Seric smtprset(m, mci, e); 7854967Seric mci->mci_state = MCIS_OPEN; 7915139Seric 8054967Seric case MCIS_OPEN: 8154967Seric return; 8254967Seric 8354967Seric case MCIS_ERROR: 8454967Seric case MCIS_SSD: 8554967Seric /* shouldn't happen */ 8654967Seric smtpquit(m, mci, e); 8754967Seric 8854967Seric case MCIS_CLOSED: 8954967Seric syserr("smtpinit: state CLOSED"); 9054967Seric return; 9154967Seric 9254967Seric case MCIS_OPENING: 9354967Seric break; 946051Seric } 954796Seric 9654967Seric mci->mci_phase = "user open"; 9754967Seric mci->mci_state = MCIS_OPENING; 9854967Seric 994865Seric /* 1004865Seric ** Get the greeting message. 10114913Seric ** This should appear spontaneously. Give it five minutes to 10214886Seric ** happen. 1034865Seric */ 1044797Seric 10514886Seric if (setjmp(CtxGreeting) != 0) 10652104Seric goto tempfail1; 10716141Seric gte = setevent((time_t) 300, greettimeout, 0); 10853751Seric mci->mci_phase = "greeting wait"; 10953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 11053751Seric r = reply(m, mci, e); 11114886Seric clrevent(gte); 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); 12153751Seric mci->mci_phase = "HELO wait"; 12253751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 12353751Seric r = reply(m, mci, e); 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); 14053751Seric r = reply(m, mci, e); 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; 15153751Seric mci->mci_errno = errno; 15253751Seric smtpquit(m, mci, e); 15354967Seric return; 15453751Seric 15553751Seric unavailable: 15653751Seric mci->mci_exitstat = EX_UNAVAILABLE; 15753751Seric mci->mci_errno = errno; 15853751Seric smtpquit(m, mci, e); 15954967Seric return; 16053751Seric } 16153751Seric 16253751Seric smtpmailfrom(m, mci, e) 16353751Seric struct mailer *m; 16454967Seric MCI *mci; 16553751Seric ENVELOPE *e; 16653751Seric { 16753751Seric int r; 16853751Seric char buf[MAXNAME]; 16953751Seric 1709315Seric /* 1714865Seric ** Send the MAIL command. 1724865Seric ** Designates the sender. 1734865Seric */ 1744796Seric 17553751Seric mci->mci_state = MCIS_ACTIVE; 17653751Seric 17753751Seric expand("\001<", buf, &buf[sizeof buf - 1], e); 17853751Seric if (e->e_from.q_mailer == LocalMailer || 17910688Seric !bitnset(M_FROMPATH, m->m_flags)) 1808436Seric { 18153751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 1828436Seric } 1838436Seric else 1848436Seric { 18553751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 18610308Seric buf[0] == '@' ? ',' : ':', buf); 1878436Seric } 18853751Seric mci->mci_phase = "MAIL wait"; 18953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 19053751Seric r = reply(m, mci, e); 1918005Seric if (r < 0 || REPLYTYPE(r) == 4) 19253751Seric { 19353751Seric mci->mci_exitstat = EX_TEMPFAIL; 19453751Seric mci->mci_errno = errno; 19553751Seric smtpquit(m, mci, e); 19653751Seric return EX_TEMPFAIL; 19753751Seric } 1987963Seric else if (r == 250) 19953751Seric { 20053751Seric mci->mci_exitstat = EX_OK; 20153751Seric return EX_OK; 20253751Seric } 2037963Seric else if (r == 552) 20453751Seric { 20553751Seric /* signal service unavailable */ 20653751Seric mci->mci_exitstat = EX_UNAVAILABLE; 20753751Seric smtpquit(m, mci, e); 20853751Seric return EX_UNAVAILABLE; 20953751Seric } 21014913Seric 21114913Seric /* protocol error -- close up */ 21253751Seric smtpquit(m, mci, e); 21353751Seric mci->mci_exitstat = EX_PROTOCOL; 21453751Seric return EX_PROTOCOL; 2154684Seric } 21614886Seric 21714886Seric 21814886Seric static 21914886Seric greettimeout() 22014886Seric { 22114886Seric /* timeout reading the greeting message */ 22214886Seric longjmp(CtxGreeting, 1); 22314886Seric } 2244684Seric /* 2254976Seric ** SMTPRCPT -- designate recipient. 2264797Seric ** 2274797Seric ** Parameters: 2284865Seric ** to -- address of recipient. 22910175Seric ** m -- the mailer we are sending to. 2304797Seric ** 2314797Seric ** Returns: 2324865Seric ** exit status corresponding to recipient status. 2334797Seric ** 2344797Seric ** Side Effects: 2354865Seric ** Sends the mail via SMTP. 2364797Seric */ 2374797Seric 23853751Seric smtprcpt(to, m, mci, e) 2394865Seric ADDRESS *to; 24010175Seric register MAILER *m; 24154967Seric MCI *mci; 24253751Seric ENVELOPE *e; 2434797Seric { 2444797Seric register int r; 2454797Seric 24653751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2474865Seric 24853751Seric mci->mci_phase = "RCPT wait"; 24953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 25053751Seric r = reply(m, mci, e); 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 27553740Seric smtpdata(m, mci, e) 2764865Seric struct mailer *m; 27754967Seric register MCI *mci; 2786980Seric register ENVELOPE *e; 2794684Seric { 2804684Seric register int r; 2814684Seric 2824797Seric /* 2834797Seric ** Send the data. 28410175Seric ** First send the command and check that it is ok. 28510175Seric ** Then send the data. 28610175Seric ** Follow it up with a dot to terminate. 28710175Seric ** Finally get the results of the transaction. 2884797Seric */ 2894797Seric 29010175Seric /* send the command and check ok to proceed */ 29153751Seric smtpmessage("DATA", m, mci); 29253751Seric mci->mci_phase = "DATA wait"; 29353751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 29453751Seric r = reply(m, mci, e); 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 */ 30353751Seric (*e->e_puthdr)(mci->mci_out, m, e); 30453740Seric putline("\n", mci->mci_out, m); 30553751Seric (*e->e_putbody)(mci->mci_out, m, e); 30610175Seric 30710175Seric /* terminate the message */ 30853740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 30910215Seric if (Verbose && !HoldErrs) 31010215Seric nmessage(Arpa_Info, ">>> ."); 31110175Seric 31210175Seric /* check for the results of the transaction */ 31353751Seric mci->mci_phase = "result wait"; 31453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 31553751Seric r = reply(m, mci, e); 31653751Seric if (r < 0) 3174797Seric return (EX_TEMPFAIL); 31853751Seric mci->mci_state = MCIS_OPEN; 31953751Seric if (REPLYTYPE(r) == 4) 32053751Seric return (EX_TEMPFAIL); 3217963Seric else if (r == 250) 3227963Seric return (EX_OK); 3237963Seric else if (r == 552 || r == 554) 3247963Seric return (EX_UNAVAILABLE); 3257964Seric return (EX_PROTOCOL); 3264684Seric } 3274684Seric /* 3284865Seric ** SMTPQUIT -- close the SMTP connection. 3294865Seric ** 3304865Seric ** Parameters: 33115535Seric ** m -- a pointer to the mailer. 3324865Seric ** 3334865Seric ** Returns: 3344865Seric ** none. 3354865Seric ** 3364865Seric ** Side Effects: 3374865Seric ** sends the final protocol and closes the connection. 3384865Seric */ 3394865Seric 34053751Seric smtpquit(m, mci, e) 34153751Seric register MAILER *m; 34254967Seric register MCI *mci; 34353751Seric ENVELOPE *e; 3444865Seric { 3459391Seric int i; 3464865Seric 34754967Seric /* send the quit message if we haven't gotten I/O error */ 34853751Seric if (mci->mci_state != MCIS_ERROR) 3499391Seric { 35053751Seric smtpmessage("QUIT", m, mci); 35153751Seric (void) reply(m, mci, e); 35253740Seric if (mci->mci_state == MCIS_CLOSED) 35310159Seric return; 3549391Seric } 3559391Seric 35652676Seric /* now actually close the connection and pick up the zombie */ 35752676Seric i = endmailer(mci, m->m_argv[0]); 3589391Seric if (i != EX_OK) 35915535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3604865Seric } 3614865Seric /* 36254967Seric ** SMTPRSET -- send a RSET (reset) command 36354967Seric */ 36454967Seric 36554967Seric smtprset(m, mci, e) 36654967Seric register MAILER *m; 36754967Seric register MCI *mci; 36854967Seric ENVELOPE *e; 36954967Seric { 37054967Seric int r; 37154967Seric 37254967Seric smtpmessage("RSET", m, mci); 37354967Seric r = reply(m, mci, e); 37454967Seric if (r < 0 || REPLYTYPE(r) == 4) 37554967Seric return EX_TEMPFAIL; 37654967Seric else if (REPLYTYPE(r) == 2) 37754967Seric return EX_OK; 37854967Seric else 37954967Seric return EX_PROTOCOL; 38054967Seric } 38154967Seric /* 38254967Seric ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 38354967Seric */ 38454967Seric 38554967Seric smtpnoop(mci) 38654967Seric register MCI *mci; 38754967Seric { 38854967Seric int r; 38954967Seric MAILER *m = mci->mci_mailer; 39054967Seric extern ENVELOPE BlankEnvelope; 39154967Seric ENVELOPE *e = &BlankEnvelope; 39254967Seric 39354967Seric smtpmessage("NOOP", m, mci); 39454967Seric r = reply(m, mci, e); 39554967Seric if (REPLYTYPE(r) != 2) 39654967Seric smtpquit(m, mci, e); 39754967Seric return r; 39854967Seric } 39954967Seric /* 4004684Seric ** REPLY -- read arpanet reply 4014684Seric ** 4024684Seric ** Parameters: 40310175Seric ** m -- the mailer we are reading the reply from. 4044684Seric ** 4054684Seric ** Returns: 4064684Seric ** reply code it reads. 4074684Seric ** 4084684Seric ** Side Effects: 4094684Seric ** flushes the mail file. 4104684Seric */ 4114684Seric 41253751Seric reply(m, mci, e) 41353751Seric MAILER *m; 41454967Seric MCI *mci; 41553751Seric ENVELOPE *e; 4164684Seric { 41753740Seric (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 */ 44153740Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in); 44253751Seric mci->mci_lastuse = curtime(); 44353751Seric 44410054Seric if (p == NULL) 44510131Seric { 44610148Seric extern char MsgBuf[]; /* err.c */ 44710148Seric extern char Arpa_TSyserr[]; /* conf.c */ 44810148Seric 44921065Seric /* if the remote end closed early, fake an error */ 45021065Seric if (errno == 0) 45121065Seric # ifdef ECONNRESET 45221065Seric errno = ECONNRESET; 45356795Seric # else /* ECONNRESET */ 45421065Seric errno = EPIPE; 45556795Seric # endif /* ECONNRESET */ 45621065Seric 457*57203Seric message(Arpa_TSyserr, "reply: read error from %s", 458*57203Seric mci->mci_host); 45910420Seric /* if debugging, pause so we can see state */ 46010420Seric if (tTd(18, 100)) 46110420Seric pause(); 46210148Seric # ifdef LOG 463*57203Seric if (LogLevel > 0) 464*57203Seric syslog(LOG_INFO, "%s", &MsgBuf[4]); 46556795Seric # endif /* LOG */ 46654967Seric mci->mci_state = MCIS_ERROR; 46753751Seric smtpquit(m, mci, e); 46810054Seric return (-1); 46910131Seric } 47010054Seric fixcrlf(SmtpReplyBuffer, TRUE); 47110054Seric 47256795Seric if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) 47314900Seric { 47414900Seric /* serious error -- log the previous command */ 47514900Seric if (SmtpMsgBuffer[0] != '\0') 47653751Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 47714900Seric SmtpMsgBuffer[0] = '\0'; 47814900Seric 47914900Seric /* now log the message as from the other side */ 48053751Seric fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 48114900Seric } 48214900Seric 48314900Seric /* display the input for verbose mode */ 4847229Seric if (Verbose && !HoldErrs) 4859391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4867356Seric 4877356Seric /* if continuation is required, we can go on */ 4889391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4894684Seric continue; 4907356Seric 4917356Seric /* decode the reply code */ 4929391Seric r = atoi(SmtpReplyBuffer); 4937356Seric 4947356Seric /* extra semantics: 0xx codes are "informational" */ 4954684Seric if (r < 100) 4964684Seric continue; 4977356Seric 4989391Seric /* reply code 421 is "Service Shutting Down" */ 49953740Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 5009391Seric { 50110054Seric /* send the quit protocol */ 50253740Seric mci->mci_state = MCIS_SSD; 50353751Seric smtpquit(m, mci, e); 5049391Seric } 5059391Seric 50621065Seric /* save temporary failure messages for posterity */ 50721065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 50821065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 50921065Seric 5104684Seric return (r); 5114684Seric } 5124684Seric } 5134796Seric /* 5144865Seric ** SMTPMESSAGE -- send message to server 5154796Seric ** 5164796Seric ** Parameters: 5174796Seric ** f -- format 51810175Seric ** m -- the mailer to control formatting. 5194796Seric ** a, b, c -- parameters 5204796Seric ** 5214796Seric ** Returns: 5224796Seric ** none. 5234796Seric ** 5244796Seric ** Side Effects: 52553740Seric ** writes message to mci->mci_out. 5264796Seric */ 5274796Seric 5284865Seric /*VARARGS1*/ 52956852Seric smtpmessage(f, m, mci VA_ARG_FORMAL) 5304796Seric char *f; 53110175Seric MAILER *m; 53254967Seric MCI *mci; 53356852Seric VA_ARG_DECL 5344796Seric { 53556852Seric VA_LOCAL_DECL 53656852Seric 53757135Seric VA_START(mci); 53856852Seric (void) vsprintf(SmtpMsgBuffer, f, ap); 53956852Seric VA_END; 5407677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 54114900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 54253740Seric if (mci->mci_out != NULL) 54353740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 54454967Seric m == NULL ? "\r\n" : m->m_eol); 5454796Seric } 5465182Seric 54756795Seric # endif /* SMTP */ 548