BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / srvrsmtp.c
index 65783b2..b32d4bd 100644 (file)
@@ -1,23 +1,48 @@
 /*
 /*
- * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1983, 1995 Eric P. Allman
+ * 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 6.56 (Berkeley) %G% (with SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.83 (Berkeley) 6/21/95 (with SMTP)";
 #else
 #else
-static char sccsid[] = "@(#)srvrsmtp.c 6.56 (Berkeley) %G% (without SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.83 (Berkeley) 6/21/95 (without SMTP)";
 #endif
 #endif /* not lint */
 
 # include <errno.h>
 #endif
 #endif /* not lint */
 
 # include <errno.h>
-# include <signal.h>
 
 # ifdef SMTP
 
 
 # ifdef SMTP
 
@@ -46,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 */
@@ -58,6 +82,8 @@ struct cmd
 /* non-standard commands */
 # define CMDONEX       16      /* onex -- sending one transaction only */
 # define CMDVERB       17      /* verb -- go into verbose mode */
 /* non-standard commands */
 # define CMDONEX       16      /* onex -- sending one transaction only */
 # define CMDVERB       17      /* verb -- go into verbose mode */
+/* use this to catch and log "door handle" attempts on your system */
+# define CMDLOGBOGUS   23      /* bogus command that should be logged */
 /* debugging-only commands, only enabled if SMTPDEBUG is defined */
 # define CMDDBGQSHOW   24      /* showq -- show send queue */
 # define CMDDBGDEBUG   25      /* debug -- set debug mode */
 /* debugging-only commands, only enabled if SMTPDEBUG is defined */
 # define CMDDBGQSHOW   24      /* showq -- show send queue */
 # define CMDDBGDEBUG   25      /* debug -- set debug mode */
@@ -70,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,
@@ -78,43 +103,99 @@ 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
         */
        "showq",        CMDDBGQSHOW,
        "debug",        CMDDBGDEBUG,
        /*
         * remaining commands are here only
         * to trap and log attempts to use them
         */
        "showq",        CMDDBGQSHOW,
        "debug",        CMDDBGDEBUG,
+       "wiz",          CMDLOGBOGUS,
        NULL,           CMDERROR,
 };
 
        NULL,           CMDERROR,
 };
 
-bool   InChild = FALSE;                /* true if running in a subprocess */
 bool   OneXact = FALSE;                /* one xaction only this run */
 bool   OneXact = FALSE;                /* one xaction only this run */
+char   *CurSmtpClient;                 /* who's at the other end of channel */
+
+static char    *skipword();
+
 
 
-#define EX_QUIT                22              /* special code for QUIT command */
+#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;
-       static char *skipword();
-       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 */
                (void) dup2(fileno(OutChannel), fileno(stdout));
        }
        settime(e);
        if (fileno(OutChannel) != fileno(stdout))
        {
                /* arrange for debugging output to go to remote host */
                (void) dup2(fileno(OutChannel), fileno(stdout));
        }
        settime(e);
-       CurHostName = RealHostName;
-       setproctitle("srvrsmtp %s startup", CurHostName);
-       expand("\201e", inp, &inp[sizeof inp], e);
-       message("220-%s", inp);
-       message("220 ESMTP spoken here");
+       peerhostname = RealHostName;
+       if (peerhostname == NULL)
+               peerhostname = "localhost";
+       CurHostName = peerhostname;
+       CurSmtpClient = macvalue('_', e);
+       if (CurSmtpClient == NULL)
+               CurSmtpClient = CurHostName;
+
+       setproctitle("server %s startup", CurSmtpClient);
+#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 */
+       expand("\201e", inp, sizeof inp, e);
+       p = strchr(inp, '\n');
+       if (p != NULL)
+               *p++ = '\0';
+       id = strchr(inp, ' ');
+       if (id == NULL)
+               id = &inp[strlen(inp)];
+       cmd = p == NULL ? "220 %.*s ESMTP%s" : "220-%.*s ESMTP%s";
+       message(cmd, id - inp, inp, id);
+
+       /* output remaining lines */
+       while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL)
+       {
+               *p++ = '\0';
+               if (isascii(*id) && isspace(*id))
+                       id++;
+               message("220-%s", id);
+       }
+       if (id != NULL)
+       {
+               if (isascii(*id) && isspace(*id))
+                       id++;
+               message("220 %s", id);
+       }
+
        protocol = NULL;
        sendinghost = macvalue('s', e);
        gothello = FALSE;
        protocol = NULL;
        sendinghost = macvalue('s', e);
        gothello = FALSE;
