add Berkeley specific header
[unix-history] / usr / src / usr.sbin / sendmail / src / usersmtp.c
index ed5fc1c..c5f6fff 100644 (file)
@@ -1,14 +1,33 @@
-# include <ctype.h>
-# include <sysexits.h>
-# include "sendmail.h"
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ *  Sendmail
+ *  Copyright (c) 1983  Eric P. Allman
+ *  Berkeley, California
+ */
 
 
-# ifndef SMTP
-SCCSID(@(#)usersmtp.c  4.3             %G%     (no SMTP));
-# else SMTP
+# include "sendmail.h"
 
 
-SCCSID(@(#)usersmtp.c  4.3             %G%);
+#ifndef lint
+#ifdef SMTP
+static char sccsid[] = "@(#)usersmtp.c 5.9 (Berkeley) %G% (with SMTP)";
+#else
+static char sccsid[] = "@(#)usersmtp.c 5.9 (Berkeley) %G% (without SMTP)";
+#endif
+#endif /* not lint */
 
 
+# include <sysexits.h>
+# include <errno.h>
 
 
+# ifdef SMTP
 
 /*
 **  USERSMTP -- run SMTP protocol from the user end.
 
 /*
 **  USERSMTP -- run SMTP protocol from the user end.
@@ -22,6 +41,7 @@ SCCSID(@(#)usersmtp.c 4.3             %G%);
 
 char   SmtpMsgBuffer[MAXLINE];         /* buffer for commands */
 char   SmtpReplyBuffer[MAXLINE];       /* buffer for replies */
 
 char   SmtpMsgBuffer[MAXLINE];         /* buffer for commands */
 char   SmtpReplyBuffer[MAXLINE];       /* buffer for replies */
+char   SmtpError[MAXLINE] = "";        /* save failure error messages */
 FILE   *SmtpOut;                       /* output file */
 FILE   *SmtpIn;                        /* input file */
 int    SmtpPid;                        /* pid of mailer */
 FILE   *SmtpOut;                       /* output file */
 FILE   *SmtpIn;                        /* input file */
 int    SmtpPid;                        /* pid of mailer */
@@ -44,6 +64,7 @@ int   SmtpState;                      /* connection state, see below */
 **
 **     Returns:
 **             appropriate exit status -- EX_OK on success.
 **
 **     Returns:
 **             appropriate exit status -- EX_OK on success.
+**             If not EX_OK, it should close the connection.
 **
 **     Side Effects:
 **             creates connection and sends initial protocol.
 **
 **     Side Effects:
 **             creates connection and sends initial protocol.
@@ -71,6 +92,8 @@ smtpinit(m, pvp)
 
        SmtpIn = SmtpOut = NULL;
        SmtpState = SMTP_CLOSED;
 
        SmtpIn = SmtpOut = NULL;
        SmtpState = SMTP_CLOSED;
+       SmtpError[0] = '\0';
+       SmtpPhase = "user open";
        SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
        if (SmtpPid < 0)
        {
        SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
        if (SmtpPid < 0)
        {
@@ -79,37 +102,59 @@ smtpinit(m, pvp)
                        printf("smtpinit: cannot open %s: stat %d errno %d\n",
                           pvp[0], ExitStat, errno);
 # endif DEBUG
                        printf("smtpinit: cannot open %s: stat %d errno %d\n",
                           pvp[0], ExitStat, errno);
 # endif DEBUG
+               if (CurEnv->e_xfp != NULL)
+               {
+                       register char *p;
+                       extern char *errstring();
+                       extern char *statstring();
+
+                       if (errno == 0)
+                       {
+                               p = statstring(ExitStat);
+                               fprintf(CurEnv->e_xfp,
+                                       "%.3s %s.%s... %s\n",
+                                       p, pvp[1], m->m_name, p);
+                       }
+                       else
+                       {
+                               fprintf(CurEnv->e_xfp,
+                                       "421 %s.%s... Deferred: %s\n",
+                                       pvp[1], m->m_name, errstring(errno));
+                       }
+               }
                return (ExitStat);
        }
        SmtpState = SMTP_OPEN;
 
        /*
        **  Get the greeting message.
                return (ExitStat);
        }
        SmtpState = SMTP_OPEN;
 
        /*
        **  Get the greeting message.
-       **      This should appear spontaneously.  Give it two minutes to
+       **      This should appear spontaneously.  Give it five minutes to
        **      happen.
        */
 
        if (setjmp(CtxGreeting) != 0)
        **      happen.
        */
 
        if (setjmp(CtxGreeting) != 0)
-               return (EX_TEMPFAIL);
-       gte = setevent(120, greettimeout, 0);
+               goto tempfail;
+       gte = setevent((time_t) 300, greettimeout, 0);
+       SmtpPhase = "greeting wait";
        r = reply(m);
        clrevent(gte);
        if (r < 0 || REPLYTYPE(r) != 2)
        r = reply(m);
        clrevent(gte);
        if (r < 0 || REPLYTYPE(r) != 2)
-               return (EX_TEMPFAIL);
+               goto tempfail;
 
        /*
        **  Send the HELO command.
        **      My mother taught me to always introduce myself.
        */
 
 
        /*
        **  Send the HELO command.
        **      My mother taught me to always introduce myself.
        */
 
-       smtpmessage("HELO %s", m, HostName);
+       smtpmessage("HELO %s", m, MyHostName);
+       SmtpPhase = "HELO wait";
        r = reply(m);
        if (r < 0)
        r = reply(m);
        if (r < 0)
-               return (EX_TEMPFAIL);
+               goto tempfail;
        else if (REPLYTYPE(r) == 5)
        else if (REPLYTYPE(r) == 5)
-               return (EX_UNAVAILABLE);
+               goto unavailable;
        else if (REPLYTYPE(r) != 2)
        else if (REPLYTYPE(r) != 2)
-               return (EX_TEMPFAIL);
+               goto tempfail;
 
        /*
        **  If this is expected to be another sendmail, send some internal
 
        /*
        **  If this is expected to be another sendmail, send some internal
@@ -122,13 +167,13 @@ smtpinit(m, pvp)
                smtpmessage("VERB", m);
                r = reply(m);
                if (r < 0)
                smtpmessage("VERB", m);
                r = reply(m);
                if (r < 0)
-                       return (EX_TEMPFAIL);
+                       goto tempfail;
 
                /* tell it we will be sending one transaction only */
                smtpmessage("ONEX", m);
                r = reply(m);
                if (r < 0)
 
                /* tell it we will be sending one transaction only */
                smtpmessage("ONEX", m);
                r = reply(m);
                if (r < 0)
-                       return (EX_TEMPFAIL);
+                       goto tempfail;
        }
 
        /*
        }
 
        /*
@@ -144,7 +189,7 @@ smtpinit(m, pvp)
        **      Designates the sender.
        */
 
        **      Designates the sender.
        */
 
-       expand("$g", buf, &buf[sizeof buf - 1], CurEnv);
+       expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
        if (CurEnv->e_from.q_mailer == LocalMailer ||
            !bitnset(M_FROMPATH, m->m_flags))
        {
        if (CurEnv->e_from.q_mailer == LocalMailer ||
            !bitnset(M_FROMPATH, m->m_flags))
        {
@@ -152,17 +197,31 @@ smtpinit(m, pvp)
        }
        else
        {
        }
        else
        {
-               smtpmessage("MAIL From:<@%s%c%s>", m, HostName,
+               smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName,
                        buf[0] == '@' ? ',' : ':', buf);
        }
                        buf[0] == '@' ? ',' : ':', buf);
        }
+       SmtpPhase = "MAIL wait";
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
-               return (EX_TEMPFAIL);
+               goto tempfail;
        else if (r == 250)
                return (EX_OK);
        else if (r == 552)
        else if (r == 250)
                return (EX_OK);
        else if (r == 552)
-               return (EX_UNAVAILABLE);
+               goto unavailable;
+
+       /* protocol error -- close up */
+       smtpquit(m);
        return (EX_PROTOCOL);
        return (EX_PROTOCOL);
+
+       /* signal a temporary failure */
+  tempfail:
+       smtpquit(m);
+       return (EX_TEMPFAIL);
+
+       /* signal service unavailable */
+  unavailable:
+       smtpquit(m);
+       return (EX_UNAVAILABLE);
 }
 
 
 }
 
 
@@ -195,6 +254,7 @@ smtprcpt(to, m)
 
        smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));
 
 
        smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));
 
