1*22712Sdist /*
2*22712Sdist **  Sendmail
3*22712Sdist **  Copyright (c) 1983  Eric P. Allman
4*22712Sdist **  Berkeley, California
5*22712Sdist **
6*22712Sdist **  Copyright (c) 1983 Regents of the University of California.
7*22712Sdist **  All rights reserved.  The Berkeley software License Agreement
8*22712Sdist **  specifies the terms and conditions for redistribution.
9*22712Sdist */
10*22712Sdist 
11*22712Sdist #ifndef lint
12*22712Sdist static char	SccsId[] = "@(#)srvrsmtp.c	5.1 (Berkeley) 06/07/85";
13*22712Sdist #endif not lint
14*22712Sdist 
159339Seric # include <errno.h>
164549Seric # include "sendmail.h"
1711728Seric # include <signal.h>
184549Seric 
195181Seric # ifndef SMTP
20*22712Sdist SCCSID(@(#)srvrsmtp.c	5.1		06/07/85	(no SMTP));
215181Seric # else SMTP
224556Seric 
23*22712Sdist SCCSID(@(#)srvrsmtp.c	5.1		06/07/85);
245181Seric 
254549Seric /*
264549Seric **  SMTP -- run the SMTP protocol.
274549Seric **
284549Seric **	Parameters:
294549Seric **		none.
304549Seric **
314549Seric **	Returns:
324549Seric **		never.
334549Seric **
344549Seric **	Side Effects:
354549Seric **		Reads commands from the input channel and processes
364549Seric **			them.
374549Seric */
384549Seric 
394549Seric struct cmd
404549Seric {
414549Seric 	char	*cmdname;	/* command name */
424549Seric 	int	cmdcode;	/* internal code, see below */
434549Seric };
444549Seric 
454549Seric /* values for cmdcode */
464549Seric # define CMDERROR	0	/* bad command */
474549Seric # define CMDMAIL	1	/* mail -- designate sender */
484976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
494549Seric # define CMDDATA	3	/* data -- send message text */
509339Seric # define CMDRSET	4	/* rset -- reset state */
519339Seric # define CMDVRFY	5	/* vrfy -- verify address */
529339Seric # define CMDHELP	6	/* help -- give usage info */
539339Seric # define CMDNOOP	7	/* noop -- do nothing */
549339Seric # define CMDQUIT	8	/* quit -- close connection and die */
559339Seric # define CMDHELO	9	/* helo -- be polite */
569339Seric # define CMDDBGQSHOW	10	/* showq -- show send queue (DEBUG) */
579339Seric # define CMDDBGDEBUG	11	/* debug -- set debug mode */
589339Seric # define CMDVERB	12	/* verb -- go into verbose mode */
599339Seric # define CMDDBGKILL	13	/* kill -- kill sendmail */
609339Seric # define CMDDBGWIZ	14	/* wiz -- become a wizard */
619339Seric # define CMDONEX	15	/* onex -- sending one transaction only */
624549Seric 
634549Seric static struct cmd	CmdTab[] =
644549Seric {
654549Seric 	"mail",		CMDMAIL,
664976Seric 	"rcpt",		CMDRCPT,
674549Seric 	"data",		CMDDATA,
684549Seric 	"rset",		CMDRSET,
694549Seric 	"vrfy",		CMDVRFY,
707762Seric 	"expn",		CMDVRFY,
714549Seric 	"help",		CMDHELP,
724549Seric 	"noop",		CMDNOOP,
734549Seric 	"quit",		CMDQUIT,
744976Seric 	"helo",		CMDHELO,
758544Seric 	"verb",		CMDVERB,
769314Seric 	"onex",		CMDONEX,
775003Seric # ifdef DEBUG
789339Seric 	"showq",	CMDDBGQSHOW,
798544Seric 	"debug",	CMDDBGDEBUG,
808544Seric 	"kill",		CMDDBGKILL,
818544Seric 	"wiz",		CMDDBGWIZ,
825003Seric # endif DEBUG
834549Seric 	NULL,		CMDERROR,
844549Seric };
854549Seric 
868544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
8715596Seric char	*WizWord;			/* the wizard word to compare against */
889339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
899378Seric bool	OneXact = FALSE;		/* one xaction only this run */
9011146Seric char	*RealHostName = NULL;		/* verified hostname, set in daemon.c */
9111146Seric 
929339Seric #define EX_QUIT		22		/* special code for QUIT command */
938544Seric 
944549Seric smtp()
954549Seric {
964549Seric 	register char *p;
978544Seric 	register struct cmd *c;
984549Seric 	char *cmd;
994549Seric 	extern char *skipword();
1004549Seric 	extern bool sameword();
1014549Seric 	bool hasmail;			/* mail command received */
1024713Seric 	int rcps;			/* number of recipients */
1035003Seric 	auto ADDRESS *vrfyqueue;
10412612Seric 	ADDRESS *a;
1058544Seric 	char inp[MAXLINE];
1067124Seric 	extern char Version[];
1077356Seric 	extern tick();
1088544Seric 	extern bool iswiz();
1099349Seric 	extern char *arpadate();
11011151Seric 	extern char *macvalue();
11112612Seric 	extern ADDRESS *recipient();
1124549Seric 
1135003Seric 	hasmail = FALSE;
1144713Seric 	rcps = 0;
1157363Seric 	if (OutChannel != stdout)
1167363Seric 	{
1177363Seric 		/* arrange for debugging output to go to remote host */
1187363Seric 		(void) close(1);
1197363Seric 		(void) dup(fileno(OutChannel));
1207363Seric 	}
12111931Seric 	settime();
12216153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
12310708Seric 	message("220", inp);
1244549Seric 	for (;;)
1254549Seric 	{
12612612Seric 		/* arrange for backout */
12712612Seric 		if (setjmp(TopFrame) > 0 && InChild)
12812612Seric 			finis();
12912612Seric 		QuickAbort = FALSE;
13012612Seric 		HoldErrs = FALSE;
13112612Seric 
1327356Seric 		/* setup for the read */
1336907Seric 		CurEnv->e_to = NULL;
1344577Seric 		Errors = 0;
1357275Seric 		(void) fflush(stdout);
1367356Seric 
1377356Seric 		/* read the input line */
1387685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1397356Seric 
1407685Seric 		/* handle errors */
1417356Seric 		if (p == NULL)
1427356Seric 		{
1434549Seric 			/* end of file, just die */
1444558Seric 			message("421", "%s Lost input channel", HostName);
1454549Seric 			finis();
1464549Seric 		}
1474549Seric 
1484549Seric 		/* clean up end of line */
1494558Seric 		fixcrlf(inp, TRUE);
1504549Seric 
1514713Seric 		/* echo command to transcript */
1529545Seric 		if (CurEnv->e_xfp != NULL)
1539545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1544713Seric 
1554549Seric 		/* break off command */
1564549Seric 		for (p = inp; isspace(*p); p++)
1574549Seric 			continue;
1584549Seric 		cmd = p;
1594549Seric 		while (*++p != '\0' && !isspace(*p))
1604549Seric 			continue;
1614549Seric 		if (*p != '\0')
1624549Seric 			*p++ = '\0';
1634549Seric 
1644549Seric 		/* decode command */
1654549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1664549Seric 		{
1674549Seric 			if (sameword(c->cmdname, cmd))
1684549Seric 				break;
1694549Seric 		}
1704549Seric 
1714549Seric 		/* process command */
1724549Seric 		switch (c->cmdcode)
1734549Seric 		{
1744976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
17514877Seric 			if (sameword(p, HostName))
17614877Seric 			{
17714877Seric 				/* connected to an echo server */
17814877Seric 				message("553", "%s I refuse to talk to myself",
17914877Seric 					HostName);
18014877Seric 				break;
18114877Seric 			}
18211146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
18311146Seric 			{
18411146Seric 				char buf[MAXNAME];
18511146Seric 
18611146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
18711146Seric 				define('s', newstr(buf), CurEnv);
18811146Seric 			}
18911146Seric 			else
19011146Seric 				define('s', newstr(p), CurEnv);
1914997Seric 			message("250", "%s Hello %s, pleased to meet you",
1924997Seric 				HostName, p);
1934976Seric 			break;
1944976Seric 
1954549Seric 		  case CMDMAIL:		/* mail -- designate sender */
19611151Seric 			/* force a sending host even if no HELO given */
19711151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
19811151Seric 				define('s', RealHostName, CurEnv);
19911151Seric 
2009314Seric 			/* check for validity of this command */
2014558Seric 			if (hasmail)
2024558Seric 			{
2034558Seric 				message("503", "Sender already specified");
2044558Seric 				break;
2054558Seric 			}
2069339Seric 			if (InChild)
2079339Seric 			{
2089339Seric 				syserr("Nested MAIL command");
2099339Seric 				exit(0);
2109339Seric 			}
2119339Seric 
2129339Seric 			/* fork a subprocess to process this command */
2139339Seric 			if (runinchild("SMTP-MAIL") > 0)
2149339Seric 				break;
2159339Seric 			initsys();
2169339Seric 
2179339Seric 			/* child -- go do the processing */
2184549Seric 			p = skipword(p, "from");
2194549Seric 			if (p == NULL)
2204549Seric 				break;
2214549Seric 			setsender(p);
2224577Seric 			if (Errors == 0)
2234549Seric 			{
2244549Seric 				message("250", "Sender ok");
2254549Seric 				hasmail = TRUE;
2264549Seric 			}
2279339Seric 			else if (InChild)
2289339Seric 				finis();
2294549Seric 			break;
2304549Seric 
2314976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
23212612Seric 			if (setjmp(TopFrame) > 0)
23314785Seric 			{
23414785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
23512612Seric 				break;
23614785Seric 			}
23712612Seric 			QuickAbort = TRUE;
2384549Seric 			p = skipword(p, "to");
2394549Seric 			if (p == NULL)
2404549Seric 				break;
24116140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
24212612Seric 			if (a == NULL)
24312612Seric 				break;
24416886Seric 			a->q_flags |= QPRIMARY;
24512612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
24612612Seric 			if (Errors != 0)
24712612Seric 				break;
24812612Seric 
24912612Seric 			/* no errors during parsing, but might be a duplicate */
25012612Seric 			CurEnv->e_to = p;
25112612Seric 			if (!bitset(QBADADDR, a->q_flags))
25212612Seric 				message("250", "Recipient ok");
25312612Seric 			else
2544549Seric 			{
25512612Seric 				/* punt -- should keep message in ADDRESS.... */
25612612Seric 				message("550", "Addressee unknown");
2574549Seric 			}
25812612Seric 			CurEnv->e_to = NULL;
25912612Seric 			rcps++;
2604549Seric 			break;
2614549Seric 
2624549Seric 		  case CMDDATA:		/* data -- text of mail */
2634976Seric 			if (!hasmail)
2644549Seric 			{
2654976Seric 				message("503", "Need MAIL command");
2664976Seric 				break;
2674549Seric 			}
2684713Seric 			else if (rcps <= 0)
2694549Seric 			{
2704976Seric 				message("503", "Need RCPT (recipient)");
2714976Seric 				break;
2724549Seric 			}
2734976Seric 
2744976Seric 			/* collect the text of the message */
2754976Seric 			collect(TRUE);
2764976Seric 			if (Errors != 0)
2774976Seric 				break;
2784976Seric 
2798238Seric 			/*
2808238Seric 			**  Arrange to send to everyone.
2818238Seric 			**	If sending to multiple people, mail back
2828238Seric 			**		errors rather than reporting directly.
2838238Seric 			**	In any case, don't mail back errors for
2848238Seric 			**		anything that has happened up to
2858238Seric 			**		now (the other end will do this).
28610197Seric 			**	Truncate our transcript -- the mail has gotten
28710197Seric 			**		to us successfully, and if we have
28810197Seric 			**		to mail this back, it will be easier
28910197Seric 			**		on the reader.
2908238Seric 			**	Then send to everyone.
2918238Seric 			**	Finally give a reply code.  If an error has
2928238Seric 			**		already been given, don't mail a
2938238Seric 			**		message back.
2949339Seric 			**	We goose error returns by clearing error bit.
2958238Seric 			*/
2968238Seric 
2974976Seric 			if (rcps != 1)
2989378Seric 			{
2999378Seric 				HoldErrs = TRUE;
30016886Seric 				ErrorMode = EM_MAIL;
3019378Seric 			}
3029339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
30310197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3044976Seric 
3054976Seric 			/* send to all recipients */
30614877Seric 			sendall(CurEnv, SM_DEFAULT);
3076907Seric 			CurEnv->e_to = NULL;
3084976Seric 
3098238Seric 			/* issue success if appropriate and reset */
3108238Seric 			if (Errors == 0 || HoldErrs)
3119283Seric 				message("250", "Ok");
3128238Seric 			else
3139339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3149339Seric 
3159339Seric 			/* if in a child, pop back to our parent */
3169339Seric 			if (InChild)
3179339Seric 				finis();
3184549Seric 			break;
3194549Seric 
3204549Seric 		  case CMDRSET:		/* rset -- reset state */
3214549Seric 			message("250", "Reset state");
3229339Seric 			if (InChild)
3239339Seric 				finis();
3249339Seric 			break;
3254549Seric 
3264549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3279339Seric 			if (runinchild("SMTP-VRFY") > 0)
3289339Seric 				break;
3295003Seric 			vrfyqueue = NULL;
3307762Seric 			QuickAbort = TRUE;
3319619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3327762Seric 			if (Errors != 0)
3339339Seric 			{
3349339Seric 				if (InChild)
3359339Seric 					finis();
3367762Seric 				break;
3379339Seric 			}
3385003Seric 			while (vrfyqueue != NULL)
3395003Seric 			{
3405003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3415003Seric 				char *code;
3425003Seric 
3437685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3445003Seric 					a = a->q_next;
3455003Seric 
3467685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3475003Seric 				{
3485003Seric 					if (a != NULL)
3495003Seric 						code = "250-";
3505003Seric 					else
3515003Seric 						code = "250";
3525003Seric 					if (vrfyqueue->q_fullname == NULL)
3535003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3545003Seric 					else
3555003Seric 						message(code, "%s <%s>",
3565003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3575003Seric 				}
3585003Seric 				else if (a == NULL)
3595003Seric 					message("554", "Self destructive alias loop");
3605003Seric 				vrfyqueue = a;
3615003Seric 			}
3629339Seric 			if (InChild)
3639339Seric 				finis();
3644549Seric 			break;
3654549Seric 
3664549Seric 		  case CMDHELP:		/* help -- give user info */
3674577Seric 			if (*p == '\0')
3684577Seric 				p = "SMTP";
3694577Seric 			help(p);
3704549Seric 			break;
3714549Seric 
3724549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3734549Seric 			message("200", "OK");
3744549Seric 			break;
3754549Seric 
3764549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3774549Seric 			message("221", "%s closing connection", HostName);
3789339Seric 			if (InChild)
3799339Seric 				ExitStat = EX_QUIT;
3804549Seric 			finis();
3814549Seric 
3828544Seric 		  case CMDVERB:		/* set verbose mode */
3838544Seric 			Verbose = TRUE;
3848544Seric 			message("200", "Verbose mode");
3858544Seric 			break;
3868544Seric 
3879314Seric 		  case CMDONEX:		/* doing one transaction only */
3889378Seric 			OneXact = TRUE;
3899314Seric 			message("200", "Only one transaction");
3909314Seric 			break;
3919314Seric 
3925003Seric # ifdef DEBUG
3939339Seric 		  case CMDDBGQSHOW:	/* show queues */
3946907Seric 			printf("Send Queue=");
3956907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3965003Seric 			break;
3977275Seric 
3987275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3997676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4007676Seric 			tTflag(p);
4017676Seric 			message("200", "Debug set");
4027275Seric 			break;
4037275Seric 
4047282Seric 		  case CMDDBGKILL:	/* kill the parent */
4058544Seric 			if (!iswiz())
4068544Seric 				break;
4077282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4087282Seric 				message("200", "Mother is dead");
4097282Seric 			else
4107282Seric 				message("500", "Can't kill Mom");
4117282Seric 			break;
4128544Seric 
4138544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4148544Seric 			if (WizWord != NULL)
4158544Seric 			{
4168544Seric 				char seed[3];
4178544Seric 				extern char *crypt();
4188544Seric 
4198544Seric 				strncpy(seed, WizWord, 2);
42015596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4218544Seric 				{
42215596Seric 					IsWiz = TRUE;
42315596Seric 					message("200", "Please pass, oh mighty wizard");
4248544Seric 					break;
4258544Seric 				}
4268544Seric 			}
42715596Seric 			message("500", "You are no wizard!");
4288544Seric 			break;
4295003Seric # endif DEBUG
4305003Seric 
4314549Seric 		  case CMDERROR:	/* unknown command */
4324549Seric 			message("500", "Command unrecognized");
4334549Seric 			break;
4344549Seric 
4354549Seric 		  default:
4364549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4374549Seric 			break;
4384549Seric 		}
4394549Seric 	}
4404549Seric }
4414549Seric /*
4424549Seric **  SKIPWORD -- skip a fixed word.
4434549Seric **
4444549Seric **	Parameters:
4454549Seric **		p -- place to start looking.
4464549Seric **		w -- word to skip.
4474549Seric **
4484549Seric **	Returns:
4494549Seric **		p following w.
4504549Seric **		NULL on error.
4514549Seric **
4524549Seric **	Side Effects:
4534549Seric **		clobbers the p data area.
4544549Seric */
4554549Seric 
4564549Seric static char *
4574549Seric skipword(p, w)
4584549Seric 	register char *p;
4594549Seric 	char *w;
4604549Seric {
4614549Seric 	register char *q;
4624549Seric 	extern bool sameword();
4634549Seric 
4644549Seric 	/* find beginning of word */
4654549Seric 	while (isspace(*p))
4664549Seric 		p++;
4674549Seric 	q = p;
4684549Seric 
4694549Seric 	/* find end of word */
4704549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4714549Seric 		p++;
4724549Seric 	while (isspace(*p))
4734549Seric 		*p++ = '\0';
4744549Seric 	if (*p != ':')
4754549Seric 	{
4764549Seric 	  syntax:
4774549Seric 		message("501", "Syntax error");
4784549Seric 		Errors++;
4794549Seric 		return (NULL);
4804549Seric 	}
4814549Seric 	*p++ = '\0';
4824549Seric 	while (isspace(*p))
4834549Seric 		p++;
4844549Seric 
4854549Seric 	/* see if the input word matches desired word */
4864549Seric 	if (!sameword(q, w))
4874549Seric 		goto syntax;
4884549Seric 
4894549Seric 	return (p);
4904549Seric }
4914577Seric /*
4924577Seric **  HELP -- implement the HELP command.
4934577Seric **
4944577Seric **	Parameters:
4954577Seric **		topic -- the topic we want help for.
4964577Seric **
4974577Seric **	Returns:
4984577Seric **		none.
4994577Seric **
5004577Seric **	Side Effects:
5014577Seric **		outputs the help file to message output.
5024577Seric */
5034577Seric 
5044577Seric help(topic)
5054577Seric 	char *topic;
5064577Seric {
5074577Seric 	register FILE *hf;
5084577Seric 	int len;
5094577Seric 	char buf[MAXLINE];
5104577Seric 	bool noinfo;
5114577Seric 
5128269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5134577Seric 	{
5144577Seric 		/* no help */
51511931Seric 		errno = 0;
5164577Seric 		message("502", "HELP not implemented");
5174577Seric 		return;
5184577Seric 	}
5194577Seric 
5204577Seric 	len = strlen(topic);
5214577Seric 	makelower(topic);
5224577Seric 	noinfo = TRUE;
5234577Seric 
5244577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5254577Seric 	{
5264577Seric 		if (strncmp(buf, topic, len) == 0)
5274577Seric 		{
5284577Seric 			register char *p;
5294577Seric 
5304577Seric 			p = index(buf, '\t');
5314577Seric 			if (p == NULL)
5324577Seric 				p = buf;
5334577Seric 			else
5344577Seric 				p++;
5354577Seric 			fixcrlf(p, TRUE);
5364577Seric 			message("214-", p);
5374577Seric 			noinfo = FALSE;
5384577Seric 		}
5394577Seric 	}
5404577Seric 
5414577Seric 	if (noinfo)
5424577Seric 		message("504", "HELP topic unknown");
5434577Seric 	else
5444577Seric 		message("214", "End of HELP info");
5454628Seric 	(void) fclose(hf);
5464577Seric }
5478544Seric /*
5488544Seric **  ISWIZ -- tell us if we are a wizard
5498544Seric **
5508544Seric **	If not, print a nasty message.
5518544Seric **
5528544Seric **	Parameters:
5538544Seric **		none.
5548544Seric **
5558544Seric **	Returns:
5568544Seric **		TRUE if we are a wizard.
5578544Seric **		FALSE if we are not a wizard.
5588544Seric **
5598544Seric **	Side Effects:
5608544Seric **		Prints a 500 exit stat if we are not a wizard.
5618544Seric */
5625181Seric 
56319038Seric #ifdef DEBUG
56419038Seric 
5658544Seric bool
5668544Seric iswiz()
5678544Seric {
5688544Seric 	if (!IsWiz)
5698544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5708544Seric 	return (IsWiz);
5718544Seric }
57219038Seric 
57319038Seric #endif DEBUG
5749339Seric /*
5759339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5769339Seric **
5779339Seric **	Parameters:
5789339Seric **		label -- a string used in error messages
5799339Seric **
5809339Seric **	Returns:
5819339Seric **		zero in the child
5829339Seric **		one in the parent
5839339Seric **
5849339Seric **	Side Effects:
5859339Seric **		none.
5869339Seric */
5878544Seric 
5889339Seric runinchild(label)
5899339Seric 	char *label;
5909339Seric {
5919339Seric 	int childpid;
5929339Seric 
59316158Seric 	if (!OneXact)
5949339Seric 	{
59516158Seric 		childpid = dofork();
59616158Seric 		if (childpid < 0)
59716158Seric 		{
59816158Seric 			syserr("%s: cannot fork", label);
59916158Seric 			return (1);
60016158Seric 		}
60116158Seric 		if (childpid > 0)
60216158Seric 		{
60316158Seric 			auto int st;
6049339Seric 
60516158Seric 			/* parent -- wait for child to complete */
60616158Seric 			st = waitfor(childpid);
60716158Seric 			if (st == -1)
60816158Seric 				syserr("%s: lost child", label);
6099339Seric 
61016158Seric 			/* if we exited on a QUIT command, complete the process */
61116158Seric 			if (st == (EX_QUIT << 8))
61216158Seric 				finis();
6139339Seric 
61416158Seric 			return (1);
61516158Seric 		}
61616158Seric 		else
61716158Seric 		{
61816158Seric 			/* child */
61916158Seric 			InChild = TRUE;
62016158Seric 		}
6219339Seric 	}
62215256Seric 
62316158Seric 	/* child (or ONEX command specified) */
62416158Seric 	clearenvelope(CurEnv);
62515256Seric 
62616158Seric 	/* open alias database */
62716158Seric 	initaliases(AliasFile, FALSE);
62816158Seric 
62916158Seric 	return (0);
6309339Seric }
6319339Seric 
6325181Seric # endif SMTP
633