@@ -122,16 +203,20 @@ smtp(e)
        for (;;)
        {
                /* arrange for backout */
        for (;;)
        {
                /* arrange for backout */
-               if (setjmp(TopFrame) > 0 && InChild)
+               if (setjmp(TopFrame) > 0)
                {
                {
-                       QuickAbort = FALSE;
-                       SuprErrs = TRUE;
-                       finis();
+                       /* if() nesting is necessary for Cray UNICOS */
+                       if (InChild)
+                       {
+                               QuickAbort = FALSE;
+                               SuprErrs = TRUE;
+                               finis();
+                       }
                }
                QuickAbort = FALSE;
                HoldErrs = FALSE;
                LogUsrErrs = FALSE;
                }
                QuickAbort = FALSE;
                HoldErrs = FALSE;
                LogUsrErrs = FALSE;
-               e->e_flags &= ~EF_VRFYONLY;
+               e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
 
                /* setup for the read */
                e->e_to = NULL;
 
                /* setup for the read */
                e->e_to = NULL;
@@ -139,20 +224,22 @@ smtp(e)
                (void) fflush(stdout);
 
                /* read the input line */
                (void) fflush(stdout);
 
                /* read the input line */
-               SmtpPhase = "srvrsmtp cmd read";
-               setproctitle("srvrsmtp %s cmd read", CurHostName);
-               p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand);
+               SmtpPhase = "server cmd read";
+               setproctitle("server %s cmd read", CurSmtpClient);
+               p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand,
+                               SmtpPhase);
 
                /* handle errors */
                if (p == NULL)
                {
                        /* end of file, just die */
 
                /* handle errors */
                if (p == NULL)
                {
                        /* end of file, just die */
+                       disconnect(1, e);
                        message("421 %s Lost input channel from %s",
                        message("421 %s Lost input channel from %s",
-                               MyHostName, CurHostName);
+                               MyHostName, CurSmtpClient);
 #ifdef LOG
 #ifdef LOG
-                       if (LogLevel > 1)
+                       if (LogLevel > (gotmail ? 1 : 19))
                                syslog(LOG_NOTICE, "lost input channel from %s",
                                syslog(LOG_NOTICE, "lost input channel from %s",
-                                       CurHostName);
+                                       CurSmtpClient);
 #endif
                        if (InChild)
                                ExitStat = EX_QUIT;
 #endif
                        if (InChild)
                                ExitStat = EX_QUIT;
@@ -167,9 +254,9 @@ smtp(e)
                        fprintf(e->e_xfp, "<<< %s\n", inp);
 
                if (e->e_id == NULL)
                        fprintf(e->e_xfp, "<<< %s\n", inp);
 
                if (e->e_id == NULL)
-                       setproctitle("%s: %s", CurHostName, inp);
+                       setproctitle("%s: %.80s", CurSmtpClient, inp);
                else
                else
-                       setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
+                       setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp);
 
                /* break off command */
                for (p = inp; isascii(*p) && isspace(*p); p++)
 
                /* break off command */
                for (p = inp; isascii(*p) && isspace(*p); p++)
@@ -203,50 +290,90 @@ smtp(e)
                        if (c->cmdcode == CMDEHLO)
                        {
                                protocol = "ESMTP";
                        if (c->cmdcode == CMDEHLO)
                        {
                                protocol = "ESMTP";
-                               SmtpPhase = "EHLO";
+                               SmtpPhase = "server EHLO";
                        }
                        else
                        {
                                protocol = "SMTP";
                        }
                        else
                        {
                                protocol = "SMTP";
-                               SmtpPhase = "HELO";
+                               SmtpPhase = "server HELO";
+                       }
+
+                       /* check for valid domain name (re 1123 5.2.5) */
+                       if (*p == '\0')
+                       {
+                               message("501 %s requires domain address",
+                                       cmdbuf);
+                               break;
+                       }
+                       else
+                       {
+                               register char *q;
+
+                               for (q = p; *q != '\0'; q++)
+                               {
+                                       if (!isascii(*q))
+                                               break;
+                                       if (isalnum(*q))
+                                               continue;
+                                       if (strchr("[].-_#", *q) == NULL)
+                                               break;
+                               }
+                               if (*q != '\0')
+                               {
+                                       message("501 Invalid domain name");
+                                       break;
+                               }
                        }
                        }
+
                        sendinghost = newstr(p);
                        sendinghost = newstr(p);
-                       if (strcasecmp(p, RealHostName) != 0)
+                       gothello = TRUE;
+                       if (c->cmdcode != CMDEHLO)
                        {
                        {
-                               auth_warning(e, "Host %s claimed to be %s",
-                                       RealHostName, p);
+                               /* print old message and be done with it */
+                               message("250 %s Hello %s, pleased to meet you",
+                                       MyHostName, CurSmtpClient);
+                               break;
                        }
                        }
-                       p = macvalue('_', e);
-                       if (p == NULL)
-                               p = RealHostName;
-                       message("250", "%s Hello %s, pleased to meet you", HostName, p);
+                       
+                       /* 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 */
-                       SmtpPhase = "MAIL";
+                       SmtpPhase = "server MAIL";
 
                        /* check for validity of this command */
                        if (!gothello)
                        {
                                /* set sending host to our known value */
                                if (sendinghost == NULL)
 
                        /* check for validity of this command */
                        if (!gothello)
                        {
                                /* set sending host to our known value */
                                if (sendinghost == NULL)
-                                       sendinghost = RealHostName;
+                                       sendinghost = peerhostname;
 
                                if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
                                {
                                        message("503 Polite people say HELO first");
                                        break;
                                }
 
                                if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
                                {
                                        message("503 Polite people say HELO first");
                                        break;
                                }
-                               else
-                               {
-                                       auth_warning(e,
-                                               "Host %s didn't use HELO protocol",
-                                               RealHostName);
-                               }
                        }
                        if (gotmail)
                        {
                                message("503 Sender already specified");
                        }
                        if (gotmail)
                        {
                                message("503 Sender already specified");
+                               if (InChild)
+                                       finis();
                                break;
                        }
                        if (InChild)
                                break;
                        }
                        if (InChild)
@@ -259,13 +386,30 @@ smtp(e)
                        /* fork a subprocess to process this command */
                        if (runinchild("SMTP-MAIL", e) > 0)
                                break;
                        /* fork a subprocess to process this command */
                        if (runinchild("SMTP-MAIL", e) > 0)
                                break;
+                       if (!gothello)
+                       {
+                               auth_warning(e,
+                                       "Host %s didn't use HELO protocol",
+                                       CurSmtpClient);
+                       }
+#ifdef PICKY_HELO_CHECK
+                       if (strcasecmp(sendinghost, peerhostname) != 0 &&
+                           (strcasecmp(peerhostname, "localhost") != 0 ||
+                            strcasecmp(sendinghost, MyHostName) != 0))
+                       {
+                               auth_warning(e, "Host %s claimed to be %s",
+                                       CurSmtpClient, sendinghost);
+                       }
+#endif
+
                        if (protocol == NULL)
                                protocol = "SMTP";
                        define('r', protocol, e);
                        define('s', sendinghost, e);
                        initsys(e);
                        nrcpts = 0;
                        if (protocol == NULL)
                                protocol = "SMTP";
                        define('r', protocol, e);
                        define('s', sendinghost, e);
                        initsys(e);
                        nrcpts = 0;
-                       setproctitle("%s %s: %s", e->e_id, CurHostName, inp);
+                       e->e_flags |= EF_LOGSENDER|EF_CLRQUEUE;
+                       setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp);
 
                        /* child -- go do the processing */
                        p = skipword(p, "from");
 
                        /* child -- go do the processing */
                        p = skipword(p, "from");