+       SmtpPhase = "RCPT wait";
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
@@ -236,6 +296,7 @@ smtpdata(m, e)
 
        /* send the command and check ok to proceed */
        smtpmessage("DATA", m);
 
        /* send the command and check ok to proceed */
        smtpmessage("DATA", m);
+       SmtpPhase = "DATA wait";
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
@@ -255,6 +316,7 @@ smtpdata(m, e)
                nmessage(Arpa_Info, ">>> .");
 
        /* check for the results of the transaction */
                nmessage(Arpa_Info, ">>> .");
 
        /* check for the results of the transaction */
+       SmtpPhase = "result wait";
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
        r = reply(m);
        if (r < 0 || REPLYTYPE(r) == 4)
                return (EX_TEMPFAIL);
@@ -268,7 +330,7 @@ smtpdata(m, e)
 **  SMTPQUIT -- close the SMTP connection.
 **
 **     Parameters:
 **  SMTPQUIT -- close the SMTP connection.
 **
 **     Parameters:
-**             name -- name of mailer we are quitting.
+**             m -- a pointer to the mailer.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -277,8 +339,7 @@ smtpdata(m, e)
 **             sends the final protocol and closes the connection.
 */
 
 **             sends the final protocol and closes the connection.
 */
 
-smtpquit(name, m)
-       char *name;
+smtpquit(m)
        register MAILER *m;
 {
        int i;
        register MAILER *m;
 {
        int i;
@@ -303,9 +364,9 @@ smtpquit(name, m)
        SmtpState = SMTP_CLOSED;
 
        /* and pick up the zombie */
        SmtpState = SMTP_CLOSED;
 
        /* and pick up the zombie */
-       i = endmailer(SmtpPid, name);
+       i = endmailer(SmtpPid, m->m_argv[0]);
        if (i != EX_OK)
        if (i != EX_OK)
-               syserr("smtpquit %s: stat %d", name, i);
+               syserr("smtpquit %s: stat %d", m->m_argv[0], i);
 }
 \f/*
 **  REPLY -- read arpanet reply
 }
 \f/*
 **  REPLY -- read arpanet reply
@@ -352,6 +413,14 @@ reply(m)
                        extern char MsgBuf[];           /* err.c */
                        extern char Arpa_TSyserr[];     /* conf.c */
 
                        extern char MsgBuf[];           /* err.c */
                        extern char Arpa_TSyserr[];     /* conf.c */
 
+                       /* if the remote end closed early, fake an error */
+                       if (errno == 0)
+# ifdef ECONNRESET
+                               errno = ECONNRESET;
+# else ECONNRESET
+                               errno = EPIPE;
+# endif ECONNRESET
+
                        message(Arpa_TSyserr, "reply: read error");
 # ifdef DEBUG
                        /* if debugging, pause so we can see state */
                        message(Arpa_TSyserr, "reply: read error");
 # ifdef DEBUG
                        /* if debugging, pause so we can see state */
@@ -362,7 +431,7 @@ reply(m)
                        syslog(LOG_ERR, "%s", &MsgBuf[4]);
 # endif LOG
                        SmtpState = SMTP_CLOSED;
                        syslog(LOG_ERR, "%s", &MsgBuf[4]);
 # endif LOG
                        SmtpState = SMTP_CLOSED;
-                       smtpquit("reply error", m);
+                       smtpquit(m);
                        return (-1);
                }
                fixcrlf(SmtpReplyBuffer, TRUE);
                        return (-1);
                }
                fixcrlf(SmtpReplyBuffer, TRUE);
@@ -398,9 +467,13 @@ reply(m)
                {
                        /* send the quit protocol */
                        SmtpState = SMTP_SSD;
                {
                        /* send the quit protocol */
                        SmtpState = SMTP_SSD;
-                       smtpquit("SMTP Shutdown", m);
+                       smtpquit(m);
                }
 
                }
 
+               /* save temporary failure messages for posterity */
+               if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
+                       (void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
+
                return (r);
        }
 }
                return (r);
        }
 }