home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / usersmtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  12.3 KB  |  522 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34.  
  35. # include "sendmail.h"
  36.  
  37. #ifndef lint
  38. #ifdef SMTP
  39. static char sccsid[] = "@(#)usersmtp.c    5.16 (Berkeley) 3/2/91 (with SMTP)";
  40. #else
  41. static char sccsid[] = "@(#)usersmtp.c    5.16 (Berkeley) 3/2/91 (without SMTP)";
  42. #endif
  43. #endif /* not lint */
  44.  
  45. # include <sysexits.h>
  46. # include <errno.h>
  47.  
  48. # ifdef SMTP
  49.  
  50. /*
  51. **  USERSMTP -- run SMTP protocol from the user end.
  52. **
  53. **    This protocol is described in RFC821.
  54. */
  55.  
  56. #define REPLYTYPE(r)    ((r) / 100)        /* first digit of reply code */
  57. #define REPLYCLASS(r)    (((r) / 10) % 10)    /* second digit of reply code */
  58. #define SMTPCLOSING    421            /* "Service Shutting Down" */
  59.  
  60. char    SmtpMsgBuffer[MAXLINE];        /* buffer for commands */
  61. char    SmtpReplyBuffer[MAXLINE];    /* buffer for replies */
  62. char    SmtpError[MAXLINE] = "";    /* save failure error messages */
  63. FILE    *SmtpOut;            /* output file */
  64. FILE    *SmtpIn;            /* input file */
  65. int    SmtpPid;            /* pid of mailer */
  66.  
  67. /* following represents the state of the SMTP connection */
  68. int    SmtpState;            /* connection state, see below */
  69.  
  70. #define SMTP_CLOSED    0        /* connection is closed */
  71. #define SMTP_OPEN    1        /* connection is open for business */
  72. #define SMTP_SSD    2        /* service shutting down */
  73. /*
  74. **  SMTPINIT -- initialize SMTP.
  75. **
  76. **    Opens the connection and sends the initial protocol.
  77. **
  78. **    Parameters:
  79. **        m -- mailer to create connection to.
  80. **        pvp -- pointer to parameter vector to pass to
  81. **            the mailer.
  82. **
  83. **    Returns:
  84. **        appropriate exit status -- EX_OK on success.
  85. **        If not EX_OK, it should close the connection.
  86. **
  87. **    Side Effects:
  88. **        creates connection and sends initial protocol.
  89. */
  90.  
  91. jmp_buf    CtxGreeting;
  92.  
  93. smtpinit(m, pvp)
  94.     struct mailer *m;
  95.     char **pvp;
  96. {
  97.     register int r;
  98.     EVENT *gte;
  99.     char buf[MAXNAME];
  100.     static int greettimeout();
  101.  
  102.     /*
  103.     **  Open the connection to the mailer.
  104.     */
  105.  
  106.     if (SmtpState == SMTP_OPEN)
  107.         syserr("smtpinit: already open");
  108.  
  109.     SmtpIn = SmtpOut = NULL;
  110.     SmtpState = SMTP_CLOSED;
  111.     SmtpError[0] = '\0';
  112.     SmtpPhase = "user open";
  113.     setproctitle("%s %s: %s", CurEnv->e_id, pvp[1], SmtpPhase);
  114.     SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
  115.     if (SmtpPid < 0)
  116.     {
  117.         if (tTd(18, 1))
  118.             printf("smtpinit: cannot open %s: stat %d errno %d\n",
  119.                pvp[0], ExitStat, errno);
  120.         if (CurEnv->e_xfp != NULL)
  121.         {
  122.             register char *p;
  123.             extern char *errstring();
  124.             extern char *statstring();
  125.  
  126.             if (errno == 0)
  127.             {
  128.                 p = statstring(ExitStat);
  129.                 fprintf(CurEnv->e_xfp,
  130.                     "%.3s %s.%s... %s\n",
  131.                     p, pvp[1], m->m_name, p);
  132.             }
  133.             else
  134.             {
  135.                 r = errno;
  136.                 fprintf(CurEnv->e_xfp,
  137.                     "421 %s.%s... Deferred: %s\n",
  138.                     pvp[1], m->m_name, errstring(errno));
  139.                 errno = r;
  140.             }
  141.         }
  142.         return (ExitStat);
  143.     }
  144.     SmtpState = SMTP_OPEN;
  145.  
  146.     /*
  147.     **  Get the greeting message.
  148.     **    This should appear spontaneously.  Give it five minutes to
  149.     **    happen.
  150.     */
  151.  
  152.     if (setjmp(CtxGreeting) != 0)
  153.         goto tempfail;
  154.     gte = setevent((time_t) 300, greettimeout, 0);
  155.     SmtpPhase = "greeting wait";
  156.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  157.     r = reply(m);
  158.     clrevent(gte);
  159.     if (r < 0 || REPLYTYPE(r) != 2)
  160.         goto tempfail;
  161.  
  162.     /*
  163.     **  Send the HELO command.
  164.     **    My mother taught me to always introduce myself.
  165.     */
  166.  
  167.     smtpmessage("HELO %s", m, MyHostName);
  168.     SmtpPhase = "HELO wait";
  169.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  170.     r = reply(m);
  171.     if (r < 0)
  172.         goto tempfail;
  173.     else if (REPLYTYPE(r) == 5)
  174.         goto unavailable;
  175.     else if (REPLYTYPE(r) != 2)
  176.         goto tempfail;
  177.  
  178.     /*
  179.     **  If this is expected to be another sendmail, send some internal
  180.     **  commands.
  181.     */
  182.  
  183.     if (bitnset(M_INTERNAL, m->m_flags))
  184.     {
  185.         /* tell it to be verbose */
  186.         smtpmessage("VERB", m);
  187.         r = reply(m);
  188.         if (r < 0)
  189.             goto tempfail;
  190.  
  191.         /* tell it we will be sending one transaction only */
  192.         smtpmessage("ONEX", m);
  193.         r = reply(m);
  194.         if (r < 0)
  195.             goto tempfail;
  196.     }
  197.  
  198.     /*
  199.     **  Send the MAIL command.
  200.     **    Designates the sender.
  201.     */
  202.  
  203.     expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
  204.     if (CurEnv->e_from.q_mailer == LocalMailer ||
  205.         !bitnset(M_FROMPATH, m->m_flags))
  206.     {
  207.         smtpmessage("MAIL From:<%s>", m, buf);
  208.     }
  209.     else
  210.     {
  211.         smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName,
  212.             buf[0] == '@' ? ',' : ':', buf);
  213.     }
  214.     SmtpPhase = "MAIL wait";
  215.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  216.     r = reply(m);
  217.     if (r < 0 || REPLYTYPE(r) == 4)
  218.         goto tempfail;
  219.     else if (r == 250)
  220.         return (EX_OK);
  221.     else if (r == 552)
  222.         goto unavailable;
  223.  
  224.     /* protocol error -- close up */
  225.     smtpquit(m);
  226.     return (EX_PROTOCOL);
  227.  
  228.     /* signal a temporary failure */
  229.   tempfail:
  230.     smtpquit(m);
  231.     return (EX_TEMPFAIL);
  232.  
  233.     /* signal service unavailable */
  234.   unavailable:
  235.     smtpquit(m);
  236.     return (EX_UNAVAILABLE);
  237. }
  238.  
  239.  
  240. static
  241. greettimeout()
  242. {
  243.     /* timeout reading the greeting message */
  244.     longjmp(CtxGreeting, 1);
  245. }
  246. /*
  247. **  SMTPRCPT -- designate recipient.
  248. **
  249. **    Parameters:
  250. **        to -- address of recipient.
  251. **        m -- the mailer we are sending to.
  252. **
  253. **    Returns:
  254. **        exit status corresponding to recipient status.
  255. **
  256. **    Side Effects:
  257. **        Sends the mail via SMTP.
  258. */
  259.  
  260. smtprcpt(to, m)
  261.     ADDRESS *to;
  262.     register MAILER *m;
  263. {
  264.     register int r;
  265.     extern char *remotename();
  266.  
  267.     smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));
  268.  
  269.     SmtpPhase = "RCPT wait";
  270.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  271.     r = reply(m);
  272.     if (r < 0 || REPLYTYPE(r) == 4)
  273.         return (EX_TEMPFAIL);
  274.     else if (REPLYTYPE(r) == 2)
  275.         return (EX_OK);
  276.     else if (r == 550 || r == 551 || r == 553)
  277.         return (EX_NOUSER);
  278.     else if (r == 552 || r == 554)
  279.         return (EX_UNAVAILABLE);
  280.     return (EX_PROTOCOL);
  281. }
  282. /*
  283. **  SMTPDATA -- send the data and clean up the transaction.
  284. **
  285. **    Parameters:
  286. **        m -- mailer being sent to.
  287. **        e -- the envelope for this message.
  288. **
  289. **    Returns:
  290. **        exit status corresponding to DATA command.
  291. **
  292. **    Side Effects:
  293. **        none.
  294. */
  295.  
  296. smtpdata(m, e)
  297.     struct mailer *m;
  298.     register ENVELOPE *e;
  299. {
  300.     register int r;
  301.  
  302.     /*
  303.     **  Send the data.
  304.     **    First send the command and check that it is ok.
  305.     **    Then send the data.
  306.     **    Follow it up with a dot to terminate.
  307.     **    Finally get the results of the transaction.
  308.     */
  309.  
  310.     /* send the command and check ok to proceed */
  311.     smtpmessage("DATA", m);
  312.     SmtpPhase = "DATA wait";
  313.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  314.     r = reply(m);
  315.     if (r < 0 || REPLYTYPE(r) == 4)
  316.         return (EX_TEMPFAIL);
  317.     else if (r == 554)
  318.         return (EX_UNAVAILABLE);
  319.     else if (r != 354)
  320.         return (EX_PROTOCOL);
  321.  
  322.     /* now output the actual message */
  323.     (*e->e_puthdr)(SmtpOut, m, CurEnv);
  324.     putline("\n", SmtpOut, m);
  325.     (*e->e_putbody)(SmtpOut, m, CurEnv);
  326.  
  327.     /* terminate the message */
  328.     fprintf(SmtpOut, ".%s", m->m_eol);
  329.     if (Verbose && !HoldErrs)
  330.         nmessage(Arpa_Info, ">>> .");
  331.  
  332.     /* check for the results of the transaction */
  333.     SmtpPhase = "result wait";
  334.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  335.     r = reply(m);
  336.     if (r < 0 || REPLYTYPE(r) == 4)
  337.         return (EX_TEMPFAIL);
  338.     else if (r == 250)
  339.         return (EX_OK);
  340.     else if (r == 552 || r == 554)
  341.         return (EX_UNAVAILABLE);
  342.     return (EX_PROTOCOL);
  343. }
  344. /*
  345. **  SMTPQUIT -- close the SMTP connection.
  346. **
  347. **    Parameters:
  348. **        m -- a pointer to the mailer.
  349. **
  350. **    Returns:
  351. **        none.
  352. **
  353. **    Side Effects:
  354. **        sends the final protocol and closes the connection.
  355. */
  356.  
  357. smtpquit(m)
  358.     register MAILER *m;
  359. {
  360.     int i;
  361.  
  362.     /* if the connection is already closed, don't bother */
  363.     if (SmtpIn == NULL)
  364.         return;
  365.  
  366.     /* send the quit message if not a forced quit */
  367.     if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD)
  368.     {
  369.         smtpmessage("QUIT", m);
  370.         (void) reply(m);
  371.         if (SmtpState == SMTP_CLOSED)
  372.             return;
  373.     }
  374.  
  375.     /* now actually close the connection */
  376.     (void) fclose(SmtpIn);
  377.     (void) fclose(SmtpOut);
  378.     SmtpIn = SmtpOut = NULL;
  379.     SmtpState = SMTP_CLOSED;
  380.  
  381.     /* and pick up the zombie */
  382.     i = endmailer(SmtpPid, m->m_argv[0]);
  383.     if (i != EX_OK)
  384.         syserr("smtpquit %s: stat %d", m->m_argv[0], i);
  385. }
  386. /*
  387. **  REPLY -- read arpanet reply
  388. **
  389. **    Parameters:
  390. **        m -- the mailer we are reading the reply from.
  391. **
  392. **    Returns:
  393. **        reply code it reads.
  394. **
  395. **    Side Effects:
  396. **        flushes the mail file.
  397. */
  398.  
  399. reply(m)
  400.     MAILER *m;
  401. {
  402.     (void) fflush(SmtpOut);
  403.  
  404.     if (tTd(18, 1))
  405.         printf("reply\n");
  406.  
  407.     /*
  408.     **  Read the input line, being careful not to hang.
  409.     */
  410.  
  411.     for (;;)
  412.     {
  413.         register int r;
  414.         register char *p;
  415.  
  416.         /* actually do the read */
  417.         if (CurEnv->e_xfp != NULL)
  418.             (void) fflush(CurEnv->e_xfp);    /* for debugging */
  419.  
  420.         /* if we are in the process of closing just give the code */
  421.         if (SmtpState == SMTP_CLOSED)
  422.             return (SMTPCLOSING);
  423.  
  424.         /* get the line from the other side */
  425.         p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn);
  426.         if (p == NULL)
  427.         {
  428.             extern char MsgBuf[];        /* err.c */
  429.             extern char Arpa_TSyserr[];    /* conf.c */
  430.  
  431.             /* if the remote end closed early, fake an error */
  432.             if (errno == 0)
  433. # ifdef ECONNRESET
  434.                 errno = ECONNRESET;
  435. # else ECONNRESET
  436.                 errno = EPIPE;
  437. # endif ECONNRESET
  438.  
  439.             message(Arpa_TSyserr, "reply: read error");
  440.             /* if debugging, pause so we can see state */
  441.             if (tTd(18, 100))
  442.                 pause();
  443. # ifdef LOG
  444.             syslog(LOG_INFO, "%s", &MsgBuf[4]);
  445. # endif LOG
  446.             SmtpState = SMTP_CLOSED;
  447.             smtpquit(m);
  448.             return (-1);
  449.         }
  450.         fixcrlf(SmtpReplyBuffer, TRUE);
  451.  
  452.         if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)
  453.         {
  454.             /* serious error -- log the previous command */
  455.             if (SmtpMsgBuffer[0] != '\0')
  456.                 fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer);
  457.             SmtpMsgBuffer[0] = '\0';
  458.  
  459.             /* now log the message as from the other side */
  460.             fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer);
  461.         }
  462.  
  463.         /* display the input for verbose mode */
  464.         if (Verbose && !HoldErrs)
  465.             nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
  466.  
  467.         /* if continuation is required, we can go on */
  468.         if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
  469.             continue;
  470.  
  471.         /* decode the reply code */
  472.         r = atoi(SmtpReplyBuffer);
  473.  
  474.         /* extra semantics: 0xx codes are "informational" */
  475.         if (r < 100)
  476.             continue;
  477.  
  478.         /* reply code 421 is "Service Shutting Down" */
  479.         if (r == SMTPCLOSING && SmtpState != SMTP_SSD)
  480.         {
  481.             /* send the quit protocol */
  482.             SmtpState = SMTP_SSD;
  483.             smtpquit(m);
  484.         }
  485.  
  486.         /* save temporary failure messages for posterity */
  487.         if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
  488.             (void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
  489.  
  490.         return (r);
  491.     }
  492. }
  493. /*
  494. **  SMTPMESSAGE -- send message to server
  495. **
  496. **    Parameters:
  497. **        f -- format
  498. **        m -- the mailer to control formatting.
  499. **        a, b, c -- parameters
  500. **
  501. **    Returns:
  502. **        none.
  503. **
  504. **    Side Effects:
  505. **        writes message to SmtpOut.
  506. */
  507.  
  508. /*VARARGS1*/
  509. smtpmessage(f, m, a, b, c)
  510.     char *f;
  511.     MAILER *m;
  512. {
  513.     (void) sprintf(SmtpMsgBuffer, f, a, b, c);
  514.     if (tTd(18, 1) || (Verbose && !HoldErrs))
  515.         nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
  516.     if (SmtpOut != NULL)
  517.         fprintf(SmtpOut, "%s%s", SmtpMsgBuffer,
  518.             m == 0 ? "\r\n" : m->m_eol);
  519. }
  520.  
  521. # endif SMTP
  522.