@@ -278,6 +422,7 @@ smtp(e)
                                {
                                        QuickAbort = FALSE;
                                        SuprErrs = TRUE;
                                {
                                        QuickAbort = FALSE;
                                        SuprErrs = TRUE;
+                                       e->e_flags &= ~EF_FATALERRS;
                                        finis();
                                }
                                break;
                                        finis();
                                }
                                break;
@@ -291,12 +436,23 @@ smtp(e)
                        if (p != NULL && *p != '\0')
                                *p++ = '\0';
 
                        if (p != NULL && *p != '\0')
                                *p++ = '\0';
 
+                       /* 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)
+                       {
+                               auth_warning(e, "%s owned process doing -bs",
+                                       RealUserName);
+                       }
+
                        /* now parse ESMTP arguments */
                        /* now parse ESMTP arguments */
-                       msize = 0;
-                       for (; p != NULL && *p != '\0'; p++)
+                       e->e_msgsize = 0;
+                       while (p != NULL && *p != '\0')
                        {
                                char *kp;
                        {
                                char *kp;
-                               char *vp;
+                               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))
@@ -324,69 +480,26 @@ smtp(e)
                                        *p++ = '\0';
 
                                if (tTd(19, 1))
                                        *p++ = '\0';
 
                                if (tTd(19, 1))
