BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / srvrsmtp.c
index f1d3b8e..b32d4bd 100644 (file)
@@ -3,16 +3,42 @@
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 # include "sendmail.h"
 
 #ifndef lint
 #ifdef SMTP
  */
 
 # include "sendmail.h"
 
 #ifndef lint
 #ifdef SMTP
-static char sccsid[] = "@(#)srvrsmtp.c 8.74 (Berkeley) %G% (with SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.83 (Berkeley) 6/21/95 (with SMTP)";
 #else
 #else
-static char sccsid[] = "@(#)srvrsmtp.c 8.74 (Berkeley) %G% (without SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.83 (Berkeley) 6/21/95 (without SMTP)";
 #endif
 #endif /* not lint */
 
 #endif
 #endif /* not lint */
 
@@ -45,7 +71,6 @@ struct cmd
 # define CMDMAIL       1       /* mail -- designate sender */
 # define CMDRCPT       2       /* rcpt -- designate recipient */
 # define CMDDATA       3       /* data -- send message text */
 # define CMDMAIL       1       /* mail -- designate sender */
 # define CMDRCPT       2       /* rcpt -- designate recipient */
 # define CMDDATA       3       /* data -- send message text */
-# define CMDHOPS       4       /* hops -- specify hop count */
 # define CMDRSET       4       /* rset -- reset state */
 # define CMDVRFY       5       /* vrfy -- verify address */
 # define CMDEXPN       6       /* expn -- expand address */
 # define CMDRSET       4       /* rset -- reset state */
 # define CMDVRFY       5       /* vrfy -- verify address */
 # define CMDEXPN       6       /* expn -- expand address */
@@ -71,7 +96,6 @@ static struct cmd     CmdTab[] =
        "rset",         CMDRSET,
        "vrfy",         CMDVRFY,
        "expn",         CMDEXPN,
        "rset",         CMDRSET,
        "vrfy",         CMDVRFY,
        "expn",         CMDEXPN,
-       "expn",         CMDVRFY,
        "help",         CMDHELP,
        "noop",         CMDNOOP,
        "quit",         CMDQUIT,
        "help",         CMDHELP,
        "noop",         CMDNOOP,
        "quit",         CMDQUIT,
@@ -79,7 +103,6 @@ static struct cmd    CmdTab[] =
        "ehlo",         CMDEHLO,
        "verb",         CMDVERB,
        "onex",         CMDONEX,
        "ehlo",         CMDEHLO,
        "verb",         CMDVERB,
        "onex",         CMDONEX,
-       "hops",         CMDHOPS,
        /*
         * remaining commands are here only
         * to trap and log attempts to use them
        /*
         * remaining commands are here only
         * to trap and log attempts to use them
@@ -94,21 +117,35 @@ bool       OneXact = FALSE;                /* one xaction only this run */
 char   *CurSmtpClient;                 /* who's at the other end of channel */
 
 static char    *skipword();
 char   *CurSmtpClient;                 /* who's at the other end of channel */
 
 static char    *skipword();
-extern char    RealUserName[];
 
 
 #define MAXBADCOMMANDS 25              /* maximum number of bad commands */
 
 
 
 #define MAXBADCOMMANDS 25              /* maximum number of bad commands */
 
