home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / usersmtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-24  |  14.4 KB  |  637 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 are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. # include "sendmail.h"
  22.  
  23. #ifndef lint
  24. # ifdef SMTP
  25. static char sccsid[] = "@(#)usersmtp.c    5.15 (Berkeley) 6/1/90 (with SMTP)";
  26. static char  rcsid[] = "@(#)$Id: usersmtp.c,v 5.15.0.11 1991/06/24 20:31:15 paul Exp $ (with SMTP)";
  27. # else /* ! SMTP */
  28. static char sccsid[] = "@(#)usersmtp.c    5.15 (Berkeley) 6/1/90 (without SMTP)";
  29. static char  rcsid[] = "@(#)$Id: usersmtp.c,v 5.15.0.11 1991/06/24 20:31:15 paul Exp $ (without SMTP)";
  30. # endif /* SMTP */
  31. #endif /* ! lint */
  32.  
  33. #include <sysexits.h>
  34. #include <errno.h>
  35.  
  36. #ifdef SMTP
  37.  
  38. # ifdef __STDC__
  39. static int reply(MAILER *);
  40. static void smtpmessage(const char *, MAILER *, ...);
  41. # else /* !__STDC__ */
  42. static int reply();
  43. static void smtpmessage();
  44. # endif /* __STDC__  */
  45.  
  46. /*
  47. **  USERSMTP -- run SMTP protocol from the user end.
  48. **
  49. **    This protocol is described in RFC821.
  50. */
  51.  
  52. # define REPLYTYPE(r)    ((r) / 100)        /* first digit of reply code */
  53. # define REPLYCLASS(r)    (((r) / 10) % 10)    /* second digit of reply code */
  54. # define SMTPGOODREPLY    250            /* positive SMTP response */
  55. # define SMTPCLOSING    421            /* "Service Shutting Down" */
  56.  
  57. static char    SmtpMsgBuffer[MAXLINE];    /* buffer for commands */
  58. static char    SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
  59. char        SmtpError[MAXLINE] = ""; /* save failure error messages */
  60. static bool    SmtpNeedIntro;        /* set before first error */
  61. static FILE    *SmtpOut;        /* output file */
  62. static FILE    *SmtpIn;        /* input file */
  63. static int    SmtpPid;        /* pid of mailer */
  64.  
  65. /* following represents the state of the SMTP connection */
  66. static int    SmtpState;        /* connection state, see below */
  67.  
  68. # define SMTP_CLOSED    0        /* connection is closed */
  69. # define SMTP_OPEN    1        /* connection is open for business */
  70. # define SMTP_SSD    2        /* service shutting down */
  71. /*
  72. **  SMTPINIT -- initialize SMTP.
  73. **
  74. **    Opens the connection and sends the initial protocol.
  75. **
  76. **    Parameters:
  77. **        m -- mailer to create connection to.
  78. **        pvp -- pointer to parameter vector to pass to
  79. **            the mailer.
  80. **        e -- the envelope to deliver (#ifdef MAIL11V3)
  81. **
  82. **    Returns:
  83. **        appropriate exit status -- EX_OK on success.
  84. **        If not EX_OK, it should close the connection.
  85. **
  86. **    Side Effects:
  87. **        creates connection and sends initial protocol.
  88. */
  89.  
  90. int
  91. # ifdef MAIL11V3
  92. smtpinit(m, pvp, e)
  93.     register ENVELOPE *e;
  94. # else /* ! MAIL11V3 */
  95. smtpinit(m, pvp)
  96. # endif /* MAIL11V3 */
  97.     MAILER *m;
  98.     char **pvp;
  99. {
  100.     register int r;
  101.     TIME_TYPE SavedReadTimeout;
  102.     char buf[MAXNAME];
  103.  
  104.     /*
  105.     **  Open the connection to the mailer.
  106.     */
  107.  
  108.     if (SmtpState == SMTP_OPEN)
  109.         syserr("smtpinit: already open");
  110.  
  111.     SmtpIn = SmtpOut = NULL;
  112.     SmtpState = SMTP_CLOSED;
  113.     SmtpError[0] = '\0';
  114.     SmtpNeedIntro = TRUE;
  115.     SmtpPhase = "user open";
  116.     setproctitle("%s %s: %s", CurEnv->e_id, pvp[1], SmtpPhase);
  117.     SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
  118.     if (SmtpPid < 0)
  119.     {
  120.         if (tTd(18, 1))
  121.             printf("smtpinit: cannot open %s: stat %d errno %d\n",
  122.                pvp[0], ExitStat, errno);
  123.         if (CurEnv->e_xfp != NULL)
  124.         {
  125.             register char *p;
  126.  
  127.             if (errno == 0)
  128.             {
  129.                 p = statstring(ExitStat);
  130.                 fprintf(CurEnv->e_xfp,
  131.                     "%.3s %s (%s)... %s\n",
  132.                     p, pvp[1], m->m_name, p);
  133.             }
  134.             else
  135.             {
  136.                 r = errno;
  137.                 fprintf(CurEnv->e_xfp,
  138.                     "421 %s (%s)... Deferred: %s\n",
  139.                     pvp[1], m->m_name, errstring(errno));
  140.                 errno = r;
  141.             }
  142.         }
  143.         return (ExitStat);
  144.     }
  145.     SmtpState = SMTP_OPEN;
  146.  
  147.     /*
  148.     **  Get the greeting message.
  149.     **    This should appear spontaneously.  Give it five minutes to
  150.     **    happen.
  151.     */
  152.  
  153.     SmtpPhase = "greeting wait";
  154.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  155.     SavedReadTimeout = ReadTimeout;
  156.     if (ReadTimeout > 300)
  157.         ReadTimeout = 300;
  158.     r = reply(m);
  159.     ReadTimeout = SavedReadTimeout;
  160.     if (r < 0 || REPLYTYPE(r) != 2)
  161.         goto tempfail;
  162.  
  163.     /*
  164.     **  Send the HELO command.
  165.     **    My mother taught me to always introduce myself.
  166.     */
  167.  
  168.     smtpmessage("HELO %s", m, MyHostName);
  169.     SmtpPhase = "HELO wait";
  170.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  171.     r = reply(m);
  172.     if (r < 0)
  173.         goto tempfail;
  174.     else if (REPLYTYPE(r) == 5)
  175.         goto unavailable;
  176.     else if (REPLYTYPE(r) != 2)
  177.         goto tempfail;
  178.  
  179.     /*
  180.     **  If this is expected to be another sendmail, send some internal
  181.     **  commands.
  182.     */
  183.  
  184.     if (bitnset(M_INTERNAL, m->m_flags))
  185.     {
  186.         /* tell it to be verbose */
  187.         smtpmessage("VERB", m);
  188.         r = reply(m);
  189.         if (r < 0)
  190.             goto tempfail;
  191.  
  192.         /* tell it we will be sending one transaction only */
  193.         smtpmessage("ONEX", m);
  194.         r = reply(m);
  195.         if (r < 0)
  196.             goto tempfail;
  197.     }
  198.  
  199. # ifdef MAIL11V3
  200.     /*
  201.     **  If this mailer can do multiple status returns after DATA command,
  202.     **  ask if it will do so.
  203.     */
  204.     if (bitnset(M_MANYSTATUS, m->m_flags))
  205.     {
  206.         smtpmessage("MULT", m);
  207.         r = reply(m);
  208.         if (r < 0)
  209.             goto tempfail;
  210.         else if (r == 250)
  211.             SmtpManyStatus = TRUE;
  212.     }
  213.     else
  214.         SmtpManyStatus = FALSE;
  215.  
  216.     /*
  217.     **  If this mailer wants to see the headers and body early, ask if
  218.     **  now is OK.
  219.     */
  220.  
  221.     if (bitnset(M_PREHEAD, m->m_flags))
  222.     {
  223.         smtpmessage("HEAD", m);
  224.         r = reply(m);
  225.         if (r < 0)
  226.             goto tempfail;
  227.         if (REPLYTYPE(r) == 2 || REPLYTYPE(r) == 3)
  228.         {
  229.             /* Send the header and message... */
  230.             (*e->e_puthdr)(SmtpOut, m, CurEnv);
  231.             putline("", SmtpOut, m);
  232.             (*e->e_putbody)(SmtpOut, m, CurEnv);
  233.  
  234.             /* followed by the proper termination. */
  235.             fprintf(SmtpOut, ".%s", m->m_eol);
  236.             r = reply(m);
  237.             if (r < 0)
  238.                 goto tempfail;
  239.         }
  240.     }
  241. # endif /* MAIL11V3 */
  242.  
  243.     /*
  244.     **  Send the MAIL command.
  245.     **    Designates the sender.
  246.     */
  247.  
  248.     expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
  249.     if (CurEnv->e_from.q_mailer == LocalMailer ||
  250.         !bitnset(M_FROMPATH, m->m_flags))
  251.     {
  252.         smtpmessage("MAIL From:<%s>", m, buf);
  253.     }
  254.     else
  255.     {
  256.         smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName,
  257.             buf[0] == '@' ? ',' : ':', buf);
  258.     }
  259.     SmtpPhase = "MAIL wait";
  260.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  261.     r = reply(m);
  262.     if (r < 0 || REPLYTYPE(r) == 4)
  263.         goto tempfail;
  264.     else if (r == 250)
  265.         return (EX_OK);
  266.     else if (r == 552)
  267.         goto unavailable;
  268. #ifdef MAIL11V3
  269.     else if (r == 559)
  270.     {
  271.         smtpquit(m);
  272.         return (EX_NOHOST);
  273.     }
  274. #endif /* MAIL11V3 */
  275.  
  276.     /* protocol error -- close up */
  277.     smtpquit(m);
  278.     return (EX_PROTOCOL);
  279.  
  280.     /* signal a temporary failure */
  281.   tempfail:
  282.     smtpquit(m);
  283.     return (EX_TEMPFAIL);
  284.  
  285.     /* signal service unavailable */
  286.   unavailable:
  287.     smtpquit(m);
  288.     return (EX_UNAVAILABLE);
  289. }
  290. /*
  291. **  SMTPRCPT -- designate recipient.
  292. **
  293. **    Parameters:
  294. **        to -- address of recipient.
  295. **        m -- the mailer we are sending to.
  296. **
  297. **    Returns:
  298. **        exit status corresponding to recipient status.
  299. **
  300. **    Side Effects:
  301. **        Sends the mail via SMTP.
  302. */
  303.  
  304. int
  305. smtprcpt(to, m)
  306.     ADDRESS *to;
  307.     register MAILER *m;
  308. {
  309.     register int r;
  310.  
  311.     smtpmessage("RCPT To:<%s>", m, to->q_user);
  312.  
  313.     SmtpPhase = "RCPT wait";
  314.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  315.     r = reply(m);
  316.     if (r < 0 || REPLYTYPE(r) == 4)
  317.         return (EX_TEMPFAIL);
  318.     else if (REPLYTYPE(r) == 2)
  319.         return (EX_OK);
  320.     else if (r == 550 || r == 551 || r == 553)
  321.         return (EX_NOUSER);
  322.     else if (r == 552 || r == 554)
  323.         return (EX_UNAVAILABLE);
  324.     return (EX_PROTOCOL);
  325. }
  326. /*
  327. **  SMTPDATA -- send the data and clean up the transaction.
  328. **
  329. **    Parameters:
  330. **        m -- mailer being sent to.
  331. **        e -- the envelope for this message.
  332. **
  333. **    Returns:
  334. **        exit status corresponding to DATA command.
  335. **
  336. **    Side Effects:
  337. **        none.
  338. */
  339.  
  340. int
  341. smtpdata(m, e)
  342.     MAILER *m;
  343.     register ENVELOPE *e;
  344. {
  345.     register int r;
  346.  
  347.     /*
  348.     **  Send the data.
  349.     **    First send the command and check that it is ok.
  350.     **    Then send the data.
  351.     **    Follow it up with a dot to terminate.
  352.     **    Finally get the results of the transaction.
  353.     */
  354.  
  355.     /* send the command and check ok to proceed */
  356.     smtpmessage("DATA", m);
  357.     SmtpPhase = "DATA wait";
  358.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  359.     r = reply(m);
  360.     if (r < 0 || REPLYTYPE(r) == 4)
  361.         return (EX_TEMPFAIL);
  362.     else if (r == 554)
  363.         return (EX_UNAVAILABLE);
  364.     else if (r != 354 && r != 250)
  365.         return (EX_PROTOCOL);
  366.  
  367.     /* now output the actual message */
  368.     (*e->e_puthdr)(SmtpOut, m, CurEnv);
  369.     putline("", SmtpOut, m);
  370.     (*e->e_putbody)(SmtpOut, m, CurEnv);
  371.  
  372.     /* terminate the message */
  373.     fprintf(SmtpOut, ".%s", m->m_eol);
  374.     if (Verbose && !HoldErrs)
  375.         nmessage(Arpa_Info, ">>> .");
  376. #ifdef MAIL11V3
  377.     /*
  378.     ** If we are running with mail11v3 support, status is collected in
  379.     ** in deliver().
  380.     */
  381.     return (EX_OK);
  382. #else /* ! MAIL11V3 */
  383.  
  384.     /* check for the results of the transaction */
  385.     SmtpPhase = "result wait";
  386.     setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  387.     r = reply(m);
  388.     if (r < 0 || REPLYTYPE(r) == 4)
  389.         return (EX_TEMPFAIL);
  390.     else if (r == 250)
  391.         return (EX_OK);
  392.     else if (r == 552 || r == 554)
  393.         return (EX_UNAVAILABLE);
  394.     return (EX_PROTOCOL);
  395. #endif /* MAIL11V3 */
  396. }
  397. /*
  398. **  SMTPQUIT -- close the SMTP connection.
  399. **
  400. **    Parameters:
  401. **        m -- a pointer to the mailer.
  402. **
  403. **    Returns:
  404. **        none.
  405. **
  406. **    Side Effects:
  407. **        sends the final protocol and closes the connection.
  408. */
  409.  
  410. void
  411. smtpquit(m)
  412.     register MAILER *m;
  413. {
  414.     int i = errno;
  415.  
  416.     /* if the connection is already closed, don't bother */
  417.     if (SmtpIn == NULL)
  418.         return;
  419.  
  420.     /* send the quit message if not a forced quit */
  421.     if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD)
  422.     {
  423.         smtpmessage("QUIT", m);
  424.         (void) reply(m);
  425.         if (SmtpState == SMTP_CLOSED)
  426.             return;
  427.     }
  428.  
  429.     /* now actually close the connection, but without trashing errno */
  430.     (void) fclose(SmtpIn);
  431.     (void) fclose(SmtpOut);
  432.     errno = i;
  433.     SmtpIn = SmtpOut = NULL;
  434.     SmtpState = SMTP_CLOSED;
  435.  
  436.     /* and pick up the zombie */
  437.     i = endmailer(SmtpPid, m->m_argv[0]);
  438.     if (i != EX_OK)
  439.         syserr("smtpquit %s: stat %d", m->m_argv[0], i);
  440. }
  441. /*
  442. **  REPLY -- read arpanet reply
  443. **
  444. **    Parameters:
  445. **        m -- the mailer we are reading the reply from.
  446. **
  447. **    Returns:
  448. **        reply code it reads.
  449. **
  450. **    Side Effects:
  451. **        flushes the mail file.
  452. */
  453.  
  454. static int
  455. reply(m)
  456.     MAILER *m;
  457. {
  458.     if (SmtpOut != NULL)
  459.         (void) fflush(SmtpOut);
  460.  
  461.     if (tTd(18, 1))
  462.         printf("reply\n");
  463.  
  464.     if (bitnset(M_BSMTP, m->m_flags))
  465.         return (SMTPGOODREPLY);
  466.  
  467.     /*
  468.     **  Read the input line, being careful not to hang.
  469.     */
  470.  
  471.     for (;;)
  472.     {
  473.         register int r;
  474.         register char *p;
  475.  
  476.         /* actually do the read */
  477.         if (CurEnv->e_xfp != NULL)
  478.             (void) fflush(CurEnv->e_xfp);    /* for debugging */
  479.  
  480.         /* if we are in the process of closing just give the code */
  481.         if (SmtpState == SMTP_CLOSED)
  482.             return (SMTPCLOSING);
  483.  
  484.         /* get the line from the other side */
  485.         p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn);
  486.         if (p == NULL)
  487.         {
  488.             extern char MsgBuf[];        /* err.c */
  489.  
  490.             /* if the remote end closed early, fake an error */
  491.             if (errno == 0)
  492. # ifdef ECONNRESET
  493.                 errno = ECONNRESET;
  494. # else /* ! ECONNRESET */
  495.                 errno = EPIPE;
  496. # endif /* ECONNRESET */
  497.  
  498.             /* Report that connection ended prematurely */
  499.             if (CurEnv->e_xfp != NULL)
  500.                 fprintf(CurEnv->e_xfp,
  501.                     "421 %s (%s)... Deferred: %s\n",
  502.                     CurHostName, m->m_name,
  503.                     errstring(errno));
  504.  
  505.             /* if debugging, pause so we can see state */
  506.             if (tTd(18, 100))
  507.                 pause();
  508. # ifdef LOG
  509.             syslog(LOG_INFO, "%s", &MsgBuf[4]);
  510. # endif /* LOG */
  511.             SmtpState = SMTP_CLOSED;
  512.             smtpquit(m);
  513.             return (-1);
  514.         }
  515.         fixcrlf(SmtpReplyBuffer, TRUE);
  516.  
  517.         if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)
  518.         {
  519.             /* serious error -- log the previous command */
  520.             /* also record who we were talking before first error */
  521.             if (SmtpNeedIntro)
  522.                 fprintf(CurEnv->e_xfp,
  523.                     "While talking to %s:\n", CurHostName);
  524.             SmtpNeedIntro = FALSE;
  525.             if (SmtpMsgBuffer[0] != '\0')
  526.                 fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer);
  527.             SmtpMsgBuffer[0] = '\0';
  528.  
  529.             /* now log the message as from the other side */
  530.             fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer);
  531.         }
  532.  
  533.         /* display the input for verbose mode */
  534.         if (Verbose && !HoldErrs)
  535.             nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
  536.  
  537.         /* if continuation is required, we can go on */
  538.         if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
  539.             continue;
  540.  
  541.         /* decode the reply code */
  542.         r = atoi(SmtpReplyBuffer);
  543.  
  544.         /* extra semantics: 0xx codes are "informational" */
  545.         if (r < 100)
  546.             continue;
  547.  
  548.         /* save temporary failure messages for posterity */
  549.         if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
  550.             (void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
  551.  
  552.         /* reply code 421 is "Service Shutting Down" */
  553.         if (r == SMTPCLOSING && SmtpState != SMTP_SSD)
  554.         {
  555.             /* send the quit protocol */
  556.             SmtpState = SMTP_SSD;
  557.             smtpquit(m);
  558.         }
  559.         errno = 0;
  560.         return (r);
  561.     }
  562. }
  563. /*
  564. **  SMTPMESSAGE -- send message to server
  565. **
  566. **    Parameters:
  567. **        f -- format
  568. **        m -- the mailer to control formatting.
  569. **        a, b, c -- parameters
  570. **
  571. **    Returns:
  572. **        none.
  573. **
  574. **    Side Effects:
  575. **        writes message to SmtpOut.
  576. */
  577.  
  578. /*VARARGS1*/
  579. static void
  580. #ifdef __STDC__
  581. smtpmessage(const char *f, MAILER *m, ...)
  582. {
  583.     va_list    ap;
  584.     va_start(ap, m);
  585. #else /* !__STDC__ */
  586. smtpmessage(f, m, va_alist)
  587.     const char *f;
  588.     MAILER *m;
  589. va_dcl
  590. {
  591.     va_list    ap;
  592.     va_start(ap);
  593. #endif /* __STDC__ */
  594.  
  595.     (void) vsprintf(SmtpMsgBuffer, f, ap);
  596.     if (tTd(18, 1) || (Verbose && !HoldErrs))
  597.         nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
  598.     if (SmtpOut != NULL)
  599.         fprintf(SmtpOut, "%s%s", SmtpMsgBuffer,
  600.             m == 0 ? "\r\n" : m->m_eol);
  601.     va_end(ap);
  602. }
  603.  
  604. # ifdef MAIL11V3
  605. /*
  606. **  SMTPSTAT -- collect status from DATA command
  607. **
  608. **    Parameters:
  609. **        m -- the mailer we are reading the status from.
  610. **
  611. **    Returns:
  612. **        status of DATA command
  613. **
  614. **    Side Effects:
  615. **        none
  616. */
  617. int
  618. smtpstat(m)
  619.     MAILER *m;
  620. {
  621.     int r;
  622.  
  623.     /* check the status returned after DATA command */
  624.     r = reply(m);
  625.     if (r < 0 || REPLYTYPE(r) == 4)
  626.         return (EX_TEMPFAIL);
  627.     else if (r == 250)
  628.         return (EX_OK);
  629.     else if (r == 552 || r == 554)
  630.         return (EX_UNAVAILABLE);
  631.     else if (r == 550 || r == 551 || r == 553)
  632.         return (EX_NOUSER);
  633.     return (EX_PROTOCOL);
  634. }
  635. # endif /* MAIL11V3 */
  636. #endif /* SMTP */
  637.