-                                       printf("MAIL: got arg %s=%s\n", kp,
+                                       printf("MAIL: got arg %s=\"%s\"\n", kp,
                                                vp == NULL ? "<null>" : vp);
 
                                                vp == NULL ? "<null>" : vp);
 
-                               if (strcasecmp(kp, "size") == 0)
-                               {
-                                       if (vp == NULL)
-                                       {
-                                               usrerr("501 SIZE requires a value");
-                                               /* NOTREACHED */
-                                       }
-                                       msize = atol(vp);
-                               }
-                               else if (strcasecmp(kp, "body") == 0)
-                               {
-                                       if (vp == NULL)
-                                       {
-                                               usrerr("501 BODY requires a value");
-                                               /* NOTREACHED */
-                                       }
-# ifdef MIME
-                                       if (strcasecmp(vp, "8bitmime") == 0)
-                                       {
-                                               e->e_bodytype = "8BITMIME";
-                                               SevenBit = FALSE;
-                                       }
-                                       else if (strcasecmp(vp, "7bit") == 0)
-                                       {
-                                               e->e_bodytype = "7BIT";
-                                               SevenBit = TRUE;
-                                       }
-                                       else
-                                       {
-                                               usrerr("501 Unknown BODY type %s",
-                                                       vp);
-                                       }
-# endif
-                               }
-                               else
-                               {
-                                       usrerr("501 %s parameter unrecognized", kp);
-                                       /* NOTREACHED */
-                               }
+                               mail_esmtp_args(kp, vp, e);
                        }
 
                        }
 
-                       if (MaxMessageSize > 0 && msize > MaxMessageSize)
+                       if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
                        {
                                usrerr("552 Message size exceeds fixed maximum message size (%ld)",
                                        MaxMessageSize);
                                /* NOTREACHED */
                        }
                                
                        {
                                usrerr("552 Message size exceeds fixed maximum message size (%ld)",
                                        MaxMessageSize);
                                /* NOTREACHED */
                        }
                                
-                       if (!enoughspace(msize))
+                       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 */
@@ -395,7 +508,7 @@ smtp(e)
                                usrerr("503 Need MAIL before RCPT");
                                break;
                        }
                                usrerr("503 Need MAIL before RCPT");
                                break;
                        }
