14796Seric # include <ctype.h> 24684Seric # include <sysexits.h> 34865Seric # include "sendmail.h" 44684Seric 55182Seric # ifndef SMTP 6*15323Seric SCCSID(@(#)usersmtp.c 4.6 10/29/83 (no SMTP)); 75182Seric # else SMTP 84684Seric 9*15323Seric SCCSID(@(#)usersmtp.c 4.6 10/29/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 2314900Seric char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 2410054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 2510054Seric FILE *SmtpOut; /* output file */ 2610054Seric FILE *SmtpIn; /* input file */ 2710054Seric int SmtpPid; /* pid of mailer */ 2811159Seric 2911159Seric /* following represents the state of the SMTP connection */ 3011159Seric int SmtpState; /* connection state, see below */ 3111159Seric 3211159Seric #define SMTP_CLOSED 0 /* connection is closed */ 3311159Seric #define SMTP_OPEN 1 /* connection is open for business */ 3411159Seric #define SMTP_SSD 2 /* service shutting down */ 359391Seric /* 364865Seric ** SMTPINIT -- initialize SMTP. 374684Seric ** 384865Seric ** Opens the connection and sends the initial protocol. 394684Seric ** 404684Seric ** Parameters: 414865Seric ** m -- mailer to create connection to. 424865Seric ** pvp -- pointer to parameter vector to pass to 434865Seric ** the mailer. 444684Seric ** 454684Seric ** Returns: 464865Seric ** appropriate exit status -- EX_OK on success. 4714913Seric ** If not EX_OK, it should close the connection. 484684Seric ** 494684Seric ** Side Effects: 504865Seric ** creates connection and sends initial protocol. 514684Seric */ 524684Seric 5314886Seric jmp_buf CtxGreeting; 5414886Seric 5510175Seric smtpinit(m, pvp) 564865Seric struct mailer *m; 574865Seric char **pvp; 584684Seric { 594865Seric register int r; 6014886Seric EVENT *gte; 614865Seric char buf[MAXNAME]; 6214886Seric extern greettimeout(); 634684Seric 644865Seric /* 654865Seric ** Open the connection to the mailer. 664865Seric */ 674684Seric 6811159Seric #ifdef DEBUG 6911159Seric if (SmtpState == SMTP_OPEN) 7011159Seric syserr("smtpinit: already open"); 7111159Seric #endif DEBUG 7211159Seric 736051Seric SmtpIn = SmtpOut = NULL; 7411159Seric SmtpState = SMTP_CLOSED; 7510175Seric SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 766051Seric if (SmtpPid < 0) 776051Seric { 786051Seric # ifdef DEBUG 797677Seric if (tTd(18, 1)) 809391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 819391Seric pvp[0], ExitStat, errno); 826051Seric # endif DEBUG 8315139Seric if (CurEnv->e_xfp != NULL) 8415139Seric { 8515139Seric extern char *errstring(); 8615139Seric 87*15323Seric fprintf(CurEnv->e_xfp, "421 %s.%s... Deferred: %s\n", 8815139Seric pvp[1], m->m_name, errstring(errno)); 8915139Seric } 906051Seric return (ExitStat); 916051Seric } 9211159Seric SmtpState = SMTP_OPEN; 934796Seric 944865Seric /* 954865Seric ** Get the greeting message. 9614913Seric ** This should appear spontaneously. Give it five minutes to 9714886Seric ** happen. 984865Seric */ 994797Seric 10014886Seric if (setjmp(CtxGreeting) != 0) 10114913Seric goto tempfail; 10214913Seric gte = setevent(300, greettimeout, 0); 10310175Seric r = reply(m); 10414886Seric clrevent(gte); 1058005Seric if (r < 0 || REPLYTYPE(r) != 2) 10614913Seric goto tempfail; 1074684Seric 1084865Seric /* 1094976Seric ** Send the HELO command. 1107963Seric ** My mother taught me to always introduce myself. 1114976Seric */ 1124976Seric 11310175Seric smtpmessage("HELO %s", m, HostName); 11410175Seric r = reply(m); 1158005Seric if (r < 0) 11614913Seric goto tempfail; 1178005Seric else if (REPLYTYPE(r) == 5) 11814913Seric goto unavailable; 1197963Seric else if (REPLYTYPE(r) != 2) 12014913Seric goto tempfail; 1214976Seric 1224976Seric /* 1239315Seric ** If this is expected to be another sendmail, send some internal 1249315Seric ** commands. 1259315Seric */ 1269315Seric 12710688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1289315Seric { 1299315Seric /* tell it to be verbose */ 13010175Seric smtpmessage("VERB", m); 13110175Seric r = reply(m); 1329315Seric if (r < 0) 13314913Seric goto tempfail; 1349315Seric 1359315Seric /* tell it we will be sending one transaction only */ 13610175Seric smtpmessage("ONEX", m); 13710175Seric r = reply(m); 1389315Seric if (r < 0) 13914913Seric goto tempfail; 1409315Seric } 1419315Seric 1429315Seric /* 1434865Seric ** Send the MAIL command. 1444865Seric ** Designates the sender. 1454865Seric */ 1464796Seric 1476980Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1488436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 14910688Seric !bitnset(M_FROMPATH, m->m_flags)) 1508436Seric { 15110308Seric smtpmessage("MAIL From:<%s>", m, buf); 1528436Seric } 1538436Seric else 1548436Seric { 15510175Seric smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 15610308Seric buf[0] == '@' ? ',' : ':', buf); 1578436Seric } 15810175Seric r = reply(m); 1598005Seric if (r < 0 || REPLYTYPE(r) == 4) 16014913Seric goto tempfail; 1617963Seric else if (r == 250) 1627963Seric return (EX_OK); 1637963Seric else if (r == 552) 16414913Seric goto unavailable; 16514913Seric 16614913Seric /* protocol error -- close up */ 16714913Seric smtpquit(m); 1687964Seric return (EX_PROTOCOL); 16914913Seric 17014913Seric /* signal a temporary failure */ 17114913Seric tempfail: 17214913Seric smtpquit(m); 17314913Seric return (EX_TEMPFAIL); 17414913Seric 17514913Seric /* signal service unavailable */ 17614913Seric unavailable: 17714913Seric smtpquit(m); 17814913Seric return (EX_UNAVAILABLE); 1794684Seric } 18014886Seric 18114886Seric 18214886Seric static 18314886Seric greettimeout() 18414886Seric { 18514886Seric /* timeout reading the greeting message */ 18614886Seric longjmp(CtxGreeting, 1); 18714886Seric } 1884684Seric /* 1894976Seric ** SMTPRCPT -- designate recipient. 1904797Seric ** 1914797Seric ** Parameters: 1924865Seric ** to -- address of recipient. 19310175Seric ** m -- the mailer we are sending to. 1944797Seric ** 1954797Seric ** Returns: 1964865Seric ** exit status corresponding to recipient status. 1974797Seric ** 1984797Seric ** Side Effects: 1994865Seric ** Sends the mail via SMTP. 2004797Seric */ 2014797Seric 20210175Seric smtprcpt(to, m) 2034865Seric ADDRESS *to; 20410175Seric register MAILER *m; 2054797Seric { 2064797Seric register int r; 20710308Seric extern char *remotename(); 2084797Seric 20910308Seric smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 2104865Seric 21110175Seric r = reply(m); 2128005Seric if (r < 0 || REPLYTYPE(r) == 4) 2134865Seric return (EX_TEMPFAIL); 2147963Seric else if (REPLYTYPE(r) == 2) 2157963Seric return (EX_OK); 2167964Seric else if (r == 550 || r == 551 || r == 553) 2177964Seric return (EX_NOUSER); 2187964Seric else if (r == 552 || r == 554) 2197964Seric return (EX_UNAVAILABLE); 2207964Seric return (EX_PROTOCOL); 2214797Seric } 2224797Seric /* 22310175Seric ** SMTPDATA -- send the data and clean up the transaction. 2244684Seric ** 2254684Seric ** Parameters: 2264865Seric ** m -- mailer being sent to. 2276980Seric ** e -- the envelope for this message. 2284684Seric ** 2294684Seric ** Returns: 2304976Seric ** exit status corresponding to DATA command. 2314684Seric ** 2324684Seric ** Side Effects: 2334865Seric ** none. 2344684Seric */ 2354684Seric 23610175Seric smtpdata(m, e) 2374865Seric struct mailer *m; 2386980Seric register ENVELOPE *e; 2394684Seric { 2404684Seric register int r; 2414684Seric 2424797Seric /* 2434797Seric ** Send the data. 24410175Seric ** First send the command and check that it is ok. 24510175Seric ** Then send the data. 24610175Seric ** Follow it up with a dot to terminate. 24710175Seric ** Finally get the results of the transaction. 2484797Seric */ 2494797Seric 25010175Seric /* send the command and check ok to proceed */ 25110175Seric smtpmessage("DATA", m); 25210175Seric r = reply(m); 2538005Seric if (r < 0 || REPLYTYPE(r) == 4) 2544797Seric return (EX_TEMPFAIL); 2557963Seric else if (r == 554) 2567963Seric return (EX_UNAVAILABLE); 2577963Seric else if (r != 354) 2587964Seric return (EX_PROTOCOL); 25910175Seric 26010175Seric /* now output the actual message */ 26110175Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 26210175Seric putline("\n", SmtpOut, m); 26310175Seric (*e->e_putbody)(SmtpOut, m, CurEnv); 26410175Seric 26510175Seric /* terminate the message */ 26610328Seric fprintf(SmtpOut, ".%s", m->m_eol); 26710215Seric if (Verbose && !HoldErrs) 26810215Seric nmessage(Arpa_Info, ">>> ."); 26910175Seric 27010175Seric /* check for the results of the transaction */ 27110175Seric r = reply(m); 2728005Seric if (r < 0 || REPLYTYPE(r) == 4) 2734797Seric return (EX_TEMPFAIL); 2747963Seric else if (r == 250) 2757963Seric return (EX_OK); 2767963Seric else if (r == 552 || r == 554) 2777963Seric return (EX_UNAVAILABLE); 2787964Seric return (EX_PROTOCOL); 2794684Seric } 2804684Seric /* 2814865Seric ** SMTPQUIT -- close the SMTP connection. 2824865Seric ** 2834865Seric ** Parameters: 2844865Seric ** name -- name of mailer we are quitting. 2854865Seric ** 2864865Seric ** Returns: 2874865Seric ** none. 2884865Seric ** 2894865Seric ** Side Effects: 2904865Seric ** sends the final protocol and closes the connection. 2914865Seric */ 2924865Seric 29310175Seric smtpquit(name, m) 2944865Seric char *name; 29510175Seric register MAILER *m; 2964865Seric { 2979391Seric int i; 2984865Seric 29910148Seric /* if the connection is already closed, don't bother */ 30010148Seric if (SmtpIn == NULL) 30110148Seric return; 30210148Seric 30310148Seric /* send the quit message if not a forced quit */ 30411159Seric if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD) 3059391Seric { 30610175Seric smtpmessage("QUIT", m); 30710175Seric (void) reply(m); 30811159Seric if (SmtpState == SMTP_CLOSED) 30910159Seric return; 3109391Seric } 3119391Seric 31210148Seric /* now actually close the connection */ 3137229Seric (void) fclose(SmtpIn); 3147229Seric (void) fclose(SmtpOut); 31510148Seric SmtpIn = SmtpOut = NULL; 31611159Seric SmtpState = SMTP_CLOSED; 31710148Seric 31810148Seric /* and pick up the zombie */ 3197229Seric i = endmailer(SmtpPid, name); 3209391Seric if (i != EX_OK) 3219391Seric syserr("smtpquit %s: stat %d", name, i); 3224865Seric } 3234865Seric /* 3244684Seric ** REPLY -- read arpanet reply 3254684Seric ** 3264684Seric ** Parameters: 32710175Seric ** m -- the mailer we are reading the reply from. 3284684Seric ** 3294684Seric ** Returns: 3304684Seric ** reply code it reads. 3314684Seric ** 3324684Seric ** Side Effects: 3334684Seric ** flushes the mail file. 3344684Seric */ 3354684Seric 33610175Seric reply(m) 33710688Seric MAILER *m; 3384684Seric { 3394865Seric (void) fflush(SmtpOut); 3404684Seric 3417677Seric if (tTd(18, 1)) 3424796Seric printf("reply\n"); 3434796Seric 3447356Seric /* 3457356Seric ** Read the input line, being careful not to hang. 3467356Seric */ 3477356Seric 3484684Seric for (;;) 3494684Seric { 3504684Seric register int r; 3517356Seric register char *p; 3524684Seric 3537685Seric /* actually do the read */ 3549547Seric if (CurEnv->e_xfp != NULL) 3559547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 3567356Seric 35710054Seric /* if we are in the process of closing just give the code */ 35811159Seric if (SmtpState == SMTP_CLOSED) 35910054Seric return (SMTPCLOSING); 36010054Seric 36110054Seric /* get the line from the other side */ 36210054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 36310054Seric if (p == NULL) 36410131Seric { 36510148Seric extern char MsgBuf[]; /* err.c */ 36610148Seric extern char Arpa_TSyserr[]; /* conf.c */ 36710148Seric 36810148Seric message(Arpa_TSyserr, "reply: read error"); 36910420Seric # ifdef DEBUG 37010420Seric /* if debugging, pause so we can see state */ 37110420Seric if (tTd(18, 100)) 37210420Seric pause(); 37310420Seric # endif DEBUG 37410148Seric # ifdef LOG 37510148Seric syslog(LOG_ERR, "%s", &MsgBuf[4]); 37610148Seric # endif LOG 37711159Seric SmtpState = SMTP_CLOSED; 37810175Seric smtpquit("reply error", m); 37910054Seric return (-1); 38010131Seric } 38110054Seric fixcrlf(SmtpReplyBuffer, TRUE); 38210054Seric 38314900Seric if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 38414900Seric { 38514900Seric /* serious error -- log the previous command */ 38614900Seric if (SmtpMsgBuffer[0] != '\0') 38714900Seric fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer); 38814900Seric SmtpMsgBuffer[0] = '\0'; 38914900Seric 39014900Seric /* now log the message as from the other side */ 39114900Seric fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer); 39214900Seric } 39314900Seric 39414900Seric /* display the input for verbose mode */ 3957229Seric if (Verbose && !HoldErrs) 3969391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 3977356Seric 3987356Seric /* if continuation is required, we can go on */ 3999391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4004684Seric continue; 4017356Seric 4027356Seric /* decode the reply code */ 4039391Seric r = atoi(SmtpReplyBuffer); 4047356Seric 4057356Seric /* extra semantics: 0xx codes are "informational" */ 4064684Seric if (r < 100) 4074684Seric continue; 4087356Seric 4099391Seric /* reply code 421 is "Service Shutting Down" */ 41011159Seric if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 4119391Seric { 41210054Seric /* send the quit protocol */ 41311159Seric SmtpState = SMTP_SSD; 41410175Seric smtpquit("SMTP Shutdown", m); 4159391Seric } 4169391Seric 4174684Seric return (r); 4184684Seric } 4194684Seric } 4204796Seric /* 4214865Seric ** SMTPMESSAGE -- send message to server 4224796Seric ** 4234796Seric ** Parameters: 4244796Seric ** f -- format 42510175Seric ** m -- the mailer to control formatting. 4264796Seric ** a, b, c -- parameters 4274796Seric ** 4284796Seric ** Returns: 4294796Seric ** none. 4304796Seric ** 4314796Seric ** Side Effects: 4324865Seric ** writes message to SmtpOut. 4334796Seric */ 4344796Seric 4354865Seric /*VARARGS1*/ 43610175Seric smtpmessage(f, m, a, b, c) 4374796Seric char *f; 43810175Seric MAILER *m; 4394796Seric { 44014900Seric (void) sprintf(SmtpMsgBuffer, f, a, b, c); 4417677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 44214900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 44311159Seric if (SmtpOut != NULL) 44414900Seric fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol); 4454796Seric } 4465182Seric 4475182Seric # endif SMTP 448