14796Seric # include <ctype.h> 24684Seric # include <sysexits.h> 34865Seric # include "sendmail.h" 44684Seric 55182Seric # ifndef SMTP 6*11725Seric SCCSID(@(#)usersmtp.c 3.43 03/26/83 (no SMTP)); 75182Seric # else SMTP 84684Seric 9*11725Seric SCCSID(@(#)usersmtp.c 3.43 03/26/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 */ 2711159Seric 2811159Seric /* following represents the state of the SMTP connection */ 2911159Seric int SmtpState; /* connection state, see below */ 3011159Seric 3111159Seric #define SMTP_CLOSED 0 /* connection is closed */ 3211159Seric #define SMTP_OPEN 1 /* connection is open for business */ 3311159Seric #define SMTP_SSD 2 /* service shutting down */ 349391Seric /* 354865Seric ** SMTPINIT -- initialize SMTP. 364684Seric ** 374865Seric ** Opens the connection and sends the initial protocol. 384684Seric ** 394684Seric ** Parameters: 404865Seric ** m -- mailer to create connection to. 414865Seric ** pvp -- pointer to parameter vector to pass to 424865Seric ** the mailer. 434684Seric ** 444684Seric ** Returns: 454865Seric ** appropriate exit status -- EX_OK on success. 464684Seric ** 474684Seric ** Side Effects: 484865Seric ** creates connection and sends initial protocol. 494684Seric */ 504684Seric 5110175Seric smtpinit(m, pvp) 524865Seric struct mailer *m; 534865Seric char **pvp; 544684Seric { 554865Seric register int r; 564865Seric char buf[MAXNAME]; 574684Seric 584865Seric /* 594865Seric ** Open the connection to the mailer. 604865Seric */ 614684Seric 6211159Seric #ifdef DEBUG 6311159Seric if (SmtpState == SMTP_OPEN) 6411159Seric syserr("smtpinit: already open"); 6511159Seric #endif DEBUG 6611159Seric 676051Seric SmtpIn = SmtpOut = NULL; 6811159Seric SmtpState = SMTP_CLOSED; 6910175Seric SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 706051Seric if (SmtpPid < 0) 716051Seric { 726051Seric # ifdef DEBUG 737677Seric if (tTd(18, 1)) 749391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 759391Seric pvp[0], ExitStat, errno); 766051Seric # endif DEBUG 776051Seric return (ExitStat); 786051Seric } 7911159Seric SmtpState = SMTP_OPEN; 804796Seric 814865Seric /* 824865Seric ** Get the greeting message. 834865Seric ** This should appear spontaneously. 844865Seric */ 854797Seric 8610175Seric r = reply(m); 878005Seric if (r < 0 || REPLYTYPE(r) != 2) 884865Seric return (EX_TEMPFAIL); 894684Seric 904865Seric /* 914976Seric ** Send the HELO command. 927963Seric ** My mother taught me to always introduce myself. 934976Seric */ 944976Seric 9510175Seric smtpmessage("HELO %s", m, HostName); 9610175Seric r = reply(m); 978005Seric if (r < 0) 988005Seric return (EX_TEMPFAIL); 998005Seric else if (REPLYTYPE(r) == 5) 1004976Seric return (EX_UNAVAILABLE); 1017963Seric else if (REPLYTYPE(r) != 2) 1024976Seric return (EX_TEMPFAIL); 1034976Seric 1044976Seric /* 1059315Seric ** If this is expected to be another sendmail, send some internal 1069315Seric ** commands. 1079315Seric */ 1089315Seric 10910688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1109315Seric { 1119315Seric /* tell it to be verbose */ 11210175Seric smtpmessage("VERB", m); 11310175Seric r = reply(m); 1149315Seric if (r < 0) 1159315Seric return (EX_TEMPFAIL); 1169315Seric 1179315Seric /* tell it we will be sending one transaction only */ 11810175Seric smtpmessage("ONEX", m); 11910175Seric r = reply(m); 1209315Seric if (r < 0) 1219315Seric return (EX_TEMPFAIL); 1229315Seric } 1239315Seric 1249315Seric /* 1254865Seric ** Send the MAIL command. 1264865Seric ** Designates the sender. 1274865Seric */ 1284796Seric 1296980Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1308436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 13110688Seric !bitnset(M_FROMPATH, m->m_flags)) 1328436Seric { 13310308Seric smtpmessage("MAIL From:<%s>", m, buf); 1348436Seric } 1358436Seric else 1368436Seric { 13710175Seric smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 13810308Seric buf[0] == '@' ? ',' : ':', buf); 1398436Seric } 14010175Seric r = reply(m); 1418005Seric if (r < 0 || REPLYTYPE(r) == 4) 1424865Seric return (EX_TEMPFAIL); 1437963Seric else if (r == 250) 1447963Seric return (EX_OK); 1457963Seric else if (r == 552) 1467963Seric return (EX_UNAVAILABLE); 1477964Seric return (EX_PROTOCOL); 1484684Seric } 1494684Seric /* 1504976Seric ** SMTPRCPT -- designate recipient. 1514797Seric ** 1524797Seric ** Parameters: 1534865Seric ** to -- address of recipient. 15410175Seric ** m -- the mailer we are sending to. 1554797Seric ** 1564797Seric ** Returns: 1574865Seric ** exit status corresponding to recipient status. 1584797Seric ** 1594797Seric ** Side Effects: 1604865Seric ** Sends the mail via SMTP. 1614797Seric */ 1624797Seric 16310175Seric smtprcpt(to, m) 1644865Seric ADDRESS *to; 16510175Seric register MAILER *m; 1664797Seric { 1674797Seric register int r; 16810308Seric extern char *remotename(); 1694797Seric 17010308Seric smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 1714865Seric 17210175Seric r = reply(m); 1738005Seric if (r < 0 || REPLYTYPE(r) == 4) 1744865Seric return (EX_TEMPFAIL); 1757963Seric else if (REPLYTYPE(r) == 2) 1767963Seric return (EX_OK); 1777964Seric else if (r == 550 || r == 551 || r == 553) 1787964Seric return (EX_NOUSER); 1797964Seric else if (r == 552 || r == 554) 1807964Seric return (EX_UNAVAILABLE); 1817964Seric return (EX_PROTOCOL); 1824797Seric } 1834797Seric /* 18410175Seric ** SMTPDATA -- send the data and clean up the transaction. 1854684Seric ** 1864684Seric ** Parameters: 1874865Seric ** m -- mailer being sent to. 1886980Seric ** e -- the envelope for this message. 1894684Seric ** 1904684Seric ** Returns: 1914976Seric ** exit status corresponding to DATA command. 1924684Seric ** 1934684Seric ** Side Effects: 1944865Seric ** none. 1954684Seric */ 1964684Seric 19710175Seric smtpdata(m, e) 1984865Seric struct mailer *m; 1996980Seric register ENVELOPE *e; 2004684Seric { 2014684Seric register int r; 2024684Seric 2034797Seric /* 2044797Seric ** Send the data. 20510175Seric ** First send the command and check that it is ok. 20610175Seric ** Then send the data. 20710175Seric ** Follow it up with a dot to terminate. 20810175Seric ** Finally get the results of the transaction. 2094797Seric */ 2104797Seric 21110175Seric /* send the command and check ok to proceed */ 21210175Seric smtpmessage("DATA", m); 21310175Seric r = reply(m); 2148005Seric if (r < 0 || REPLYTYPE(r) == 4) 2154797Seric return (EX_TEMPFAIL); 2167963Seric else if (r == 554) 2177963Seric return (EX_UNAVAILABLE); 2187963Seric else if (r != 354) 2197964Seric return (EX_PROTOCOL); 22010175Seric 22110175Seric /* now output the actual message */ 22210175Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 22310175Seric putline("\n", SmtpOut, m); 22410175Seric (*e->e_putbody)(SmtpOut, m, CurEnv); 22510175Seric 22610175Seric /* terminate the message */ 22710328Seric fprintf(SmtpOut, ".%s", m->m_eol); 22810215Seric if (Verbose && !HoldErrs) 22910215Seric nmessage(Arpa_Info, ">>> ."); 23010175Seric 23110175Seric /* check for the results of the transaction */ 23210175Seric r = reply(m); 2338005Seric if (r < 0 || REPLYTYPE(r) == 4) 2344797Seric return (EX_TEMPFAIL); 2357963Seric else if (r == 250) 2367963Seric return (EX_OK); 2377963Seric else if (r == 552 || r == 554) 2387963Seric return (EX_UNAVAILABLE); 2397964Seric return (EX_PROTOCOL); 2404684Seric } 2414684Seric /* 2424865Seric ** SMTPQUIT -- close the SMTP connection. 2434865Seric ** 2444865Seric ** Parameters: 2454865Seric ** name -- name of mailer we are quitting. 2464865Seric ** 2474865Seric ** Returns: 2484865Seric ** none. 2494865Seric ** 2504865Seric ** Side Effects: 2514865Seric ** sends the final protocol and closes the connection. 2524865Seric */ 2534865Seric 25410175Seric smtpquit(name, m) 2554865Seric char *name; 25610175Seric register MAILER *m; 2574865Seric { 2589391Seric int i; 2594865Seric 26010148Seric /* if the connection is already closed, don't bother */ 26110148Seric if (SmtpIn == NULL) 26210148Seric return; 26310148Seric 26410148Seric /* send the quit message if not a forced quit */ 26511159Seric if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD) 2669391Seric { 26710175Seric smtpmessage("QUIT", m); 26810175Seric (void) reply(m); 26911159Seric if (SmtpState == SMTP_CLOSED) 27010159Seric return; 2719391Seric } 2729391Seric 27310148Seric /* now actually close the connection */ 2747229Seric (void) fclose(SmtpIn); 2757229Seric (void) fclose(SmtpOut); 27610148Seric SmtpIn = SmtpOut = NULL; 27711159Seric SmtpState = SMTP_CLOSED; 27810148Seric 27910148Seric /* and pick up the zombie */ 2807229Seric i = endmailer(SmtpPid, name); 2819391Seric if (i != EX_OK) 2829391Seric syserr("smtpquit %s: stat %d", name, i); 2834865Seric } 2844865Seric /* 2854684Seric ** REPLY -- read arpanet reply 2864684Seric ** 2874684Seric ** Parameters: 28810175Seric ** m -- the mailer we are reading the reply from. 2894684Seric ** 2904684Seric ** Returns: 2914684Seric ** reply code it reads. 2924684Seric ** 2934684Seric ** Side Effects: 2944684Seric ** flushes the mail file. 2954684Seric */ 2964684Seric 29710175Seric reply(m) 29810688Seric MAILER *m; 2994684Seric { 3004865Seric (void) fflush(SmtpOut); 3014684Seric 3027677Seric if (tTd(18, 1)) 3034796Seric printf("reply\n"); 3044796Seric 3057356Seric /* 3067356Seric ** Read the input line, being careful not to hang. 3077356Seric */ 3087356Seric 3094684Seric for (;;) 3104684Seric { 3114684Seric register int r; 3127356Seric register char *p; 3134684Seric 3147685Seric /* actually do the read */ 3159547Seric if (CurEnv->e_xfp != NULL) 3169547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 3177356Seric 31810054Seric /* if we are in the process of closing just give the code */ 31911159Seric if (SmtpState == SMTP_CLOSED) 32010054Seric return (SMTPCLOSING); 32110054Seric 32210054Seric /* get the line from the other side */ 32310054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 32410054Seric if (p == NULL) 32510131Seric { 32610148Seric extern char MsgBuf[]; /* err.c */ 32710148Seric extern char Arpa_TSyserr[]; /* conf.c */ 32810148Seric 32910148Seric message(Arpa_TSyserr, "reply: read error"); 33010420Seric # ifdef DEBUG 33110420Seric /* if debugging, pause so we can see state */ 33210420Seric if (tTd(18, 100)) 33310420Seric pause(); 33410420Seric # endif DEBUG 33510148Seric # ifdef LOG 33610148Seric syslog(LOG_ERR, "%s", &MsgBuf[4]); 33710148Seric # endif LOG 33811159Seric SmtpState = SMTP_CLOSED; 33910175Seric smtpquit("reply error", m); 34010054Seric return (-1); 34110131Seric } 34210054Seric fixcrlf(SmtpReplyBuffer, TRUE); 34310054Seric 3447356Seric /* log the input in the transcript for future error returns */ 3457229Seric if (Verbose && !HoldErrs) 3469391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 34710131Seric else if (CurEnv->e_xfp != NULL) 3489547Seric fprintf(CurEnv->e_xfp, "%s\n", SmtpReplyBuffer); 3497356Seric 3507356Seric /* if continuation is required, we can go on */ 3519391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 3524684Seric continue; 3537356Seric 3547356Seric /* decode the reply code */ 3559391Seric r = atoi(SmtpReplyBuffer); 3567356Seric 3577356Seric /* extra semantics: 0xx codes are "informational" */ 3584684Seric if (r < 100) 3594684Seric continue; 3607356Seric 3619391Seric /* reply code 421 is "Service Shutting Down" */ 36211159Seric if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 3639391Seric { 36410054Seric /* send the quit protocol */ 36511159Seric SmtpState = SMTP_SSD; 36610175Seric smtpquit("SMTP Shutdown", m); 3679391Seric } 3689391Seric 3694684Seric return (r); 3704684Seric } 3714684Seric } 3724796Seric /* 3734865Seric ** SMTPMESSAGE -- send message to server 3744796Seric ** 3754796Seric ** Parameters: 3764796Seric ** f -- format 37710175Seric ** m -- the mailer to control formatting. 3784796Seric ** a, b, c -- parameters 3794796Seric ** 3804796Seric ** Returns: 3814796Seric ** none. 3824796Seric ** 3834796Seric ** Side Effects: 3844865Seric ** writes message to SmtpOut. 3854796Seric */ 3864796Seric 3874865Seric /*VARARGS1*/ 38810175Seric smtpmessage(f, m, a, b, c) 3894796Seric char *f; 39010175Seric MAILER *m; 3914796Seric { 392*11725Seric char buf[MAXLINE]; 3934796Seric 3944865Seric (void) sprintf(buf, f, a, b, c); 3957677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 3968237Seric nmessage(Arpa_Info, ">>> %s", buf); 39710131Seric else if (CurEnv->e_xfp != NULL) 3989547Seric fprintf(CurEnv->e_xfp, ">>> %s\n", buf); 39911159Seric if (SmtpOut != NULL) 40010328Seric fprintf(SmtpOut, "%s%s", buf, m->m_eol); 4014796Seric } 4025182Seric 4035182Seric # endif SMTP 404