-                       SmtpPhase = "RCPT";
+                       SmtpPhase = "server RCPT";
                        if (setjmp(TopFrame) > 0)
                        {
                                e->e_flags &= ~EF_FATALERRS;
                        if (setjmp(TopFrame) > 0)
                        {
                                e->e_flags &= ~EF_FATALERRS;
@@ -403,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;
 
@@ -418,7 +577,9 @@ smtp(e)
                        e->e_to = p;
                        if (!bitset(QBADADDR, a->q_flags))
                        {
                        e->e_to = p;
                        if (!bitset(QBADADDR, a->q_flags))
                        {
-                               message("250 Recipient ok");
+                               message("250 Recipient ok%s",
+                                       bitset(QQUEUEUP, a->q_flags) ?
+                                               " (will queue)" : "");
                                nrcpts++;
                        }
                        else
                                nrcpts++;
                        }
                        else
@@ -430,32 +591,51 @@ smtp(e)
                        break;
 
                  case CMDDATA:         /* data -- text of mail */
                        break;
 
                  case CMDDATA:         /* data -- text of mail */
-                       SmtpPhase = "DATA";
+                       SmtpPhase = "server DATA";
                        if (!gotmail)
                        {
                                message("503 Need MAIL command");
                                break;
                        }
                        if (!gotmail)
                        {
                                message("503 Need MAIL command");
                                break;
                        }
-                       else if (e->e_nrcpts <= 0)
+                       else if (nrcpts <= 0)
                        {
                                message("503 Need RCPT (recipient)");
                                break;
                        }
 
                        /* check to see if we need to re-expand aliases */
                        {
                                message("503 Need RCPT (recipient)");
                                break;
                        }
 
                        /* check to see if we need to re-expand aliases */
+                       /* also reset QBADADDR on already-diagnosted addrs */
+                       doublequeue = FALSE;
                        for (a = e->e_sendqueue; a != NULL; a = a->q_next)
                        {
                                if (bitset(QVERIFIED, a->q_flags))
                        for (a = e->e_sendqueue; a != NULL; a = a->q_next)
                        {
                                if (bitset(QVERIFIED, a->q_flags))
-                                       break;
+                               {
+                                       /* need to re-expand aliases */
+                                       doublequeue = TRUE;
+                               }
+                               if (bitset(QBADADDR, a->q_flags))
+                               {
+                                       /* make this "go away" */
+                                       a->q_flags |= QDONTSEND;
+                                       a->q_flags &= ~QBADADDR;
+                               }
                        }
 
                        /* collect the text of the message */
                        SmtpPhase = "collect";
                        }
 
                        /* collect the text of the message */
                        SmtpPhase = "collect";
-                       collect(TRUE, a != NULL, e);
-                       e->e_flags &= ~EF_FATALERRS;
+                       buffer_errors();
+                       collect(InChannel, TRUE, doublequeue, NULL, e);
+                       flush_errors(TRUE);
                        if (Errors != 0)
                                goto abortmessage;
 
                        if (Errors != 0)
                                goto abortmessage;
 
+                       /* make sure we actually do delivery */
+                       e->e_flags &= ~EF_CLRQUEUE;
+
+                       /* from now on, we have to operate silently */
+                       buffer_errors();
+                       e->e_errormode = EM_MAIL;
+
                        /*
                        **  Arrange to send to everyone.
                        **      If sending to multiple people, mail back
                        /*
                        **  Arrange to send to everyone.
                        **      If sending to multiple people, mail back
@@ -475,51 +655,34 @@ smtp(e)
                        */
 
                        SmtpPhase = "delivery";
                        */
 
                        SmtpPhase = "delivery";
-                       if (nrcpts != 1 && a == NULL)
-                       {
-                               HoldErrs = TRUE;
-                               e->e_errormode = EM_MAIL;
-                       }
                        e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
                        id = e->e_id;
 
                        e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
                        id = e->e_id;
 
-                       /* send to all recipients */
-                       sendall(e, Verbose ? SM_DELIVER : SM_QUEUE);
-                       e->e_to = NULL;
-
-                       /* save statistics */
-                       markstats(e, (ADDRESS *) NULL);
-
-                       unlockqueue(e);
-
-                       /* issue success if appropriate and reset */
-                       if (Errors == 0 || HoldErrs)
-                               message("250 %s Message accepted for delivery", id);
-
-                       if (bitset(EF_FATALERRS, e->e_flags) && !HoldErrs)
+                       if (doublequeue)
                        {
                        {
-                               /* avoid sending back an extra message */
-                               e->e_flags &= ~EF_FATALERRS;
-                               e->e_flags |= EF_CLRQUEUE;
+                               /* make sure it is in the queue */
+                               queueup(e, TRUE, FALSE);
+                               if (e->e_sendmode == SM_QUEUE)
+                                       e->e_flags |= EF_KEEPQUEUE;
                        }
                        else
                        {
                        }
                        else
                        {
-                               /* from now on, we have to operate silently */
-                               HoldErrs = TRUE;
-                               e->e_errormode = EM_MAIL;
-
-                               /* if we just queued, poke it */
-                               if (a != NULL && e->e_sendmode != SM_QUEUE)
-                               {
-                                       unlockqueue(e);
-                                       dowork(id, TRUE, TRUE, e);
-                                       e->e_id = NULL;
-                               }
+                               /* send to all recipients */
+                               sendall(e, SM_DEFAULT);
                        }
                        }
+                       e->e_to = NULL;
 
 
-                       /* now make it really happen */
-                       if (!Verbose && e->e_sendmode != SM_QUEUE)
-                               dowork(id, TRUE, e);
+                       /* issue success message */
+                       message("250 %s Message accepted for delivery", id);
+
+                       /* if we just queued, poke it */
+                       if (doublequeue && e->e_sendmode != SM_QUEUE)
+                       {
+                               extern pid_t dowork();
+
+                               unlockqueue(e);
+                               (void) dowork(id, TRUE, TRUE, e);
+                       }
 
   abortmessage:
                        /* if in a child, pop back to our parent */
 
   abortmessage:
                        /* if in a child, pop back to our parent */
@@ -535,6 +698,10 @@ smtp(e)
 
                  case CMDRSET:         /* rset -- reset state */
                        message("250 Reset state");
 
                  case CMDRSET:         /* rset -- reset state */
                        message("250 Reset state");
+
+                       /* arrange to ignore any current send list */
+                       e->e_sendqueue = NULL;
+                       e->e_flags |= EF_CLRQUEUE;
                        if (InChild)
                                finis();
 
                        if (InChild)
                                finis();
 
@@ -551,9 +718,14 @@ smtp(e)
                                                PrivacyFlags))
                        {
                                if (vrfy)
                                                PrivacyFlags))
                        {
                                if (vrfy)
-                                       message("252 Who's to say?");
+                                       message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
                                else
                                else
-                                       message("502 That's none of your business");
+                                       message("502 Sorry, we do not allow this operation");
+#ifdef LOG
+                               if (LogLevel > 5)
+                                       syslog(LOG_INFO, "%s: %s [rejected]",
+                                               CurSmtpClient, inp);
+#endif
                                break;
                        }
                        else if (!gothello &&
                                break;
                        }
                        else if (!gothello &&
@@ -567,9 +739,47 @@ smtp(e)
                                break;
 #ifdef LOG
                        if (LogLevel > 5)
                                break;
 #ifdef LOG
                        if (LogLevel > 5)
-                               syslog(LOG_INFO, "%s: %s", CurHostName, inp);
+                               syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp);
 #endif
 #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 */