+void
 smtp(e)
        register ENVELOPE *e;
 {
        register char *p;
        register struct cmd *c;
        char *cmd;
 smtp(e)
        register ENVELOPE *e;
 {
        register char *p;
        register struct cmd *c;
        char *cmd;
-       extern ADDRESS *sendto();
+       auto ADDRESS *vrfyqueue;
        ADDRESS *a;
        ADDRESS *a;
+       bool gotmail;                   /* mail command received */
+       bool gothello;                  /* helo command received */
+       bool vrfy;                      /* set if this is a vrfy command */
+       char *protocol;                 /* sending protocol */
+       char *sendinghost;              /* sending hostname */
+       char *peerhostname;             /* name of SMTP peer or "localhost" */
+       auto char *delimptr;
+       char *id;
+       int nrcpts = 0;                 /* number of RCPT commands */
+       bool doublequeue;
+       int badcommands = 0;            /* count of bad commands */
+       char inp[MAXLINE];
+       char cmdbuf[MAXLINE];
+       extern ENVELOPE BlankEnvelope;
+       extern void help __P((char *));
 
 
-       hasmail = FALSE;
        if (fileno(OutChannel) != fileno(stdout))
        {
                /* arrange for debugging output to go to remote host */
        if (fileno(OutChannel) != fileno(stdout))
        {
                /* arrange for debugging output to go to remote host */
@@ -124,9 +161,17 @@ smtp(e)
                CurSmtpClient = CurHostName;
 
        setproctitle("server %s startup", CurSmtpClient);
                CurSmtpClient = CurHostName;
 
        setproctitle("server %s startup", CurSmtpClient);
-       expand("\201e", inp, sizeof inp, e);
+#ifdef LOG
+       if (LogLevel > 11)
+       {
+               /* log connection information */
+               syslog(LOG_INFO, "SMTP connect from %s (%s)",
+                       CurSmtpClient, anynet_ntoa(&RealHostAddr));
+       }
+#endif
 
        /* output the first line, inserting "ESMTP" as second word */
 
        /* output the first line, inserting "ESMTP" as second word */
+       expand("\201e", inp, sizeof inp, e);
        p = strchr(inp, '\n');
        if (p != NULL)
                *p++ = '\0';
        p = strchr(inp, '\n');
        if (p != NULL)
                *p++ = '\0';
@@ -180,7 +225,7 @@ smtp(e)
 
                /* read the input line */
                SmtpPhase = "server cmd read";
 
                /* read the input line */
                SmtpPhase = "server cmd read";
-               setproctitle("server %s cmd read", CurHostName);
+               setproctitle("server %s cmd read", CurSmtpClient);
                p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand,
                                SmtpPhase);
 
                p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand,
                                SmtpPhase);
 
@@ -281,7 +326,31 @@ smtp(e)
                        }
 
                        sendinghost = newstr(p);
                        }
 
                        sendinghost = newstr(p);
-                       message("250", "%s Hello %s, pleased to meet you", HostName, p);
+                       gothello = TRUE;
+                       if (c->cmdcode != CMDEHLO)
+                       {
+                               /* print old message and be done with it */
+                               message("250 %s Hello %s, pleased to meet you",
+                                       MyHostName, CurSmtpClient);
+                               break;
+                       }
+                       
+                       /* print extended message and brag */
+                       message("250-%s Hello %s, pleased to meet you",
+                               MyHostName, CurSmtpClient);
+                       if (!bitset(PRIV_NOEXPN, PrivacyFlags))
+                               message("250-EXPN");
+#if MIME8TO7
+                       message("250-8BITMIME");
+#endif
+                       if (MaxMessageSize > 0)
+                               message("250-SIZE %ld", MaxMessageSize);
+                       else
+                               message("250-SIZE");
+#if DSN
+                       message("250-X-DSN-04 (Draft of May 29, 1995)");
+#endif
+                       message("250 HELP");
                        break;
 
                  case CMDMAIL:         /* mail -- designate sender */
                        break;
 
                  case CMDMAIL:         /* mail -- designate sender */
@@ -321,7 +390,7 @@ smtp(e)
                        {
                                auth_warning(e,
                                        "Host %s didn't use HELO protocol",
                        {
                                auth_warning(e,
                                        "Host %s didn't use HELO protocol",
-                                       peerhostname);
+                                       CurSmtpClient);
                        }
 #ifdef PICKY_HELO_CHECK
                        if (strcasecmp(sendinghost, peerhostname) != 0 &&
                        }
 #ifdef PICKY_HELO_CHECK
                        if (strcasecmp(sendinghost, peerhostname) != 0 &&
@@ -329,7 +398,7 @@ smtp(e)
                             strcasecmp(sendinghost, MyHostName) != 0))
                        {
                                auth_warning(e, "Host %s claimed to be %s",
                             strcasecmp(sendinghost, MyHostName) != 0))
                        {
                                auth_warning(e, "Host %s claimed to be %s",
-                                       peerhostname, sendinghost);
+                                       CurSmtpClient, sendinghost);
                        }
 #endif
 
                        }
 #endif
 
