summaryrefslogtreecommitdiff
path: root/usr.sbin/sendmail/src/srvrsmtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/sendmail/src/srvrsmtp.c')
-rw-r--r--usr.sbin/sendmail/src/srvrsmtp.c635
1 files changed, 444 insertions, 191 deletions
diff --git a/usr.sbin/sendmail/src/srvrsmtp.c b/usr.sbin/sendmail/src/srvrsmtp.c
index e2a09e400f52..69a4fbe35007 100644
--- a/usr.sbin/sendmail/src/srvrsmtp.c
+++ b/usr.sbin/sendmail/src/srvrsmtp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1983, 1995 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -36,9 +36,9 @@
#ifndef lint
#ifdef SMTP
-static char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (with SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (with SMTP)";
#else
-static char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (without SMTP)";
+static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (without SMTP)";
#endif
#endif /* not lint */
@@ -117,35 +117,34 @@ bool OneXact = FALSE; /* one xaction only this run */
char *CurSmtpClient; /* who's at the other end of channel */
static char *skipword();
-extern char RealUserName[];
#define MAXBADCOMMANDS 25 /* maximum number of bad commands */
+void
smtp(e)
- register ENVELOPE *e;
+ register ENVELOPE *volatile e;
{
register char *p;
register struct cmd *c;
char *cmd;
auto ADDRESS *vrfyqueue;
ADDRESS *a;
- bool gotmail; /* mail command received */
- bool gothello; /* helo command received */
+ volatile bool gotmail; /* mail command received */
+ volatile bool gothello; /* helo command received */
bool vrfy; /* set if this is a vrfy command */
- char *protocol; /* sending protocol */
- char *sendinghost; /* sending hostname */
- unsigned long msize; /* approximate maximum message size */
- char *peerhostname; /* name of SMTP peer or "localhost" */
+ char *volatile protocol; /* sending protocol */
+ char *volatile sendinghost; /* sending hostname */
+ char *volatile peerhostname; /* name of SMTP peer or "localhost" */
auto char *delimptr;
char *id;
- int nrcpts; /* number of RCPT commands */
+ volatile int nrcpts = 0; /* number of RCPT commands */
bool doublequeue;
- int badcommands = 0; /* count of bad commands */
+ volatile int badcommands = 0; /* count of bad commands */
char inp[MAXLINE];
char cmdbuf[MAXLINE];
- extern char Version[];
extern ENVELOPE BlankEnvelope;
+ extern void help __P((char *));
if (fileno(OutChannel) != fileno(stdout))
{
@@ -162,28 +161,41 @@ smtp(e)
CurSmtpClient = CurHostName;
setproctitle("server %s startup", CurSmtpClient);
- expand("\201e", inp, &inp[sizeof inp], e);
- if (BrokenSmtpPeers)
+#ifdef LOG
+ if (LogLevel > 11)
{
- p = strchr(inp, '\n');
- if (p != NULL)
- *p = '\0';
- message("220 %s", inp);
+ /* log connection information */
+ syslog(LOG_INFO, "SMTP connect from %.100s (%.100s)",
+ CurSmtpClient, anynet_ntoa(&RealHostAddr));
}
- else
- {
- char *q = inp;
+#endif
- while (q != NULL)
- {
- p = strchr(q, '\n');
- if (p != NULL)
- *p++ = '\0';
- message("220-%s", q);
- q = p;
- }
- message("220 ESMTP spoken here");
+ /* output the first line, inserting "ESMTP" as second word */
+ expand(SmtpGreeting, 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;
@@ -213,7 +225,7 @@ smtp(e)
/* 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);
@@ -226,7 +238,7 @@ smtp(e)
MyHostName, CurSmtpClient);
#ifdef LOG
if (LogLevel > (gotmail ? 1 : 19))
- syslog(LOG_NOTICE, "lost input channel from %s",
+ syslog(LOG_NOTICE, "lost input channel from %.100s",
CurSmtpClient);
#endif
if (InChild)
@@ -285,6 +297,39 @@ smtp(e)
protocol = "SMTP";
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 (isspace(*q))
+ {
+ *q = '\0';
+ break;
+ }
+ if (strchr("[].-_#", *q) == NULL)
+ break;
+ }
+ if (*q != '\0')
+ {
+ message("501 Invalid domain name");
+ break;
+ }
+ }
+
sendinghost = newstr(p);
gothello = TRUE;
if (c->cmdcode != CMDEHLO)
@@ -300,10 +345,19 @@ smtp(e)
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
+ if (SendMIMEErrors)
+ message("250-DSN");
+#endif
+ message("250-VERB");
+ message("250-ONEX");
message("250 HELP");
break;
@@ -344,7 +398,7 @@ smtp(e)
{
auth_warning(e,
"Host %s didn't use HELO protocol",
- peerhostname);
+ CurSmtpClient);
}
#ifdef PICKY_HELO_CHECK
if (strcasecmp(sendinghost, peerhostname) != 0 &&
@@ -352,7 +406,7 @@ smtp(e)
strcasecmp(sendinghost, MyHostName) != 0))
{
auth_warning(e, "Host %s claimed to be %s",
- peerhostname, sendinghost);
+ CurSmtpClient, sendinghost);
}
#endif
@@ -362,7 +416,7 @@ smtp(e)
define('s', sendinghost, e);
initsys(e);
nrcpts = 0;
- e->e_flags |= EF_LOGSENDER;
+ e->e_flags |= EF_LOGSENDER|EF_CLRQUEUE;
setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp);
/* child -- go do the processing */
@@ -392,19 +446,21 @@ smtp(e)
/* check for possible spoofing */
if (RealUid != 0 && OpMode == MD_SMTP &&
- (e->e_from.q_mailer != LocalMailer &&
- strcmp(e->e_from.q_user, RealUserName) != 0))
+ !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 */
- msize = 0;
+ e->e_msgsize = 0;
while (p != NULL && *p != '\0')
{
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))
@@ -435,59 +491,17 @@ smtp(e)
printf("MAIL: got arg %s=\"%s\"\n", kp,
vp == NULL ? "<null>" : vp);
- if (strcasecmp(kp, "size") == 0)
- {
- if (vp == NULL)
- {
- usrerr("501 SIZE requires a value");
- /* NOTREACHED */
- }
-# ifdef __STDC__
- msize = strtoul(vp, (char **) NULL, 10);
-# else
- msize = strtol(vp, (char **) NULL, 10);
-# endif
- }
- 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 */
}
-
- if (!enoughspace(msize))
+
+ if (!enoughdiskspace(e->e_msgsize))
{
message("452 Insufficient disk space; try again later");
break;
@@ -517,11 +531,53 @@ smtp(e)
p = skipword(p, "to");
if (p == NULL)
break;
- a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', NULL, e);
+ a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e);
if (a == NULL)
break;
- a->q_flags |= QPRIMARY;
- a = recipient(a, &e->e_sendqueue, e);
+ 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;
@@ -575,10 +631,18 @@ smtp(e)
/* collect the text of the message */
SmtpPhase = "collect";
- collect(TRUE, doublequeue, e);
+ buffer_errors();
+ collect(InChannel, TRUE, doublequeue, NULL, e);
+ flush_errors(TRUE);
if (Errors != 0)
goto abortmessage;
- HoldErrs = TRUE;
+
+ /* 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.
@@ -599,42 +663,32 @@ smtp(e)
*/
SmtpPhase = "delivery";
- if (nrcpts != 1 && !doublequeue)
- {
- HoldErrs = TRUE;
- e->e_errormode = EM_MAIL;
- }
e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
id = e->e_id;
- /* send to all recipients */
- sendall(e, doublequeue ? SM_QUEUE : SM_DEFAULT);
- e->e_to = NULL;
-
- /* 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, FALSE);
}
else
{
- /* from now on, we have to operate silently */
- HoldErrs = TRUE;
- e->e_errormode = EM_MAIL;
+ /* send to all recipients */
+ sendall(e, SM_DEFAULT);
+ }
+ e->e_to = NULL;
- /* if we just queued, poke it */
- if (doublequeue && e->e_sendmode != SM_QUEUE)
- {
- extern pid_t dowork();
+ /* issue success message */
+ message("250 %s Message accepted for delivery", id);
- unlockqueue(e);
- (void) dowork(id, TRUE, TRUE, e);
- }
+ /* if we just queued, poke it */
+ if (doublequeue && e->e_sendmode != SM_QUEUE &&
+ e->e_sendmode != SM_DEFER)
+ {
+ extern pid_t dowork();
+
+ unlockqueue(e);
+ (void) dowork(id, TRUE, TRUE, e);
}
abortmessage:
@@ -651,6 +705,9 @@ smtp(e)
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();
@@ -668,13 +725,14 @@ smtp(e)
PrivacyFlags))
{
if (vrfy)
- message("252 Who's to say?");
+ message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
else
message("502 Sorry, we do not allow this operation");
#ifdef LOG
if (LogLevel > 5)
- syslog(LOG_INFO, "%s: %s [rejected]",
- CurSmtpClient, inp);
+ syslog(LOG_INFO, "%.100s: %s [rejected]",
+ CurSmtpClient,
+ shortenstring(inp, 203));
#endif
break;
}
@@ -689,14 +747,16 @@ smtp(e)
break;
#ifdef LOG
if (LogLevel > 5)
- syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp);
+ syslog(LOG_INFO, "%.100s: %s",
+ CurSmtpClient,
+ shortenstring(inp, 203));
#endif
vrfyqueue = NULL;
QuickAbort = TRUE;
if (vrfy)
e->e_flags |= EF_VRFYONLY;
while (*p != '\0' && isascii(*p) && isspace(*p))
- *p++;
+ p++;
if (*p == '\0')
{
message("501 Argument required");
@@ -704,7 +764,7 @@ smtp(e)
}
else
{
- (void) sendtolist(p, NULLADDR, &vrfyqueue, e);
+ (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
}
if (Errors != 0)
{
@@ -718,6 +778,8 @@ smtp(e)
}
while (vrfyqueue != NULL)
{
+ extern void printvrfyaddr __P((ADDRESS *, bool));
+
a = vrfyqueue;
while ((a = a->q_next) != NULL &&
bitset(QDONTSEND|QBADADDR, a->q_flags))
@@ -742,6 +804,9 @@ smtp(e)
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);
@@ -786,8 +851,8 @@ doquit:
# ifdef LOG
if (LogLevel > 0)
syslog(LOG_CRIT,
- "\"%s\" command from %s (%s)",
- c->cmdname, peerhostname,
+ "\"%s\" command from %.100s (%.100s)",
+ c->cmdname, CurSmtpClient,
anynet_ntoa(&RealHostAddr));
# endif
/* FALL THROUGH */
@@ -847,7 +912,7 @@ skipword(p, w)
{
syntax:
message("501 Syntax error in parameters scanning \"%s\"",
- firstp);
+ shortenstring(firstp, 203));
Errors++;
return (NULL);
}
@@ -865,6 +930,183 @@ skipword(p, w)
return (p);
}
/*
+** 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 */
+ }
+}
+ /*
+** 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 */
+ }
+}
+ /*
** PRINTVRFYADDR -- print an entry in the verify queue
**
** Parameters:
@@ -878,6 +1120,7 @@ skipword(p, w)
** Prints the appropriate 250 codes.
*/
+void
printvrfyaddr(a, last)
register ADDRESS *a;
bool last;
@@ -905,66 +1148,6 @@ printvrfyaddr(a, last)
}
}
/*
-** HELP -- implement the HELP command.
-**
-** Parameters:
-** topic -- the topic we want help for.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** outputs the help file to message output.
-*/
-
-help(topic)
- char *topic;
-{
- register FILE *hf;
- int len;
- char buf[MAXLINE];
- bool noinfo;
-
- if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
- {
- /* no help */
- errno = 0;
- message("502 HELP not implemented");
- return;
- }
-
- if (topic == NULL || *topic == '\0')
- topic = "smtp";
- else
- makelower(topic);
-
- len = strlen(topic);
- noinfo = TRUE;
-
- while (fgets(buf, sizeof buf, hf) != NULL)
- {
- if (strncmp(buf, topic, len) == 0)
- {
- register char *p;
-
- p = strchr(buf, '\t');
- if (p == NULL)
- p = buf;
- else
- p++;
- fixcrlf(p, TRUE);
- message("214-%s", p);
- noinfo = FALSE;
- }
- }
-
- if (noinfo)
- message("504 HELP topic unknown");
- else
- message("214 End of HELP info");
- (void) fclose(hf);
-}
- /*
** RUNINCHILD -- return twice -- once in the child, then in the parent again
**
** Parameters:
@@ -978,6 +1161,7 @@ help(topic)
** none.
*/
+int
runinchild(label, e)
char *label;
register ENVELOPE *e;
@@ -989,7 +1173,7 @@ runinchild(label, e)
childpid = dofork();
if (childpid < 0)
{
- syserr("%s: cannot fork", label);
+ syserr("451 %s: cannot fork", label);
return (1);
}
if (childpid > 0)
@@ -997,12 +1181,12 @@ runinchild(label, e)
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("%s: lost child", label);
+ syserr("451 %s: lost child", label);
else if (!WIFEXITED(st))
- syserr("%s: died on signal %d",
+ syserr("451 %s: died on signal %d",
label, st & 0177);
/* if we exited on a QUIT command, complete the process */
@@ -1030,3 +1214,72 @@ runinchild(label, e)
}
# endif /* SMTP */
+ /*
+** HELP -- implement the HELP command.
+**
+** Parameters:
+** topic -- the topic we want help for.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** outputs the help file to message output.
+*/
+
+void
+help(topic)
+ char *topic;
+{
+ register FILE *hf;
+ int len;
+ bool noinfo;
+ char buf[MAXLINE];
+ extern char Version[];
+
+
+ if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
+ {
+ /* no help */
+ errno = 0;
+ message("502 Sendmail %s -- HELP not implemented", Version);
+ return;
+ }
+
+ if (topic == NULL || *topic == '\0')
+ {
+ topic = "smtp";
+ message("214-This is Sendmail version %s", Version);
+ noinfo = FALSE;
+ }
+ else
+ {
+ makelower(topic);
+ noinfo = TRUE;
+ }
+
+ len = strlen(topic);
+
+ while (fgets(buf, sizeof buf, hf) != NULL)
+ {
+ if (strncmp(buf, topic, len) == 0)
+ {
+ register char *p;
+
+ p = strchr(buf, '\t');
+ if (p == NULL)
+ p = buf;
+ else
+ p++;
+ fixcrlf(p, TRUE);
+ message("214-%s", p);
+ noinfo = FALSE;
+ }
+ }
+
+ if (noinfo)
+ message("504 HELP topic \"%.10s\" unknown", topic);
+ else
+ message("214 End of HELP info");
+ (void) fclose(hf);
+}