14796Seric # include <ctype.h> 24684Seric # include <sysexits.h> 34865Seric # include "sendmail.h" 44684Seric 55182Seric # ifndef SMTP 6*10215Seric SCCSID(@(#)usersmtp.c 3.37 01/09/83 (no SMTP)); 75182Seric # else SMTP 84684Seric 9*10215Seric SCCSID(@(#)usersmtp.c 3.37 01/09/83); 105182Seric 119391Seric 129391Seric 134684Seric /* 149391Seric ** USERSMTP -- run SMTP protocol from the user end. 159391Seric ** 169391Seric ** This protocol is described in RFC821. 179391Seric */ 189391Seric 199391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 209391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 219391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 229391Seric 2310054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 2410054Seric FILE *SmtpOut; /* output file */ 2510054Seric FILE *SmtpIn; /* input file */ 2610054Seric int SmtpPid; /* pid of mailer */ 2710054Seric bool SmtpClosing; /* set on a forced close */ 289391Seric /* 294865Seric ** SMTPINIT -- initialize SMTP. 304684Seric ** 314865Seric ** Opens the connection and sends the initial protocol. 324684Seric ** 334684Seric ** Parameters: 344865Seric ** m -- mailer to create connection to. 354865Seric ** pvp -- pointer to parameter vector to pass to 364865Seric ** the mailer. 374684Seric ** 384684Seric ** Returns: 394865Seric ** appropriate exit status -- EX_OK on success. 404684Seric ** 414684Seric ** Side Effects: 424865Seric ** creates connection and sends initial protocol. 434684Seric */ 444684Seric 4510175Seric smtpinit(m, pvp) 464865Seric struct mailer *m; 474865Seric char **pvp; 484684Seric { 494865Seric register int r; 504865Seric char buf[MAXNAME]; 517685Seric extern char *canonname(); 524684Seric 534865Seric /* 544865Seric ** Open the connection to the mailer. 554865Seric */ 564684Seric 576051Seric SmtpIn = SmtpOut = NULL; 5810148Seric SmtpClosing = FALSE; 5910175Seric SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 606051Seric if (SmtpPid < 0) 616051Seric { 626051Seric # ifdef DEBUG 637677Seric if (tTd(18, 1)) 649391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 659391Seric pvp[0], ExitStat, errno); 666051Seric # endif DEBUG 676051Seric return (ExitStat); 686051Seric } 694796Seric 704865Seric /* 714865Seric ** Get the greeting message. 724865Seric ** This should appear spontaneously. 734865Seric */ 744797Seric 7510175Seric r = reply(m); 768005Seric if (r < 0 || REPLYTYPE(r) != 2) 774865Seric return (EX_TEMPFAIL); 784684Seric 794865Seric /* 804976Seric ** Send the HELO command. 817963Seric ** My mother taught me to always introduce myself. 824976Seric */ 834976Seric 8410175Seric smtpmessage("HELO %s", m, HostName); 8510175Seric r = reply(m); 868005Seric if (r < 0) 878005Seric return (EX_TEMPFAIL); 888005Seric else if (REPLYTYPE(r) == 5) 894976Seric return (EX_UNAVAILABLE); 907963Seric else if (REPLYTYPE(r) != 2) 914976Seric return (EX_TEMPFAIL); 924976Seric 934976Seric /* 949315Seric ** If this is expected to be another sendmail, send some internal 959315Seric ** commands. 969315Seric */ 979315Seric 989315Seric if (bitset(M_INTERNAL, m->m_flags)) 999315Seric { 1009315Seric /* tell it to be verbose */ 10110175Seric smtpmessage("VERB", m); 10210175Seric r = reply(m); 1039315Seric if (r < 0) 1049315Seric return (EX_TEMPFAIL); 1059315Seric 1069315Seric /* tell it we will be sending one transaction only */ 10710175Seric smtpmessage("ONEX", m); 10810175Seric r = reply(m); 1099315Seric if (r < 0) 1109315Seric return (EX_TEMPFAIL); 1119315Seric } 1129315Seric 1139315Seric /* 1144865Seric ** Send the MAIL command. 1154865Seric ** Designates the sender. 1164865Seric */ 1174796Seric 1186980Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1198436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 12010175Seric !bitset(M_FROMPATH, m->m_flags)) 1218436Seric { 12210175Seric smtpmessage("MAIL From:<%s>", m, canonname(buf, 1)); 1238436Seric } 1248436Seric else 1258436Seric { 12610175Seric smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 12710175Seric buf[0] == '@' ? ',' : ':', canonname(buf, 1)); 1288436Seric } 12910175Seric r = reply(m); 1308005Seric if (r < 0 || REPLYTYPE(r) == 4) 1314865Seric return (EX_TEMPFAIL); 1327963Seric else if (r == 250) 1337963Seric return (EX_OK); 1347963Seric else if (r == 552) 1357963Seric return (EX_UNAVAILABLE); 1367964Seric return (EX_PROTOCOL); 1374684Seric } 1384684Seric /* 1394976Seric ** SMTPRCPT -- designate recipient. 1404797Seric ** 1414797Seric ** Parameters: 1424865Seric ** to -- address of recipient. 14310175Seric ** m -- the mailer we are sending to. 1444797Seric ** 1454797Seric ** Returns: 1464865Seric ** exit status corresponding to recipient status. 1474797Seric ** 1484797Seric ** Side Effects: 1494865Seric ** Sends the mail via SMTP. 1504797Seric */ 1514797Seric 15210175Seric smtprcpt(to, m) 1534865Seric ADDRESS *to; 15410175Seric register MAILER *m; 1554797Seric { 1564797Seric register int r; 1577685Seric extern char *canonname(); 1584797Seric 15910175Seric smtpmessage("RCPT To:<%s>", m, canonname(to->q_user, 2)); 1604865Seric 16110175Seric r = reply(m); 1628005Seric if (r < 0 || REPLYTYPE(r) == 4) 1634865Seric return (EX_TEMPFAIL); 1647963Seric else if (REPLYTYPE(r) == 2) 1657963Seric return (EX_OK); 1667964Seric else if (r == 550 || r == 551 || r == 553) 1677964Seric return (EX_NOUSER); 1687964Seric else if (r == 552 || r == 554) 1697964Seric return (EX_UNAVAILABLE); 1707964Seric return (EX_PROTOCOL); 1714797Seric } 1724797Seric /* 17310175Seric ** SMTPDATA -- send the data and clean up the transaction. 1744684Seric ** 1754684Seric ** Parameters: 1764865Seric ** m -- mailer being sent to. 1776980Seric ** e -- the envelope for this message. 1784684Seric ** 1794684Seric ** Returns: 1804976Seric ** exit status corresponding to DATA command. 1814684Seric ** 1824684Seric ** Side Effects: 1834865Seric ** none. 1844684Seric */ 1854684Seric 18610175Seric smtpdata(m, e) 1874865Seric struct mailer *m; 1886980Seric register ENVELOPE *e; 1894684Seric { 1904684Seric register int r; 1914684Seric 1924797Seric /* 1934797Seric ** Send the data. 19410175Seric ** First send the command and check that it is ok. 19510175Seric ** Then send the data. 19610175Seric ** Follow it up with a dot to terminate. 19710175Seric ** Finally get the results of the transaction. 1984797Seric */ 1994797Seric 20010175Seric /* send the command and check ok to proceed */ 20110175Seric smtpmessage("DATA", m); 20210175Seric r = reply(m); 2038005Seric if (r < 0 || REPLYTYPE(r) == 4) 2044797Seric return (EX_TEMPFAIL); 2057963Seric else if (r == 554) 2067963Seric return (EX_UNAVAILABLE); 2077963Seric else if (r != 354) 2087964Seric return (EX_PROTOCOL); 20910175Seric 21010175Seric /* now output the actual message */ 21110175Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 21210175Seric putline("\n", SmtpOut, m); 21310175Seric (*e->e_putbody)(SmtpOut, m, CurEnv); 21410175Seric 21510175Seric /* terminate the message */ 216*10215Seric fprintf(SmtpOut, ".%s", crlf(m)); 217*10215Seric if (Verbose && !HoldErrs) 218*10215Seric nmessage(Arpa_Info, ">>> ."); 21910175Seric 22010175Seric /* check for the results of the transaction */ 22110175Seric r = reply(m); 2228005Seric if (r < 0 || REPLYTYPE(r) == 4) 2234797Seric return (EX_TEMPFAIL); 2247963Seric else if (r == 250) 2257963Seric return (EX_OK); 2267963Seric else if (r == 552 || r == 554) 2277963Seric return (EX_UNAVAILABLE); 2287964Seric return (EX_PROTOCOL); 2294684Seric } 2304684Seric /* 2314865Seric ** SMTPQUIT -- close the SMTP connection. 2324865Seric ** 2334865Seric ** Parameters: 2344865Seric ** name -- name of mailer we are quitting. 2354865Seric ** 2364865Seric ** Returns: 2374865Seric ** none. 2384865Seric ** 2394865Seric ** Side Effects: 2404865Seric ** sends the final protocol and closes the connection. 2414865Seric */ 2424865Seric 24310175Seric smtpquit(name, m) 2444865Seric char *name; 24510175Seric register MAILER *m; 2464865Seric { 2479391Seric int i; 2484865Seric 24910148Seric /* if the connection is already closed, don't bother */ 25010148Seric if (SmtpIn == NULL) 25110148Seric return; 25210148Seric 25310148Seric /* send the quit message if not a forced quit */ 25410148Seric if (!SmtpClosing) 2559391Seric { 25610175Seric smtpmessage("QUIT", m); 25710175Seric (void) reply(m); 25810159Seric if (SmtpClosing) 25910159Seric return; 2609391Seric } 2619391Seric 26210148Seric /* now actually close the connection */ 2637229Seric (void) fclose(SmtpIn); 2647229Seric (void) fclose(SmtpOut); 26510148Seric SmtpIn = SmtpOut = NULL; 26610148Seric 26710148Seric /* and pick up the zombie */ 2687229Seric i = endmailer(SmtpPid, name); 2699391Seric if (i != EX_OK) 2709391Seric syserr("smtpquit %s: stat %d", name, i); 2714865Seric } 2724865Seric /* 2734684Seric ** REPLY -- read arpanet reply 2744684Seric ** 2754684Seric ** Parameters: 27610175Seric ** m -- the mailer we are reading the reply from. 2774684Seric ** 2784684Seric ** Returns: 2794684Seric ** reply code it reads. 2804684Seric ** 2814684Seric ** Side Effects: 2824684Seric ** flushes the mail file. 2834684Seric */ 2844684Seric 28510175Seric reply(m) 2864684Seric { 2874865Seric (void) fflush(SmtpOut); 2884684Seric 2897677Seric if (tTd(18, 1)) 2904796Seric printf("reply\n"); 2914796Seric 2927356Seric /* 2937356Seric ** Read the input line, being careful not to hang. 2947356Seric */ 2957356Seric 2964684Seric for (;;) 2974684Seric { 2984684Seric register int r; 2997356Seric register char *p; 3004684Seric 3017685Seric /* actually do the read */ 3029547Seric if (CurEnv->e_xfp != NULL) 3039547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 3047356Seric 30510054Seric /* if we are in the process of closing just give the code */ 30610054Seric if (SmtpClosing) 30710054Seric return (SMTPCLOSING); 30810054Seric 30910054Seric /* get the line from the other side */ 31010054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 31110054Seric if (p == NULL) 31210131Seric { 31310148Seric extern char MsgBuf[]; /* err.c */ 31410148Seric extern char Arpa_TSyserr[]; /* conf.c */ 31510148Seric 31610148Seric message(Arpa_TSyserr, "reply: read error"); 31710148Seric # ifdef LOG 31810148Seric syslog(LOG_ERR, "%s", &MsgBuf[4]); 31910148Seric # endif LOG 32010148Seric SmtpClosing = TRUE; 32110175Seric smtpquit("reply error", m); 32210054Seric return (-1); 32310131Seric } 32410054Seric fixcrlf(SmtpReplyBuffer, TRUE); 32510054Seric 3267356Seric /* log the input in the transcript for future error returns */ 3277229Seric if (Verbose && !HoldErrs) 3289391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 32910131Seric else if (CurEnv->e_xfp != NULL) 3309547Seric fprintf(CurEnv->e_xfp, "%s\n", SmtpReplyBuffer); 3317356Seric 3327356Seric /* if continuation is required, we can go on */ 3339391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 3344684Seric continue; 3357356Seric 3367356Seric /* decode the reply code */ 3379391Seric r = atoi(SmtpReplyBuffer); 3387356Seric 3397356Seric /* extra semantics: 0xx codes are "informational" */ 3404684Seric if (r < 100) 3414684Seric continue; 3427356Seric 3439391Seric /* reply code 421 is "Service Shutting Down" */ 34410054Seric if (r == SMTPCLOSING) 3459391Seric { 34610054Seric /* send the quit protocol */ 34710175Seric smtpquit("SMTP Shutdown", m); 3489391Seric SmtpClosing = TRUE; 3499391Seric } 3509391Seric 3514684Seric return (r); 3524684Seric } 3534684Seric } 3544796Seric /* 3554865Seric ** SMTPMESSAGE -- send message to server 3564796Seric ** 3574796Seric ** Parameters: 3584796Seric ** f -- format 35910175Seric ** m -- the mailer to control formatting. 3604796Seric ** a, b, c -- parameters 3614796Seric ** 3624796Seric ** Returns: 3634796Seric ** none. 3644796Seric ** 3654796Seric ** Side Effects: 3664865Seric ** writes message to SmtpOut. 3674796Seric */ 3684796Seric 3694865Seric /*VARARGS1*/ 37010175Seric smtpmessage(f, m, a, b, c) 3714796Seric char *f; 37210175Seric MAILER *m; 3734796Seric { 3744796Seric char buf[100]; 3754796Seric 3764865Seric (void) sprintf(buf, f, a, b, c); 3777677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 3788237Seric nmessage(Arpa_Info, ">>> %s", buf); 37910131Seric else if (CurEnv->e_xfp != NULL) 3809547Seric fprintf(CurEnv->e_xfp, ">>> %s\n", buf); 3819391Seric if (!SmtpClosing) 382*10215Seric fprintf(SmtpOut, "%s%s", buf, crlf(m)); 3834796Seric } 3845182Seric 3855182Seric # endif SMTP 386