@@ -369,6 +438,7 @@ smtp(e)
 
                        /* check for possible spoofing */
                        if (RealUid != 0 && OpMode == MD_SMTP &&
 
                        /* check for possible spoofing */
                        if (RealUid != 0 && OpMode == MD_SMTP &&
+                           !wordinclass(RealUserName, 't') &&
                            !bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
                            strcmp(e->e_from.q_user, RealUserName) != 0)
                        {
                            !bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
                            strcmp(e->e_from.q_user, RealUserName) != 0)
                        {
@@ -382,6 +452,7 @@ smtp(e)
                        {
                                char *kp;
                                char *vp = NULL;
                        {
                                char *kp;
                                char *vp = NULL;
+                               extern void mail_esmtp_args __P((char *, char *, ENVELOPE *));
 
                                /* locate the beginning of the keyword */
                                while (isascii(*p) && isspace(*p))
 
                                /* locate the beginning of the keyword */
                                while (isascii(*p) && isspace(*p))
@@ -422,18 +493,13 @@ smtp(e)
                                /* NOTREACHED */
                        }
                                
                                /* NOTREACHED */
                        }
                                
-                       if (!enoughspace(e->e_msgsize))
+                       if (!enoughdiskspace(e->e_msgsize))
                        {
                                message("452 Insufficient disk space; try again later");
                                break;
                        }
                        message("250 Sender ok");
                        gotmail = TRUE;
                        {
                                message("452 Insufficient disk space; try again later");
                                break;
                        }
                        message("250 Sender ok");
                        gotmail = TRUE;
-
-                       /* optimize: non-interactive, don't expand aliases */
-                       if (e->e_sendmode != SM_DELIVER)
-                               e->e_flags |= EF_VRFYONLY;
-
                        break;
 
                  case CMDRCPT:         /* rcpt -- designate recipient */
                        break;
 
                  case CMDRCPT:         /* rcpt -- designate recipient */
@@ -450,14 +516,60 @@ smtp(e)
                        }
                        QuickAbort = TRUE;
                        LogUsrErrs = TRUE;
                        }
                        QuickAbort = TRUE;
                        LogUsrErrs = TRUE;
+
+                       if (e->e_sendmode != SM_DELIVER)
+                               e->e_flags |= EF_VRFYONLY;
+
                        p = skipword(p, "to");
                        if (p == NULL)
                                break;
                        p = skipword(p, "to");
                        if (p == NULL)
                                break;
-                       a = sendto(p, 1, (ADDRESS *) NULL, 0);
-# ifdef DEBUG
-                       if (Debug > 1)
-                               printaddr(a, TRUE);
-# endif DEBUG
+                       a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e);
+                       if (a == NULL)
+                               break;
+                       p = delimptr;
+
+                       /* now parse ESMTP arguments */
+                       while (p != NULL && *p != '\0')
+                       {
+                               char *kp;
+                               char *vp = NULL;
+                               extern void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *));
+
+                               /* locate the beginning of the keyword */
+                               while (isascii(*p) && isspace(*p))
+                                       p++;
+                               if (*p == '\0')
+                                       break;
+                               kp = p;
+
+                               /* skip to the value portion */
+                               while (isascii(*p) && isalnum(*p) || *p == '-')
+                                       p++;
+                               if (*p == '=')
+                               {
+                                       *p++ = '\0';
+                                       vp = p;
+
+                                       /* skip to the end of the value */
+                                       while (*p != '\0' && *p != ' ' &&
+                                              !(isascii(*p) && iscntrl(*p)) &&
+                                              *p != '=')
+                                               p++;
+                               }
+
+                               if (*p != '\0')
+                                       *p++ = '\0';
+
+                               if (tTd(19, 1))
+                                       printf("RCPT: got arg %s=\"%s\"\n", kp,
+                                               vp == NULL ? "<null>" : vp);
+
+                               rcpt_esmtp_args(a, kp, vp, e);
+                       }
+
+                       /* save in recipient list after ESMTP mods */
+                       a = recipient(a, &e->e_sendqueue, 0, e);
+
                        if (Errors != 0)
                                break;
 
                        if (Errors != 0)
                                break;
 
