122712Sdist /*
222712Sdist **  Sendmail
322712Sdist **  Copyright (c) 1983  Eric P. Allman
422712Sdist **  Berkeley, California
522712Sdist **
622712Sdist **  Copyright (c) 1983 Regents of the University of California.
722712Sdist **  All rights reserved.  The Berkeley software License Agreement
822712Sdist **  specifies the terms and conditions for redistribution.
922712Sdist */
1022712Sdist 
1122712Sdist 
129339Seric # include <errno.h>
134549Seric # include "sendmail.h"
1411728Seric # include <signal.h>
154549Seric 
165181Seric # ifndef SMTP
17*23106Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.3 (Berkeley) 06/08/85	(no SMTP)";
185181Seric # else SMTP
194556Seric 
20*23106Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.3 (Berkeley) 06/08/85";
215181Seric 
224549Seric /*
234549Seric **  SMTP -- run the SMTP protocol.
244549Seric **
254549Seric **	Parameters:
264549Seric **		none.
274549Seric **
284549Seric **	Returns:
294549Seric **		never.
304549Seric **
314549Seric **	Side Effects:
324549Seric **		Reads commands from the input channel and processes
334549Seric **			them.
344549Seric */
354549Seric 
364549Seric struct cmd
374549Seric {
384549Seric 	char	*cmdname;	/* command name */
394549Seric 	int	cmdcode;	/* internal code, see below */
404549Seric };
414549Seric 
424549Seric /* values for cmdcode */
434549Seric # define CMDERROR	0	/* bad command */
444549Seric # define CMDMAIL	1	/* mail -- designate sender */
454976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
464549Seric # define CMDDATA	3	/* data -- send message text */
479339Seric # define CMDRSET	4	/* rset -- reset state */
489339Seric # define CMDVRFY	5	/* vrfy -- verify address */
499339Seric # define CMDHELP	6	/* help -- give usage info */
509339Seric # define CMDNOOP	7	/* noop -- do nothing */
519339Seric # define CMDQUIT	8	/* quit -- close connection and die */
529339Seric # define CMDHELO	9	/* helo -- be polite */
539339Seric # define CMDDBGQSHOW	10	/* showq -- show send queue (DEBUG) */
549339Seric # define CMDDBGDEBUG	11	/* debug -- set debug mode */
559339Seric # define CMDVERB	12	/* verb -- go into verbose mode */
569339Seric # define CMDDBGKILL	13	/* kill -- kill sendmail */
579339Seric # define CMDDBGWIZ	14	/* wiz -- become a wizard */
589339Seric # define CMDONEX	15	/* onex -- sending one transaction only */
594549Seric 
604549Seric static struct cmd	CmdTab[] =
614549Seric {
624549Seric 	"mail",		CMDMAIL,
634976Seric 	"rcpt",		CMDRCPT,
644549Seric 	"data",		CMDDATA,
654549Seric 	"rset",		CMDRSET,
664549Seric 	"vrfy",		CMDVRFY,
677762Seric 	"expn",		CMDVRFY,
684549Seric 	"help",		CMDHELP,
694549Seric 	"noop",		CMDNOOP,
704549Seric 	"quit",		CMDQUIT,
714976Seric 	"helo",		CMDHELO,
728544Seric 	"verb",		CMDVERB,
739314Seric 	"onex",		CMDONEX,
745003Seric # ifdef DEBUG
759339Seric 	"showq",	CMDDBGQSHOW,
768544Seric 	"debug",	CMDDBGDEBUG,
778544Seric 	"kill",		CMDDBGKILL,
788544Seric 	"wiz",		CMDDBGWIZ,
795003Seric # endif DEBUG
804549Seric 	NULL,		CMDERROR,
814549Seric };
824549Seric 
838544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
8415596Seric char	*WizWord;			/* the wizard word to compare against */
859339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
869378Seric bool	OneXact = FALSE;		/* one xaction only this run */
8711146Seric char	*RealHostName = NULL;		/* verified hostname, set in daemon.c */
8811146Seric 
899339Seric #define EX_QUIT		22		/* special code for QUIT command */
908544Seric 
914549Seric smtp()
924549Seric {
934549Seric 	register char *p;
948544Seric 	register struct cmd *c;
954549Seric 	char *cmd;
964549Seric 	extern char *skipword();
974549Seric 	extern bool sameword();
984549Seric 	bool hasmail;			/* mail command received */
994713Seric 	int rcps;			/* number of recipients */
1005003Seric 	auto ADDRESS *vrfyqueue;
10112612Seric 	ADDRESS *a;
1028544Seric 	char inp[MAXLINE];
1037124Seric 	extern char Version[];
1047356Seric 	extern tick();
1058544Seric 	extern bool iswiz();
1069349Seric 	extern char *arpadate();
10711151Seric 	extern char *macvalue();
10812612Seric 	extern ADDRESS *recipient();
1094549Seric 
1105003Seric 	hasmail = FALSE;
1114713Seric 	rcps = 0;
1127363Seric 	if (OutChannel != stdout)
1137363Seric 	{
1147363Seric 		/* arrange for debugging output to go to remote host */
1157363Seric 		(void) close(1);
1167363Seric 		(void) dup(fileno(OutChannel));
1177363Seric 	}
11811931Seric 	settime();
11916153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
12010708Seric 	message("220", inp);
1214549Seric 	for (;;)
1224549Seric 	{
12312612Seric 		/* arrange for backout */
12412612Seric 		if (setjmp(TopFrame) > 0 && InChild)
12512612Seric 			finis();
12612612Seric 		QuickAbort = FALSE;
12712612Seric 		HoldErrs = FALSE;
12812612Seric 
1297356Seric 		/* setup for the read */
1306907Seric 		CurEnv->e_to = NULL;
1314577Seric 		Errors = 0;
1327275Seric 		(void) fflush(stdout);
1337356Seric 
1347356Seric 		/* read the input line */
1357685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1367356Seric 
1377685Seric 		/* handle errors */
1387356Seric 		if (p == NULL)
1397356Seric 		{
1404549Seric 			/* end of file, just die */
1414558Seric 			message("421", "%s Lost input channel", HostName);
1424549Seric 			finis();
1434549Seric 		}
1444549Seric 
1454549Seric 		/* clean up end of line */
1464558Seric 		fixcrlf(inp, TRUE);
1474549Seric 
1484713Seric 		/* echo command to transcript */
1499545Seric 		if (CurEnv->e_xfp != NULL)
1509545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1514713Seric 
1524549Seric 		/* break off command */
1534549Seric 		for (p = inp; isspace(*p); p++)
1544549Seric 			continue;
1554549Seric 		cmd = p;
1564549Seric 		while (*++p != '\0' && !isspace(*p))
1574549Seric 			continue;
1584549Seric 		if (*p != '\0')
1594549Seric 			*p++ = '\0';
1604549Seric 
1614549Seric 		/* decode command */
1624549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1634549Seric 		{
1644549Seric 			if (sameword(c->cmdname, cmd))
1654549Seric 				break;
1664549Seric 		}
1674549Seric 
1684549Seric 		/* process command */
1694549Seric 		switch (c->cmdcode)
1704549Seric 		{
1714976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
17214877Seric 			if (sameword(p, HostName))
17314877Seric 			{
17414877Seric 				/* connected to an echo server */
17514877Seric 				message("553", "%s I refuse to talk to myself",
17614877Seric 					HostName);
17714877Seric 				break;
17814877Seric 			}
17911146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
18011146Seric 			{
18111146Seric 				char buf[MAXNAME];
18211146Seric 
18311146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
18411146Seric 				define('s', newstr(buf), CurEnv);
18511146Seric 			}
18611146Seric 			else
18711146Seric 				define('s', newstr(p), CurEnv);
1884997Seric 			message("250", "%s Hello %s, pleased to meet you",
1894997Seric 				HostName, p);
1904976Seric 			break;
1914976Seric 
1924549Seric 		  case CMDMAIL:		/* mail -- designate sender */
19311151Seric 			/* force a sending host even if no HELO given */
19411151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
19511151Seric 				define('s', RealHostName, CurEnv);
19611151Seric 
1979314Seric 			/* check for validity of this command */
1984558Seric 			if (hasmail)
1994558Seric 			{
2004558Seric 				message("503", "Sender already specified");
2014558Seric 				break;
2024558Seric 			}
2039339Seric 			if (InChild)
2049339Seric 			{
2059339Seric 				syserr("Nested MAIL command");
2069339Seric 				exit(0);
2079339Seric 			}
2089339Seric 
2099339Seric 			/* fork a subprocess to process this command */
2109339Seric 			if (runinchild("SMTP-MAIL") > 0)
2119339Seric 				break;
2129339Seric 			initsys();
2139339Seric 
2149339Seric 			/* child -- go do the processing */
2154549Seric 			p = skipword(p, "from");
2164549Seric 			if (p == NULL)
2174549Seric 				break;
2184549Seric 			setsender(p);
2194577Seric 			if (Errors == 0)
2204549Seric 			{
2214549Seric 				message("250", "Sender ok");
2224549Seric 				hasmail = TRUE;
2234549Seric 			}
2249339Seric 			else if (InChild)
2259339Seric 				finis();
2264549Seric 			break;
2274549Seric 
2284976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
22912612Seric 			if (setjmp(TopFrame) > 0)
23014785Seric 			{
23114785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
23212612Seric 				break;
23314785Seric 			}
23412612Seric 			QuickAbort = TRUE;
2354549Seric 			p = skipword(p, "to");
2364549Seric 			if (p == NULL)
2374549Seric 				break;
23816140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
23912612Seric 			if (a == NULL)
24012612Seric 				break;
24116886Seric 			a->q_flags |= QPRIMARY;
24212612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
24312612Seric 			if (Errors != 0)
24412612Seric 				break;
24512612Seric 
24612612Seric 			/* no errors during parsing, but might be a duplicate */
24712612Seric 			CurEnv->e_to = p;
24812612Seric 			if (!bitset(QBADADDR, a->q_flags))
24912612Seric 				message("250", "Recipient ok");
25012612Seric 			else
2514549Seric 			{
25212612Seric 				/* punt -- should keep message in ADDRESS.... */
25312612Seric 				message("550", "Addressee unknown");
2544549Seric 			}
25512612Seric 			CurEnv->e_to = NULL;
25612612Seric 			rcps++;
2574549Seric 			break;
2584549Seric 
2594549Seric 		  case CMDDATA:		/* data -- text of mail */
2604976Seric 			if (!hasmail)
2614549Seric 			{
2624976Seric 				message("503", "Need MAIL command");
2634976Seric 				break;
2644549Seric 			}
2654713Seric 			else if (rcps <= 0)
2664549Seric 			{
2674976Seric 				message("503", "Need RCPT (recipient)");
2684976Seric 				break;
2694549Seric 			}
2704976Seric 
2714976Seric 			/* collect the text of the message */
2724976Seric 			collect(TRUE);
2734976Seric 			if (Errors != 0)
2744976Seric 				break;
2754976Seric 
2768238Seric 			/*
2778238Seric 			**  Arrange to send to everyone.
2788238Seric 			**	If sending to multiple people, mail back
2798238Seric 			**		errors rather than reporting directly.
2808238Seric 			**	In any case, don't mail back errors for
2818238Seric 			**		anything that has happened up to
2828238Seric 			**		now (the other end will do this).
28310197Seric 			**	Truncate our transcript -- the mail has gotten
28410197Seric 			**		to us successfully, and if we have
28510197Seric 			**		to mail this back, it will be easier
28610197Seric 			**		on the reader.
2878238Seric 			**	Then send to everyone.
2888238Seric 			**	Finally give a reply code.  If an error has
2898238Seric 			**		already been given, don't mail a
2908238Seric 			**		message back.
2919339Seric 			**	We goose error returns by clearing error bit.
2928238Seric 			*/
2938238Seric 
2944976Seric 			if (rcps != 1)
2959378Seric 			{
2969378Seric 				HoldErrs = TRUE;
29716886Seric 				ErrorMode = EM_MAIL;
2989378Seric 			}
2999339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
30010197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3014976Seric 
3024976Seric 			/* send to all recipients */
30314877Seric 			sendall(CurEnv, SM_DEFAULT);
3046907Seric 			CurEnv->e_to = NULL;
3054976Seric 
3068238Seric 			/* issue success if appropriate and reset */
3078238Seric 			if (Errors == 0 || HoldErrs)
3089283Seric 				message("250", "Ok");
3098238Seric 			else
3109339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3119339Seric 
3129339Seric 			/* if in a child, pop back to our parent */
3139339Seric 			if (InChild)
3149339Seric 				finis();
3154549Seric 			break;
3164549Seric 
3174549Seric 		  case CMDRSET:		/* rset -- reset state */
3184549Seric 			message("250", "Reset state");
3199339Seric 			if (InChild)
3209339Seric 				finis();
3219339Seric 			break;
3224549Seric 
3234549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3249339Seric 			if (runinchild("SMTP-VRFY") > 0)
3259339Seric 				break;
3265003Seric 			vrfyqueue = NULL;
3277762Seric 			QuickAbort = TRUE;
3289619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3297762Seric 			if (Errors != 0)
3309339Seric 			{
3319339Seric 				if (InChild)
3329339Seric 					finis();
3337762Seric 				break;
3349339Seric 			}
3355003Seric 			while (vrfyqueue != NULL)
3365003Seric 			{
3375003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3385003Seric 				char *code;
3395003Seric 
3407685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3415003Seric 					a = a->q_next;
3425003Seric 
3437685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3445003Seric 				{
3455003Seric 					if (a != NULL)
3465003Seric 						code = "250-";
3475003Seric 					else
3485003Seric 						code = "250";
3495003Seric 					if (vrfyqueue->q_fullname == NULL)
3505003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3515003Seric 					else
3525003Seric 						message(code, "%s <%s>",
3535003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3545003Seric 				}
3555003Seric 				else if (a == NULL)
3565003Seric 					message("554", "Self destructive alias loop");
3575003Seric 				vrfyqueue = a;
3585003Seric 			}
3599339Seric 			if (InChild)
3609339Seric 				finis();
3614549Seric 			break;
3624549Seric 
3634549Seric 		  case CMDHELP:		/* help -- give user info */
3644577Seric 			if (*p == '\0')
3654577Seric 				p = "SMTP";
3664577Seric 			help(p);
3674549Seric 			break;
3684549Seric 
3694549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3704549Seric 			message("200", "OK");
3714549Seric 			break;
3724549Seric 
3734549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3744549Seric 			message("221", "%s closing connection", HostName);
3759339Seric 			if (InChild)
3769339Seric 				ExitStat = EX_QUIT;
3774549Seric 			finis();
3784549Seric 
3798544Seric 		  case CMDVERB:		/* set verbose mode */
3808544Seric 			Verbose = TRUE;
3818544Seric 			message("200", "Verbose mode");
3828544Seric 			break;
3838544Seric 
3849314Seric 		  case CMDONEX:		/* doing one transaction only */
3859378Seric 			OneXact = TRUE;
3869314Seric 			message("200", "Only one transaction");
3879314Seric 			break;
3889314Seric 
3895003Seric # ifdef DEBUG
3909339Seric 		  case CMDDBGQSHOW:	/* show queues */
3916907Seric 			printf("Send Queue=");
3926907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3935003Seric 			break;
3947275Seric 
3957275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3967676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3977676Seric 			tTflag(p);
3987676Seric 			message("200", "Debug set");
3997275Seric 			break;
4007275Seric 
4017282Seric 		  case CMDDBGKILL:	/* kill the parent */
4028544Seric 			if (!iswiz())
4038544Seric 				break;
4047282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4057282Seric 				message("200", "Mother is dead");
4067282Seric 			else
4077282Seric 				message("500", "Can't kill Mom");
4087282Seric 			break;
4098544Seric 
4108544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4118544Seric 			if (WizWord != NULL)
4128544Seric 			{
4138544Seric 				char seed[3];
4148544Seric 				extern char *crypt();
4158544Seric 
416*23106Seric 				(void) strncpy(seed, WizWord, 2);
41715596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4188544Seric 				{
41915596Seric 					IsWiz = TRUE;
42015596Seric 					message("200", "Please pass, oh mighty wizard");
4218544Seric 					break;
4228544Seric 				}
4238544Seric 			}
42415596Seric 			message("500", "You are no wizard!");
4258544Seric 			break;
4265003Seric # endif DEBUG
4275003Seric 
4284549Seric 		  case CMDERROR:	/* unknown command */
4294549Seric 			message("500", "Command unrecognized");
4304549Seric 			break;
4314549Seric 
4324549Seric 		  default:
4334549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4344549Seric 			break;
4354549Seric 		}
4364549Seric 	}
4374549Seric }
4384549Seric /*
4394549Seric **  SKIPWORD -- skip a fixed word.
4404549Seric **
4414549Seric **	Parameters:
4424549Seric **		p -- place to start looking.
4434549Seric **		w -- word to skip.
4444549Seric **
4454549Seric **	Returns:
4464549Seric **		p following w.
4474549Seric **		NULL on error.
4484549Seric **
4494549Seric **	Side Effects:
4504549Seric **		clobbers the p data area.
4514549Seric */
4524549Seric 
4534549Seric static char *
4544549Seric skipword(p, w)
4554549Seric 	register char *p;
4564549Seric 	char *w;
4574549Seric {
4584549Seric 	register char *q;
4594549Seric 	extern bool sameword();
4604549Seric 
4614549Seric 	/* find beginning of word */
4624549Seric 	while (isspace(*p))
4634549Seric 		p++;
4644549Seric 	q = p;
4654549Seric 
4664549Seric 	/* find end of word */
4674549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4684549Seric 		p++;
4694549Seric 	while (isspace(*p))
4704549Seric 		*p++ = '\0';
4714549Seric 	if (*p != ':')
4724549Seric 	{
4734549Seric 	  syntax:
4744549Seric 		message("501", "Syntax error");
4754549Seric 		Errors++;
4764549Seric 		return (NULL);
4774549Seric 	}
4784549Seric 	*p++ = '\0';
4794549Seric 	while (isspace(*p))
4804549Seric 		p++;
4814549Seric 
4824549Seric 	/* see if the input word matches desired word */
4834549Seric 	if (!sameword(q, w))
4844549Seric 		goto syntax;
4854549Seric 
4864549Seric 	return (p);
4874549Seric }
4884577Seric /*
4894577Seric **  HELP -- implement the HELP command.
4904577Seric **
4914577Seric **	Parameters:
4924577Seric **		topic -- the topic we want help for.
4934577Seric **
4944577Seric **	Returns:
4954577Seric **		none.
4964577Seric **
4974577Seric **	Side Effects:
4984577Seric **		outputs the help file to message output.
4994577Seric */
5004577Seric 
5014577Seric help(topic)
5024577Seric 	char *topic;
5034577Seric {
5044577Seric 	register FILE *hf;
5054577Seric 	int len;
5064577Seric 	char buf[MAXLINE];
5074577Seric 	bool noinfo;
5084577Seric 
5098269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5104577Seric 	{
5114577Seric 		/* no help */
51211931Seric 		errno = 0;
5134577Seric 		message("502", "HELP not implemented");
5144577Seric 		return;
5154577Seric 	}
5164577Seric 
5174577Seric 	len = strlen(topic);
5184577Seric 	makelower(topic);
5194577Seric 	noinfo = TRUE;
5204577Seric 
5214577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5224577Seric 	{
5234577Seric 		if (strncmp(buf, topic, len) == 0)
5244577Seric 		{
5254577Seric 			register char *p;
5264577Seric 
5274577Seric 			p = index(buf, '\t');
5284577Seric 			if (p == NULL)
5294577Seric 				p = buf;
5304577Seric 			else
5314577Seric 				p++;
5324577Seric 			fixcrlf(p, TRUE);
5334577Seric 			message("214-", p);
5344577Seric 			noinfo = FALSE;
5354577Seric 		}
5364577Seric 	}
5374577Seric 
5384577Seric 	if (noinfo)
5394577Seric 		message("504", "HELP topic unknown");
5404577Seric 	else
5414577Seric 		message("214", "End of HELP info");
5424628Seric 	(void) fclose(hf);
5434577Seric }
5448544Seric /*
5458544Seric **  ISWIZ -- tell us if we are a wizard
5468544Seric **
5478544Seric **	If not, print a nasty message.
5488544Seric **
5498544Seric **	Parameters:
5508544Seric **		none.
5518544Seric **
5528544Seric **	Returns:
5538544Seric **		TRUE if we are a wizard.
5548544Seric **		FALSE if we are not a wizard.
5558544Seric **
5568544Seric **	Side Effects:
5578544Seric **		Prints a 500 exit stat if we are not a wizard.
5588544Seric */
5595181Seric 
56019038Seric #ifdef DEBUG
56119038Seric 
5628544Seric bool
5638544Seric iswiz()
5648544Seric {
5658544Seric 	if (!IsWiz)
5668544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5678544Seric 	return (IsWiz);
5688544Seric }
56919038Seric 
57019038Seric #endif DEBUG
5719339Seric /*
5729339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5739339Seric **
5749339Seric **	Parameters:
5759339Seric **		label -- a string used in error messages
5769339Seric **
5779339Seric **	Returns:
5789339Seric **		zero in the child
5799339Seric **		one in the parent
5809339Seric **
5819339Seric **	Side Effects:
5829339Seric **		none.
5839339Seric */
5848544Seric 
5859339Seric runinchild(label)
5869339Seric 	char *label;
5879339Seric {
5889339Seric 	int childpid;
5899339Seric 
59016158Seric 	if (!OneXact)
5919339Seric 	{
59216158Seric 		childpid = dofork();
59316158Seric 		if (childpid < 0)
59416158Seric 		{
59516158Seric 			syserr("%s: cannot fork", label);
59616158Seric 			return (1);
59716158Seric 		}
59816158Seric 		if (childpid > 0)
59916158Seric 		{
60016158Seric 			auto int st;
6019339Seric 
60216158Seric 			/* parent -- wait for child to complete */
60316158Seric 			st = waitfor(childpid);
60416158Seric 			if (st == -1)
60516158Seric 				syserr("%s: lost child", label);
6069339Seric 
60716158Seric 			/* if we exited on a QUIT command, complete the process */
60816158Seric 			if (st == (EX_QUIT << 8))
60916158Seric 				finis();
6109339Seric 
61116158Seric 			return (1);
61216158Seric 		}
61316158Seric 		else
61416158Seric 		{
61516158Seric 			/* child */
61616158Seric 			InChild = TRUE;
61716158Seric 		}
6189339Seric 	}
61915256Seric 
62016158Seric 	/* child (or ONEX command specified) */
62116158Seric 	clearenvelope(CurEnv);
62215256Seric 
62316158Seric 	/* open alias database */
62416158Seric 	initaliases(AliasFile, FALSE);
62516158Seric 
62616158Seric 	return (0);
6279339Seric }
6289339Seric 
6295181Seric # endif SMTP
630