@@ -577,11 +787,19 @@ smtp(e)
                        break;
 
                  case CMDNOOP:         /* noop -- do nothing */
                        break;
 
                  case CMDNOOP:         /* noop -- do nothing */
-                       message("200 OK");
+                       message("250 OK");
                        break;
 
                  case CMDQUIT:         /* quit -- leave mail */
                        message("221 %s closing connection", MyHostName);
                        break;
 
                  case CMDQUIT:         /* quit -- leave mail */
                        message("221 %s closing connection", MyHostName);
+
+doquit:
+                       /* arrange to ignore any current send list */
+                       e->e_sendqueue = NULL;
+
+                       /* avoid future 050 messages */
+                       disconnect(1, e);
+
                        if (InChild)
                                ExitStat = EX_QUIT;
                        finis();
                        if (InChild)
                                ExitStat = EX_QUIT;
                        finis();
@@ -616,20 +834,27 @@ smtp(e)
                        break;
 
 # else /* not SMTPDEBUG */
                        break;
 
 # else /* not SMTPDEBUG */
-
                  case CMDDBGQSHOW:     /* show queues */
                  case CMDDBGDEBUG:     /* set debug mode */
                  case CMDDBGQSHOW:     /* show queues */
                  case CMDDBGDEBUG:     /* set debug mode */
+# endif /* SMTPDEBUG */
+                 case CMDLOGBOGUS:     /* bogus command */
 # ifdef LOG
                        if (LogLevel > 0)
 # ifdef LOG
                        if (LogLevel > 0)
-                               syslog(LOG_NOTICE,
+                               syslog(LOG_CRIT,
                                    "\"%s\" command from %s (%s)",
                                    "\"%s\" command from %s (%s)",
-                                   c->cmdname, RealHostName,
+                                   c->cmdname, CurSmtpClient,
                                    anynet_ntoa(&RealHostAddr));
 # endif
                        /* FALL THROUGH */
                                    anynet_ntoa(&RealHostAddr));
 # endif
                        /* FALL THROUGH */
-# endif /* SMTPDEBUG */
 
                  case CMDERROR:        /* unknown command */
 
                  case CMDERROR:        /* unknown command */
+                       if (++badcommands > MAXBADCOMMANDS)
+                       {
+                               message("421 %s Too many bad commands; closing connection",
+                                       MyHostName);
+                               goto doquit;
+                       }
+
                        message("500 Command unrecognized");
                        break;
 
                        message("500 Command unrecognized");
                        break;
 