@@ -572,10 +684,6 @@ smtp(e)
                                (void) dowork(id, TRUE, TRUE, e);
                        }
 
                                (void) dowork(id, TRUE, TRUE, e);
                        }
 
-                       /* now make it really happen */
-                       if (!Verbose && e->e_sendmode != SM_QUEUE)
-                               dowork(id, TRUE, e);
-
   abortmessage:
                        /* if in a child, pop back to our parent */
                        if (InChild)
   abortmessage:
                        /* if in a child, pop back to our parent */
                        if (InChild)
@@ -633,7 +741,45 @@ smtp(e)
                        if (LogLevel > 5)
                                syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp);
 #endif
                        if (LogLevel > 5)
                                syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp);
 #endif
-                               paddrtree(a);
+                       vrfyqueue = NULL;
+                       QuickAbort = TRUE;
+                       if (vrfy)
+                               e->e_flags |= EF_VRFYONLY;
+                       while (*p != '\0' && isascii(*p) && isspace(*p))
+                               p++;
+                       if (*p == '\0')
+                       {
+                               message("501 Argument required");
+                               Errors++;
+                       }
+                       else
+                       {
+                               (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
+                       }
+                       if (Errors != 0)
+                       {
+                               if (InChild)
+                                       finis();
+                               break;
+                       }
+                       if (vrfyqueue == NULL)
+                       {
+                               message("554 Nothing to %s", vrfy ? "VRFY" : "EXPN");
+                       }
+                       while (vrfyqueue != NULL)
+                       {
+                               extern void printvrfyaddr __P((ADDRESS *, bool));
+
+                               a = vrfyqueue;
+                               while ((a = a->q_next) != NULL &&
+                                      bitset(QDONTSEND|QBADADDR, a->q_flags))
+                                       continue;
+                               if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
+                                       printvrfyaddr(vrfyqueue, a == NULL);
+                               vrfyqueue = vrfyqueue->q_next;
+                       }
+                       if (InChild)
+                               finis();
                        break;
 
                  case CMDHELP:         /* help -- give user info */
                        break;
 
                  case CMDHELP:         /* help -- give user info */
@@ -696,7 +842,7 @@ doquit:
                        if (LogLevel > 0)
                                syslog(LOG_CRIT,
                                    "\"%s\" command from %s (%s)",
                        if (LogLevel > 0)
                                syslog(LOG_CRIT,
                                    "\"%s\" command from %s (%s)",
-                                   c->cmdname, peerhostname,
+                                   c->cmdname, CurSmtpClient,
                                    anynet_ntoa(&RealHostAddr));
 # endif
                        /* FALL THROUGH */
                                    anynet_ntoa(&RealHostAddr));
 # endif
                        /* FALL THROUGH */
@@ -785,6 +931,7 @@ skipword(p, w)
 **             none.
 */
 
 **             none.
 */
 
+void
 mail_esmtp_args(kp, vp, e)
        char *kp;
        char *vp;
 mail_esmtp_args(kp, vp, e)
        char *kp;
        char *vp;
@@ -810,10 +957,9 @@ mail_esmtp_args(kp, vp, e)
                        usrerr("501 BODY requires a value");
                        /* NOTREACHED */
                }
                        usrerr("501 BODY requires a value");
                        /* NOTREACHED */
                }
-               if (strcasecmp(vp, "8bitmime") == 0)
+               else if (strcasecmp(vp, "8bitmime") == 0)
                {
                        SevenBitInput = FALSE;
                {
                        SevenBitInput = FALSE;
-                       e->e_flags |= EF_NL_NOT_EOL;
                }
                else if (strcasecmp(vp, "7bit") == 0)
                {
                }
                else if (strcasecmp(vp, "7bit") == 0)
                {
@@ -886,6 +1032,7 @@ mail_esmtp_args(kp, vp, e)
 **             none.
 */
 
 **             none.
 */
 
+void
 rcpt_esmtp_args(a, kp, vp, e)
        ADDRESS *a;
        char *kp;
 rcpt_esmtp_args(a, kp, vp, e)
        ADDRESS *a;
        char *kp;
@@ -931,7 +1078,7 @@ rcpt_esmtp_args(a, kp, vp, e)
                        usrerr("501 ORCPT requires a value");
                        /* NOTREACHED */
                }
                        usrerr("501 ORCPT requires a value");
                        /* NOTREACHED */
                }
-               if (!xtextok(vp))
+               if (strchr(vp, ';') == NULL || !xtextok(vp))
                {
                        usrerr("501 Syntax error in ORCPT parameter value");
                        /* NOTREACHED */
                {
                        usrerr("501 Syntax error in ORCPT parameter value");
                        /* NOTREACHED */
@@ -963,6 +1110,7 @@ rcpt_esmtp_args(a, kp, vp, e)
 **             Prints the appropriate 250 codes.
 */
 
 **             Prints the appropriate 250 codes.
 */
 
+void
 printvrfyaddr(a, last)
        register ADDRESS *a;
        bool last;
 printvrfyaddr(a, last)
        register ADDRESS *a;
        bool last;
@@ -1002,6 +1150,7 @@ printvrfyaddr(a, last)
 **             outputs the help file to message output.
 */
 
 **             outputs the help file to message output.
 */
 
+void
 help(topic)
        char *topic;
 {
 help(topic)
        char *topic;
 {
@@ -1071,6 +1220,7 @@ help(topic)
 **             none.
 */
 
 **             none.
 */
 
+int
 runinchild(label, e)
        char *label;
        register ENVELOPE *e;
 runinchild(label, e)
        char *label;
        register ENVELOPE *e;
@@ -1090,7 +1240,7 @@ runinchild(label, e)
                        auto int st;
 
                        /* parent -- wait for child to complete */
                        auto int st;
 
                        /* parent -- wait for child to complete */
-                       setproctitle("server %s child wait", CurHostName);
+                       setproctitle("server %s child wait", CurSmtpClient);
                        st = waitfor(childpid);
                        if (st == -1)
                                syserr("451 %s: lost child", label);
                        st = waitfor(childpid);
                        if (st == -1)
                                syserr("451 %s: lost child", label);
@@ -1121,57 +1271,5 @@ runinchild(label, e)
 
        return (0);
 }
 
        return (0);
 }
-\f/*
-**  PADDRTREE -- print address tree
-**
-**     Used by VRFY and EXPD to dump the tree of addresses produced.
-**
-**     Parameters:
-**             a -- address of root.
-**
-**     Returns:
-**             none.
-**
-**     Side Effects:
-**             prints the tree in a nice order.
-*/
-
-paddrtree(a)
-       register ADDRESS *a;
-{
-       static ADDRESS *prev;
-       static int lev;
-
-       if (a == NULL)
-               return;
-       lev++;
-       if (!bitset(QDONTSEND, a->q_flags))
-       {
-               if (prev != NULL)
-               {
-                       if (prev->q_fullname != NULL)
-                               message("250-", "%s <%s>", prev->q_fullname, prev->q_paddr);
-                       else
-                               message("250-", "<%s>", prev->q_paddr);
-               }
-               prev = a;
-       }
-       paddrtree(a->q_child);
-       paddrtree(a->q_sibling);
-       if (--lev <= 0)
-       {
-               if (prev != NULL)
-               {
-                       /* last one */
-                       if (prev->q_fullname != NULL)
-                               message("250", "%s <%s>", prev->q_fullname, prev->q_paddr);
-                       else
-                               message("250", "<%s>", prev->q_paddr);
-                       prev = NULL;
-               }
-               else
-                       message("550", "User unknown");
-       }
-}
 
 # endif /* SMTP */
 
 # endif /* SMTP */