@@ -661,6 +886,7 @@ skipword(p, w)
        char *w;
 {
        register char *q;
        char *w;
 {
        register char *q;
+       char *firstp = p;
 
        /* find beginning of word */
        while (isascii(*p) && isspace(*p))
 
        /* find beginning of word */
        while (isascii(*p) && isspace(*p))
@@ -675,7 +901,8 @@ skipword(p, w)
        if (*p != ':')
        {
          syntax:
        if (*p != ':')
        {
          syntax:
-               message("501 Syntax error");
+               message("501 Syntax error in parameters scanning \"%s\"",
+                       firstp);
                Errors++;
                return (NULL);
        }
                Errors++;
                return (NULL);
        }
@@ -683,6 +910,9 @@ skipword(p, w)
        while (isascii(*p) && isspace(*p))
                p++;
 
        while (isascii(*p) && isspace(*p))
                p++;
 
+       if (*p == '\0')
+               goto syntax;
+
        /* see if the input word matches desired word */
        if (strcasecmp(q, w))
                goto syntax;
        /* see if the input word matches desired word */
        if (strcasecmp(q, w))
                goto syntax;
@@ -690,6 +920,183 @@ skipword(p, w)
        return (p);
 }
 \f/*
        return (p);
 }
 \f/*
+**  MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
+**
+**     Parameters:
+**             kp -- the parameter key.
+**             vp -- the value of that parameter.
+**             e -- the envelope.
+**
+**     Returns:
+**             none.
+*/
+
+void
+mail_esmtp_args(kp, vp, e)
+       char *kp;
+       char *vp;
+       ENVELOPE *e;
+{
+       if (strcasecmp(kp, "size") == 0)
+       {
+               if (vp == NULL)
+               {
+                       usrerr("501 SIZE requires a value");
+                       /* NOTREACHED */
+               }
+# if defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY)
+               e->e_msgsize = strtoul(vp, (char **) NULL, 10);
+# else
+               e->e_msgsize = strtol(vp, (char **) NULL, 10);
+# endif
+       }
+       else if (strcasecmp(kp, "body") == 0)
+       {
+               if (vp == NULL)
+               {
+                       usrerr("501 BODY requires a value");
+                       /* NOTREACHED */
+               }
+               else if (strcasecmp(vp, "8bitmime") == 0)
+               {
+                       SevenBitInput = FALSE;
+               }
+               else if (strcasecmp(vp, "7bit") == 0)
+               {
+                       SevenBitInput = TRUE;
+               }
+               else
+               {
+                       usrerr("501 Unknown BODY type %s",
+                               vp);
+                       /* NOTREACHED */
+               }
+               e->e_bodytype = newstr(vp);
+       }
+       else if (strcasecmp(kp, "envid") == 0)
+       {
+               if (vp == NULL)
+               {
+                       usrerr("501 ENVID requires a value");
+                       /* NOTREACHED */
+               }
+               if (!xtextok(vp))
+               {
+                       usrerr("501 Syntax error in ENVID parameter value");
+                       /* NOTREACHED */
+               }
+               if (e->e_envid != NULL)
+               {
+                       usrerr("501 Duplicate ENVID parameter");
+                       /* NOTREACHED */
+               }
+               e->e_envid = newstr(vp);
+       }
+       else if (strcasecmp(kp, "ret") == 0)
+       {
+               if (vp == NULL)
+               {
+                       usrerr("501 RET requires a value");
+                       /* NOTREACHED */
+               }
+               if (bitset(EF_RET_PARAM, e->e_flags))
+               {
+                       usrerr("501 Duplicate RET parameter");
+                       /* NOTREACHED */
+               }
+               e->e_flags |= EF_RET_PARAM;
+               if (strcasecmp(vp, "hdrs") == 0)
+                       e->e_flags |= EF_NO_BODY_RETN;
+               else if (strcasecmp(vp, "full") != 0)
+               {
+                       usrerr("501 Bad argument \"%s\" to RET", vp);
+                       /* NOTREACHED */
+               }
+       }
+       else
+       {
+               usrerr("501 %s parameter unrecognized", kp);
+               /* NOTREACHED */
+       }
+}
+\f/*
+**  RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
+**
+**     Parameters:
+**             a -- the address corresponding to the To: parameter.
+**             kp -- the parameter key.
+**             vp -- the value of that parameter.
+**             e -- the envelope.
+**
+**     Returns:
+**             none.
+*/
+
+void
+rcpt_esmtp_args(a, kp, vp, e)
+       ADDRESS *a;
+       char *kp;
+       char *vp;
+       ENVELOPE *e;
+{
+       if (strcasecmp(kp, "notify") == 0)
+       {
+               char *p;
+
+               if (vp == NULL)
+               {
+                       usrerr("501 NOTIFY requires a value");
+                       /* NOTREACHED */
+               }
+               a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY);
+               a->q_flags |= QHASNOTIFY;
+               if (strcasecmp(vp, "never") == 0)
+                       return;
+               for (p = vp; p != NULL; vp = p)
+               {
+                       p = strchr(p, ',');
+                       if (p != NULL)
+                               *p++ = '\0';
+                       if (strcasecmp(vp, "success") == 0)
+                               a->q_flags |= QPINGONSUCCESS;
+                       else if (strcasecmp(vp, "failure") == 0)
+                               a->q_flags |= QPINGONFAILURE;
+                       else if (strcasecmp(vp, "delay") == 0)
+                               a->q_flags |= QPINGONDELAY;
+                       else
+                       {
+                               usrerr("501 Bad argument \"%s\"  to NOTIFY",
+                                       vp);
+                               /* NOTREACHED */
+                       }
+               }
+       }
+       else if (strcasecmp(kp, "orcpt") == 0)
+       {
+               if (vp == NULL)
+               {
+                       usrerr("501 ORCPT requires a value");
+                       /* NOTREACHED */
+               }
+               if (strchr(vp, ';') == NULL || !xtextok(vp))
+               {
+                       usrerr("501 Syntax error in ORCPT parameter value");
+                       /* NOTREACHED */
+               }
+               if (a->q_orcpt != NULL)
+               {
+                       usrerr("501 Duplicate ORCPT parameter");
+                       /* NOTREACHED */
+               }
+               a->q_orcpt = newstr(vp);
+       }
+       else
+       {
+               usrerr("501 %s parameter unrecognized", kp);
+               /* NOTREACHED */
+       }
+}
+\f/*
 **  PRINTVRFYADDR -- print an entry in the verify queue
 **
 **     Parameters:
 **  PRINTVRFYADDR -- print an entry in the verify queue
 **
 **     Parameters:
@@ -703,6 +1110,7 @@ skipword(p, w)
 **             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;
@@ -742,29 +1150,38 @@ printvrfyaddr(a, last)
 **             outputs the help file to message output.
 */
 
 **             outputs the help file to message output.
 */
 
+void
 help(topic)
        char *topic;
 {
        register FILE *hf;
        int len;
 help(topic)
        char *topic;
 {
        register FILE *hf;
        int len;
-       char buf[MAXLINE];
        bool noinfo;
        bool noinfo;
+       char buf[MAXLINE];
+       extern char Version[];
+
 
        if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
        {
                /* no help */
                errno = 0;
 
        if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
        {
                /* no help */
                errno = 0;
-               message("502 HELP not implemented");
+               message("502 Sendmail %s -- HELP not implemented", Version);
                return;
        }
 
        if (topic == NULL || *topic == '\0')
                return;
        }
 
        if (topic == NULL || *topic == '\0')
+       {
                topic = "smtp";
                topic = "smtp";
+               message("214-This is Sendmail version %s", Version);
+               noinfo = FALSE;
+       }
        else
        else
+       {
                makelower(topic);
                makelower(topic);
+               noinfo = TRUE;
+       }
 
        len = strlen(topic);
 
        len = strlen(topic);
-       noinfo = TRUE;
 
        while (fgets(buf, sizeof buf, hf) != NULL)
        {
 
        while (fgets(buf, sizeof buf, hf) != NULL)
        {
@@ -803,6 +1220,7 @@ help(topic)
 **             none.
 */
 
 **             none.
 */
 
+int
 runinchild(label, e)
        char *label;
        register ENVELOPE *e;
 runinchild(label, e)
        char *label;
        register ENVELOPE *e;
@@ -814,7 +1232,7 @@ runinchild(label, e)
                childpid = dofork();
                if (childpid < 0)
                {
                childpid = dofork();
                if (childpid < 0)
                {
-                       syserr("%s: cannot fork", label);
+                       syserr("451 %s: cannot fork", label);
                        return (1);
                }
                if (childpid > 0)
                        return (1);
                }
                if (childpid > 0)
@@ -822,14 +1240,20 @@ runinchild(label, e)
                        auto int st;
 
                        /* parent -- wait for child to complete */
                        auto int st;
 
                        /* parent -- wait for child to complete */
-                       setproctitle("srvrsmtp %s child wait", CurHostName);
+                       setproctitle("server %s child wait", CurSmtpClient);
                        st = waitfor(childpid);
                        if (st == -1)
                        st = waitfor(childpid);
                        if (st == -1)
-                               syserr("%s: lost child", label);
+                               syserr("451 %s: lost child", label);
+                       else if (!WIFEXITED(st))
+                               syserr("451 %s: died on signal %d",
+                                       label, st & 0177);
 
                        /* if we exited on a QUIT command, complete the process */
 
                        /* if we exited on a QUIT command, complete the process */
-                       if (st == (EX_QUIT << 8))
+                       if (WEXITSTATUS(st) == EX_QUIT)
+                       {
+                               disconnect(1, e);
                                finis();
                                finis();
+                       }
 
                        return (1);
                }
 
                        return (1);
                }
@@ -843,61 +1267,9 @@ runinchild(label, e)
        }
 
        /* open alias database */
        }
 
        /* open alias database */
-       initaliases(FALSE, e);
+       initmaps(FALSE, 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 */